restrict typing in input field in UI by making it read-only

I have a field at the top of my UI before the text to be annotated (this is a prompt, and the text below it is the response). The prompt is there for additional information for the annotator. The text doesn't fit into the field, it just runs to the edge and gets cut off. I would like the field to increase as the text does. I tried card_css, in prodigy.json,
but this didn't impact the field, just increased the size of the field where my main text is and the choices. Sample in screenshot.

How can I wrap the text in the prompt field? And possibly allow for line breaks already in the .jsonl data? I would also like to display this but not in a text_input field, but something static. Is there a way to do this?

I was able to increase the size and see a scroll bar, but I don't want the annotators to edit the content in this box. Can I disable editing?

Thanks!
Cheyanne

Is there a reason why you cannot render the prompt as a block of custom HTML?

@koaning Are there any examples of this?

Our documentation page on custom interfaces has a section on blocks as well as custom HTML components that use a template.

Alternatively, you might also like the demo in this Youtube video. Here I am using Jinja2 templates directly from Python to create a custom interface for data deduplication.

@koaning I reviewed the video and also went through the forums and custom interfaces documentation, but I'm still unable to render custom html output in the UI.

I edited the prodigy.json by changing false to true, but then got an error that said this setting may overlap with my recipe configuration, so I removed it.

"html_template": true,
⚠ Config setting 'html_template' defined in recipe is overwritten by a
different value set in the global or local prodigy.json. This may lead to
unexpected results and potentially changes to the core behavior of the recipe.
If that's surprising, you should probably remove the setting 'html_template'
from your prodigy.json.

After removing it, I am still getting this error:

⚠ Config setting 'html_template' defined in recipe is overwritten by a
different value set in the global or local prodigy.json. This may lead to
unexpected results and potentially changes to the core behavior of the recipe.
If that's surprising, you should probably remove the setting 'html_template'
from your prodigy.json.
✘ Invalid components returned by recipe
'custom-labels-prompt-multi-intent'

config -> html_template   str type expected           
config -> html_template   value is not a valid boolean

{'dataset': 'flow_control_test2', 'view_id': 'blocks', 'config': {'html_template': <Template 'deployment_prompt.html'>, 'blocks': [{'view_id': 'text_input', 'field_id': 'deployment', 'field_label': 'deployment', 'field_rows': 1}, {'view_id': 'text_input', 'field_id': 'prompt', 'field_label': 'prompt', 'field_rows': 2}, {'view_id': 'choice'}, {'view_id': 'text_input', 'field_label': 'user input field'}, {'view_id': 'html', 'html_template': <Template 'deployment_prompt.html'>}], 'choice_style': 'multiple'}, 'stream': <generator object add_options at 0x1278fd6d0>}

I have tried adding the following components to my return statement in my custom recipe:

    return {
        "dataset": dataset,
        "view_id": "blocks",
        "config": {"html_template": template, "blocks": blocks, "choice_style": "multiple"},
#        "config": {
#            "blocks": [
#                {"view_id": "choice", "choice_style": "multiple"},
#                {"view_id": "html", "html_template": template},
#                ]
#            },
        "stream": stream
#        "config": {"blocks": blocks, "choice_style": "multiple"}
    }

The last config line is my original recipe.

Anything I am missing?

Other components of my recipe that I added for html. I am calling an html file in my templates dir:

import jinja2
from jinja2 import Environment, select_autoescape, FileSystemLoader, Markup, PackageLoader
ROWS_WITH_HTML = [
    {"view_id": "text_input", "field_id": "deployment", "field_label": "deployment", "field_rows": 1},
    {"view_id": "text_input", "field_id": "prompt", "field_label": "prompt", "field_rows": 2},
    {"view_id": "choice"},
    {
        "view_id": "text_input", 
        "field_label": "user input field"
    }
]
   blocks = ROWS_WITH_HTML
    templateLoader = jinja2.FileSystemLoader(searchpath="path_to_templates")
    templateEnv = jinja2.Environment(loader=templateLoader, autoescape=select_autoescape(["html"]))
#    env = Environment(loader=FileSystemLoader(searchpath='path_to_templates'))
    template = templateEnv.get_template('deployment_prompt.html') 
    blocks += [{"view_id": "html", "html_template": template}]

Thanks,
Cheyanne

If you're using the Jinja2 pattern from the Youtube video (code can be found here), then you won't need to set the html_template parameter in your Prodigy config. The way it works in that video is that we merely add an html key to each item in the stream, via;

def add_options(stream):
    # Helper function to add options to every task in a stream
    options = [
        {"id": "duplicate", "text": "✅ duplicate"},
        {"id": "unique", "text": "❌ unique"},
        {"id": "check", "text": "🤔 double-check"},
    ]
    for task in stream:
        task["options"] = options
        task["html"] = env.get_template("intermediate.html").render(item1=task['item1'], item2=task['item2'])
        yield task

This is enough to render custom HTML in the recipe, but in the video, I am using the "choice" view_id. The HTML is generated on-the-fly here using none of the templating tools that Prodigy provides.

@prodigy.recipe(
    "duplicate",
    dataset=("The dataset to save to", "positional", None, str),
    file_path=("The jsonl file with matched items", "positional", None, str),
)
def check_duplicate(dataset, file_path):
    """Annotate yes/no duplicate."""
    stream = JSONL(file_path)     # load in the JSONL file
    stream = add_options(stream)  # add options to each task

    return {
        "dataset": dataset,   # save annotations in this dataset
        "view_id": "choice",  # use the choice interface
        "stream": stream,
        "config": {"choice_auto_accept": True},
    }

You seem to be interested in doing something similar, but using the "blocks" view. that adds two text fields .That's also possible. To do that I only need to change the check_duplicate function.

@prodigy.recipe(
    "duplicate",
    dataset=("The dataset to save to", "positional", None, str),
    file_path=("The jsonl file with matched items", "positional", None, str),
)
def check_duplicate(dataset, file_path):
    """Annotate yes/no duplicate."""
    stream = JSONL(file_path)     # load in the JSONL file
    stream = add_options(stream)  # add options to each task

    return {
        "dataset": dataset,   # save annotations in this dataset
        "view_id": "blocks",  # use the blocks interface
        "stream": stream,
        "config": {
            "blocks": [
                {"view_id": "text_input", "field_rows": 3, "field_id": "first_field"},
                {"view_id": "html"},
                {"view_id": "text_input", "field_rows": 3, "field_id": "first_field"},
            ]
        }
    }

When I do that the custom HTML is wrapped between two text inputs.

This is a setup that works with jinja2 and it omits the templating feature of spaCy. Let me know if this does/not work for you or if you prefer an alternative setup that uses the Prodigy HTML templates.