How to include both a multiple-choice question and a single-choice question in the same image annotation task.

For each image to be annotated, I have two questions: One is a multiple-choice (non-exclusive) question, with 4 choices, and the other is a single-choice (exclusive) question with 3 choices. I would like to include both in the same task, so that the annotators don't have to go over the same images for a second round, but I don't know how exactly I can specify the config file and/or the streamed data.

My current setup shown below is only for the multiple-choice question (plus a text-input field). I don't know how I can set things up properly so that the single choice question can be incorporated. Any pointer would be greatly appreciated!

@prodigy.recipe("image-annotation",
    dataset=("Dataset to save answers to", "positional", None, str),
    source=("Data to annotate (file path or '-' to read from standard input)", "positional", None, str),
    single_choice_labels=("Comma-separated label(s) for single-choice question", "option", "l1", get_labels),
    multiple_choice_labels=("Comma-separated label(s) to multiple-choice question", "option", "l2", get_labels),
    view_id=("Annotation interface", "option", "v", str),
    exclusive=("Treat classes as mutually exclusive (if not set, an example can have multiple correct classes)", "flag", "E", bool)
)
def image_annotation(dataset, source, single_choice_labels, multiple_choice_labels, view_id, exclusive=False):
    single_choice_labels = single_choice_labels
    multiple_choice_labels = multiple_choice_labels

    OPTIONS_SINGLE_CHOICE = [{"id": i, "text": x.upper()} for i, x in enumerate(single_choice_labels)]    
    OPTIONS_MULTIPLE_CHOICE = [{"id": i, "text": x.upper()} for i, x in enumerate(multiple_choice_labels)]
    
    def get_stream():
        image_dict = pickle.load(open(source, 'rb'))
        for path, item in image_dict.items():
            img = file_to_b64(path)
            yield {"image": img, 
                   "path": path,
                   "config": {"choice_style": "multiple"},
                   "options": OPTIONS_MULTIPLE_CHOICE}
    return {
        "dataset": dataset,
        "stream": get_stream(),
        "view_id": "blocks",
        "config": {"blocks": [{"view_id": "choice",},
                              {"view_id": "text_input", 
                               "field_rows": 2, 
                               "field_label": 'Write any comments you might have'}]}}
1 Like

Hi! The main problem here is that the choice UI currently writes to the same key, "accept", so you can't easily have two choice blocks (even though it's possible to display them by overriding the "options" on the block). I think I already have this topic on my list of enhancements, though: if we allow customising the key to save the selected options to, you can have any number of choice blocks, if they write to different keys.

In the meantime, one solution would be to make one of the option blocks a custom HTML block with radio buttons or checkboxes. See this thread for examples: