diff --git a/docs/web/docs/guides/tutorials/model_in_the_loop.md b/docs/web/docs/guides/tutorials/model_in_the_loop.md index fe137fd3e..8b6e9b57f 100644 --- a/docs/web/docs/guides/tutorials/model_in_the_loop.md +++ b/docs/web/docs/guides/tutorials/model_in_the_loop.md @@ -73,7 +73,10 @@ docker-compose -f docker/docker-compose.dev.yml run \ python /mephisto/examples/remote_procedure/interactive_image_generation/run_task__local__inhouse.py ``` -3. Once your Task launches, your console will display you URLs like this: `http://localhost:3001?worker_id=WORKER_USERNAME&id=1` +3. Once your Task launches, your console will display you Task Unit URLs like this: `http://localhost:3001?worker_id=WORKER_USERNAME&id=1` + +4. Opening a Task Unit URL will show you a page like this: +![Model-in-the-loop](./screenshots/model_in_the_loop.jpg) #### Further Details diff --git a/docs/web/docs/guides/tutorials/screenshots/model_in_the_loop.jpg b/docs/web/docs/guides/tutorials/screenshots/model_in_the_loop.jpg new file mode 100644 index 000000000..b70d6b34a Binary files /dev/null and b/docs/web/docs/guides/tutorials/screenshots/model_in_the_loop.jpg differ diff --git a/examples/form_composer_demo/webapp/src/reviewapp_dynamic.jsx b/examples/form_composer_demo/webapp/src/reviewapp_dynamic.jsx index 2002525f2..216394c9e 100644 --- a/examples/form_composer_demo/webapp/src/reviewapp_dynamic.jsx +++ b/examples/form_composer_demo/webapp/src/reviewapp_dynamic.jsx @@ -36,7 +36,7 @@ function ReviewApp() { } window.addEventListener("resize", updateSize); updateSize(); - // HACK: Catch-all resize, if normal resizes failed (e.g. acync long loading images) + // HACK: Catch-all resize, if normal resizes failed (e.g. slow acync loading of images) setTimeout(() => { updateSize(); }, 3000); diff --git a/examples/form_composer_demo/webapp/src/reviewapp_simple.jsx b/examples/form_composer_demo/webapp/src/reviewapp_simple.jsx index 7f4bd8ad8..657541074 100644 --- a/examples/form_composer_demo/webapp/src/reviewapp_simple.jsx +++ b/examples/form_composer_demo/webapp/src/reviewapp_simple.jsx @@ -36,7 +36,7 @@ function ReviewApp() { } window.addEventListener("resize", updateSize); updateSize(); - // HACK: Catch-all resize, if normal resizes failed (e.g. acync long loading images) + // HACK: Catch-all resize, if normal resizes failed (e.g. slow acync loading of images) setTimeout(() => { updateSize(); }, 3000); diff --git a/examples/remote_procedure/elementary_remote_procedure/README.md b/examples/remote_procedure/elementary_remote_procedure/README.md new file mode 100644 index 000000000..590fc614e --- /dev/null +++ b/examples/remote_procedure/elementary_remote_procedure/README.md @@ -0,0 +1,36 @@ + + +# Mephisto Elementary remote procedure example + +This task is a _very simplistic_ bare-bones example of being able to set up a task where the frontend directly connects to the backend +using the `useMephistoRemoteProcedureTask` hook from the `mephisto-task` package. +It should serve as a decent example of how to get a `RemoteProcedureBlueprint` task up off the ground. + +Deploying the task as-is brings up a page where the user needs to click the "query backend" button enough times +for the task to be considered ready to submit. + +It makes use of the function_registry to use a `"handle_with_model"` method that, admittedly, doesn't use any models, +but hopefully demonstrates where a model can fit into this type of task. + +As it stands, these queries are still just a single request to single response model, +but that should be sufficient for most tasks that want to have a backend in-the-loop for an otherwise frontend-heavy task. + +## End-to-end example + +Now let's see how the whole end-to-end list of commands looks like for the example `Elementary remote procedure`: + +```shell +# 1. In your console + +docker-compose -f docker/docker-compose.dev.yml up +docker exec -it mephisto_dc bash + +# 2.Inside Docker container + +cd /mephisto/examples/remote_procedure/elementary_remote_procedure +python ./run_task__local__inhouse.py +``` diff --git a/examples/remote_procedure/template/__init__.py b/examples/remote_procedure/elementary_remote_procedure/__init__.py similarity index 100% rename from examples/remote_procedure/template/__init__.py rename to examples/remote_procedure/elementary_remote_procedure/__init__.py diff --git a/examples/remote_procedure/template/assets/.gitkeep b/examples/remote_procedure/elementary_remote_procedure/assets/.gitkeep similarity index 100% rename from examples/remote_procedure/template/assets/.gitkeep rename to examples/remote_procedure/elementary_remote_procedure/assets/.gitkeep diff --git a/examples/remote_procedure/template/hydra_configs/conf/example_local_mock.yaml b/examples/remote_procedure/elementary_remote_procedure/hydra_configs/conf/example__local__inhouse.yaml similarity index 74% rename from examples/remote_procedure/template/hydra_configs/conf/example_local_mock.yaml rename to examples/remote_procedure/elementary_remote_procedure/hydra_configs/conf/example__local__inhouse.yaml index 5ab8d7af9..a35b373ad 100644 --- a/examples/remote_procedure/template/hydra_configs/conf/example_local_mock.yaml +++ b/examples/remote_procedure/elementary_remote_procedure/hydra_configs/conf/example__local__inhouse.yaml @@ -7,24 +7,28 @@ defaults: - /mephisto/blueprint: remote_procedure - /mephisto/architect: local - - /mephisto/provider: mock + - /mephisto/provider: inhouse mephisto: blueprint: - task_source: ${task_dir}/webapp/build/bundle.js + task_source: ${task_dir}/webapp/build/bundle.remote_procedure.js + task_source_review: ${task_dir}/webapp/build/bundle.review.js link_task_source: false # NOTE pick something based on your task block_qualification: test_qual_block units_per_assignment: 1 + log_level: "debug" + provider: + ui_base_url: "http://localhost:3001" task: allowed_concurrent: 1 - task_name: remote-procedure-test-task + task_name: "Elementary remote procedure" task_title: "Test a static task that also has access to live backend queries" # NOTE you'll want to update your task description task_description: "You will be shown a form that you can submit at any time, but can also toggle a backend query" # NOTE set a reasonable reward task_reward: 0.05 # NOTE will want real tags - task_tags: "test,task,fix-me" + task_tags: "test,task,fix-me,elementary_remote_procedure" # NOTE Model-in-the-loop tasks need to be careful to configure only as many concurrent # connections as their model can handle at once max_num_concurrent_units: 40 diff --git a/examples/remote_procedure/template/run_task.py b/examples/remote_procedure/elementary_remote_procedure/run_task__local__inhouse.py similarity index 98% rename from examples/remote_procedure/template/run_task.py rename to examples/remote_procedure/elementary_remote_procedure/run_task__local__inhouse.py index e1b54f4c2..9f2ccaa8d 100644 --- a/examples/remote_procedure/template/run_task.py +++ b/examples/remote_procedure/elementary_remote_procedure/run_task__local__inhouse.py @@ -61,7 +61,7 @@ def _onboarding_always_valid(onboarding_data: dict) -> bool: return True -@task_script(default_config_file="example_local_mock") +@task_script(default_config_file="example__local__inhouse") def main(operator: Operator, cfg: DictConfig) -> None: examples.build_remote_procedure_template( force_rebuild=cfg.mephisto.task.force_rebuild, diff --git a/examples/remote_procedure/template/webapp/.babelrc b/examples/remote_procedure/elementary_remote_procedure/webapp/.babelrc similarity index 100% rename from examples/remote_procedure/template/webapp/.babelrc rename to examples/remote_procedure/elementary_remote_procedure/webapp/.babelrc diff --git a/examples/remote_procedure/template/webapp/.eslintrc b/examples/remote_procedure/elementary_remote_procedure/webapp/.eslintrc similarity index 100% rename from examples/remote_procedure/template/webapp/.eslintrc rename to examples/remote_procedure/elementary_remote_procedure/webapp/.eslintrc diff --git a/examples/remote_procedure/template/webapp/cypress.config.js b/examples/remote_procedure/elementary_remote_procedure/webapp/cypress.config.js similarity index 100% rename from examples/remote_procedure/template/webapp/cypress.config.js rename to examples/remote_procedure/elementary_remote_procedure/webapp/cypress.config.js diff --git a/examples/remote_procedure/template/webapp/cypress/e2e/remote_procedure_template.cy.js b/examples/remote_procedure/elementary_remote_procedure/webapp/cypress/e2e/remote_procedure_template.cy.js similarity index 97% rename from examples/remote_procedure/template/webapp/cypress/e2e/remote_procedure_template.cy.js rename to examples/remote_procedure/elementary_remote_procedure/webapp/cypress/e2e/remote_procedure_template.cy.js index 6857cc445..e8f2fa3db 100644 --- a/examples/remote_procedure/template/webapp/cypress/e2e/remote_procedure_template.cy.js +++ b/examples/remote_procedure/elementary_remote_procedure/webapp/cypress/e2e/remote_procedure_template.cy.js @@ -4,7 +4,7 @@ * LICENSE file in the root directory of this source tree. */ -describe("Loads remote_procedure_template", () => { +describe("Loads elementary_remote_procedure", () => { it("Makes request for agent", () => { cy.intercept({ pathname: "/request_agent" }).as("agentRequest"); cy.visit("/"); diff --git a/examples/remote_procedure/template/webapp/link_mephisto_task.sh b/examples/remote_procedure/elementary_remote_procedure/webapp/link_mephisto_task.sh similarity index 100% rename from examples/remote_procedure/template/webapp/link_mephisto_task.sh rename to examples/remote_procedure/elementary_remote_procedure/webapp/link_mephisto_task.sh diff --git a/examples/remote_procedure/template/webapp/package.json b/examples/remote_procedure/elementary_remote_procedure/webapp/package.json similarity index 79% rename from examples/remote_procedure/template/webapp/package.json rename to examples/remote_procedure/elementary_remote_procedure/webapp/package.json index df44ad125..c4d3e1c1e 100644 --- a/examples/remote_procedure/template/webapp/package.json +++ b/examples/remote_procedure/elementary_remote_procedure/webapp/package.json @@ -1,20 +1,20 @@ { - "name": "remote-procedure-template-example", + "name": "elementary-remote-procedure", "version": "1.0.1", "description": "", "main": "webpack.config.js", "scripts": { "dev": "webpack --mode development", - "test": "cypress open" + "test": "cypress open", + "build:remote_procedure": "webpack --config=webpack.config.remote_procedure.js --mode development", + "build:review": "webpack --config=webpack.config.review.js --mode development" }, "keywords": [], "author": "", "dependencies": { - "bootstrap": "^4.6.0", - "mephisto-task": "2.0.4", + "bootstrap": "^5.3.1", "rc-slider": "^8.6.3", "react": "^16", - "react-bootstrap": "^1.6.0", "react-dom": "^16", "react-table": "^6.8.6" }, diff --git a/examples/remote_procedure/template/webapp/src/app.jsx b/examples/remote_procedure/elementary_remote_procedure/webapp/src/app_remote_procedure.jsx similarity index 89% rename from examples/remote_procedure/template/webapp/src/app.jsx rename to examples/remote_procedure/elementary_remote_procedure/webapp/src/app_remote_procedure.jsx index f13626b7e..a60551e75 100644 --- a/examples/remote_procedure/template/webapp/src/app.jsx +++ b/examples/remote_procedure/elementary_remote_procedure/webapp/src/app_remote_procedure.jsx @@ -4,15 +4,17 @@ * LICENSE file in the root directory of this source tree. */ -import React from "react"; -import ReactDOM from "react-dom"; -import { BaseFrontend, LoadingScreen } from "./components/core_components.jsx"; - import { + ErrorBoundary, MephistoContext, useMephistoRemoteProcedureTask, - ErrorBoundary, } from "mephisto-core"; +import React from "react"; +import ReactDOM from "react-dom"; +import { + LoadingScreen, + ElementaryRemoteProcedureTaskFrontend, +} from "./components/core_components_remote_procedure.jsx"; /* ================= Application Components ================= */ @@ -51,27 +53,32 @@ function RemoteProcedureApp() { // At the moment, this task has no onboarding return

