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.56k stars 2.54k forks source link

Pass in input parameters as a dict whose keys are all of the input components #2471

Closed vzakharov closed 2 years ago

vzakharov commented 2 years ago

Is your feature request related to a problem? Please describe.

When writing an event handler, I don’t always know in advance what kind of inputs it will need. For example, when generating music with OpenAI Jukebox, you need to obviously need to take “generation length” as an input, but you might also add other parameters down the line (artist name, lyrics, etc.)

Currently I have to add them one by one in a specific order and remember/follow that order throughout coding.

Describe the solution you'd like

It would be much easier if I just could pass a dict containing any parameters I might need as **kwargs to the event handler.

Additional context

As you’ve already implemented a similar approach for outputs (which can be returned as a dict rather than a list), it sounds like it would make sense to make the same possible for event handler arguments?

abidlabs commented 2 years ago

Hi @vzakharov thanks for the suggestion! cc @aliabid94 with regards to updating the Blocks API..

vzakharov commented 2 years ago

Just realized kwargs would make no sense (as how would you be able which key corresponds to which component?). A better way would be to pass a dict (perhaps named as _inputs), where keys are components themselves (and not just strings).

aliabid94 commented 2 years ago

Looking into this!

TashaSkyUp commented 2 years ago

I feel like being able to pass the input and output for events as dicts would be a game-changer for Gradio. Having to maintain an ever-changing and possibly amended list is.. cumbersome.

jrhe commented 1 year ago

Just realized kwargs would make no sense (as how would you be able which key corresponds to which component?). A better way would be to pass a dict (perhaps named as _inputs), where keys are components themselves (and not just strings).

Can you elaborate on this? I'm trying to understand why you'd want to use the components as keys rather than a string set in the component, e.g. label, or a dedicated ID parameter.

I find using the components as keys very cumbersome, as it means the components have to be in scope for the event handler, more tightly coupling the event handlers to the interface. With string keys, the event handlers become plain functions which can be called anywhere with no knowledge of gradio, and the interface of the event handler can be more explicitly defined with keyword arguments.

CWKSC commented 6 months ago

According to: https://www.gradio.app/guides/blocks-and-event-listeners#function-return-list-vs-dict

Components as keys is trouble, I can't define the event function in another file

Look like event listener cannot bind outside with gr.Blocks:

AttributeError: Cannot call xxxxxx outside of a gradio.Blocks context.

I tried pass components with State, but it will give me error:

TypeError: The initial value of `gr.State` must be able to be deepcopied. The initial value of type <class 'dict'> cannot be deepcopied.

One possible workaround is manually call __enter__ and __exit__ on gr.Blocks instead of using with statement

Construct the block in middle and bind the event listener later


Updated:

My purpose is to partial update the value or status of component

https://www.gradio.app/guides/blocks-and-event-listeners#running-events-consecutively

I find it useful to Running Events Consecutively, don't use a dict for output, all functions return or yield using list, and split the event function with .then() or .success()

Now I can have some function that only update the message, and don't mixed with other process:

def update_message():
    return gr.Markdown("...")
<component>.<event>(
    <func1>,
    ...
).success(
    update_message,
    outputs=[<text_component>]
).success(
    <func2>,
    ...
)