We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Issue terminal chat service
Hello,

First of all thank you for this amazing framework.
I was trying to run the terminal chat example (code from today without changes except port).

It seems that there are only 'max_worker' clients possible to connect in total. For example when I set max_worker=1 in the config.yml, I can connect with the client one time successfully. But when I stop the client ('[DONE]'), start it again and it gets stuck right at the beginning.

How can I prevent the server from getting stuck once >max_workers clients have been connected? I already tried removing the agent from memory, however it seems that the issue is that the thread is just not ending.

![image](https://user-images.githubusercontent.com/32954413/107663358-94f0e000-6c8b-11eb-8cd3-97fd1806197a.png)

I use Python 3.7.5 and Ubuntu 18.04 LTS.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `parlai/chat_service/services/terminal_chat/client.py`
Content:
```
1 #!/usr/bin/env python3
2 
3 # Copyright (c) Facebook, Inc. and its affiliates.
4 # This source code is licensed under the MIT license found in the
5 # LICENSE file in the root directory of this source tree.
6 
7 import json
8 import uuid
9 import websocket
10 import time
11 import threading
12 from parlai.core.params import ParlaiParser
13 
14 
15 def _get_rand_id():
16     """
17     :return: The string of a random id using uuid4
18     """
19     return str(uuid.uuid4())
20 
21 
22 def _prBlueBG(text):
23     """
24     Print given in text with a blue background.
25 
26     :param text: The text to be printed
27     """
28     print("\033[44m{}\033[0m".format(text), sep="")
29 
30 
31 def on_message(ws, message):
32     """
33     Prints the incoming message from the server.
34 
35     :param ws: a WebSocketApp
36     :param message: json with 'text' field to be printed
37     """
38     incoming_message = json.loads(message)
39     print("\033[0m\n")
40     print("Bot: " + incoming_message['text'])
41     quick_replies = incoming_message.get('quick_replies')
42     if quick_replies is not None and len(quick_replies) > 0:
43         print(f"\nOptions: [{'|'.join(quick_replies)}]")
44     print("\033[44m\n")
45 
46 
47 def on_error(ws, error):
48     """
49     Prints an error, if occurs.
50 
51     :param ws: WebSocketApp
52     :param error: An error
53     """
54     print(error)
55 
56 
57 def on_close(ws):
58     """
59     Cleanup before closing connection.
60 
61     :param ws: WebSocketApp
62     """
63     # Reset color formatting if necessary
64     print("\033[0m")
65     print("Connection closed")
66 
67 
68 def _run(ws, id):
69     """
70     Takes user input and sends it to a websocket.
71 
72     :param ws: websocket.WebSocketApp
73     """
74     while True:
75         x = input("\033[44m Me: ")
76         print("\033[0m", end="")
77         data = {}
78         data['id'] = id
79         data['text'] = x
80         json_data = json.dumps(data)
81         ws.send(json_data)
82         time.sleep(1)
83         if x == "[DONE]":
84             break
85     ws.close()
86 
87 
88 def on_open(ws):
89     """
90     Starts a new thread that loops, taking user input and sending it to the websocket.
91 
92     :param ws: websocket.WebSocketApp that sends messages to a terminal_manager
93     """
94     id = _get_rand_id()
95     threading.Thread(target=_run, args=(ws, id)).start()
96 
97 
98 def setup_args():
99     """
100     Set up args, specifically for the port number.
101 
102     :return: A parser that parses the port from commandline arguments.
103     """
104     parser = ParlaiParser(False, False)
105     parser_grp = parser.add_argument_group('Terminal Chat')
106     parser_grp.add_argument(
107         '--port', default=35496, type=int, help='Port to run the terminal chat server'
108     )
109     return parser.parse_args()
110 
111 
112 if __name__ == "__main__":
113     opt = setup_args()
114     port = opt.get('port', 34596)
115     print("Connecting to port: ", port)
116     ws = websocket.WebSocketApp(
117         "ws://localhost:{}/websocket".format(port),
118         on_message=on_message,
119         on_error=on_error,
120         on_close=on_close,
121     )
122     ws.on_open = on_open
123     ws.run_forever()
124
```

Path: `parlai/chat_service/tasks/chatbot/worlds.py`
Content:
```
1 #!/usr/bin/env python3
2 
3 # Copyright (c) Facebook, Inc. and its affiliates.
4 # This source code is licensed under the MIT license found in the
5 # LICENSE file in the root directory of this source tree.
6 #
7 # py parlai/chat_service/tasks/overworld_demo/run.py --debug --verbose
8 
9 from parlai.core.worlds import World
10 from parlai.chat_service.services.messenger.worlds import OnboardWorld
11 from parlai.core.agents import create_agent_from_shared
12 
13 
14 # ---------- Chatbot demo ---------- #
15 class MessengerBotChatOnboardWorld(OnboardWorld):
16     """
17     Example messenger onboarding world for Chatbot Model.
18     """
19 
20     @staticmethod
21     def generate_world(opt, agents):
22         return MessengerBotChatOnboardWorld(opt=opt, agent=agents[0])
23 
24     def parley(self):
25         self.episodeDone = True
26 
27 
28 class MessengerBotChatTaskWorld(World):
29     """
30     Example one person world that talks to a provided agent (bot).
31     """
32 
33     MAX_AGENTS = 1
34     MODEL_KEY = 'blender_90M'
35 
36     def __init__(self, opt, agent, bot):
37         self.agent = agent
38         self.episodeDone = False
39         self.model = bot
40         self.first_time = True
41 
42     @staticmethod
43     def generate_world(opt, agents):
44         if opt['models'] is None:
45             raise RuntimeError("Model must be specified")
46         return MessengerBotChatTaskWorld(
47             opt,
48             agents[0],
49             create_agent_from_shared(
50                 opt['shared_bot_params'][MessengerBotChatTaskWorld.MODEL_KEY]
51             ),
52         )
53 
54     @staticmethod
55     def assign_roles(agents):
56         agents[0].disp_id = 'ChatbotAgent'
57 
58     def parley(self):
59         if self.first_time:
60             self.agent.observe(
61                 {
62                     'id': 'World',
63                     'text': 'Welcome to the ParlAI Chatbot demo. '
64                     'You are now paired with a bot - feel free to send a message.'
65                     'Type [DONE] to finish the chat, or [RESET] to reset the dialogue history.',
66                 }
67             )
68             self.first_time = False
69         a = self.agent.act()
70         if a is not None:
71             if '[DONE]' in a['text']:
72                 self.episodeDone = True
73             elif '[RESET]' in a['text']:
74                 self.model.reset()
75                 self.agent.observe({"text": "[History Cleared]", "episode_done": False})
76             else:
77                 print("===act====")
78                 print(a)
79                 print("~~~~~~~~~~~")
80                 self.model.observe(a)
81                 response = self.model.act()
82                 print("===response====")
83                 print(response)
84                 print("~~~~~~~~~~~")
85                 self.agent.observe(response)
86 
87     def episode_done(self):
88         return self.episodeDone
89 
90     def shutdown(self):
91         self.agent.shutdown()
92 
93 
94 # ---------- Overworld -------- #
95 class MessengerOverworld(World):
96     """
97     World to handle moving agents to their proper places.
98     """
99 
100     def __init__(self, opt, agent):
101         self.agent = agent
102         self.opt = opt
103         self.first_time = True
104         self.episodeDone = False
105 
106     @staticmethod
107     def generate_world(opt, agents):
108         return MessengerOverworld(opt, agents[0])
109 
110     @staticmethod
111     def assign_roles(agents):
112         for a in agents:
113             a.disp_id = 'Agent'
114 
115     def episode_done(self):
116         return self.episodeDone
117 
118     def parley(self):
119         if self.first_time:
120             self.agent.observe(
121                 {
122                     'id': 'Overworld',
123                     'text': 'Welcome to the overworld for the ParlAI messenger '
124                     'chatbot demo. Please type "begin" to start.',
125                     'quick_replies': ['begin'],
126                 }
127             )
128             self.first_time = False
129         a = self.agent.act()
130         if a is not None and a['text'].lower() == 'begin':
131             self.episodeDone = True
132             return 'default'
133         elif a is not None:
134             self.agent.observe(
135                 {
136                     'id': 'Overworld',
137                     'text': 'Invalid option. Please type "begin".',
138                     'quick_replies': ['begin'],
139                 }
140             )
141
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/parlai/chat_service/services/terminal_chat/client.py b/parlai/chat_service/services/terminal_chat/client.py
--- a/parlai/chat_service/services/terminal_chat/client.py
+++ b/parlai/chat_service/services/terminal_chat/client.py
@@ -11,6 +11,13 @@
 import threading
 from parlai.core.params import ParlaiParser
 
+# the socket callback functions operate asynchronously.
+# upon exit of a chat, we do not want the user to view any additional messages from the server.
+# alas, it is necessary to send two messages ([DONE], and EXIT) in order to fully exist the world pool
+# to prevent receiving a message after sending [DONE], we track the user's state with
+# this global variable.
+RUNNING = True
+
 
 def _get_rand_id():
     """
@@ -35,6 +42,8 @@
     :param ws: a WebSocketApp
     :param message: json with 'text' field to be printed
     """
+    if not RUNNING:
+        return
     incoming_message = json.loads(message)
     print("\033[0m\n")
     print("Bot: " + incoming_message['text'])
@@ -71,16 +80,22 @@
 
     :param ws: websocket.WebSocketApp
     """
+    global RUNNING
     while True:
         x = input("\033[44m Me: ")
         print("\033[0m", end="")
         data = {}
         data['id'] = id
         data['text'] = x
+        if x == "[DONE]":
+            RUNNING = False
         json_data = json.dumps(data)
         ws.send(json_data)
         time.sleep(1)
         if x == "[DONE]":
+            time.sleep(1)
+            data['text'] = 'EXIT'
+            ws.send(json.dumps(data))
             break
     ws.close()
 
diff --git a/parlai/chat_service/tasks/chatbot/worlds.py b/parlai/chat_service/tasks/chatbot/worlds.py
--- a/parlai/chat_service/tasks/chatbot/worlds.py
+++ b/parlai/chat_service/tasks/chatbot/worlds.py
@@ -121,12 +121,15 @@
                 {
                     'id': 'Overworld',
                     'text': 'Welcome to the overworld for the ParlAI messenger '
-                    'chatbot demo. Please type "begin" to start.',
-                    'quick_replies': ['begin'],
+                    'chatbot demo. Please type "begin" to start, or "exit" to exit',
+                    'quick_replies': ['begin', 'exit'],
                 }
             )
             self.first_time = False
         a = self.agent.act()
+        if a is not None and a['text'].lower() == 'exit':
+            self.episode_done = True
+            return 'EXIT'
         if a is not None and a['text'].lower() == 'begin':
             self.episodeDone = True
             return 'default'

{"golden_diff": "diff --git a/parlai/chat_service/services/terminal_chat/client.py b/parlai/chat_service/services/terminal_chat/client.py\n--- a/parlai/chat_service/services/terminal_chat/client.py\n+++ b/parlai/chat_service/services/terminal_chat/client.py\n@@ -11,6 +11,13 @@\n import threading\n from parlai.core.params import ParlaiParser\n \n+# the socket callback functions operate asynchronously.\n+# upon exit of a chat, we do not want the user to view any additional messages from the server.\n+# alas, it is necessary to send two messages ([DONE], and EXIT) in order to fully exist the world pool\n+# to prevent receiving a message after sending [DONE], we track the user's state with\n+# this global variable.\n+RUNNING = True\n+\n \n def _get_rand_id():\n     \"\"\"\n@@ -35,6 +42,8 @@\n     :param ws: a WebSocketApp\n     :param message: json with 'text' field to be printed\n     \"\"\"\n+    if not RUNNING:\n+        return\n     incoming_message = json.loads(message)\n     print(\"\\033[0m\\n\")\n     print(\"Bot: \" + incoming_message['text'])\n@@ -71,16 +80,22 @@\n \n     :param ws: websocket.WebSocketApp\n     \"\"\"\n+    global RUNNING\n     while True:\n         x = input(\"\\033[44m Me: \")\n         print(\"\\033[0m\", end=\"\")\n         data = {}\n         data['id'] = id\n         data['text'] = x\n+        if x == \"[DONE]\":\n+            RUNNING = False\n         json_data = json.dumps(data)\n         ws.send(json_data)\n         time.sleep(1)\n         if x == \"[DONE]\":\n+            time.sleep(1)\n+            data['text'] = 'EXIT'\n+            ws.send(json.dumps(data))\n             break\n     ws.close()\n \ndiff --git a/parlai/chat_service/tasks/chatbot/worlds.py b/parlai/chat_service/tasks/chatbot/worlds.py\n--- a/parlai/chat_service/tasks/chatbot/worlds.py\n+++ b/parlai/chat_service/tasks/chatbot/worlds.py\n@@ -121,12 +121,15 @@\n                 {\n                     'id': 'Overworld',\n                     'text': 'Welcome to the overworld for the ParlAI messenger '\n-                    'chatbot demo. Please type \"begin\" to start.',\n-                    'quick_replies': ['begin'],\n+                    'chatbot demo. Please type \"begin\" to start, or \"exit\" to exit',\n+                    'quick_replies': ['begin', 'exit'],\n                 }\n             )\n             self.first_time = False\n         a = self.agent.act()\n+        if a is not None and a['text'].lower() == 'exit':\n+            self.episode_done = True\n+            return 'EXIT'\n         if a is not None and a['text'].lower() == 'begin':\n             self.episodeDone = True\n             return 'default'\n", "issue": "Issue terminal chat service\nHello,\r\n\r\nFirst of all thank you for this amazing framework.\r\nI was trying to run the terminal chat example (code from today without changes except port).\r\n\r\nIt seems that there are only 'max_worker' clients possible to connect in total. For example when I set max_worker=1 in the config.yml, I can connect with the client one time successfully. But when I stop the client ('[DONE]'), start it again and it gets stuck right at the beginning.\r\n\r\nHow can I prevent the server from getting stuck once >max_workers clients have been connected? I already tried removing the agent from memory, however it seems that the issue is that the thread is just not ending.\r\n\r\n![image](https://user-images.githubusercontent.com/32954413/107663358-94f0e000-6c8b-11eb-8cd3-97fd1806197a.png)\r\n\r\nI use Python 3.7.5 and Ubuntu 18.04 LTS.\r\n\n", "before_files": [{"content": "#!/usr/bin/env python3\n\n# Copyright (c) Facebook, Inc. and its affiliates.\n# This source code is licensed under the MIT license found in the\n# LICENSE file in the root directory of this source tree.\n\nimport json\nimport uuid\nimport websocket\nimport time\nimport threading\nfrom parlai.core.params import ParlaiParser\n\n\ndef _get_rand_id():\n    \"\"\"\n    :return: The string of a random id using uuid4\n    \"\"\"\n    return str(uuid.uuid4())\n\n\ndef _prBlueBG(text):\n    \"\"\"\n    Print given in text with a blue background.\n\n    :param text: The text to be printed\n    \"\"\"\n    print(\"\\033[44m{}\\033[0m\".format(text), sep=\"\")\n\n\ndef on_message(ws, message):\n    \"\"\"\n    Prints the incoming message from the server.\n\n    :param ws: a WebSocketApp\n    :param message: json with 'text' field to be printed\n    \"\"\"\n    incoming_message = json.loads(message)\n    print(\"\\033[0m\\n\")\n    print(\"Bot: \" + incoming_message['text'])\n    quick_replies = incoming_message.get('quick_replies')\n    if quick_replies is not None and len(quick_replies) > 0:\n        print(f\"\\nOptions: [{'|'.join(quick_replies)}]\")\n    print(\"\\033[44m\\n\")\n\n\ndef on_error(ws, error):\n    \"\"\"\n    Prints an error, if occurs.\n\n    :param ws: WebSocketApp\n    :param error: An error\n    \"\"\"\n    print(error)\n\n\ndef on_close(ws):\n    \"\"\"\n    Cleanup before closing connection.\n\n    :param ws: WebSocketApp\n    \"\"\"\n    # Reset color formatting if necessary\n    print(\"\\033[0m\")\n    print(\"Connection closed\")\n\n\ndef _run(ws, id):\n    \"\"\"\n    Takes user input and sends it to a websocket.\n\n    :param ws: websocket.WebSocketApp\n    \"\"\"\n    while True:\n        x = input(\"\\033[44m Me: \")\n        print(\"\\033[0m\", end=\"\")\n        data = {}\n        data['id'] = id\n        data['text'] = x\n        json_data = json.dumps(data)\n        ws.send(json_data)\n        time.sleep(1)\n        if x == \"[DONE]\":\n            break\n    ws.close()\n\n\ndef on_open(ws):\n    \"\"\"\n    Starts a new thread that loops, taking user input and sending it to the websocket.\n\n    :param ws: websocket.WebSocketApp that sends messages to a terminal_manager\n    \"\"\"\n    id = _get_rand_id()\n    threading.Thread(target=_run, args=(ws, id)).start()\n\n\ndef setup_args():\n    \"\"\"\n    Set up args, specifically for the port number.\n\n    :return: A parser that parses the port from commandline arguments.\n    \"\"\"\n    parser = ParlaiParser(False, False)\n    parser_grp = parser.add_argument_group('Terminal Chat')\n    parser_grp.add_argument(\n        '--port', default=35496, type=int, help='Port to run the terminal chat server'\n    )\n    return parser.parse_args()\n\n\nif __name__ == \"__main__\":\n    opt = setup_args()\n    port = opt.get('port', 34596)\n    print(\"Connecting to port: \", port)\n    ws = websocket.WebSocketApp(\n        \"ws://localhost:{}/websocket\".format(port),\n        on_message=on_message,\n        on_error=on_error,\n        on_close=on_close,\n    )\n    ws.on_open = on_open\n    ws.run_forever()\n", "path": "parlai/chat_service/services/terminal_chat/client.py"}, {"content": "#!/usr/bin/env python3\n\n# Copyright (c) Facebook, Inc. and its affiliates.\n# This source code is licensed under the MIT license found in the\n# LICENSE file in the root directory of this source tree.\n#\n# py parlai/chat_service/tasks/overworld_demo/run.py --debug --verbose\n\nfrom parlai.core.worlds import World\nfrom parlai.chat_service.services.messenger.worlds import OnboardWorld\nfrom parlai.core.agents import create_agent_from_shared\n\n\n# ---------- Chatbot demo ---------- #\nclass MessengerBotChatOnboardWorld(OnboardWorld):\n    \"\"\"\n    Example messenger onboarding world for Chatbot Model.\n    \"\"\"\n\n    @staticmethod\n    def generate_world(opt, agents):\n        return MessengerBotChatOnboardWorld(opt=opt, agent=agents[0])\n\n    def parley(self):\n        self.episodeDone = True\n\n\nclass MessengerBotChatTaskWorld(World):\n    \"\"\"\n    Example one person world that talks to a provided agent (bot).\n    \"\"\"\n\n    MAX_AGENTS = 1\n    MODEL_KEY = 'blender_90M'\n\n    def __init__(self, opt, agent, bot):\n        self.agent = agent\n        self.episodeDone = False\n        self.model = bot\n        self.first_time = True\n\n    @staticmethod\n    def generate_world(opt, agents):\n        if opt['models'] is None:\n            raise RuntimeError(\"Model must be specified\")\n        return MessengerBotChatTaskWorld(\n            opt,\n            agents[0],\n            create_agent_from_shared(\n                opt['shared_bot_params'][MessengerBotChatTaskWorld.MODEL_KEY]\n            ),\n        )\n\n    @staticmethod\n    def assign_roles(agents):\n        agents[0].disp_id = 'ChatbotAgent'\n\n    def parley(self):\n        if self.first_time:\n            self.agent.observe(\n                {\n                    'id': 'World',\n                    'text': 'Welcome to the ParlAI Chatbot demo. '\n                    'You are now paired with a bot - feel free to send a message.'\n                    'Type [DONE] to finish the chat, or [RESET] to reset the dialogue history.',\n                }\n            )\n            self.first_time = False\n        a = self.agent.act()\n        if a is not None:\n            if '[DONE]' in a['text']:\n                self.episodeDone = True\n            elif '[RESET]' in a['text']:\n                self.model.reset()\n                self.agent.observe({\"text\": \"[History Cleared]\", \"episode_done\": False})\n            else:\n                print(\"===act====\")\n                print(a)\n                print(\"~~~~~~~~~~~\")\n                self.model.observe(a)\n                response = self.model.act()\n                print(\"===response====\")\n                print(response)\n                print(\"~~~~~~~~~~~\")\n                self.agent.observe(response)\n\n    def episode_done(self):\n        return self.episodeDone\n\n    def shutdown(self):\n        self.agent.shutdown()\n\n\n# ---------- Overworld -------- #\nclass MessengerOverworld(World):\n    \"\"\"\n    World to handle moving agents to their proper places.\n    \"\"\"\n\n    def __init__(self, opt, agent):\n        self.agent = agent\n        self.opt = opt\n        self.first_time = True\n        self.episodeDone = False\n\n    @staticmethod\n    def generate_world(opt, agents):\n        return MessengerOverworld(opt, agents[0])\n\n    @staticmethod\n    def assign_roles(agents):\n        for a in agents:\n            a.disp_id = 'Agent'\n\n    def episode_done(self):\n        return self.episodeDone\n\n    def parley(self):\n        if self.first_time:\n            self.agent.observe(\n                {\n                    'id': 'Overworld',\n                    'text': 'Welcome to the overworld for the ParlAI messenger '\n                    'chatbot demo. Please type \"begin\" to start.',\n                    'quick_replies': ['begin'],\n                }\n            )\n            self.first_time = False\n        a = self.agent.act()\n        if a is not None and a['text'].lower() == 'begin':\n            self.episodeDone = True\n            return 'default'\n        elif a is not None:\n            self.agent.observe(\n                {\n                    'id': 'Overworld',\n                    'text': 'Invalid option. Please type \"begin\".',\n                    'quick_replies': ['begin'],\n                }\n            )\n", "path": "parlai/chat_service/tasks/chatbot/worlds.py"}], "after_files": [{"content": "#!/usr/bin/env python3\n\n# Copyright (c) Facebook, Inc. and its affiliates.\n# This source code is licensed under the MIT license found in the\n# LICENSE file in the root directory of this source tree.\n\nimport json\nimport uuid\nimport websocket\nimport time\nimport threading\nfrom parlai.core.params import ParlaiParser\n\n# the socket callback functions operate asynchronously.\n# upon exit of a chat, we do not want the user to view any additional messages from the server.\n# alas, it is necessary to send two messages ([DONE], and EXIT) in order to fully exist the world pool\n# to prevent receiving a message after sending [DONE], we track the user's state with\n# this global variable.\nRUNNING = True\n\n\ndef _get_rand_id():\n    \"\"\"\n    :return: The string of a random id using uuid4\n    \"\"\"\n    return str(uuid.uuid4())\n\n\ndef _prBlueBG(text):\n    \"\"\"\n    Print given in text with a blue background.\n\n    :param text: The text to be printed\n    \"\"\"\n    print(\"\\033[44m{}\\033[0m\".format(text), sep=\"\")\n\n\ndef on_message(ws, message):\n    \"\"\"\n    Prints the incoming message from the server.\n\n    :param ws: a WebSocketApp\n    :param message: json with 'text' field to be printed\n    \"\"\"\n    if not RUNNING:\n        return\n    incoming_message = json.loads(message)\n    print(\"\\033[0m\\n\")\n    print(\"Bot: \" + incoming_message['text'])\n    quick_replies = incoming_message.get('quick_replies')\n    if quick_replies is not None and len(quick_replies) > 0:\n        print(f\"\\nOptions: [{'|'.join(quick_replies)}]\")\n    print(\"\\033[44m\\n\")\n\n\ndef on_error(ws, error):\n    \"\"\"\n    Prints an error, if occurs.\n\n    :param ws: WebSocketApp\n    :param error: An error\n    \"\"\"\n    print(error)\n\n\ndef on_close(ws):\n    \"\"\"\n    Cleanup before closing connection.\n\n    :param ws: WebSocketApp\n    \"\"\"\n    # Reset color formatting if necessary\n    print(\"\\033[0m\")\n    print(\"Connection closed\")\n\n\ndef _run(ws, id):\n    \"\"\"\n    Takes user input and sends it to a websocket.\n\n    :param ws: websocket.WebSocketApp\n    \"\"\"\n    global RUNNING\n    while True:\n        x = input(\"\\033[44m Me: \")\n        print(\"\\033[0m\", end=\"\")\n        data = {}\n        data['id'] = id\n        data['text'] = x\n        if x == \"[DONE]\":\n            RUNNING = False\n        json_data = json.dumps(data)\n        ws.send(json_data)\n        time.sleep(1)\n        if x == \"[DONE]\":\n            time.sleep(1)\n            data['text'] = 'EXIT'\n            ws.send(json.dumps(data))\n            break\n    ws.close()\n\n\ndef on_open(ws):\n    \"\"\"\n    Starts a new thread that loops, taking user input and sending it to the websocket.\n\n    :param ws: websocket.WebSocketApp that sends messages to a terminal_manager\n    \"\"\"\n    id = _get_rand_id()\n    threading.Thread(target=_run, args=(ws, id)).start()\n\n\ndef setup_args():\n    \"\"\"\n    Set up args, specifically for the port number.\n\n    :return: A parser that parses the port from commandline arguments.\n    \"\"\"\n    parser = ParlaiParser(False, False)\n    parser_grp = parser.add_argument_group('Terminal Chat')\n    parser_grp.add_argument(\n        '--port', default=35496, type=int, help='Port to run the terminal chat server'\n    )\n    return parser.parse_args()\n\n\nif __name__ == \"__main__\":\n    opt = setup_args()\n    port = opt.get('port', 34596)\n    print(\"Connecting to port: \", port)\n    ws = websocket.WebSocketApp(\n        \"ws://localhost:{}/websocket\".format(port),\n        on_message=on_message,\n        on_error=on_error,\n        on_close=on_close,\n    )\n    ws.on_open = on_open\n    ws.run_forever()\n", "path": "parlai/chat_service/services/terminal_chat/client.py"}, {"content": "#!/usr/bin/env python3\n\n# Copyright (c) Facebook, Inc. and its affiliates.\n# This source code is licensed under the MIT license found in the\n# LICENSE file in the root directory of this source tree.\n#\n# py parlai/chat_service/tasks/overworld_demo/run.py --debug --verbose\n\nfrom parlai.core.worlds import World\nfrom parlai.chat_service.services.messenger.worlds import OnboardWorld\nfrom parlai.core.agents import create_agent_from_shared\n\n\n# ---------- Chatbot demo ---------- #\nclass MessengerBotChatOnboardWorld(OnboardWorld):\n    \"\"\"\n    Example messenger onboarding world for Chatbot Model.\n    \"\"\"\n\n    @staticmethod\n    def generate_world(opt, agents):\n        return MessengerBotChatOnboardWorld(opt=opt, agent=agents[0])\n\n    def parley(self):\n        self.episodeDone = True\n\n\nclass MessengerBotChatTaskWorld(World):\n    \"\"\"\n    Example one person world that talks to a provided agent (bot).\n    \"\"\"\n\n    MAX_AGENTS = 1\n    MODEL_KEY = 'blender_90M'\n\n    def __init__(self, opt, agent, bot):\n        self.agent = agent\n        self.episodeDone = False\n        self.model = bot\n        self.first_time = True\n\n    @staticmethod\n    def generate_world(opt, agents):\n        if opt['models'] is None:\n            raise RuntimeError(\"Model must be specified\")\n        return MessengerBotChatTaskWorld(\n            opt,\n            agents[0],\n            create_agent_from_shared(\n                opt['shared_bot_params'][MessengerBotChatTaskWorld.MODEL_KEY]\n            ),\n        )\n\n    @staticmethod\n    def assign_roles(agents):\n        agents[0].disp_id = 'ChatbotAgent'\n\n    def parley(self):\n        if self.first_time:\n            self.agent.observe(\n                {\n                    'id': 'World',\n                    'text': 'Welcome to the ParlAI Chatbot demo. '\n                    'You are now paired with a bot - feel free to send a message.'\n                    'Type [DONE] to finish the chat, or [RESET] to reset the dialogue history.',\n                }\n            )\n            self.first_time = False\n        a = self.agent.act()\n        if a is not None:\n            if '[DONE]' in a['text']:\n                self.episodeDone = True\n            elif '[RESET]' in a['text']:\n                self.model.reset()\n                self.agent.observe({\"text\": \"[History Cleared]\", \"episode_done\": False})\n            else:\n                print(\"===act====\")\n                print(a)\n                print(\"~~~~~~~~~~~\")\n                self.model.observe(a)\n                response = self.model.act()\n                print(\"===response====\")\n                print(response)\n                print(\"~~~~~~~~~~~\")\n                self.agent.observe(response)\n\n    def episode_done(self):\n        return self.episodeDone\n\n    def shutdown(self):\n        self.agent.shutdown()\n\n\n# ---------- Overworld -------- #\nclass MessengerOverworld(World):\n    \"\"\"\n    World to handle moving agents to their proper places.\n    \"\"\"\n\n    def __init__(self, opt, agent):\n        self.agent = agent\n        self.opt = opt\n        self.first_time = True\n        self.episodeDone = False\n\n    @staticmethod\n    def generate_world(opt, agents):\n        return MessengerOverworld(opt, agents[0])\n\n    @staticmethod\n    def assign_roles(agents):\n        for a in agents:\n            a.disp_id = 'Agent'\n\n    def episode_done(self):\n        return self.episodeDone\n\n    def parley(self):\n        if self.first_time:\n            self.agent.observe(\n                {\n                    'id': 'Overworld',\n                    'text': 'Welcome to the overworld for the ParlAI messenger '\n                    'chatbot demo. Please type \"begin\" to start, or \"exit\" to exit',\n                    'quick_replies': ['begin', 'exit'],\n                }\n            )\n            self.first_time = False\n        a = self.agent.act()\n        if a is not None and a['text'].lower() == 'exit':\n            self.episode_done = True\n            return 'EXIT'\n        if a is not None and a['text'].lower() == 'begin':\n            self.episodeDone = True\n            return 'default'\n        elif a is not None:\n            self.agent.observe(\n                {\n                    'id': 'Overworld',\n                    'text': 'Invalid option. Please type \"begin\".',\n                    'quick_replies': ['begin'],\n                }\n            )\n", "path": "parlai/chat_service/tasks/chatbot/worlds.py"}]}