This task doesn't currently have an onboarding example set

; } + if (blockedReason !== null) { return

{blockedExplanation}

; } + if (isLoading) { return ; } + if (isPreview) { if (!taskConfig.has_preview) { return ; } + if (previewHtml === null) { return
Loading...
; } + return
; } return ( -
- + +
Loading...; +} + +function Directions({ children }) { + return ( +
+
{children}
+
+ ); +} + +function Instructions() { + return ( +
+

+ Elementary example of remote procedure +

+ +
+ This is a simple task to demonstrate communication with the server +
+ +

+ To submit this task, you must make a few backend queries first +

+
+ ); +} + +function ElementaryRemoteProcedureTaskFrontend({ + taskData, + handleRemoteCall, + handleSubmit, + finalResults = null, +}) { + const inReviewState = finalResults !== null; + + if (!inReviewState && !taskData) { + return ; + } + + const [queryCount, setQueryCount] = React.useState(0); + let canSubmit = queryCount > 3; + + const disabledQueryButton = inReviewState; + const disabledSubmitButton = inReviewState || !canSubmit; + + return ( +
+ {/* Final result of template example (needed only for TaskReview app) */} + {inReviewState && ( +
+ Task result: {finalResults.backendActionsDone} +
+ )} + + + + + + +
+ ); +} + +export { LoadingScreen, ElementaryRemoteProcedureTaskFrontend }; diff --git a/examples/remote_procedure/template/webapp/src/css/style.css b/examples/remote_procedure/elementary_remote_procedure/webapp/src/css/style.css similarity index 100% rename from examples/remote_procedure/template/webapp/src/css/style.css rename to examples/remote_procedure/elementary_remote_procedure/webapp/src/css/style.css diff --git a/examples/remote_procedure/elementary_remote_procedure/webapp/src/main_remote_procedure.js b/examples/remote_procedure/elementary_remote_procedure/webapp/src/main_remote_procedure.js new file mode 100644 index 000000000..28c702699 --- /dev/null +++ b/examples/remote_procedure/elementary_remote_procedure/webapp/src/main_remote_procedure.js @@ -0,0 +1,9 @@ +/* + * Copyright (c) Meta Platforms and its affiliates. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import "bootstrap/dist/css/bootstrap.min.css"; +import "./app_remote_procedure.jsx"; +import "./css/style.css"; diff --git a/examples/remote_procedure/template/webapp/src/main.js b/examples/remote_procedure/elementary_remote_procedure/webapp/src/review.js similarity index 90% rename from examples/remote_procedure/template/webapp/src/main.js rename to examples/remote_procedure/elementary_remote_procedure/webapp/src/review.js index f710171aa..adeb1c7d5 100644 --- a/examples/remote_procedure/template/webapp/src/main.js +++ b/examples/remote_procedure/elementary_remote_procedure/webapp/src/review.js @@ -3,6 +3,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -import "./app.jsx"; -import "./css/style.css"; + import "bootstrap/dist/css/bootstrap.min.css"; +import "./css/style.css"; +import "./reviewapp.jsx"; diff --git a/examples/remote_procedure/elementary_remote_procedure/webapp/src/reviewapp.jsx b/examples/remote_procedure/elementary_remote_procedure/webapp/src/reviewapp.jsx new file mode 100644 index 000000000..be2a97a1f --- /dev/null +++ b/examples/remote_procedure/elementary_remote_procedure/webapp/src/reviewapp.jsx @@ -0,0 +1,63 @@ +/* + * 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 React from "react"; +import ReactDOM from "react-dom"; +import { ElementaryRemoteProcedureTaskFrontend } from "./components/core_components_remote_procedure.jsx"; + +function ReviewApp() { + const appRef = React.useRef(null); + const [reviewData, setReviewData] = React.useState(null); + + // Requirement #1. Render review components after receiving Task data via message + window.onmessage = function (e) { + const data = JSON.parse(e.data); + setReviewData(data["REVIEW_DATA"]); + }; + + // Requirement #2. Resize iframe height to fit its content + React.useLayoutEffect(() => { + function updateSize() { + if (appRef.current) { + window.top.postMessage( + JSON.stringify({ + IFRAME_DATA: { + height: appRef.current.offsetHeight, + }, + }), + "*" + ); + } + } + window.addEventListener("resize", updateSize); + updateSize(); + // HACK: Catch-all resize, if normal resizes failed (e.g. slow acync loading of images) + setTimeout(() => { + updateSize(); + }, 3000); + return () => window.removeEventListener("resize", updateSize); + }, []); + + // Requirement #3. This component must return a div with `ref={appRef}` + // so we can get displayed height of this component (for iframe resizing) + return ( +
+ {reviewData ? ( +
+ +
+ ) : ( +
Loading...
+ )} +
+ ); +} + +ReactDOM.render(, document.getElementById("app")); diff --git a/examples/remote_procedure/template/webapp/src/static/index.html b/examples/remote_procedure/elementary_remote_procedure/webapp/src/static/index.html similarity index 57% rename from examples/remote_procedure/template/webapp/src/static/index.html rename to examples/remote_procedure/elementary_remote_procedure/webapp/src/static/index.html index a8ed9fea6..b7c5d6b3f 100644 --- a/examples/remote_procedure/template/webapp/src/static/index.html +++ b/examples/remote_procedure/elementary_remote_procedure/webapp/src/static/index.html @@ -9,19 +9,7 @@ - Remote Query Example - - - - + Simple Remote Query Example diff --git a/examples/remote_procedure/elementary_remote_procedure/webapp/webpack.config.remote_procedure.js b/examples/remote_procedure/elementary_remote_procedure/webapp/webpack.config.remote_procedure.js new file mode 100644 index 000000000..fcd26efcf --- /dev/null +++ b/examples/remote_procedure/elementary_remote_procedure/webapp/webpack.config.remote_procedure.js @@ -0,0 +1,53 @@ +/* + * Copyright (c) Meta Platforms and its affiliates. + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +var path = require("path"); +var webpack = require("webpack"); + +module.exports = { + entry: "./src/main_remote_procedure.js", + output: { + path: __dirname, + filename: "build/bundle.remote_procedure.js", + }, + resolve: { + alias: { + react: path.resolve("./node_modules/react"), + // Use local library with code that can submit FormData + "mephisto-core": path.resolve( + __dirname, + "../../../../packages/mephisto-core" + ), + }, + fallback: { + net: false, + dns: false, + }, + }, + module: { + rules: [ + { + test: /\.(js|jsx)$/, + loader: "babel-loader", + exclude: /node_modules/, + options: { presets: ["@babel/env"] }, + }, + { + test: /\.css$/, + use: ["style-loader", "css-loader"], + }, + { + test: /\.(svg|png|jpe?g|ttf)$/, + loader: "url-loader", + options: { limit: 100000 }, + }, + { + test: /\.jpg$/, + loader: "file-loader", + }, + ], + }, +}; diff --git a/examples/remote_procedure/template/webapp/webpack.config.js b/examples/remote_procedure/elementary_remote_procedure/webapp/webpack.config.review.js similarity index 94% rename from examples/remote_procedure/template/webapp/webpack.config.js rename to examples/remote_procedure/elementary_remote_procedure/webapp/webpack.config.review.js index 1958271ed..6350057f6 100644 --- a/examples/remote_procedure/template/webapp/webpack.config.js +++ b/examples/remote_procedure/elementary_remote_procedure/webapp/webpack.config.review.js @@ -8,10 +8,10 @@ var path = require("path"); var webpack = require("webpack"); module.exports = { - entry: "./src/main.js", + entry: "./src/review.js", output: { path: __dirname, - filename: "build/bundle.js", + filename: "build/bundle.review.js", }, resolve: { alias: { diff --git a/examples/remote_procedure/interactive_image_generation/data/task_data.json b/examples/remote_procedure/interactive_image_generation/data/task_data.json index 4e1e15622..894c6997f 100644 --- a/examples/remote_procedure/interactive_image_generation/data/task_data.json +++ b/examples/remote_procedure/interactive_image_generation/data/task_data.json @@ -78,7 +78,7 @@ "fields": [ { "id": "id_prompt_0", - "label": "Please provide a detailed prompt to algorithm to generate an image that resemples the target image above", + "label": "Please provide a detailed prompt to algorithm to generate an image that resembles the target image above", "name": "prompt_0", "type": "textarea", "validators": { @@ -119,7 +119,7 @@ "fields": [ { "id": "id_score_1", - "label": "How closely does the prompted image match the target image (on scale 1-10)?", + "label": "How closely does the generated image match the target image (on scale 1-10)?", "multiple": false, "name": "score_1", "options": [ @@ -222,7 +222,7 @@ "fields": [ { "id": "id_score_2", - "label": "How closely does the prompted image match the target image (on scale 1-10)?", + "label": "How closely does the generated image match the target image (on scale 1-10)?", "multiple": false, "name": "score_2", "options": [ @@ -411,7 +411,7 @@ "fields": [ { "id": "id_prompt_0", - "label": "Please provide a detailed prompt to algorithm to generate an image that resemples the target image above", + "label": "Please provide a detailed prompt to algorithm to generate an image that resembles the target image above", "name": "prompt_0", "type": "textarea", "validators": { @@ -452,7 +452,7 @@ "fields": [ { "id": "id_score_1", - "label": "How closely does the prompted image match the target image (on scale 1-10)?", + "label": "How closely does the generated image match the target image (on scale 1-10)?", "multiple": false, "name": "score_1", "options": [ @@ -555,7 +555,7 @@ "fields": [ { "id": "id_score_2", - "label": "How closely does the prompted image match the target image (on scale 1-10)?", + "label": "How closely does the generated image match the target image (on scale 1-10)?", "multiple": false, "name": "score_2", "options": [ diff --git a/examples/remote_procedure/interactive_image_generation/data/unit_config.json b/examples/remote_procedure/interactive_image_generation/data/unit_config.json index 45926e72f..d2c5fe03e 100644 --- a/examples/remote_procedure/interactive_image_generation/data/unit_config.json +++ b/examples/remote_procedure/interactive_image_generation/data/unit_config.json @@ -77,7 +77,7 @@ "fields": [ { "id": "id_prompt_0", - "label": "Please provide a detailed prompt to algorithm to generate an image that resemples the target image above", + "label": "Please provide a detailed prompt to algorithm to generate an image that resembles the target image above", "name": "prompt_0", "type": "textarea", "validators": { @@ -118,7 +118,7 @@ "fields": [ { "id": "id_score_1", - "label": "How closely does the prompted image match the target image (on scale 1-10)?", + "label": "How closely does the generated image match the target image (on scale 1-10)?", "multiple": false, "name": "score_1", "options": [ @@ -221,7 +221,7 @@ "fields": [ { "id": "id_score_2", - "label": "How closely does the prompted image match the target image (on scale 1-10)?", + "label": "How closely does the generated image match the target image (on scale 1-10)?", "multiple": false, "name": "score_2", "options": [ diff --git a/examples/remote_procedure/interactive_image_generation/run_task__local__inhouse.py b/examples/remote_procedure/interactive_image_generation/run_task__local__inhouse.py index 9686616e0..3501c2b9b 100644 --- a/examples/remote_procedure/interactive_image_generation/run_task__local__inhouse.py +++ b/examples/remote_procedure/interactive_image_generation/run_task__local__inhouse.py @@ -347,7 +347,7 @@ def main(operator: Operator, cfg: DictConfig) -> None: "getNextFieldset": _get_next_fieldset, } - examples.build_interactive_image_generation( + examples.build_remote_procedure_interactive_image_generation( force_rebuild=cfg.mephisto.task.force_rebuild, post_install_script=cfg.mephisto.task.post_install_script, ) diff --git a/examples/remote_procedure/interactive_image_generation/webapp/src/main_remote_procedure.js b/examples/remote_procedure/interactive_image_generation/webapp/src/main_remote_procedure.js index f0ad60db1..fb17deeab 100644 --- a/examples/remote_procedure/interactive_image_generation/webapp/src/main_remote_procedure.js +++ b/examples/remote_procedure/interactive_image_generation/webapp/src/main_remote_procedure.js @@ -5,7 +5,7 @@ */ import "bootstrap-select/dist/css/bootstrap-select.min.css"; -import "bootstrap/dist/css/bootstrap.css"; +import "bootstrap/dist/css/bootstrap.min.css"; import "./app_remote_procedure.jsx"; import "./css/style.css"; diff --git a/examples/remote_procedure/interactive_image_generation/webapp/src/review.js b/examples/remote_procedure/interactive_image_generation/webapp/src/review.js index 2c2d5a14d..964343bd9 100644 --- a/examples/remote_procedure/interactive_image_generation/webapp/src/review.js +++ b/examples/remote_procedure/interactive_image_generation/webapp/src/review.js @@ -4,7 +4,7 @@ * LICENSE file in the root directory of this source tree. */ -import "bootstrap/dist/css/bootstrap.css"; +import "bootstrap/dist/css/bootstrap.min.css"; import "bootstrap-select/dist/css/bootstrap-select.min.css"; import "./reviewapp.jsx"; import "./css/style.css"; diff --git a/examples/remote_procedure/interactive_image_generation/webapp/src/reviewapp.jsx b/examples/remote_procedure/interactive_image_generation/webapp/src/reviewapp.jsx index 5fb9fdfa3..2a737834d 100644 --- a/examples/remote_procedure/interactive_image_generation/webapp/src/reviewapp.jsx +++ b/examples/remote_procedure/interactive_image_generation/webapp/src/reviewapp.jsx @@ -36,7 +36,7 @@ function ReviewApp() { } window.addEventListener("resize", updateSize); updateSize(); - // HACK: Catch-all resize, if normal resizes failed (e.g. acync long loading images) + // HACK: Catch-all resize, if normal resizes failed (e.g. slow acync loading of images) setTimeout(() => { updateSize(); }, 3000); diff --git a/examples/remote_procedure/mnist/webapp/src/reviewapp.jsx b/examples/remote_procedure/mnist/webapp/src/reviewapp.jsx index e5c498817..ac0a0deb6 100644 --- a/examples/remote_procedure/mnist/webapp/src/reviewapp.jsx +++ b/examples/remote_procedure/mnist/webapp/src/reviewapp.jsx @@ -34,7 +34,7 @@ function ReviewApp() { } window.addEventListener("resize", updateSize); updateSize(); - // HACK: Catch-all resize, if normal resizes failed (e.g. acync long loading images) + // HACK: Catch-all resize, if normal resizes failed (e.g. slow acync loading of images) setTimeout(() => { updateSize(); }, 3000); diff --git a/examples/remote_procedure/template/README.md b/examples/remote_procedure/template/README.md deleted file mode 100644 index 65b5bc77f..000000000 --- a/examples/remote_procedure/template/README.md +++ /dev/null @@ -1,15 +0,0 @@ - - -# Mephisto Remote Query Template - -This task is an _extremely rough_ bare-bones example of being able to set up a task where the frontend directly connects to the backend using the `useMephistoRemoteProcedureTask` hook from the `mephisto-task` package. It should serve as a decent example of how to get a `RemoteProcedureBlueprint` task up off the ground. - -Deploying the task as-is brings up a page where the user needs to click the "query backend" button enough times for the task to be considered ready to submit. - -It makes use of the function_registry to use a `"handle_with_model"` method that, admittedly, doesn't use any models, but hopefully demonstrates where a model can fit into this type of task. - -As it stands, these queries are still just a single request to single response model, but that should be sufficient for most tasks that want to have a backend in-the-loop for an otherwise frontend-heavy task. \ No newline at end of file diff --git a/examples/remote_procedure/template/webapp/src/components/core_components.jsx b/examples/remote_procedure/template/webapp/src/components/core_components.jsx deleted file mode 100644 index e94271daf..000000000 --- a/examples/remote_procedure/template/webapp/src/components/core_components.jsx +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) Meta Platforms and its affiliates. - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React from "react"; -function LoadingScreen() { - return Loading...; -} - -function Directions({ children }) { - return ( -
-
-
-

