Checkbox results do not show up in output

I used the following code to create a checkbox to track errors in our documents. If I check the box, I do not see any results of the checkbox in my output.

Any thoughts on how I can

  • ensure the results show up as 1 (checked) or 0 (unchecked) in the output?
    {"view_id": "html", "html_template": "<div style='float:left;'>" +
        "<input type='checkbox' id='stt' name='stt' value='STT Error' style='margin-right:10px;' data-id='{{chat_id}}'>" +
        "<label for='stt'>STT Error</label>" +
      "</div>"
    },

I made a slight variation of what your code does by adding some Javascript.

import prodigy

@prodigy.recipe("checkbox")
def checkbox():
    template = """
    <form>
        <div>
            <p>{{text}}</p>
            <label onclick="update()">check this box!</label>
            <input class="checkbox" type='checkbox' value='{{n}}' onchange="update()">
        </div>
    </form>
    """
 
    javascript = """
    function update(){
        let checked = document.querySelector(".checkbox").checked;
        prodigy.update({"checked": checked})
        console.log("update ran");
    }

    document.addEventListener('prodigyanswer', event => {
        const {answer, task} = event.detail;
        console.log(answer);
        console.log(task);
    })
    """
    return {
        "dataset": "checkbox-demo",
        "view_id": "html",
        "stream": ({'text': f"This is example {i}", "n": i} for i in range(1000)),
        "config": {
            "html_template": template,
            "javascript": javascript,
        },
    }

I can this recipe via:

python -m prodigy checkbox -F recipe.py

And this gives me this interface:

When you click the checkbox, you should see that the console logs "update ran". When you hit A to accept you'll also see a log appear of the answer and the task. This is what the task looks like when I check the checkbox.

{
  checked: true
  n: 0
  text: "This is example 0"
  _input_hash: 780466941
  _task_hash: -621577502
  _view_id: "HTML"
}

You'll notice that checked is set to true. I can also confirm, after hitting the save button, that this is stored in Prodigy.

python -m prodigy db-out checkbox-demo
# {"text":"This is example 0","n":0,"_input_hash":780466941,"_task_hash":-621577502,"_view_id":"html","checked":true,"answer":"accept","_timestamp":1656571196}

Does this suffice?

As a best practice, I do recommend adding checked as a key in your task stream that has a default value set to False. Javascript can be used to inject anything into the task, but it would be more consistent if it merely updates keys instead of adding new ones.

I have a follow-up question for this issue. The following code works well in other recipes I have written, but for some reason the checkbox state persists as "checked" with this recipe. I've tried clearing the cache, using an incognito browser, etc. I would like to use "view_id": "blocks", in the return statement.

If I reload the page, the checkbox shows up unchecked as unloading.

import json
from typing import Dict, Generator

import prodigy
from prodigy.components.loaders import JSONL

from annotator.recipes.utils import EUP

UNLIMITED_ROWS = [
    {"view_id": "html", "html_template":
        "<div style=\"padding: 0 10px; border: 1px solid #ddd; border-radius: 4px; text-align: left;\">" +
        "<label style=\"font-size: 14px; opacity: 0.90; margin-bottom: 10px;\">eup</label>" +
        "<div style=\"max-height: 300px; overflow-y: scroll; margin-bottom: 10px;\">{{eup}}" +
        "<br>" +
        "<br>" +
        "<label style=\"font-size: 14px; opacity: 0.90; margin-bottom: 10px;\">utterance</label>" +
        "<div style=\"max-height: 300px; overflow-y: scroll; margin-bottom: 10px;\">{{utterance}}"
      "</div>"
    },
    {"view_id": "choice"},
    {"view_id": "html", "html_template": "<div style='float:left;'>" +
        "<input type='checkbox' id='newname' name='new_name' value='New Name' style='margin-right:10px;' data-id='{{chat_id}}' onchange='update()'" +
        "<label onclick='update()'>New Name</label>" + 
      "</div>"
    },
    {"view_id": "text_input", "field_label": "user input field"}
]

def add_options(
        stream, label_field="label", choices=EUP
) -> Generator[Dict, None, None]:
    """
    Convert each line in the ``stream`` to a ``task`` with a text and an
    options field

    :param stream: the input stream
    :param label_field: key; defaults to "label"
    :param choices: the different choices
    :yield: a task Dict with text and options
    """
    for line in stream:
        if label_field in line:
            options = json.loads(line[label_field])
        else:
            options = []
        for word in (options + choices):
            if word not in options:
                options.append(word)
        task = {
            "eup": line["eup"],
            "utterance": line["utterance"],
            "newname": False,
            "options": [
                {"id": o, "deployment": o, "prompt": o,
                "text": o} for o in options
            ]
        }

        yield task

@prodigy.recipe(
    "eup",
    dataset=("The dataset to save to", "positional", None, str),
    file_path=("Path to texts", "positional", None, str),
    label_field=("Label to use for the accept task", "option", "f", str),
    choice_field=("Choices to add to the input", "option", "c", str)
)
def custom_labels(dataset, file_path, label_field, choice_field):
    """
    Annotate the text with labels from the list from the ``label_field`` in
    the input file. Augmented with choices from ``choice_field``.
    """

    blocks = UNLIMITED_ROWS

    stream = JSONL(file_path)
    stream = add_options(stream)  # add options to each task

    javascript = """
    function update(){
        let checked = document.querySelector(".checkbox").checked;
        prodigy.update({"checked": checked})
        console.log("update ran");
    }

    document.addEventListener('prodigyanswer', event => {
        const {answer, task} = event.detail;
        console.log(answer);
        console.log(task);
    })
    """

    return {
        "dataset": dataset,
        "view_id": "blocks",
        "stream": list(stream),
        "config": {
          "blocks": blocks,
          "javascript": javascript
        }
    }

I have it working now with this code:

    javascript = """
      // Set checkboxname to false by default
      prodigy.update({ checkboxname: false });

      function updateUnnatural() {
        prodigy.update({ checkboxname: document.getElementById('checkboxname').checked });
      }

      document.addEventListener('prodigyanswer', (event) => {
        // Reset checkboxname to false
        prodigy.update({ checkboxname: false });

        document.getElementById('checkboxname').checked = false;  
      });
    """
2 Likes