Modular prompt builder using CheckboxGroups

The main goal is to have something like a prompt builder, where the user has several words at their disposal and can check/uncheck them to build a small phrase, preferably keeping the order at which they were selected.

I’m not sure if this is the best approach to the problem but I think the most appropriate component to use would be a CheckboxGroup. I have several categories of words, those are loaded into Accordion layouts, inside the categories are subcategories that I’m trying to replicate with the CheckboxGroups, the data comes from a json file, when the user clicks a word, that word must be appended to a prompt list variable, in the end joining all the words into a Label component. This is the draft of what I’m working with right now (excuse the incomplete update_prompt function, that’s where I’m stuck at the moment):

        import json

        def create_accordion(title, data):
            with container:
                with gr.Accordion(title, open=False):
                    for subcategory in data:
                        cg = gr.CheckboxGroup(label=subcategory, choices=data[subcategory])
                        cg.change(update_prompt, cg, cg)

        def update_prompt(value):
            lbl.visible = True if len(prompt) > 0 else False
            prompt.append(value)
            # lbl.value = ", ".join(prompt)
            return value

        prompt = []

        lbl = gr.Label(visible=False)

        with gr.Box() as container:
            gr.Markdown("Select Words:")

        with open("./scripts/prompt_maker_words.json") as j:
            options = json.load(j)

        for category in options:
            create_accordion(category, options[category])

The issue I’m struggling with right now is the unchecking, making sure there are no duplicates in the final prompt and order preservation.

When passing the CheckboxGroup to the change() function, the inputs value is a list of all the True values inside the group, but without knowing where it came from I can’t reliably update the prompt variable, perhaps passing the whole component would help in extracting the label value for instance.

Some of the things that might help:

  • Be able to iterate over all the checkbox values inside the Box container and rebuild prompt every time change() is triggered. The main drawback with this would be loss of order.

  • Turning the prompt variable into a dict, with each category (CheckboxGroup label) having their own key with the corresponding value being the current True values of the corresponding CheckboxGroup. However I’m not entirely sure how to get the label value of the CheckboxGroup when passing it to the change() function. The order would also be lost.

I also tried with Checkbox components instead but the return value is just True, it’s not much usable in this case where I don’t know where the variable is coming from. Is there a way to pass in the whole component? Do we have access to all the children components of the main container (Box layout in this case)?

If it helps this is what the json looks like:

{
  "Category 1": {
    "Subcategory 1": ["Item 1", "Item 2", "Item 3"],
    "Subcategory 2": ["Item 1", "Item 2"]
  }
}

Does anyone have any tips that could guide me in the right direction? This seems like a simple problem but my knowledge about the framework is still too limited to take full advantage of it.

Thanks in advance!

Update: Looking at the instance of CheckboxGroup created in the create_accordion function, I can see there is an internal _id variable unique to each component, this might be useful to use in a tuple for checking previous entries of the same group/component.