{children}

-
-
-
- ); -} - -function TaskFrontend({ taskData, handleRemoteCall, handleSubmit }) { - if (!taskData) { - return ; - } - - const [queryCount, setQueryCount] = React.useState(0); - let canSubmit = queryCount > 3; - - return ( -
-

- This is a simple task to demonstrate a static task with backend - capabilities. -

-

- To submit this task, you must make a few backend queries first -

- - - -
- ); -} - -export { LoadingScreen, TaskFrontend as BaseFrontend }; diff --git a/examples/remote_procedure/toxicity_detection/README.md b/examples/remote_procedure/toxicity_detection/README.md index ac4197138..65e90ade6 100644 --- a/examples/remote_procedure/toxicity_detection/README.md +++ b/examples/remote_procedure/toxicity_detection/README.md @@ -5,11 +5,13 @@ --> # Mephisto Toxicity Detection Demo + ## Summary This task presents the worker with a text input. -Written text can only be submitted if its toxicity is is calculated to be <= 0.5. If the toxicity is > 0.5 an alert is shown and the text is not submitted. +Written text can only be submitted if its toxicity is calculated to be <= 0.5. +If the toxicity is > 0.5 an alert is shown and the text is not submitted. The toxicity of written text is calculated from the detoxify python library. @@ -23,7 +25,27 @@ pip install detoxify Then typing ```bash -python run_task.py +python run_task__local__inhouse.py ``` should run the demo. + +## End-to-end example + +Now let's see how the whole end-to-end list of commands looks like for the example `Toxicity Example`: + +```shell +# 1. In your console + +docker-compose -f docker/docker-compose.dev.yml up +docker exec -it mephisto_dc bash + +# 2.Inside Docker container + +# 2a. Install `detoxify` python library +pip install detoxify + +# 2b. Run the Task +cd /mephisto/examples/remote_procedure/toxicity_detection +python ./run_task__local__inhouse.py +``` diff --git a/examples/remote_procedure/toxicity_detection/hydra_configs/conf/example_local_mock.yaml b/examples/remote_procedure/toxicity_detection/hydra_configs/conf/example__local__inhouse.yaml similarity index 78% rename from examples/remote_procedure/toxicity_detection/hydra_configs/conf/example_local_mock.yaml rename to examples/remote_procedure/toxicity_detection/hydra_configs/conf/example__local__inhouse.yaml index 1f5bbdbb8..f954dc269 100644 --- a/examples/remote_procedure/toxicity_detection/hydra_configs/conf/example_local_mock.yaml +++ b/examples/remote_procedure/toxicity_detection/hydra_configs/conf/example__local__inhouse.yaml @@ -7,17 +7,21 @@ defaults: - /mephisto/blueprint: remote_procedure - /mephisto/architect: local - - /mephisto/provider: mock + - /mephisto/provider: inhouse mephisto: blueprint: - task_source: ${task_dir}/webapp/build/bundle.js + task_source: ${task_dir}/webapp/build/bundle.remote_procedure.js + task_source_review: ${task_dir}/webapp/build/bundle.review.js link_task_source: false # NOTE pick something based on your task block_qualification: test_qual_block units_per_assignment: 1 + log_level: "debug" + provider: + ui_base_url: "http://localhost:3001" task: allowed_concurrent: 1 - task_name: remote-procedure-test-task + task_name: "Toxicity Example" task_title: "Provide feedback on our toxicity detection model" # NOTE you'll want to update your task description task_description: "Type text into the input box. You will not be able to submit your message to the backend if the message is too toxic (>0.5)." diff --git a/examples/remote_procedure/toxicity_detection/run_task.py b/examples/remote_procedure/toxicity_detection/run_task__local__inhouse.py similarity index 97% rename from examples/remote_procedure/toxicity_detection/run_task.py rename to examples/remote_procedure/toxicity_detection/run_task__local__inhouse.py index 6deb6586a..40ede5bde 100644 --- a/examples/remote_procedure/toxicity_detection/run_task.py +++ b/examples/remote_procedure/toxicity_detection/run_task__local__inhouse.py @@ -56,7 +56,7 @@ def _calculate_toxicity( } -@task_script(default_config_file="example_local_mock") +@task_script(default_config_file="example__local__inhouse") def main(operator: Operator, cfg: DictConfig) -> None: examples.build_remote_procedure_toxicity_detection( force_rebuild=cfg.mephisto.task.force_rebuild, diff --git a/examples/remote_procedure/toxicity_detection/webapp/link_mephisto_task.sh b/examples/remote_procedure/toxicity_detection/webapp/link_mephisto_task.sh deleted file mode 100644 index 6936741b2..000000000 --- a/examples/remote_procedure/toxicity_detection/webapp/link_mephisto_task.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/sh - -# Copyright (c) Meta Platforms and its affiliates. -# This source code is licensed under the MIT license found in the -# LICENSE file in the root directory of this source tree. - -npm link mephisto-task diff --git a/examples/remote_procedure/toxicity_detection/webapp/package.json b/examples/remote_procedure/toxicity_detection/webapp/package.json index 24259b2e8..e8d6781f4 100644 --- a/examples/remote_procedure/toxicity_detection/webapp/package.json +++ b/examples/remote_procedure/toxicity_detection/webapp/package.json @@ -2,16 +2,17 @@ "name": "remote-procedure-toxicity-detection-example", "version": "1.0.1", "description": "", - "main": "webpack.config.js", + "main": "webpack.config.remote_procedure.js", "scripts": { "dev": "webpack --mode development", - "test": "cypress open" + "test": "cypress open", + "build:remote_procedure": "webpack --config=webpack.config.remote_procedure.js --mode development", + "build:review": "webpack --config=webpack.config.review.js --mode development" }, "keywords": [], "author": "", "dependencies": { - "bootstrap": "^4.6.0", - "mephisto-task": "2.0.4", + "bootstrap": "^5.3.1", "rc-slider": "^8.6.3", "react": "^18.2.0", "react-bootstrap": "^1.6.0", diff --git a/examples/remote_procedure/toxicity_detection/webapp/src/app.jsx b/examples/remote_procedure/toxicity_detection/webapp/src/app_remote_procedure.jsx similarity index 87% rename from examples/remote_procedure/toxicity_detection/webapp/src/app.jsx rename to examples/remote_procedure/toxicity_detection/webapp/src/app_remote_procedure.jsx index 65be91ef9..7af4f6ee5 100644 --- a/examples/remote_procedure/toxicity_detection/webapp/src/app.jsx +++ b/examples/remote_procedure/toxicity_detection/webapp/src/app_remote_procedure.jsx @@ -7,10 +7,10 @@ import React from "react"; import ReactDOM from "react-dom"; import { - BaseFrontend, + ToxicityTaskFrontend, LoadingScreen, Instructions, -} from "./components/core_components.jsx"; +} from "./components/core_components_remote_procedure.jsx"; import { MephistoContext, @@ -50,12 +50,8 @@ function RemoteProcedureApp() { return ( -
- + diff --git a/examples/remote_procedure/toxicity_detection/webapp/src/components/core_components.jsx b/examples/remote_procedure/toxicity_detection/webapp/src/components/core_components.jsx deleted file mode 100644 index 2c4b8cde9..000000000 --- a/examples/remote_procedure/toxicity_detection/webapp/src/components/core_components.jsx +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) Meta Platforms and its affiliates. - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - -import React, { Fragment, useState } from "react"; - -function LoadingScreen() { - return Loading...; -} - -function Directions({ children }) { - return ( -
-
-
-

{children}

-
-
-
- ); -} -function Instructions() { - return ( -
-

Toxicity Detection Model

-

- To submit this task, you'll need to enter one or many sentences in the - input box below. The model will calculate the toxicity of the inputted - text. -

-
- ); -} - -function TaskFrontend({ handleSubmit, handleToxicityCalculation }) { - const [text, setText] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const [result, setResult] = useState(""); - const [toxicity, setToxicity] = useState(0); - const [submitError, setSubmitError] = useState(null); - - function calculateToxicity() { - setIsLoading(true); - handleToxicityCalculation({ - text: text, - }) - .then((response) => { - setSubmitError(null); - setIsLoading(false); - const parsedToxicity = parseFloat(response.toxicity); - setToxicity(parsedToxicity); - if (parsedToxicity <= 0.5) { - handleSubmit({ toxicity: response.toxicity }); - } else { - setResult( - `The statement, "${text}," has a toxicity of: ${response.toxicity}. This message is too toxic to submit.` - ); - } - }) - .catch((err) => { - setIsLoading(false); - setSubmitError(err); - console.error(err); - }); - } - - return ( - - -
-