Hey. I am trying to port the DealNoDeal legacy Mturk task to the React front-end. This would allow me to use some of the functionalities like having custom Javascript/button clicks in the Task description on the LeftPane. Few related questions along these lines:
1) Has anyone already done that? Is there an example of modifying the LeftPane with additional frontend elements like buttons and controlling the behavior?
I think I would probably need to write a custom TextDescription component, but any leads should be helpful. Currently, the component sets "dangerouslySetInnerHTML={{ __html: task_desc }}", which ignores the in the text description of DealNoDeal.
Also, there is some similarity to using forms as per this PR. Is there a straight forward way to add these forms in the left pane?
2) How can I add HTML elements to the 'text' in observe dictionary? Say I want to make my System response bold or add a URL using href. For the legacy frontend, it seems like just using these HTML tags in the 'text' field works, but the same doesn't seem to work for me in the React setting.
3) I have seen this at multiple places - what is the difference between the Main and Static versions? For instance, MainApp and StaticApp in ParlAI/parlai/mturk/core/react_server/dev/app.jsx
@JackUrb @pringshia
FYI we would be happy to accept your PR upstream when you succeed.
Hi @kushalchawla - depending on how urgent you're feeling about doing this, we're soon to releasing an upgrade over the ParlAI MTurk framework. There will be a template to allow all PMT react tasks to work with the new tooling, but in a compatibility mode of sorts.
What would not be wasted work immediately is trying to port as much of the app as you can into BaseFrontend React component, as this will be almost directly compatible with the new code. The new framework doesn't have any of the getCorrectComponent wrappings though, so it's unclear jumping into this right now is the best time as I don't really have a good example to point you in though. Next week could be a very different story.
To answer your questions:
light/light_chats task has fairly complicated control logic attached to the TextResponse, and similarly one could attach control logic to the TaskDescription but again it's somewhat complicated when using getCorrectComponent.dangerouslySetInnerHTML tag, but generally it's better form to put special content into thetask_data field of your act and have the rendering logic of your ChatMessage component.Hey @JackUrb - Thanks for your reply. I will get to as much as I can, but I think it seems reasonable to wait for the update. I will keep this open for now then. I request you to please reply back, in case the updated version can help solve this in a more straightforward manner.
Hey @JackUrb @stephenroller
What exactly is getCorrectComponent wrapper doing? Why do we need it and how does that make things complicated, as per your last comment?
Hey @JackUrb
Could you please also confirm my understanding of how to send data in-between back-end and front-end?
1) From back-end to front-end: Using "task_data" field of the action dict and then calling mturk_agent.observe on it. -> The task_data field can be then used in which ever way by the respective React components.-> Hence, this can be used to show a customized TaskDescription to each mturk_agent.
2) From front-end to back-end: Seems like onMessageSend is our guy, be it called from TextResponse or TaskDescription or a FormResponse. Does this finally end up as the returned output of the mturk_agent.act()? Whatever I put in the first parameter here (called text), appears in the 'text' field of the return act object, and the stuff in the second parameter (called data), ends up in the 'task_data' of the returned object. This is the flow which I understand:
Data gathered from UI -> triggers onMessageSend -> triggers socket_handler.handleQueueMessage -> returns the act object, as the output of .act() function.
Please let me know if this sounds correct. I think this should be enough for me to migrate my requirements to React.
getCorrectComponent was used as a method to 'hotswap' react components that were part of the UI with customized ones created by users for specific tasks. You could rewrite one low level component (like the chat message) and have it placed deep in the component tree. This design pattern was flexible and lean, but overly complicated to understand and utilize. In the new setup we're just building individual webapps with some shared components, so no complicated swapping required.initialTaskData object, and yes you would use this to fill your TaskDescription component. The task_data from an act is appended to a different object, which is more appropriately used to change the state of a task or display special content on a message.Hi @kushalchawla - we've opened up the new tooling here. It's in _alpha_ at the moment so documentation is more sparse than we'd like, but the quickstart guide there and the parlai_chat_demo example should give you an idea on how the new flow looks like. Happy to get more into depth with what's going on here though, will write up some code pointers Wednesday.
Hey @JackUrb
Thanks a lot for giving me the heads up. For now, it seems like most of the issues I found can be resolved in one way or the other in ParlAI. Hence, for now, I was planning to just continue with it. However, I have still not completed my code and there are still two weeks before we push our data collection study live.
How about this? At least till Wednesday, I will continue making progress on ParlAI. I request you to please guide me on what levels porting to the newer system might be helpful, above ParlAI. If for my specific task, porting is not that helpful, I think I should probably continue with ParlAI, without delaying my study further. Please advise on what you think is the most efficient route for my project.
If the goal is to get things running, by all means ParlAI-MTurk will be the shorter route, but the drawback is anyone reproducing your collection will be doing so on legacy software fairly soon. Upgrading won't give you any additional functionality immediately, and if you're already close it won't be any _easier_ to port, but it does make reproduction and extension easier in the future.
The act of porting your task code to Mephisto is something you can do quite easily after you have the ParlAI-MTurk version complete though, as I will have a standardized guide for doing that.
Hey @JackUrb
Easy reproduction and extension are the objectives that I am definitely aiming for. I would love to have my code as a sample MTurk task on ParlAI/Mephisto. Given the complexity, I am myself maintaining states at the back-end in which the MTurkers can be in. I think it can be a useful example in the future.
Hence, if porting is easy enough, then definitely, let's go for it at this stage itself. I can at least give it a shot, and if I face any unprecedented issues, we rollback. In such a case, I can always update my code after data collection, just so that I can push the updated code for others to use.
Given that, I request you to please share that standardized guide for porting as soon as available. For now, I will continue my development on ParlAI.
Please let me know how this all sounds. Also requesting for any other advice you may have. Thanks a lot for being prompt with this. Super helpful.
Alright so here are the important code pointers (Though you might want to wait for https://github.com/facebookresearch/Mephisto/pull/171 to land first, which comes with a lot of JS code quality improvements and makes the frontend codebase a lot cleaner):
Generally you can start by copying over this example directory to your new working directory, and replacing the webapp folder with this one.
From here, you can navigate to your webapp directory, run npm install; npm run build to build the frontend for the first time. If this worked properly, you should see text about having a custom task description in your browser when you run python parlai_test_script.py --use-custom-task true.
Now you can directly edit components in the webapp/src/components/core_components.jsx file (will be named Core.jsx if you copy after 171 lands). Replace anything in here with the version you've written for the ParlAI-MTurk core_components.jsx file. While doing this, in Mephisto you should remove anything about getCorrectComponent and just refer to components directly.
Finally, the props that are passed into BaseFrontend have changed. What you receive is going to be different depending on if you'll transition before or after 171 though, so I'll wait to hear more about that.
On the backend side, your run file is going to be replaced with what's present in the parlai_test_script for the most part. You will need to add a make_world and get_world_params method to your worlds.py file as described in the setup guide and as seen in the example.
If you're passing custom opts to your world, you can specify world_opts and put them into extra_args as seen here. These world_opts can contain a class that gets passed to make_world that you can use to share state between world initializations.
Hey @JackUrb
Thanks a lot for all the details. I will try to give this a shot but mostly it feels like I am behind my schedule and its probably the best to shift my code after the study.
I found a simple way to block the users from using mobile devices in ParlAI: I just read the task description itself to know whether they are on mobile or not in the onboarding world. If they are on mobile, I just do not allow them to proceed (return an act) and ask them to click 'Return' to exit from the HIT. This seems to work for now.