gradio-app / gradio

Build and share delightful machine learning apps, all in Python. 🌟 Star to support our work!
http://www.gradio.app
Apache License 2.0
33.43k stars 2.53k forks source link

More documentation around event chaining, especially for things like clearing and triggering other components #7348

Closed JohnDuncanScott closed 4 months ago

JohnDuncanScott commented 8 months ago

[x] I have searched to see if a similar issue already exists.

Is your feature request related to a problem? Please describe.
The documentation is generally really good, but I'm struggling with chaining different events together. The concrete example I have is: ` chatbot = gr.Chatbot(height=300, render=False) textbox = gr.Textbox(container=False, scale=7, render=False) clear_button = gr.ClearButton([textbox, chatbot], render=False)

system_prompt_dropdown = gr.Dropdown(
    choices=[prompt.value for prompt in SystemPromptType],
    value=default_system_prompt_type_value,
    label="Character type (sets description)",
    render=False,
)
system_prompt_dropdown.change(
    gradio_system_prompt_dropdown_change,
    inputs=system_prompt_dropdown,
    outputs=system_prompt_textbox,
)

`

When the dropdown change event happens (i.e. the user selects a value), I would like to call the click event on the clear_button button programmatically so that it then clears textbox and chatbot. I can't seem to get this to work and I'm not sure what the correct way is of "calling" a component from another component, while also re-using the variables I've defined, if that makes sense?

So basically, on dropdown change, call clear button click. My Python is rusty and I'm just learning Gradio, so apologies if it's something obvious :).

Describe the solution you'd like
More documentation.

dwipper commented 8 months ago

@JohnDuncanScott An easy way to accomplish the clearing of the textbox (or anything other controls) is to clear the value of the textbox as part of the return from your gradio_system_prompt_dropdown_change function. it would look something like this:

def gradio_system_prompt_dropdown_change():
    return gr.Textbox(value="")

This sets the value of the gradio_system_prompt_dropdown_change output referenced in your .change event. It's covered in a section on this page: https://www.gradio.app/guides/blocks-and-event-listeners

You can also ask question like this on the Gradio Discord: https://discord.com/channels/879548962464493619/1025174734427656283

JohnDuncanScott commented 8 months ago

Thanks for the response, I saw that, but it's not quite what I want I think. Each of those components have customisations, so the new component would need to match that. You'd need to create a factory method for each component just to initialise it and then re-create it back to being empty and keep the original customisation (unless I'm misunderstanding the documentation) (e.g. in your above example, I'm assuming the new textbox would lose the container=False, scale=7 customisation since it's replacing the original).

I have a clear button that already has been given the components to clear. I just need to be able to fire a clear event to it somehow after the change event fires on the other component. That seems the cleanest way of doing it.

I can ask questions on the Discord, but because those are hidden away from search engines people don't get the benefit of seeing these discussions to solve future similar questions :).

dwipper commented 8 months ago

@JohnDuncanScott Actually, the rest of the customizations of the component stay as-is. Only the specific param passed in the return gets changed. So it's not that a new component is created, it just updates the current component. But I do agree that in certain circumstances, it would be better to simulate a click on the Clear button that already has a variety of logic built into it's click event.

JohnDuncanScott commented 8 months ago

Ah I see, thanks for clarifying. It would be great to tweak the docs to mention that. The code looks like it's creating a new instance and returning that but I appreciate it's more subtle and clever than that now. I will take that approach as I only have a couple of components.

Is it actually possible to simulate the click with the current API out of curiosity?

realliyifei commented 8 months ago

@dwipper Updating Component Configurations seems to not work for Dropdown. Here I want to change the choices of dropdown depending on the radio value (then the next step is to generate the contents by the selected choices in dropdown), but then the Dropdown component is not responsible.

def change_textbox(choice):
    return gr.Dropdown(label=f"Select a paper {choice}", choices=['test3', 'test4']) 

with gr.Blocks() as demo:
    radio = gr.Radio(
        ["short", "long", "none"], label="What kind of essay would you like to write?"
    )
    text = gr.Dropdown(label="Select a paper 1", choices=['test1', 'test2']) 
    radio.change(fn=change_textbox, inputs=radio, outputs=text) 
dwipper commented 8 months ago

@realliyifei Running the above code, I noticed that the DD wasn't interactive. When I changed that, it works:

import gradio as gr

def change_textbox(choice):
    return gr.Dropdown(label=f"Select a paper {choice}", choices=["test3", "test4"])

with gr.Blocks() as demo:
    radio = gr.Radio(
        ["short", "long", "none"], label="What kind of essay would you like to write?"
    )
    text = gr.Dropdown(label="Select a paper 1", choices=['test1', 'test2'], interactive=True)
    radio.change(fn=change_textbox, inputs=radio, outputs=text)

demo.launch()