Skip to content

Commit

Permalink
VideoAnnotator UI fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
meta-paul committed Sep 25, 2024
1 parent ca044d4 commit e5aa95c
Show file tree
Hide file tree
Showing 34 changed files with 555 additions and 167 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ While attributes values are limited to numbers and text, these fields (at any hi
_Note that, due to limitations of JSON format, HTML content needs to be converted into a single long string of text._

You can style fields with HTML-classes in `classes` attribute. You can use any bootstrap classes or our built-in classes:
- `hidden` - if you need to hide element and show it later with custom triggerm, but you do not need it be a fully hidden field (`"type": "hidden"`)
- `hidden` - if you need to hide element and show it later with custom trigger, but you do not need it be a fully hidden field (`"type": "hidden"`)
- `centered` - centered horizontally

TBD: Other classes and styles insertions
Expand Down
2 changes: 1 addition & 1 deletion docs/web/docs/guides/how_to_use/review_app/running.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ where

Command `mephisto review_app` supports the following options:

- `-h/--host` - host where TaskReview app will be served
- `-H/--host` - host where TaskReview app will be served
- `-p/--port` - port where TaskReview app will be served
- `-d/--debug` - run in debug mode (with extra logging)
- `-f/--force-rebuild` - force rebuild React bundle (use if your Task client code has been updated)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,34 @@ Task data config file `task_data.json` specifies layout of all form versions tha
"instruction": "<div class=\"instruction\">\n Please annotate everything you think is necessary.\n</div>\n\n<style>\n .instruction {\n font-style: italic;\n }\n</style>\n",
"video": "https://my-bucket.s3.amazonaws.com/my-folder/video.mp4",
"show_instructions_as_modal": true,
"segment_fields": [
{
"id": "id_title",
"label": "Segment name",
"name": "title",
"type": "input",
"validators": {
"required": true,
"minLength": 1,
"maxLength": 40
}
},
{
"id": "id_description",
"label": "Describe what you see in this segment",
"name": "description",
"type": "textarea",
"validators": {
"minLength": 2,
"maxLength": 500,
"checkForbiddenWords": true
},
"triggers": {
"onFocus": ["onFocusDescription", "\"Describe what you see in this segment\""]
}
},
{ ... }
],
"submit_button": {
"instruction": "If you are ready and think that you described everything, submit the results.",
"text": "Submit",
Expand All @@ -63,7 +91,7 @@ Task data config file `task_data.json` specifies layout of all form versions tha
]
```

### Assignment config levels
### Unit config levels

VideoAnnotator UI layout consists of the following layers of UI object hierarchy:

Expand All @@ -83,7 +111,6 @@ While attributes values are limited to numbers and text, these fields (at any hi
_Note that, due to limitations of JSON format, HTML content needs to be converted into a single long string of text._

You can style fields with HTML-classes in `classes` attribute. You can use any bootstrap classes or our built-in classes:
- `hidden` - if you need to hide element and show it later with custom triggerm, but you do not need it be a fully hidden field (`"type": "hidden"`)
- `centered` - centered horizontally

TBD: Other classes and styles insertions
Expand All @@ -101,16 +128,98 @@ TBD: Other classes and styles insertions
- `show_instructions_as_modal` - Enables showing `instruction` content as a modal (opened by clicking a sticky button in top-right corner); this make lengthy task instructions available from any place of a lengthy form without scrolling the page (Boolean, Optional, Default: false)
- `title` - HTML header of the form (String)
- `video` - URL to preuploaded video file (String)
- `segment_fields` - **List of fields** that will be added into each track segment
- `submit_button` - Button to submit the whole form and thus finish a task (Object)
- `id` - Unique HTML id of the button, in case we need to refer to it from custom handlers code (String, Optional)
- `instruction` - Text shown above the "Submit" button (String, Optional)
- `text` - Label shown on the button (String)
- `tooltip` - Browser tooltip shown on mouseover (String, Optional)
- `triggers` - Functions that are being called on available React-events (`onClick`, see [JS trigger insertion](/docs/guides/how_to_use/video_annotator/configuration/insertions/#js-trigger-insertion))

---

#### Config level: field

Each item of `segment_fields` list is an object that corresponds to the track segment field displayed in the resulting Task UI page.

Here's example of a single field config:

```json
{
"id": "id_title",
"label": "Segment name",
"name": "title",
"type": "input",
"validators": {
"required": true,
"minLength": 2,
"maxLength": 20,
"regexp": ["^[a-z\.\-']+$", "ig"]
// or can use this --> "regexp": "^[a-z\.\-']+$"
},
"value": ""
}
```

---

### Attributes for "field" config level

#### `value` attribute

The `value` attribute specifies initial value of a field, and has the following format:

- String for `input`, `textarea`, `email`, `number`, `password`, `radio`, and `select` with `"multiple": false` field types
- For `radio` and `select` fields, it must be one of the input options' values
- Object for `checkbox`
- The object should consist of all checkbox options with their Boolean value, e.g. `{"react": true, "python": true, "sql": false}`
- Array<String\> for `select` with `"multiple": true`
- All array items must be input options' values, e.g. `["python", "sql"]`


#### Attributes - all fields

The most important attributes are: `label`, `name`, `type`, `validators`

- `help` - HTML explanation of the field/fieldset displayed in small font below the field (String, Optional)
- `id` - Unique HTML id of the field, in case we need to refer to it from custom handlers code (String, Optional)
- `classes` = Custom classes that you can use to restyle element or refer to it from custom handlers code (String, Optional)
- `label` - Field name displayed above the field (String)
- `name` - Unique name under which this field's data will be sent to the server (String)
- `placeholder` - Text faintly displayed in the field before user provides a value (String, Optional)
- `tooltip` - Text shown in browser tooltip on mouseover (String, Optional)
- `type` - Type of the field (`input`, `email`, `select`, `textarea`, `checkbox`, `radio`, `file`, `hidden`) (String)
- `validators` - Validators preventing incorrect data from being submitted (Object[<String\>: String|Boolean|Number], Optional). Supported key-value pairs for the `validators` object:
- `required`: Ensure field is not left empty (Boolean)
- `minLength`: Ensure minimal number of typed characters or selected choices (Number)
- `maxLength`: Ensure maximum number of typed characters or selected choices (Number)
- `regexp`: Ensure provided value confirms to a Javascript regular expression. It can be:
- (String): a regexp string (e.g. `"^[a-zA-Z0-9._-]+$"`) in which case default matching flags are `igm` are used
- (2-item Array[String, String]): a regexp string followed by matching flags (e.g. `["^[a-zA-Z0-9._-]+$", "ig"]`)
- `value` - Initial value of the field (String, Optional)
- `triggers` - Functions that are being called on available React-events (`onClick`, `onChange`, `onBlur`, `onFocus`, see [JS trigger insertion](/docs/guides/how_to_use/video_annotator/configuration/insertions/#js-trigger-insertion))


#### Attributes - select field

- `multiple` - Support selection of multiple provided options, not just one (Boolean. Default: false)
- `options` - list of available options to select from. Each option is an object with these attributes:
- `label`: displayed text (String)
- `value`: value sent to the server (String|Number|Boolean)


#### Attributes - checkbox and radio fields

- `options` - list of available options to select from. Each option is an object with these attributes:
- `label`: displayed text (String)
- `value`: value sent to the server (String|Number|Boolean)
- `checked`: initial state of selection (Boolean, default: false)

_Note that, comparing FormComposer, VideoAnnotator segments do not have fields `file` and `hidden`._

## Config file: `unit_config.json`

Assignment config file `unit_config.json` specifies layout of an annotator in the same way as `task_data.json`, but with a few notable differences:
Unit config file `unit_config.json` specifies layout of an annotator in the same way as `task_data.json`, but with a few notable differences:
- It contains a single JSON object (not a JSON array of objects)
- Some of its form attributes definitions must contain dynamic tokens (whose values will be extrapolated, i.e. substituted with variable chunks of text) - see further below.

Expand Down
2 changes: 1 addition & 1 deletion examples/video_annotator_demo/data/dynamic/task_data.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@
{
"id": "id_person_name",
"label": "Person name",
"help": "The name of talking person",
"help": "Select name of the person who is talking",
"multiple": false,
"name": "person_name",
"type": "select",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
{
"id": "id_person_name",
"label": "Person name",
"help": "The name of talking person",
"help": "Select name of the person who is talking",
"multiple": false,
"name": "person_name",
"type": "select",
Expand Down
11 changes: 8 additions & 3 deletions mephisto/client/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from mephisto.client.cli_db_commands import db_cli
from mephisto.client.cli_form_composer_commands import form_composer_cli
from mephisto.client.cli_metrics_commands import metrics_cli
from mephisto.client.cli_review_app_commands import review_app
from mephisto.client.cli_review_app_commands import review_app_cli
from mephisto.client.cli_scripts_commands import run_script
from mephisto.client.cli_video_annotator_commands import video_annotator_cli
from mephisto.client.cli_wut_commands import run_wut
Expand All @@ -24,7 +24,12 @@
logger = ConsoleWriter()


@click.group(cls=RichGroup)
@click.group(
cls=RichGroup,
context_settings={
"help_option_names": ["-h", "--help"],
},
)
def cli():
"""[deep_sky_blue4]Bring your research ideas to life
with powerful crowdsourcing tooling[/]
Expand Down Expand Up @@ -179,7 +184,7 @@ def register_provider(args):
run_script
)
cli.command("wut", cls=RichCommand, context_settings={"ignore_unknown_options": True})(run_wut)
cli.command("review_app", cls=RichCommand)(review_app)
cli.add_command(review_app_cli)
cli.add_command(form_composer_cli)
cli.add_command(video_annotator_cli)
cli.add_command(metrics_cli)
Expand Down
2 changes: 1 addition & 1 deletion mephisto/client/cli_db_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def _print_used_options_for_running_command_message(ctx: click.Context, options:
logger.debug(message)


@click.group(name="db", context_settings=dict(help_option_names=["-h", "--help"]), cls=RichGroup)
@click.group(name="db", cls=RichGroup)
def db_cli():
"""Operations with Mephisto DB and provider-specific datastores"""
pass
Expand Down
7 changes: 1 addition & 6 deletions mephisto/client/cli_form_composer_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,7 @@ def _get_form_composer_app_path() -> str:
return app_path


@click.group(
name="form_composer",
context_settings=dict(help_option_names=["-h", "--help"]),
cls=RichGroup,
invoke_without_command=True,
)
@click.group(name="form_composer", cls=RichGroup, invoke_without_command=True)
@click.pass_context
@click.option(
"-o",
Expand Down
6 changes: 1 addition & 5 deletions mephisto/client/cli_metrics_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,7 @@
logger = ConsoleWriter()


@click.group(
name="metrics",
context_settings=dict(help_option_names=["-h", "--help"]),
cls=RichGroup,
)
@click.group(name="metrics", cls=RichGroup)
def metrics_cli():
"""View task health and status with Mephisto Metrics"""
pass
Expand Down
64 changes: 57 additions & 7 deletions mephisto/client/cli_review_app_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,65 @@
import click
from flask.cli import pass_script_info
from flask.cli import ScriptInfo
from rich_click import RichGroup

from mephisto.utils.console_writer import ConsoleWriter
from mephisto.tools.building_react_apps import review_app as _review_app
from mephisto.utils.console_writer import ConsoleWriter

logger = ConsoleWriter()


@click.option("-h", "--host", type=str, default="127.0.0.1")
@click.option("-p", "--port", type=int, default=5000)
@click.option("-d", "--debug", type=bool, default=False, is_flag=True)
@click.option("-f", "--force-rebuild", type=bool, default=False, is_flag=True)
@click.option("-s", "--skip-build", type=bool, default=False, is_flag=True)
@click.group(
name="review_app",
cls=RichGroup,
invoke_without_command=True,
)
@click.pass_context
@click.option(
"-H",
"--host",
type=str,
default="127.0.0.1",
help="Host where TaskReview app will be served",
)
@click.option(
"-p",
"--port",
type=int,
default=5000,
help="Port where TaskReview app will be served",
)
@click.option(
"-d",
"--debug",
type=bool,
default=False,
is_flag=True,
help="Run in debug mode (with extra logging)",
)
@click.option(
"-f",
"--force-rebuild",
type=bool,
default=False,
is_flag=True,
help="Force rebuild React bundle (use if your Task client code has been updated)",
)
@click.option(
"-s",
"--skip-build",
type=bool,
default=False,
is_flag=True,
help=(
"Skip all installation and building steps for the UI, and directly launch the server "
"(use if no code has been changed)"
),
)
@pass_script_info
def review_app(
def review_app_cli(
info: ScriptInfo,
ctx: click.Context,
host: Optional[str],
port: Optional[int],
debug: bool = False,
Expand All @@ -36,6 +80,12 @@ def review_app(
Launch a local review server.
Custom implementation of `flask run <app_name>` command (`flask.cli.run_command`)
"""

if ctx.invoked_subcommand is not None:
# It's needed to add the ability to run other commands,
# run default code only if there's no other command after `review_app`
return

from flask.cli import show_server_banner
from flask.helpers import get_debug_flag
from mephisto.review_app.server import create_app
Expand Down
7 changes: 1 addition & 6 deletions mephisto/client/cli_video_annotator_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,7 @@ def _get_video_annotator_app_path() -> str:
return app_path


@click.group(
name="video_annotator",
context_settings=dict(help_option_names=["-h", "--help"]),
cls=RichGroup,
invoke_without_command=True,
)
@click.group(name="video_annotator", cls=RichGroup, invoke_without_command=True)
@click.pass_context
@click.option(
"-o",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,13 @@
from mephisto.generators.generators_utils.constants import CONTENTTYPE_BY_EXTENSION
from mephisto.generators.generators_utils.constants import JSON_IDENTATION
from mephisto.generators.generators_utils.constants import S3_URL_EXPIRATION_MINUTES
from mephisto.utils.logger_core import get_logger
from mephisto.utils.console_writer import ConsoleWriter
from .config_validation_constants import CUSTOM_TRIGGERS_JS_FILE_NAME
from .config_validation_constants import CUSTOM_TRIGGERS_JS_FILE_NAME_ENV_KEY
from .config_validation_constants import CUSTOM_VALIDATORS_JS_FILE_NAME
from .config_validation_constants import CUSTOM_VALIDATORS_JS_FILE_NAME_ENV_KEY

logger = get_logger(name=__name__)
logger = ConsoleWriter()
s3_client = boto3.client("s3")


Expand Down
7 changes: 7 additions & 0 deletions mephisto/review_app/client/src/pages/TaskPage/TaskPage.css
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@
color: #ccc;
}

.task .review-board .right-side .info .task-name {
text-overflow: ellipsis;
max-width: 250px;
white-space: nowrap;
overflow: hidden;
}

.task .review-board .right-side .info .grey {
color: #999;
}
Expand Down
Loading

0 comments on commit e5aa95c

Please sign in to comment.