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
+ );
+}
+
+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 (
-
-
- 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.
-
-
- );
-}
-
-export { LoadingScreen, TaskFrontend as BaseFrontend, Instructions };
diff --git a/examples/remote_procedure/toxicity_detection/webapp/src/components/core_components_remote_procedure.jsx b/examples/remote_procedure/toxicity_detection/webapp/src/components/core_components_remote_procedure.jsx
new file mode 100644
index 000000000..f4d86b0b7
--- /dev/null
+++ b/examples/remote_procedure/toxicity_detection/webapp/src/components/core_components_remote_procedure.jsx
@@ -0,0 +1,151 @@
+/*
+ * 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
+
+
+ In this task, you need to enter at least one sentence in the text box
+ below. Then our model will calculate toxicity of the provided text.
+
+
+ );
+}
+
+export { LoadingScreen, ToxicityTaskFrontend, Instructions };
diff --git a/examples/remote_procedure/toxicity_detection/webapp/src/main_remote_procedure.js b/examples/remote_procedure/toxicity_detection/webapp/src/main_remote_procedure.js
new file mode 100644
index 000000000..a02b47cbb
--- /dev/null
+++ b/examples/remote_procedure/toxicity_detection/webapp/src/main_remote_procedure.js
@@ -0,0 +1,8 @@
+/*
+ * 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 "./app_remote_procedure.jsx";
+import "./css/style.css";
+import "bootstrap/dist/css/bootstrap.min.css";
diff --git a/examples/remote_procedure/toxicity_detection/webapp/src/main.js b/examples/remote_procedure/toxicity_detection/webapp/src/review.js
similarity index 90%
rename from examples/remote_procedure/toxicity_detection/webapp/src/main.js
rename to examples/remote_procedure/toxicity_detection/webapp/src/review.js
index f710171aa..adeb1c7d5 100644
--- a/examples/remote_procedure/toxicity_detection/webapp/src/main.js
+++ b/examples/remote_procedure/toxicity_detection/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/toxicity_detection/webapp/src/reviewapp.jsx b/examples/remote_procedure/toxicity_detection/webapp/src/reviewapp.jsx
new file mode 100644
index 000000000..31614bd33
--- /dev/null
+++ b/examples/remote_procedure/toxicity_detection/webapp/src/reviewapp.jsx
@@ -0,0 +1,61 @@
+/*
+ * 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 { ToxicityTaskFrontend } 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/toxicity_detection/webapp/src/static/index.html b/examples/remote_procedure/toxicity_detection/webapp/src/static/index.html
index a8ed9fea6..a6e7bf40b 100644
--- a/examples/remote_procedure/toxicity_detection/webapp/src/static/index.html
+++ b/examples/remote_procedure/toxicity_detection/webapp/src/static/index.html
@@ -10,18 +10,6 @@
Remote Query Example
-
-
-
-
diff --git a/examples/remote_procedure/toxicity_detection/webapp/webpack.config.remote_procedure.js b/examples/remote_procedure/toxicity_detection/webapp/webpack.config.remote_procedure.js
new file mode 100644
index 000000000..fcd26efcf
--- /dev/null
+++ b/examples/remote_procedure/toxicity_detection/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/toxicity_detection/webapp/webpack.config.js b/examples/remote_procedure/toxicity_detection/webapp/webpack.config.review.js
similarity index 94%
rename from examples/remote_procedure/toxicity_detection/webapp/webpack.config.js
rename to examples/remote_procedure/toxicity_detection/webapp/webpack.config.review.js
index 1958271ed..6350057f6 100644
--- a/examples/remote_procedure/toxicity_detection/webapp/webpack.config.js
+++ b/examples/remote_procedure/toxicity_detection/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/video_annotator_demo/webapp/src/reviewapp_dynamic.jsx b/examples/video_annotator_demo/webapp/src/reviewapp_dynamic.jsx
index fd76bc332..e61451cce 100644
--- a/examples/video_annotator_demo/webapp/src/reviewapp_dynamic.jsx
+++ b/examples/video_annotator_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/video_annotator_demo/webapp/src/reviewapp_simple.jsx b/examples/video_annotator_demo/webapp/src/reviewapp_simple.jsx
index 255a87ae4..cd10973ed 100644
--- a/examples/video_annotator_demo/webapp/src/reviewapp_simple.jsx
+++ b/examples/video_annotator_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/mephisto/abstractions/blueprints/remote_procedure/remote_procedure_blueprint.py b/mephisto/abstractions/blueprints/remote_procedure/remote_procedure_blueprint.py
index 4f825b88d..99a59a987 100644
--- a/mephisto/abstractions/blueprints/remote_procedure/remote_procedure_blueprint.py
+++ b/mephisto/abstractions/blueprints/remote_procedure/remote_procedure_blueprint.py
@@ -4,77 +4,75 @@
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
-from mephisto.abstractions.blueprint import (
- Blueprint,
- BlueprintArgs,
- SharedTaskState,
-)
-from dataclasses import dataclass, field
-from mephisto.abstractions.blueprints.mixins.onboarding_required import (
- OnboardingRequired,
- OnboardingSharedState,
- OnboardingRequiredArgs,
-)
-from mephisto.abstractions.blueprints.mixins.screen_task_required import (
- ScreenTaskRequired,
- ScreenTaskRequiredArgs,
- ScreenTaskSharedState,
-)
-from mephisto.abstractions.blueprints.mixins.use_gold_unit import (
- UseGoldUnit,
- UseGoldUnitArgs,
- GoldUnitSharedState,
-)
-from mephisto.data_model.assignment import InitializationData
+import csv
+import json
+import os
+import types
+from dataclasses import dataclass
+from dataclasses import field
+from typing import Any
+from typing import Callable
+from typing import ClassVar
+from typing import Dict
+from typing import Iterable
+from typing import List
+from typing import Mapping
+from typing import Optional
+from typing import Type
+from typing import TYPE_CHECKING
+
+from omegaconf import DictConfig
+from omegaconf import MISSING
+
+from mephisto.abstractions.blueprint import Blueprint
+from mephisto.abstractions.blueprint import BlueprintArgs
+from mephisto.abstractions.blueprint import SharedTaskState
+from mephisto.abstractions.blueprints.mixins.onboarding_required import OnboardingRequired
+from mephisto.abstractions.blueprints.mixins.onboarding_required import OnboardingRequiredArgs
+from mephisto.abstractions.blueprints.mixins.onboarding_required import OnboardingSharedState
+from mephisto.abstractions.blueprints.mixins.screen_task_required import ScreenTaskRequired
+from mephisto.abstractions.blueprints.mixins.screen_task_required import ScreenTaskRequiredArgs
+from mephisto.abstractions.blueprints.mixins.screen_task_required import ScreenTaskSharedState
+from mephisto.abstractions.blueprints.mixins.use_gold_unit import GoldUnitSharedState
+from mephisto.abstractions.blueprints.mixins.use_gold_unit import UseGoldUnit
+from mephisto.abstractions.blueprints.mixins.use_gold_unit import UseGoldUnitArgs
from mephisto.abstractions.blueprints.remote_procedure.remote_procedure_agent_state import (
RemoteProcedureAgentState,
)
-from mephisto.abstractions.blueprints.remote_procedure.remote_procedure_task_runner import (
- RemoteProcedureTaskRunner,
-)
from mephisto.abstractions.blueprints.remote_procedure.remote_procedure_task_builder import (
RemoteProcedureTaskBuilder,
)
-from mephisto.operations.registry import register_mephisto_abstraction
-from omegaconf import DictConfig, MISSING
-
-import os
-import csv
-import json
-import types
-
-from typing import (
- ClassVar,
- Callable,
- Type,
- Any,
- Dict,
- Iterable,
- Optional,
- Mapping,
- TYPE_CHECKING,
+from mephisto.abstractions.blueprints.remote_procedure.remote_procedure_task_runner import (
+ RemoteProcedureTaskRunner,
)
+from mephisto.data_model.assignment import InitializationData
+from mephisto.operations.registry import register_mephisto_abstraction
if TYPE_CHECKING:
+ from mephisto.abstractions.blueprint import AgentState
+ from mephisto.abstractions.blueprint import TaskBuilder
+ from mephisto.abstractions.blueprint import TaskRunner
from mephisto.data_model.task_run import TaskRun
- from mephisto.abstractions.blueprint import AgentState, TaskRunner, TaskBuilder
BLUEPRINT_TYPE_REMOTE_PROCEDURE = "remote_procedure"
+RemoteProcedureRequestIdType = str
+RemoteProcedureArgsType = Any
+RemoteProcedureType = Callable[
+ [RemoteProcedureRequestIdType, RemoteProcedureArgsType, RemoteProcedureAgentState],
+ Optional[Dict[str, Any]],
+]
+FunctionRegistryType = Mapping[str, RemoteProcedureType]
+
@dataclass
class SharedRemoteProcedureTaskState(
- ScreenTaskSharedState, OnboardingSharedState, GoldUnitSharedState, SharedTaskState
+ ScreenTaskSharedState,
+ OnboardingSharedState,
+ GoldUnitSharedState,
+ SharedTaskState,
):
- function_registry: Optional[
- Mapping[
- str,
- Callable[
- [str, Any, "RemoteProcedureAgentState"],
- Optional[Dict[str, Any]],
- ],
- ]
- ] = None
+ function_registry: Optional[FunctionRegistryType] = None
static_task_data: Iterable[Any] = field(default_factory=list)
@@ -86,12 +84,12 @@ class RemoteProcedureBlueprintArgs(
_group: str = field(
default="RemoteProcedureBlueprintArgs",
metadata={
- "help": """
- Tasks launched from remote query blueprints need a
- source html file to display to workers, as well as a csv
- containing values that will be inserted into templates in
- the html.
- """
+ "help": (
+ "Tasks launched from remote query blueprints need a "
+ "source html file to display to workers, as well as a CSV file "
+ "containing values that will be inserted into templates in "
+ "the html."
+ ),
},
)
task_source: str = field(
@@ -120,23 +118,28 @@ class RemoteProcedureBlueprintArgs(
link_task_source: bool = field(
default=False,
metadata={
- "help": """
- Symlinks the task_source file in your development folder to the
- one used for the server. Useful for local development so you can run
- a watch-based build for your task_source, allowing the UI code to
- update without having to restart the server each time.
- """,
+ "help": (
+ "Symlinks the task_source file in your development folder to the "
+ "one used for the server. Useful for local development so you can run "
+ "a watch-based build for your task_source, allowing the UI code to "
+ "update without having to restart the server each time."
+ ),
"required": False,
},
)
units_per_assignment: int = field(
- default=1, metadata={"help": "How many workers you want to do each assignment"}
+ default=1,
+ metadata={
+ "help": "How many workers you want to do each assignment",
+ },
)
@register_mephisto_abstraction()
class RemoteProcedureBlueprint(ScreenTaskRequired, OnboardingRequired, UseGoldUnit, Blueprint):
- """Blueprint for a task that runs a parlai chat"""
+ """Blueprint for a task that needs calling remote procedures from UI"""
+
+ BLUEPRINT_TYPE = BLUEPRINT_TYPE_REMOTE_PROCEDURE
AgentStateClass: ClassVar[Type["AgentState"]] = RemoteProcedureAgentState
OnboardingAgentStateClass: ClassVar[Type["AgentState"]] = RemoteProcedureAgentState
@@ -144,7 +147,6 @@ class RemoteProcedureBlueprint(ScreenTaskRequired, OnboardingRequired, UseGoldUn
TaskRunnerClass: ClassVar[Type["TaskRunner"]] = RemoteProcedureTaskRunner
ArgsClass = RemoteProcedureBlueprintArgs
SharedStateClass = SharedRemoteProcedureTaskState
- BLUEPRINT_TYPE = BLUEPRINT_TYPE_REMOTE_PROCEDURE
def __init__(
self,
@@ -153,24 +155,34 @@ def __init__(
shared_state: "SharedRemoteProcedureTaskState",
):
super().__init__(task_run, args, shared_state)
- self._initialization_data_dicts: Iterable[Dict[str, Any]] = []
+
+ self._initialization_data_dicts: List[Dict[str, Any]] = []
blue_args = args.blueprint
+
+ # CSV
if blue_args.get("data_csv", None) is not None:
csv_file = os.path.expanduser(blue_args.data_csv)
with open(csv_file, "r", encoding="utf-8-sig") as csv_fp:
csv_reader = csv.reader(csv_fp)
headers = next(csv_reader)
+
for row in csv_reader:
row_data = {}
for i, col in enumerate(row):
row_data[headers[i]] = col
self._initialization_data_dicts.append(row_data)
+
+ # JSON
elif blue_args.get("data_json", None) is not None:
json_file = os.path.expanduser(blue_args.data_json)
+
with open(json_file, "r", encoding="utf-8-sig") as json_fp:
json_data = json.load(json_fp)
+
for jd in json_data:
self._initialization_data_dicts.append(jd)
+
+ # JSONL
elif blue_args.get("data_jsonl", None) is not None:
jsonl_file = os.path.expanduser(blue_args.data_jsonl)
with open(jsonl_file, "r", encoding="utf-8-sig") as jsonl_fp:
@@ -179,6 +191,8 @@ def __init__(
j = json.loads(line)
self._initialization_data_dicts.append(j)
line = jsonl_fp.readline()
+
+ # Task data (dynamically passed as `static_task_data` argument - not from files)
elif shared_state.static_task_data is not None:
self._initialization_data_dicts = shared_state.static_task_data
else:
@@ -191,16 +205,28 @@ def assert_task_args(cls, args: "DictConfig", shared_state: "SharedTaskState") -
assert isinstance(
shared_state, SharedRemoteProcedureTaskState
), "Must use SharedTaskState with RemoteProcedureBlueprint"
+
blue_args = args.blueprint
+
+ # CSV
if blue_args.get("data_csv", None) is not None:
csv_file = os.path.expanduser(blue_args.data_csv)
+
assert os.path.exists(csv_file), f"Provided csv file {csv_file} doesn't exist"
+
+ # JSON
elif blue_args.get("data_json", None) is not None:
json_file = os.path.expanduser(blue_args.data_json)
+
assert os.path.exists(json_file), f"Provided JSON file {json_file} doesn't exist"
+
+ # JSONL
elif blue_args.get("data_jsonl", None) is not None:
jsonl_file = os.path.expanduser(blue_args.data_jsonl)
+
assert os.path.exists(jsonl_file), f"Provided JSON-L file {jsonl_file} doesn't exist"
+
+ # Task data (dynamically passed as `static_task_data` argument - not from files)
elif shared_state.static_task_data is not None:
if isinstance(shared_state.static_task_data, types.GeneratorType):
# TODO can we check something about this?
@@ -211,10 +237,11 @@ def assert_task_args(cls, args: "DictConfig", shared_state: "SharedTaskState") -
), "Length of data dict provided was 0"
else:
raise AssertionError("Must provide one of a data csv, json, json-L, or a list of tasks")
+
assert shared_state.function_registry is not None, (
"Must provide a valid function registry to use with the task, a mapping "
"of function names to functions that take as input a string and an agent "
- "and return a string. "
+ "and return a string."
)
def get_initialization_data(self) -> Iterable["InitializationData"]:
@@ -234,7 +261,8 @@ def data_generator() -> Iterable["InitializationData"]:
else:
return [
InitializationData(
- shared=d, unit_data=[{}] * self.args.blueprint.units_per_assignment
+ shared=d,
+ unit_data=[{}] * self.args.blueprint.units_per_assignment,
)
for d in self._initialization_data_dicts
]
diff --git a/mephisto/abstractions/blueprints/static_html_task/static_html_blueprint.py b/mephisto/abstractions/blueprints/static_html_task/static_html_blueprint.py
index d6a4907d4..130fbecdc 100644
--- a/mephisto/abstractions/blueprints/static_html_task/static_html_blueprint.py
+++ b/mephisto/abstractions/blueprints/static_html_task/static_html_blueprint.py
@@ -57,7 +57,7 @@ class StaticHTMLBlueprintArgs(StaticBlueprintArgs):
metadata={
"help": (
"Tasks launched from static blueprints need a "
- "source html file to display to workers, as well as a csv "
+ "source html file to display to workers, as well as a CSV file "
"containing values that will be inserted into templates in "
"the html. "
)
diff --git a/mephisto/client/cli.py b/mephisto/client/cli.py
index ac6aa3520..beb286fe2 100644
--- a/mephisto/client/cli.py
+++ b/mephisto/client/cli.py
@@ -116,45 +116,67 @@ def list_requesters():
@click.argument("args", nargs=-1)
def register_provider(args):
"""Register a requester with a crowd provider"""
+
if len(args) == 0:
logger.error("\n[red]Usage: mephisto register arg1=value arg2=value[/red]")
logger.info("\n[b]Valid Providers[/b]")
- provider_text = """"""
+
+ provider_text = ""
+
for provider in get_valid_provider_types():
provider_text += "\n* " + provider
+
provider_text_markdown = Markdown(provider_text)
console.print(provider_text_markdown)
+
return
from mephisto.abstractions.databases.local_database import LocalMephistoDB
+ from mephisto.operations.hydra_config import get_extra_argument_dicts
+ from mephisto.operations.hydra_config import parse_arg_dict
from mephisto.operations.registry import get_crowd_provider_from_type
- from mephisto.operations.hydra_config import (
- parse_arg_dict,
- get_extra_argument_dicts,
- )
- provider_type, requester_args = args[0], args[1:]
- args_dict = dict(arg.split("=", 1) for arg in requester_args)
+ provider_type, requester_consose_args = args[0], args[1:]
+ args_dict = dict((a.split("=", 1) if "=" in a else (a, "")) for a in requester_consose_args)
crowd_provider = get_crowd_provider_from_type(provider_type)
RequesterClass = crowd_provider.RequesterClass
- if len(requester_args) == 0:
- params = get_extra_argument_dicts(RequesterClass)
+ # Params from RequesterArgs by provider type
+ params = get_extra_argument_dicts(RequesterClass)
+
+ # Names of passed args in console
+ requester_console_arg_names = set(
+ [(a.split("=") if "=" in a else a)[0] for a in requester_consose_args]
+ )
+
+ # Names of requred provider args
+ required_arg_names = set(
+ [name for p in params for name, data in p["args"].items() if data.get("required") is True]
+ )
+
+ has_passed_required_params = len(required_arg_names) == 0 or (
+ required_arg_names.issubset(requester_console_arg_names)
+ )
+ if not has_passed_required_params:
for param in params:
click.echo("\n" + param["desc"])
param_keys = list(param["args"].keys())
+
if len(param_keys) > 0:
first_arg_key = param_keys[0]
requester_headers = list(param["args"][first_arg_key].keys())
requester_table = create_table(requester_headers, "[b]Arguments[/b]")
+
for arg in param["args"]:
arg_values = list(param["args"][arg].values())
arg_values = [str(x) for x in arg_values]
requester_table.add_row(*arg_values)
+
console.print(requester_table)
else:
logger.error("[red]Requester has no args[/red]")
+
return
try:
@@ -169,10 +191,12 @@ def register_provider(args):
db = LocalMephistoDB()
requester_name = parsed_options.name
requesters = db.find_requesters(requester_name=requester_name)
+
if len(requesters) == 0:
requester = RequesterClass.new(db, requester_name)
else:
requester = requesters[0]
+
try:
requester.register(parsed_options)
logger.info(f'[green]Registered requester "{requester_name}" successfully.[/green]')
diff --git a/mephisto/generators/form_composer/webapp/src/reviewapp.jsx b/mephisto/generators/form_composer/webapp/src/reviewapp.jsx
index ad12a65d3..3f29ecead 100644
--- a/mephisto/generators/form_composer/webapp/src/reviewapp.jsx
+++ b/mephisto/generators/form_composer/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/mephisto/generators/video_annotator/webapp/src/reviewapp.jsx b/mephisto/generators/video_annotator/webapp/src/reviewapp.jsx
index d5689cfcb..54110e171 100644
--- a/mephisto/generators/video_annotator/webapp/src/reviewapp.jsx
+++ b/mephisto/generators/video_annotator/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/mephisto/scripts/tests/react_apps.py b/mephisto/scripts/tests/react_apps.py
index 451ebb8e6..2e493f979 100644
--- a/mephisto/scripts/tests/react_apps.py
+++ b/mephisto/scripts/tests/react_apps.py
@@ -44,6 +44,10 @@ def _clean(remove_package_locks: bool):
examples.clean_form_composer_demo(remove_package_locks, verbose=verbose)
examples.clean_video_annotator_demo(remove_package_locks, verbose=verbose)
examples.clean_parlai_chat_task_demo(remove_package_locks, verbose=verbose)
+ examples.clean_remote_procedure_interactive_image_generation(
+ remove_package_locks,
+ verbose=verbose,
+ )
examples.clean_remote_procedure_mnist(remove_package_locks, verbose=verbose)
examples.clean_remote_procedure_template(remove_package_locks, verbose=verbose)
examples.clean_remote_procedure_toxicity_detection(remove_package_locks, verbose=verbose)
diff --git a/mephisto/tools/building_react_apps/examples.py b/mephisto/tools/building_react_apps/examples.py
index 9fa387410..e657fd0ea 100644
--- a/mephisto/tools/building_react_apps/examples.py
+++ b/mephisto/tools/building_react_apps/examples.py
@@ -34,7 +34,11 @@
"interactive_image_generation",
)
REMOTE_PROCEDURE_MNIST_EXAMPLE_PATH = os.path.join(EXAMPLES_PATH, "remote_procedure", "mnist")
-REMOTE_PROCEDURE_TEMPLATE_EXAMPLE_PATH = os.path.join(EXAMPLES_PATH, "remote_procedure", "template")
+REMOTE_PROCEDURE_TEMPLATE_EXAMPLE_PATH = os.path.join(
+ EXAMPLES_PATH,
+ "remote_procedure",
+ "elementary_remote_procedure",
+)
REMOTE_PROCEDURE_TOXICITY_DETECTION_EXAMPLE_PATH = os.path.join(
EXAMPLES_PATH,
"remote_procedure",
@@ -187,42 +191,6 @@ def build_form_composer_dynamic_presigned_urls_ec2_prolific(
)
-def build_interactive_image_generation(
- force_rebuild: bool = False,
- post_install_script: Optional[str] = None,
-) -> None:
- packages.build_mephisto_core_package(force_rebuild=force_rebuild, verbose=True)
- packages.build_mephisto_addons_package(force_rebuild=force_rebuild, verbose=True)
-
- # Set env vars for `custom_validators.js` and `custom_triggers.js`
- from mephisto.client.cli_form_composer_commands import FORM_COMPOSER__DATA_DIR_NAME
-
- data_path = os.path.join(
- REMOTE_PROCEDURE_INTERACTIVE_IMAGE_GENERATION_EXAMPLE_PATH,
- FORM_COMPOSER__DATA_DIR_NAME,
- )
- set_insertions_env_var(data_path)
- set_custom_validators_js_env_var(data_path)
- set_custom_triggers_js_env_var(data_path)
-
- # Build Review UI for the application
- build_custom_bundle(
- REMOTE_PROCEDURE_INTERACTIVE_IMAGE_GENERATION_EXAMPLE_PATH,
- force_rebuild=force_rebuild,
- webapp_name="webapp",
- build_command="build:review",
- )
-
- # Build Task UI for the application
- build_custom_bundle(
- REMOTE_PROCEDURE_INTERACTIVE_IMAGE_GENERATION_EXAMPLE_PATH,
- force_rebuild=force_rebuild,
- webapp_name="webapp",
- post_install_script=post_install_script,
- build_command="build:remote_procedure",
- )
-
-
# --- Video Annotator ---
@@ -314,6 +282,14 @@ def build_parlai_chat_task_demo(
# --- Remote Procedure ---
+def clean_remote_procedure_interactive_image_generation(
+ remove_package_locks: bool,
+ verbose: bool = False,
+):
+ webapp_path = os.path.join(REMOTE_PROCEDURE_INTERACTIVE_IMAGE_GENERATION_EXAMPLE_PATH, "webapp")
+ clean_single_react_app(webapp_path, remove_package_locks=remove_package_locks, verbose=verbose)
+
+
def clean_remote_procedure_mnist(remove_package_locks: bool, verbose: bool = False):
webapp_path = os.path.join(REMOTE_PROCEDURE_MNIST_EXAMPLE_PATH, "webapp")
clean_single_react_app(webapp_path, remove_package_locks=remove_package_locks, verbose=verbose)
@@ -329,6 +305,42 @@ def clean_remote_procedure_toxicity_detection(remove_package_locks: bool, verbos
clean_single_react_app(webapp_path, remove_package_locks=remove_package_locks, verbose=verbose)
+def build_remote_procedure_interactive_image_generation(
+ force_rebuild: bool = False,
+ post_install_script: Optional[str] = None,
+) -> None:
+ packages.build_mephisto_core_package(force_rebuild=force_rebuild, verbose=True)
+ packages.build_mephisto_addons_package(force_rebuild=force_rebuild, verbose=True)
+
+ # Set env vars for `custom_validators.js` and `custom_triggers.js`
+ from mephisto.client.cli_form_composer_commands import FORM_COMPOSER__DATA_DIR_NAME
+
+ data_path = os.path.join(
+ REMOTE_PROCEDURE_INTERACTIVE_IMAGE_GENERATION_EXAMPLE_PATH,
+ FORM_COMPOSER__DATA_DIR_NAME,
+ )
+ set_insertions_env_var(data_path)
+ set_custom_validators_js_env_var(data_path)
+ set_custom_triggers_js_env_var(data_path)
+
+ # Build Review UI for the application
+ build_custom_bundle(
+ REMOTE_PROCEDURE_INTERACTIVE_IMAGE_GENERATION_EXAMPLE_PATH,
+ force_rebuild=force_rebuild,
+ webapp_name="webapp",
+ build_command="build:review",
+ )
+
+ # Build Task UI for the application
+ build_custom_bundle(
+ REMOTE_PROCEDURE_INTERACTIVE_IMAGE_GENERATION_EXAMPLE_PATH,
+ force_rebuild=force_rebuild,
+ webapp_name="webapp",
+ post_install_script=post_install_script,
+ build_command="build:remote_procedure",
+ )
+
+
def build_remote_procedure_mnist(
force_rebuild: bool = False,
post_install_script: Optional[str] = None,
@@ -358,12 +370,20 @@ def build_remote_procedure_template(
) -> None:
packages.build_mephisto_core_package(force_rebuild=force_rebuild, verbose=True)
+ # Build Review UI for the application
+ build_custom_bundle(
+ REMOTE_PROCEDURE_TEMPLATE_EXAMPLE_PATH,
+ force_rebuild=force_rebuild,
+ webapp_name="webapp",
+ build_command="build:review",
+ )
+
# Build Task UI for the application
build_custom_bundle(
REMOTE_PROCEDURE_TEMPLATE_EXAMPLE_PATH,
force_rebuild=force_rebuild,
post_install_script=post_install_script,
- build_command="dev",
+ build_command="build:remote_procedure",
)
@@ -373,12 +393,20 @@ def build_remote_procedure_toxicity_detection(
) -> None:
packages.build_mephisto_core_package(force_rebuild=force_rebuild, verbose=True)
+ # Build Review UI for the application
+ build_custom_bundle(
+ REMOTE_PROCEDURE_TOXICITY_DETECTION_EXAMPLE_PATH,
+ force_rebuild=force_rebuild,
+ webapp_name="webapp",
+ build_command="build:review",
+ )
+
# Build Task UI for the application
build_custom_bundle(
REMOTE_PROCEDURE_TOXICITY_DETECTION_EXAMPLE_PATH,
force_rebuild=force_rebuild,
post_install_script=post_install_script,
- build_command="dev",
+ build_command="build:remote_procedure",
)
diff --git a/mephisto/tools/scripts.py b/mephisto/tools/scripts.py
index e84a7fd2d..afe891e57 100644
--- a/mephisto/tools/scripts.py
+++ b/mephisto/tools/scripts.py
@@ -98,6 +98,7 @@ def task_script(
else:
assert default_config_file is not None, "Must provide one of config or default_config_file"
used_config = build_default_task_config(default_config_file)
+
register_script_config(name="taskconfig", module=used_config)
def task_script_wrapper(script_func: TaskFunction) -> TaskFunction:
@@ -160,11 +161,13 @@ def augment_config_from_db(script_cfg: DictConfig, db: "MephistoDB") -> DictConf
if provider_type is None:
print("No requester specified, defaulting to mock")
provider_type = "mock"
+
if provider_type == "mock":
req = get_mock_requester(db)
requester_name = req.requester_name
else:
reqs = db.find_requesters(provider_type=provider_type)
+
if len(reqs) == 0:
print(
f"No requesters found for provider type {provider_type}, please "
@@ -187,12 +190,14 @@ def augment_config_from_db(script_cfg: DictConfig, db: "MephistoDB") -> DictConf
else:
# Ensure provided requester exists
reqs = db.find_requesters(requester_name=requester_name)
+
if len(reqs) == 0:
print(
f"No requesters found under name {requester_name}, "
"have you registered with `mephisto register`?"
)
exit(1)
+
requester_provider_type = reqs[0].provider_type
if provider_type != requester_provider_type:
print(
@@ -206,6 +211,7 @@ def augment_config_from_db(script_cfg: DictConfig, db: "MephistoDB") -> DictConf
if provider_type in ["mturk"]:
try_prerun_cleanup(db, cfg.provider.requester_name)
input(f"This task is going to launch live on {provider_type}, press enter to continue: ")
+
if provider_type in ["mturk_sandbox", "mturk"] and architect_type not in [
"heroku",
"ec2",
@@ -218,6 +224,7 @@ def augment_config_from_db(script_cfg: DictConfig, db: "MephistoDB") -> DictConf
cfg.provider.requester_name = requester_name
cfg.provider._provider_type = provider_type
+
return script_cfg