@@ -287,7 +304,7 @@
Live Chat
$('div#message_thread').append(`
- `+self_display_name+`: `+reward_text+`
+ `+agent_id+`: `+reward_text+`
`);
@@ -295,7 +312,7 @@
Live Chat
$('div#message_thread').append(`
- `+self_display_name+`: `+message_text+`
+ `+agent_id+`: `+message_text+`
`);
@@ -308,8 +325,8 @@
Live Chat
$("div#message_thread").css("display", "");
scroll_conversation_to_bottom();
}
- if (received_message_from_other_agents) {
- $("div#response-type-text-input").css("display", "");
+ if (received_message_from_other_agents && (!task_done) && new_messages[new_messages.length-1]['id'] === previous_agent_id) {
+ update_for_response_type('text_input');
$("input#id_text_input").focus();
}
}
@@ -362,6 +379,7 @@
Live Chat
show_new_messages_on_UI(new_messages);
if (done_after_responding) {
update_for_response_type('done');
+ task_done = true;
} else {
check_done(new_messages);
}
@@ -454,9 +472,12 @@
Live Chat
$("form#mturk_submit_form input#workerId").val(get_url_parameter('workerId'));
$("form#mturk_submit_form").attr("action", mturk_submit_url);
$("input#id_text_input").focus();
- update_for_response_type('text_input');
+ if (cur_agent_index == 0) {
+ update_for_response_type('text_input');
+ } else {
+ update_for_response_type('idle');
+ }
if (is_approval_page) {
- self_display_name = 'Worker';
$("div#left-pane").css("min-height", $(window).height());
}
if (is_cover_page) {
diff --git a/parlai/mturk/core/setup_aws.py b/parlai/mturk/core/setup_aws.py
index 4cdaecb70fb..3e380c11f3b 100644
--- a/parlai/mturk/core/setup_aws.py
+++ b/parlai/mturk/core/setup_aws.py
@@ -14,21 +14,23 @@
import json
import webbrowser
import hashlib
+import getpass
from botocore.exceptions import ClientError
from botocore.exceptions import ProfileNotFound
aws_profile_name = 'parlai_mturk'
region_name = 'us-west-2'
+user_name = getpass.getuser()
iam_role_name = 'parlai_relay_server'
-lambda_function_name = 'parlai_relay_server'
+lambda_function_name = 'parlai_relay_server_' + user_name
lambda_permission_statement_id = 'lambda-permission-statement-id'
-api_gateway_name = 'ParlaiRelayServer'
+api_gateway_name = 'ParlaiRelayServer_' + user_name
endpoint_api_name_html = 'html' # For GET-ing HTML
endpoint_api_name_json = 'json' # For GET-ing and POST-ing JSON
-rds_db_instance_identifier = 'parlai-mturk-db'
-rds_db_name = 'parlai_mturk_db'
+rds_db_instance_identifier = 'parlai-mturk-db-' + user_name
+rds_db_name = 'parlai_mturk_db_' + user_name
rds_username = 'parlai_user'
rds_password = 'parlai_user_password'
rds_security_group_name = 'parlai-mturk-db-security-group'
@@ -228,7 +230,7 @@ def setup_rds():
return host
-def setup_relay_server_api(mturk_submit_url, rds_host, task_config, is_sandbox, num_hits, requester_key_gt, should_clean_up_after_upload=True):
+def setup_relay_server_api(mturk_submit_url, rds_host, task_description, is_sandbox, num_hits, requester_key_gt, should_clean_up_after_upload=True):
# Dynamically generate handler.py file, and then create zip file
print("Lambda: Preparing relay server code...")
@@ -253,7 +255,7 @@ def setup_relay_server_api(mturk_submit_url, rds_host, task_config, is_sandbox,
"requester_key_gt = \'" + requester_key_gt + "\'\n" + \
"num_hits = " + str(num_hits) + "\n" + \
"is_sandbox = " + str(is_sandbox) + "\n" + \
- 'task_description = ' + task_config['task_description'])
+ 'task_description = ' + task_description)
with open(os.path.join(parent_dir, lambda_server_directory_name, 'handler.py'), 'w') as handler_file:
handler_file.write(handler_file_string)
create_zip_file(
@@ -644,13 +646,13 @@ def create_zip_file(lambda_server_directory_name, lambda_server_zip_file_name, f
if verbose:
print("Done!")
-def setup_aws(task_config, num_hits, is_sandbox):
+def setup_aws(task_description, num_hits, is_sandbox):
mturk_submit_url = 'https://workersandbox.mturk.com/mturk/externalSubmit'
if not is_sandbox:
mturk_submit_url = 'https://www.mturk.com/mturk/externalSubmit'
requester_key_gt = get_requester_key()
rds_host = setup_rds()
- html_api_endpoint_url, json_api_endpoint_url = setup_relay_server_api(mturk_submit_url, rds_host, task_config, is_sandbox, num_hits, requester_key_gt)
+ html_api_endpoint_url, json_api_endpoint_url = setup_relay_server_api(mturk_submit_url, rds_host, task_description, is_sandbox, num_hits, requester_key_gt)
return html_api_endpoint_url, json_api_endpoint_url, requester_key_gt
diff --git a/parlai/mturk/run_mturk.py b/parlai/mturk/run_mturk.py
deleted file mode 100644
index f4f55ab1b27..00000000000
--- a/parlai/mturk/run_mturk.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright (c) 2017-present, Facebook, Inc.
-# All rights reserved.
-# This source code is licensed under the BSD-style license found in the
-# LICENSE file in the root directory of this source tree. An additional grant
-# of patent rights can be found in the PATENTS file in the same directory.
-from parlai.core.params import ParlaiParser
-from core import manage_hit
-
-argparser = ParlaiParser(False, False)
-argparser.add_parlai_data_path()
-argparser.add_mturk_args()
-
-opt = argparser.parse_args()
-
-task_module_name = 'parlai.mturk.tasks.' + opt['task']
-Agent = __import__(task_module_name+'.agents', fromlist=['']).default_agent_class
-task_config = __import__(task_module_name+'.task_config', fromlist=['']).task_config
-
-print("Creating HIT tasks for "+task_module_name+" ...")
-
-manage_hit.create_hits(
- opt=opt,
- task_config=task_config,
- task_module_name=task_module_name,
- bot=Agent(opt=opt),
-)
\ No newline at end of file
diff --git a/parlai/mturk/tasks/model_evaluator/agents.py b/parlai/mturk/tasks/model_evaluator/agents.py
deleted file mode 100644
index 43f68f43109..00000000000
--- a/parlai/mturk/tasks/model_evaluator/agents.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# Copyright (c) 2017-present, Facebook, Inc.
-# All rights reserved.
-# This source code is licensed under the BSD-style license found in the
-# LICENSE file in the root directory of this source tree. An additional grant
-# of patent rights can be found in the PATENTS file in the same directory.
-import copy
-import importlib
-from parlai.core.agents import Agent
-from parlai.core.agents import create_agent
-from parlai.core.worlds import create_task
-
-class ModelEvaluatorAgent(Agent):
- """
- MTurk agent for evaluating a dialog model's performance given a context.
- Assumes the context is a context from a given task, e.g.
- from SQuAD, CBT, etc.
- """
- def __init__(self, opt, shared=None):
- self.opt = copy.deepcopy(opt)
- self.id = 'Model Evaluator'
-
- # The dialog model we will evaluate
- agent_opt = {}
- agent_opt['model'] = 'ir_baseline'
- agent = create_agent(agent_opt)
-
- # The task that we will evaluate the dialog model on
- task_opt = {}
- task_opt['datatype'] = 'test'
- task_opt['datapath'] = opt['datapath']
- task_opt['task'] = '#MovieDD-Reddit'
- self.world = create_task(task_opt, agent)
-
- def observe(self, observation):
- self.observation = observation
-
- # The rating given by turker
- # Because we only have one turn in this conversation, we don't need to track turn_index
- # print(self.observation)
- return observation
-
- def act(self):
- # All agents act once in the world
- self.world.parley()
-
- ad = {}
- # Show the dialog model's response to the context, and ask the turker to rate the response
- ad['text'] = (
- self.world.get_acts()[0]['text'] + "\n\n" +
- "How would you rate the following response (from 0 to 10):\n\n" +
- self.world.get_acts()[1]['text'])
-
- # TODO: deal with multi-turn dialogs, for now we will just deal
- # with 1-turn dialogs in this task.
- ad['episode_done'] = True # self.world.episode_done()
- return ad
-
-default_agent_class = ModelEvaluatorAgent
diff --git a/parlai/mturk/tasks/model_evaluator/run.py b/parlai/mturk/tasks/model_evaluator/run.py
new file mode 100644
index 00000000000..4c2db99e501
--- /dev/null
+++ b/parlai/mturk/tasks/model_evaluator/run.py
@@ -0,0 +1,50 @@
+# Copyright (c) 2017-present, Facebook, Inc.
+# All rights reserved.
+# This source code is licensed under the BSD-style license found in the
+# LICENSE file in the root directory of this source tree. An additional grant
+# of patent rights can be found in the PATENTS file in the same directory.
+from parlai.core.params import ParlaiParser
+from parlai.mturk.tasks.model_evaluator.worlds import ModelEvaluatorWorld
+from parlai.mturk.core.agents import MTurkAgent
+from task_config import task_config
+import time
+import os
+
+
+def main():
+ argparser = ParlaiParser(False, False)
+ argparser.add_parlai_data_path()
+ argparser.add_mturk_args()
+
+ # The dialog model we want to evaluate
+ from parlai.agents.ir_baseline.ir_baseline import IrBaselineAgent
+ IrBaselineAgent.add_cmdline_args(argparser)
+ opt = argparser.parse_args()
+ opt['task'] = os.path.basename(os.getcwd())
+ model_agent = IrBaselineAgent(opt=opt)
+
+ # The task that we will evaluate the dialog model on
+ task_opt = {}
+ task_opt['datatype'] = 'test'
+ task_opt['datapath'] = opt['datapath']
+ task_opt['task'] = '#MovieDD-Reddit'
+
+ # Create the MTurk agent which provides a chat interface to the Turker
+ opt.update(task_config)
+ mturk_agent_id = 'Worker'
+ opt['agent_id'] = mturk_agent_id
+ opt['mturk_agent_ids'] = [mturk_agent_id]
+ opt['all_agent_ids'] = [ModelEvaluatorWorld.evaluator_agent_id, mturk_agent_id]
+ opt['conversation_id'] = str(int(time.time()))
+
+ mturk_agent = MTurkAgent(opt=opt)
+
+ world = ModelEvaluatorWorld(opt=opt, model_agent=model_agent, task_opt=task_opt, mturk_agent=mturk_agent)
+
+ while not world.episode_done():
+ world.parley()
+
+ world.shutdown()
+
+if __name__ == '__main__':
+ main()
diff --git a/parlai/mturk/tasks/model_evaluator/task_config.py b/parlai/mturk/tasks/model_evaluator/task_config.py
index 315d7c1aca2..a78dcbcf4a2 100644
--- a/parlai/mturk/tasks/model_evaluator/task_config.py
+++ b/parlai/mturk/tasks/model_evaluator/task_config.py
@@ -6,7 +6,6 @@
task_config = {}
-
"""A short and descriptive title about the kind of task the HIT contains.
On the Amazon Mechanical Turk web site, the HIT title appears in search results,
and everywhere the HIT is mentioned.
@@ -27,11 +26,6 @@
task_config['hit_keywords'] = 'chat,dialog,rating'
-"""A short name indicating the turker's role in the conversation.
-"""
-task_config['worker_agent_id'] = 'Teacher'
-
-
"""A detailed task description that will be shown on the HIT task preview page
and on the left side of the chat page. Supports HTML formatting.
"""
diff --git a/parlai/mturk/tasks/model_evaluator/worlds.py b/parlai/mturk/tasks/model_evaluator/worlds.py
new file mode 100644
index 00000000000..6d7a26d78e3
--- /dev/null
+++ b/parlai/mturk/tasks/model_evaluator/worlds.py
@@ -0,0 +1,45 @@
+from parlai.core.worlds import World, validate, create_task
+
+class ModelEvaluatorWorld(World):
+ """
+ World for letting Turkers evaluate a dialog model's performance given a context.
+ Assumes the context is a context from a given task, e.g. from SQuAD, CBT, etc.
+ """
+
+ evaluator_agent_id = 'Model Evaluator'
+
+ def __init__(self, opt, model_agent, task_opt, mturk_agent):
+ self.task_world = create_task(task_opt, model_agent)
+ self.mturk_agent = mturk_agent
+ self.episodeDone = False
+
+ def parley(self):
+ self.task_world.parley()
+
+ ad = {}
+ # Show the dialog model's response to the context, and ask the turker to rate the response
+ ad['id'] = self.__class__.evaluator_agent_id
+ ad['text'] = (
+ self.task_world.get_acts()[0]['text'] + "\n\n" +
+ "How would you rate the following response (from 0 to 10):\n\n" +
+ self.task_world.get_acts()[1]['text'])
+
+ # TODO: deal with multi-turn dialogs, for now we will just deal
+ # with 1-turn dialogs in this task.
+ ad['episode_done'] = True # self.world.episode_done()
+
+ self.mturk_agent.observe(validate(ad))
+ rating = self.mturk_agent.act()
+
+ self.episodeDone = True
+
+ def episode_done(self):
+ return self.episodeDone
+
+ def report(self):
+ # TODO: Add logging code here
+ pass
+
+ def shutdown(self):
+ self.task_world.shutdown()
+ self.mturk_agent.shutdown()
diff --git a/parlai/mturk/tasks/multi_agent_dialog/run.py b/parlai/mturk/tasks/multi_agent_dialog/run.py
new file mode 100644
index 00000000000..13fe5de401e
--- /dev/null
+++ b/parlai/mturk/tasks/multi_agent_dialog/run.py
@@ -0,0 +1,54 @@
+import os
+import time
+from parlai.core.params import ParlaiParser
+from parlai.mturk.core.agents import MTurkAgent
+from parlai.agents.local_human.local_human import LocalHumanAgent
+from parlai.core.worlds import MultiAgentDialogWorld
+from task_config import task_config
+
+"""
+This task consists of two local human agents and two MTurk agents,
+chatting with each other in a free-form format.
+You can end the conversation by sending a message ending with
+`[DONE]` from human_1.
+"""
+def main():
+ argparser = ParlaiParser(False, False)
+ argparser.add_parlai_data_path()
+ argparser.add_mturk_args()
+ opt = argparser.parse_args()
+ opt['task'] = os.path.basename(os.getcwd())
+
+ mturk_agent_1_id = 'mturk_agent_1'
+ mturk_agent_2_id = 'mturk_agent_2'
+ human_agent_1_id = 'human_1'
+ human_agent_2_id = 'human_2'
+
+ # Create the MTurk agents
+ opt.update(task_config)
+ opt['conversation_id'] = str(int(time.time()))
+
+ opt['mturk_agent_ids'] = [mturk_agent_1_id, mturk_agent_2_id]
+ opt['all_agent_ids'] = [human_agent_1_id, human_agent_2_id, mturk_agent_1_id, mturk_agent_2_id]
+
+ opt['agent_id'] = mturk_agent_1_id
+ mturk_agent_1 = MTurkAgent(opt=opt)
+
+ opt['agent_id'] = mturk_agent_2_id
+ mturk_agent_2 = MTurkAgent(opt=opt)
+
+ # Create the local human agents
+ human_agent_1 = LocalHumanAgent(opt=None)
+ human_agent_1.id = human_agent_1_id
+ human_agent_2 = LocalHumanAgent(opt=None)
+ human_agent_2.id = human_agent_2_id
+
+ world = MultiAgentDialogWorld(opt=opt, agents=[human_agent_1, human_agent_2, mturk_agent_1, mturk_agent_2])
+
+ while not world.episode_done():
+ world.parley()
+
+ world.shutdown()
+
+if __name__ == '__main__':
+ main()
diff --git a/parlai/mturk/tasks/multi_agent_dialog/task_config.py b/parlai/mturk/tasks/multi_agent_dialog/task_config.py
new file mode 100644
index 00000000000..3a9b2e7b4dc
--- /dev/null
+++ b/parlai/mturk/tasks/multi_agent_dialog/task_config.py
@@ -0,0 +1,39 @@
+# Copyright (c) 2017-present, Facebook, Inc.
+# All rights reserved.
+# This source code is licensed under the BSD-style license found in the
+# LICENSE file in the root directory of this source tree. An additional grant
+# of patent rights can be found in the PATENTS file in the same directory.
+
+task_config = {}
+
+"""A short and descriptive title about the kind of task the HIT contains.
+On the Amazon Mechanical Turk web site, the HIT title appears in search results,
+and everywhere the HIT is mentioned.
+"""
+task_config['hit_title'] = 'Chat with three other people'
+
+
+"""A description includes detailed information about the kind of task the HIT contains.
+On the Amazon Mechanical Turk web site, the HIT description appears in the expanded
+view of search results, and in the HIT and assignment screens.
+"""
+task_config['hit_description'] = 'Chat with three other people.'
+
+
+"""One or more words or phrases that describe the HIT, separated by commas.
+On MTurk website, these words are used in searches to find HITs.
+"""
+task_config['hit_keywords'] = 'chat,dialog'
+
+
+"""A detailed task description that will be shown on the HIT task preview page
+and on the left side of the chat page. Supports HTML formatting.
+"""
+task_config['task_description'] = \
+'''\'\'\'
+In this task, you are going to chat with three other people.
+
+If you are ready, please click "Accept HIT" to start this task.
+\'\'\''''
+
+
diff --git a/parlai/mturk/tasks/qa_data_collection/run.py b/parlai/mturk/tasks/qa_data_collection/run.py
new file mode 100644
index 00000000000..2daf73be9ce
--- /dev/null
+++ b/parlai/mturk/tasks/qa_data_collection/run.py
@@ -0,0 +1,50 @@
+# Copyright (c) 2017-present, Facebook, Inc.
+# All rights reserved.
+# This source code is licensed under the BSD-style license found in the
+# LICENSE file in the root directory of this source tree. An additional grant
+# of patent rights can be found in the PATENTS file in the same directory.
+from parlai.core.params import ParlaiParser
+from parlai.mturk.tasks.qa_data_collection.worlds import QADataCollectionWorld
+from parlai.mturk.core.agents import MTurkAgent
+from task_config import task_config
+import time
+import os
+import importlib
+
+
+def main():
+ argparser = ParlaiParser(False, False)
+ argparser.add_parlai_data_path()
+ argparser.add_mturk_args()
+ opt = argparser.parse_args()
+ opt['task'] = os.path.basename(os.getcwd())
+
+ # Initialize a SQuAD teacher agent, which we will later get context from
+ module_name = 'parlai.tasks.squad.agents'
+ class_name = 'DefaultTeacher'
+ my_module = importlib.import_module(module_name)
+ task_class = getattr(my_module, class_name)
+ task_opt = {}
+ task_opt['datatype'] = 'train'
+ task_opt['datapath'] = opt['datapath']
+ task = task_class(task_opt)
+
+ # Create the MTurk agent which provides a chat interface to the Turker
+ opt.update(task_config)
+ mturk_agent_id = 'Worker'
+ opt['agent_id'] = mturk_agent_id
+ opt['mturk_agent_ids'] = [mturk_agent_id]
+ opt['all_agent_ids'] = [QADataCollectionWorld.collector_agent_id, mturk_agent_id]
+ opt['conversation_id'] = str(int(time.time()))
+
+ mturk_agent = MTurkAgent(opt=opt)
+
+ world = QADataCollectionWorld(opt=opt, task=task, mturk_agent=mturk_agent)
+
+ while not world.episode_done():
+ world.parley()
+
+ world.shutdown()
+
+if __name__ == '__main__':
+ main()
diff --git a/parlai/mturk/tasks/qa_data_collection/task_config.py b/parlai/mturk/tasks/qa_data_collection/task_config.py
index ba7b2b9b067..7e23158704e 100644
--- a/parlai/mturk/tasks/qa_data_collection/task_config.py
+++ b/parlai/mturk/tasks/qa_data_collection/task_config.py
@@ -27,11 +27,6 @@
task_config['hit_keywords'] = 'chat,question,answer'
-"""A short name indicating the turker's role in the conversation.
-"""
-task_config['worker_agent_id'] = 'Teacher'
-
-
"""A detailed task description that will be shown on the HIT task preview page
and on the left side of the chat page. Supports HTML formatting.
"""
diff --git a/parlai/mturk/tasks/qa_data_collection/agents.py b/parlai/mturk/tasks/qa_data_collection/worlds.py
similarity index 54%
rename from parlai/mturk/tasks/qa_data_collection/agents.py
rename to parlai/mturk/tasks/qa_data_collection/worlds.py
index 5e3caaa334e..a3a9522206a 100644
--- a/parlai/mturk/tasks/qa_data_collection/agents.py
+++ b/parlai/mturk/tasks/qa_data_collection/worlds.py
@@ -3,49 +3,28 @@
# This source code is licensed under the BSD-style license found in the
# LICENSE file in the root directory of this source tree. An additional grant
# of patent rights can be found in the PATENTS file in the same directory.
-import copy
-import importlib
-from parlai.core.agents import Agent
-from parlai.core.agents import create_agent
+from parlai.core.worlds import World, validate
-class QADataCollectionAgent(Agent):
+
+class QADataCollectionWorld(World):
"""
- MTurk agent for recording a turker's question and answer given a context.
+ World for recording a turker's question and answer given a context.
Assumes the context is a random context from a given task, e.g.
from SQuAD, CBT, etc.
"""
- def __init__(self, opt, shared=None):
- self.opt = copy.deepcopy(opt)
- self.id = 'QA Collector'
- self.turn_index = -1
- # Initialize a SQuAD teacher agent, which we will later get context from
- module_name = 'parlai.tasks.squad.agents'
- class_name = 'DefaultTeacher'
- my_module = importlib.import_module(module_name)
- task_class = getattr(my_module, class_name)
- task_opt = {}
- task_opt['datatype'] = 'train'
- task_opt['datapath'] = opt['datapath']
- self.task = task_class(task_opt)
+ collector_agent_id = 'QA Collector'
- def observe(self, observation):
- self.observation = observation
+ def __init__(self, opt, task, mturk_agent):
+ self.task = task
+ self.mturk_agent = mturk_agent
+ self.episodeDone = False
+ self.turn_index = -1
- if self.turn_index == 0:
- # Turker's question, from the first turn
- # print(self.observation)
- pass
- elif self.turn_index == 1:
- # Turker's answer, from the second turn
- # print(self.observation)
- pass
- return observation
-
- def act(self):
+ def parley(self):
self.turn_index = (self.turn_index + 1) % 2; # Each turn starts from the QA Collector agent
ad = { 'episode_done': False }
- ad['id'] = self.id
+ ad['id'] = self.__class__.collector_agent_id
if self.turn_index == 0:
# At the first turn, the QA Collector agent provides the context and
@@ -59,6 +38,9 @@ def act(self):
ad['text'] = (context +
'\n\nPlease provide a question given this context.')
+ self.mturk_agent.observe(validate(ad))
+ self.question = self.mturk_agent.act() # Can log the turker's question here
+
if self.turn_index == 1:
# At the second turn, the QA Collector collects the turker's question from the first turn,
# and then prompts the turker to provide the answer
@@ -68,6 +50,18 @@ def act(self):
ad['episode_done'] = True # end of episode
- return ad
+ self.mturk_agent.observe(validate(ad))
+ self.answer = self.mturk_agent.act() # Can log the turker's answer here
+
+ self.episodeDone = True
+
+ def episode_done(self):
+ return self.episodeDone
+
+ def report(self):
+ # TODO: Add logging code here
+ pass
-default_agent_class = QADataCollectionAgent
+ def shutdown(self):
+ self.task.shutdown()
+ self.mturk_agent.shutdown()