mirror of
https://github.com/gradio-app/gradio.git
synced 2025-04-12 12:40:29 +08:00
Allow showing progress updates on arbitrary components (#10492)
* changes * changes * add changeset * changes * changes * add changeset * add changeset * format * typing * changes --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Ali Abid <aliabid94@gmail.com>
This commit is contained in:
parent
0c62e3e7b9
commit
29880d51fb
7
.changeset/neat-cobras-lie.md
Normal file
7
.changeset/neat-cobras-lie.md
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
"@gradio/client": minor
|
||||
"@gradio/core": minor
|
||||
"gradio": minor
|
||||
---
|
||||
|
||||
feat:Allow showing progress updates on arbitrary components
|
@ -249,6 +249,7 @@ export interface Dependency {
|
||||
trigger: "click" | "load" | string;
|
||||
max_batch_size: number;
|
||||
show_progress: "full" | "minimal" | "hidden";
|
||||
show_progress_on: number[] | null;
|
||||
frontend_fn: ((...args: unknown[]) => Promise<unknown[]>) | null;
|
||||
status?: string;
|
||||
queue: boolean | null;
|
||||
|
@ -1 +1 @@
|
||||
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: cancel_events"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import time\n", "import gradio as gr\n", "import atexit\n", "import pathlib\n", "\n", "log_file = pathlib.Path(__file__).parent / \"cancel_events_output_log.txt\"\n", "\n", "def fake_diffusion(steps):\n", " log_file.write_text(\"\")\n", " for i in range(steps):\n", " print(f\"Current step: {i}\")\n", " with log_file.open(\"a\") as f:\n", " f.write(f\"Current step: {i}\\n\")\n", " time.sleep(0.2)\n", " yield str(i)\n", "\n", "def long_prediction(*args, **kwargs):\n", " time.sleep(10)\n", " return 42\n", "\n", "with gr.Blocks() as demo:\n", " with gr.Row():\n", " with gr.Column():\n", " n = gr.Slider(1, 10, value=9, step=1, label=\"Number Steps\")\n", " run = gr.Button(value=\"Start Iterating\")\n", " output = gr.Textbox(label=\"Iterative Output\")\n", " stop = gr.Button(value=\"Stop Iterating\")\n", " with gr.Column():\n", " textbox = gr.Textbox(label=\"Prompt\")\n", " prediction = gr.Number(label=\"Expensive Calculation\")\n", " run_pred = gr.Button(value=\"Run Expensive Calculation\")\n", " with gr.Column():\n", " cancel_on_change = gr.Textbox(\n", " label=\"Cancel Iteration and Expensive Calculation on Change\"\n", " )\n", " cancel_on_submit = gr.Textbox(\n", " label=\"Cancel Iteration and Expensive Calculation on Submit\"\n", " )\n", " echo = gr.Textbox(label=\"Echo\")\n", " with gr.Row():\n", " with gr.Column():\n", " image = gr.Image(\n", " sources=[\"webcam\"], label=\"Cancel on clear\", interactive=True\n", " )\n", " with gr.Column():\n", " video = gr.Video(\n", " sources=[\"webcam\"], label=\"Cancel on start recording\", interactive=True\n", " )\n", "\n", " click_event = run.click(fake_diffusion, n, output)\n", " stop.click(fn=None, inputs=None, outputs=None, cancels=[click_event])\n", " pred_event = run_pred.click(\n", " fn=long_prediction, inputs=[textbox], outputs=prediction\n", " )\n", "\n", " cancel_on_change.change(None, None, None, cancels=[click_event, pred_event])\n", " cancel_on_submit.submit(\n", " lambda s: s, cancel_on_submit, echo, cancels=[click_event, pred_event]\n", " )\n", " image.clear(None, None, None, cancels=[click_event, pred_event])\n", " video.start_recording(None, None, None, cancels=[click_event, pred_event])\n", "\n", " demo.queue(max_size=20)\n", " atexit.register(lambda: log_file.unlink())\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
|
||||
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: cancel_events"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import time\n", "import gradio as gr\n", "import atexit\n", "import pathlib\n", "\n", "log_file = pathlib.Path(__file__).parent / \"cancel_events_output_log.txt\"\n", "\n", "def fake_diffusion(steps):\n", " log_file.write_text(\"\")\n", " for i in range(steps):\n", " print(f\"Current step: {i}\")\n", " with log_file.open(\"a\") as f:\n", " f.write(f\"Current step: {i}\\n\")\n", " time.sleep(0.2)\n", " yield str(i)\n", "\n", "def long_prediction(*args, **kwargs):\n", " time.sleep(4)\n", " return 42, 42\n", "\n", "with gr.Blocks() as demo:\n", " with gr.Row():\n", " with gr.Column():\n", " n = gr.Slider(1, 10, value=9, step=1, label=\"Number Steps\")\n", " run = gr.Button(value=\"Start Iterating\")\n", " output = gr.Textbox(label=\"Iterative Output\")\n", " stop = gr.Button(value=\"Stop Iterating\")\n", " with gr.Column():\n", " textbox = gr.Textbox(label=\"Prompt\")\n", " loading_box = gr.Textbox(label=\"Loading indicator for expensive calculation\")\n", " loading_box2 = gr.Textbox(label=\"Loading indicator for expensive calculation\")\n", " prediction = gr.Number(label=\"Expensive Calculation\")\n", " prediction2 = gr.Number(label=\"Expensive Calculation\")\n", " run_pred = gr.Button(value=\"Run Expensive Calculation\")\n", " with gr.Column():\n", " cancel_on_change = gr.Textbox(\n", " label=\"Cancel Iteration and Expensive Calculation on Change\"\n", " )\n", " cancel_on_submit = gr.Textbox(\n", " label=\"Cancel Iteration and Expensive Calculation on Submit\"\n", " )\n", " echo = gr.Textbox(label=\"Echo\")\n", " with gr.Row():\n", " with gr.Column():\n", " image = gr.Image(\n", " sources=[\"webcam\"], label=\"Cancel on clear\", interactive=True\n", " )\n", " with gr.Column():\n", " video = gr.Video(\n", " sources=[\"webcam\"], label=\"Cancel on start recording\", interactive=True\n", " )\n", "\n", " click_event = run.click(fake_diffusion, n, output)\n", " stop.click(fn=None, inputs=None, outputs=None, cancels=[click_event])\n", " pred_event = run_pred.click(\n", " fn=long_prediction, inputs=[textbox], outputs=[prediction, prediction2], show_progress_on=[loading_box, loading_box2]\n", " )\n", "\n", " cancel_on_change.change(None, None, None, cancels=[click_event, pred_event])\n", " cancel_on_submit.submit(\n", " lambda s: s, cancel_on_submit, echo, cancels=[click_event, pred_event]\n", " )\n", " image.clear(None, None, None, cancels=[click_event, pred_event])\n", " video.start_recording(None, None, None, cancels=[click_event, pred_event])\n", "\n", " demo.queue(max_size=20)\n", " atexit.register(lambda: log_file.unlink())\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
|
@ -15,8 +15,8 @@ def fake_diffusion(steps):
|
||||
yield str(i)
|
||||
|
||||
def long_prediction(*args, **kwargs):
|
||||
time.sleep(10)
|
||||
return 42
|
||||
time.sleep(4)
|
||||
return 42, 42
|
||||
|
||||
with gr.Blocks() as demo:
|
||||
with gr.Row():
|
||||
@ -27,7 +27,10 @@ with gr.Blocks() as demo:
|
||||
stop = gr.Button(value="Stop Iterating")
|
||||
with gr.Column():
|
||||
textbox = gr.Textbox(label="Prompt")
|
||||
loading_box = gr.Textbox(label="Loading indicator for expensive calculation")
|
||||
loading_box2 = gr.Textbox(label="Loading indicator for expensive calculation")
|
||||
prediction = gr.Number(label="Expensive Calculation")
|
||||
prediction2 = gr.Number(label="Expensive Calculation")
|
||||
run_pred = gr.Button(value="Run Expensive Calculation")
|
||||
with gr.Column():
|
||||
cancel_on_change = gr.Textbox(
|
||||
@ -50,7 +53,7 @@ with gr.Blocks() as demo:
|
||||
click_event = run.click(fake_diffusion, n, output)
|
||||
stop.click(fn=None, inputs=None, outputs=None, cancels=[click_event])
|
||||
pred_event = run_pred.click(
|
||||
fn=long_prediction, inputs=[textbox], outputs=prediction
|
||||
fn=long_prediction, inputs=[textbox], outputs=[prediction, prediction2], show_progress_on=[loading_box, loading_box2]
|
||||
)
|
||||
|
||||
cancel_on_change.change(None, None, None, cancels=[click_event, pred_event])
|
||||
|
@ -511,6 +511,7 @@ class BlockFunction:
|
||||
api_name: str | Literal[False] = False,
|
||||
js: str | None = None,
|
||||
show_progress: Literal["full", "minimal", "hidden"] = "full",
|
||||
show_progress_on: Sequence[Component] | None = None,
|
||||
cancels: list[int] | None = None,
|
||||
collects_event_data: bool = False,
|
||||
trigger_after: int | None = None,
|
||||
@ -548,6 +549,7 @@ class BlockFunction:
|
||||
self.api_name = api_name
|
||||
self.js = js
|
||||
self.show_progress = show_progress
|
||||
self.show_progress_on = show_progress_on
|
||||
self.cancels = cancels or []
|
||||
self.collects_event_data = collects_event_data
|
||||
self.trigger_after = trigger_after
|
||||
@ -605,6 +607,9 @@ class BlockFunction:
|
||||
"api_name": self.api_name,
|
||||
"scroll_to_output": self.scroll_to_output,
|
||||
"show_progress": self.show_progress,
|
||||
"show_progress_on": None
|
||||
if self.show_progress_on is None
|
||||
else [block._id for block in self.show_progress_on],
|
||||
"batch": self.batch,
|
||||
"max_batch_size": self.max_batch_size,
|
||||
"cancels": self.cancels,
|
||||
@ -708,6 +713,7 @@ class BlocksConfig:
|
||||
postprocess: bool = True,
|
||||
scroll_to_output: bool = False,
|
||||
show_progress: Literal["full", "minimal", "hidden"] = "full",
|
||||
show_progress_on: Component | Sequence[Component] | None = None,
|
||||
api_name: str | None | Literal[False] = None,
|
||||
js: str | None = None,
|
||||
no_target: bool = False,
|
||||
@ -741,6 +747,7 @@ class BlocksConfig:
|
||||
postprocess: whether to run the postprocess methods of the output components after running the function
|
||||
scroll_to_output: whether to scroll to output of dependency on trigger
|
||||
show_progress: how to show the progress animation while event is running: "full" shows a spinner which covers the output component area as well as a runtime display in the upper right corner, "minimal" only shows the runtime display, "hidden" shows no progress animation at all
|
||||
show_progress_on: Component or list of components to show the progress animation on. If None, will show the progress animation on all of the output components.
|
||||
api_name: defines how the endpoint appears in the API docs. Can be a string, None, or False. If set to a string, the endpoint will be exposed in the API docs with the given name. If None (default), the name of the function will be used as the API endpoint. If False, the endpoint will not be exposed in the API docs and downstream apps (including those that `gr.load` this app) will not be able to use this event.
|
||||
js: Optional frontend js method to run before running 'fn'. Input arguments for js method are values of 'inputs' and 'outputs', return should be a list of values for output components
|
||||
no_target: if True, sets "targets" to [], used for the Blocks.load() event and .then() events
|
||||
@ -785,6 +792,8 @@ class BlocksConfig:
|
||||
outputs = []
|
||||
elif not isinstance(outputs, Sequence):
|
||||
outputs = [outputs]
|
||||
if show_progress_on and not isinstance(show_progress_on, Sequence):
|
||||
show_progress_on = [show_progress_on]
|
||||
|
||||
if fn is not None and not cancels:
|
||||
check_function_inputs_match(fn, inputs, inputs_as_dict)
|
||||
@ -863,6 +872,7 @@ class BlocksConfig:
|
||||
api_name=api_name,
|
||||
js=js,
|
||||
show_progress=show_progress,
|
||||
show_progress_on=show_progress_on,
|
||||
cancels=cancels,
|
||||
collects_event_data=collects_event_data,
|
||||
trigger_after=trigger_after,
|
||||
|
@ -27,6 +27,7 @@ INTERFACE_TEMPLATE = '''
|
||||
api_name: str | None | Literal[False] = None,
|
||||
scroll_to_output: bool = False,
|
||||
show_progress: Literal["full", "minimal", "hidden"] = "full",
|
||||
show_progress_on: Component | Sequence[Component] | None = None,
|
||||
queue: bool | None = None,
|
||||
batch: bool = False,
|
||||
max_batch_size: int = 4,
|
||||
@ -51,6 +52,7 @@ INTERFACE_TEMPLATE = '''
|
||||
api_name: defines how the endpoint appears in the API docs. Can be a string, None, or False. If False, the endpoint will not be exposed in the api docs. If set to None, will use the functions name as the endpoint route. If set to a string, the endpoint will be exposed in the api docs with the given name.
|
||||
scroll_to_output: if True, will scroll to output component on completion
|
||||
show_progress: how to show the progress animation while event is running: "full" shows a spinner which covers the output component area as well as a runtime display in the upper right corner, "minimal" only shows the runtime display, "hidden" shows no progress animation at all
|
||||
show_progress_on: Component or list of components to show the progress animation on. If None, will show the progress animation on all of the output components.
|
||||
queue: if True, will place the request on the queue, if the queue has been enabled. If False, will not put this event on the queue, even if the queue has been enabled. If None, will use the queue setting of the gradio app.
|
||||
batch: if True, then the function should process a batch of inputs, meaning that it should accept a list of input values for each parameter. The lists should be of equal length (and be up to length `max_batch_size`). The function is then *required* to return a tuple of lists (even if there is only 1 output component), with each list in the tuple corresponding to one output component.
|
||||
max_batch_size: maximum number of inputs to batch together if this is called from the queue (only relevant if batch=True)
|
||||
|
@ -474,6 +474,7 @@ if TYPE_CHECKING:
|
||||
Union[str, None, Literal[False]],
|
||||
bool,
|
||||
Literal["full", "minimal", "hidden"],
|
||||
Union[Component, Sequence[Component], None],
|
||||
Union[bool, None],
|
||||
bool,
|
||||
int,
|
||||
@ -578,6 +579,7 @@ class EventListener(str):
|
||||
api_name: str | None | Literal[False] = None,
|
||||
scroll_to_output: bool = False,
|
||||
show_progress: Literal["full", "minimal", "hidden"] = _show_progress,
|
||||
show_progress_on: Component | Sequence[Component] | None = None,
|
||||
queue: bool = True,
|
||||
batch: bool = False,
|
||||
max_batch_size: int = 4,
|
||||
@ -601,6 +603,7 @@ class EventListener(str):
|
||||
api_name: defines how the endpoint appears in the API docs. Can be a string, None, or False. If set to a string, the endpoint will be exposed in the API docs with the given name. If None (default), the name of the function will be used as the API endpoint. If False, the endpoint will not be exposed in the API docs and downstream apps (including those that `gr.load` this app) will not be able to use this event.
|
||||
scroll_to_output: If True, will scroll to output component on completion
|
||||
show_progress: how to show the progress animation while event is running: "full" shows a spinner which covers the output component area as well as a runtime display in the upper right corner, "minimal" only shows the runtime display, "hidden" shows no progress animation at all
|
||||
show_progress_on: Component or list of components to show the progress animation on. If None, will show the progress animation on all of the output components.
|
||||
queue: If True, will place the request on the queue, if the queue has been enabled. If False, will not put this event on the queue, even if the queue has been enabled. If None, will use the queue setting of the gradio app.
|
||||
batch: If True, then the function should process a batch of inputs, meaning that it should accept a list of input values for each parameter. The lists should be of equal length (and be up to length `max_batch_size`). The function is then *required* to return a tuple of lists (even if there is only 1 output component), with each list in the tuple corresponding to one output component.
|
||||
max_batch_size: Maximum number of inputs to batch together if this is called from the queue (only relevant if batch=True)
|
||||
@ -625,6 +628,7 @@ class EventListener(str):
|
||||
api_name=api_name,
|
||||
scroll_to_output=scroll_to_output,
|
||||
show_progress=show_progress,
|
||||
show_progress_on=show_progress_on,
|
||||
queue=queue,
|
||||
batch=batch,
|
||||
max_batch_size=max_batch_size,
|
||||
@ -672,6 +676,7 @@ class EventListener(str):
|
||||
postprocess=postprocess,
|
||||
scroll_to_output=scroll_to_output,
|
||||
show_progress=show_progress,
|
||||
show_progress_on=show_progress_on,
|
||||
api_name=api_name,
|
||||
js=js,
|
||||
concurrency_limit=concurrency_limit,
|
||||
@ -738,6 +743,7 @@ def on(
|
||||
api_name: str | None | Literal[False] = None,
|
||||
scroll_to_output: bool = False,
|
||||
show_progress: Literal["full", "minimal", "hidden"] = "full",
|
||||
show_progress_on: Component | Sequence[Component] | None = None,
|
||||
queue: bool = True,
|
||||
batch: bool = False,
|
||||
max_batch_size: int = 4,
|
||||
@ -764,7 +770,8 @@ def on(
|
||||
outputs: List of gradio.components to use as outputs. If the function returns no outputs, this should be an empty list.
|
||||
api_name: Defines how the endpoint appears in the API docs. Can be a string, None, or False. If False, the endpoint will not be exposed in the api docs. If set to None, will use the functions name as the endpoint route. If set to a string, the endpoint will be exposed in the api docs with the given name.
|
||||
scroll_to_output: If True, will scroll to output component on completion
|
||||
show_progress: how to show the progress animation while event is running: "full" shows a spinner which covers the output component area as well as a runtime display in the upper right corner, "minimal" only shows the runtime display, "hidden" shows no progress animation at all
|
||||
show_progress: how to show the progress animation while event is running: "full" shows a spinner which covers the output component area as well as a runtime display in the upper right corner, "minimal" only shows the runtime display, "hidden" shows no progress animation at all,
|
||||
show_progress_on: Component or list of components to show the progress animation on. If None, will show the progress animation on all of the output components.
|
||||
queue: If True, will place the request on the queue, if the queue has been enabled. If False, will not put this event on the queue, even if the queue has been enabled. If None, will use the queue setting of the gradio app.
|
||||
batch: If True, then the function should process a batch of inputs, meaning that it should accept a list of input values for each parameter. The lists should be of equal length (and be up to length `max_batch_size`). The function is then *required* to return a tuple of lists (even if there is only 1 output component), with each list in the tuple corresponding to one output component.
|
||||
max_batch_size: Maximum number of inputs to batch together if this is called from the queue (only relevant if batch=True)
|
||||
@ -813,6 +820,7 @@ def on(
|
||||
api_name=api_name,
|
||||
scroll_to_output=scroll_to_output,
|
||||
show_progress=show_progress,
|
||||
show_progress_on=show_progress_on,
|
||||
queue=queue,
|
||||
batch=batch,
|
||||
max_batch_size=max_batch_size,
|
||||
@ -864,6 +872,7 @@ def on(
|
||||
postprocess=postprocess,
|
||||
scroll_to_output=scroll_to_output,
|
||||
show_progress=show_progress,
|
||||
show_progress_on=show_progress_on,
|
||||
api_name=api_name,
|
||||
js=js,
|
||||
concurrency_limit=concurrency_limit,
|
||||
|
@ -131,7 +131,11 @@ export function create_components(initial_layout: ComponentMeta | undefined): {
|
||||
components.push(_rootNode);
|
||||
|
||||
dependencies.forEach((dep) => {
|
||||
loading_status.register(dep.id, dep.inputs, dep.outputs);
|
||||
loading_status.register(
|
||||
dep.id,
|
||||
dep.inputs,
|
||||
dep.show_progress_on || dep.outputs
|
||||
);
|
||||
dep.frontend_fn = process_frontend_fn(
|
||||
dep.js,
|
||||
!!dep.backend_fn,
|
||||
|
@ -55,6 +55,7 @@ export interface Dependency {
|
||||
js: string | null;
|
||||
scroll_to_output: boolean;
|
||||
show_progress: "full" | "minimal" | "hidden";
|
||||
show_progress_on: number[] | null;
|
||||
frontend_fn: ((...args: unknown[]) => Promise<unknown[]>) | null;
|
||||
status?: string;
|
||||
queue: boolean | null;
|
||||
|
Loading…
x
Reference in New Issue
Block a user