Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Timer component #8505

Merged
merged 54 commits into from
Jun 28, 2024
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
be480a4
chagnes
Jun 7, 2024
486c20e
add changeset
gradio-pr-bot Jun 7, 2024
9b04005
changes
Jun 7, 2024
c204ab0
changes
Jun 9, 2024
53af29d
Merge branch 'timer_event_listener' of https://github.com/gradio-app/…
Jun 9, 2024
d5dc03e
changes
Jun 10, 2024
4d0a537
Merge remote-tracking branch 'origin' into timer_event_listener
Jun 10, 2024
789fba8
Merge remote-tracking branch 'origin' into timer_event_listener
Jun 10, 2024
cb9fd09
changes
Jun 10, 2024
05924ef
Merge remote-tracking branch 'origin' into timer_event_listener
Jun 12, 2024
3a69f74
changes
Jun 12, 2024
f4f2f15
Merge remote-tracking branch 'origin' into timer_event_listener
Jun 12, 2024
3d641da
changes
Jun 12, 2024
54f025d
changes
Jun 12, 2024
0d69e96
changes
Jun 12, 2024
8b74afa
changes
Jun 12, 2024
0af8d6d
changes
Jun 13, 2024
023a246
changes
Jun 13, 2024
bde393b
changes
Jun 13, 2024
eec6f35
changes
Jun 13, 2024
742112a
Merge remote-tracking branch 'origin' into timer_event_listener
Jun 13, 2024
a2e0bdf
changes
Jun 13, 2024
e5bf2fe
Merge branch 'main' into timer_event_listener
aliabid94 Jun 14, 2024
398f92c
change
Jun 14, 2024
47b3905
add docs
aliabd Jun 15, 2024
187e717
add changeset
gradio-pr-bot Jun 15, 2024
e89ddca
remove demo
aliabd Jun 15, 2024
376db8f
Merge branch 'timer_event_listener' of https://github.com/gradio-app/…
aliabd Jun 15, 2024
eef0b53
Merge branch 'main' into timer_event_listener
pngwn Jun 15, 2024
2031e82
Merge branch 'main' into timer_event_listener
aliabd Jun 15, 2024
1404e52
Merge branch 'main' into timer_event_listener
abidlabs Jun 19, 2024
c778af5
add changeset
gradio-pr-bot Jun 20, 2024
f94b60e
changes
Jun 20, 2024
cf9d69a
add changeset
gradio-pr-bot Jun 20, 2024
cf7828a
changes
Jun 25, 2024
53b4222
changes
Jun 25, 2024
6915705
changes
Jun 25, 2024
5fa2dbb
add changeset
gradio-pr-bot Jun 25, 2024
bcf3dca
Merge remote-tracking branch 'origin' into timer_event_listener
Jun 25, 2024
d0655dd
Merge branch 'timer_event_listener' of https://github.com/gradio-app/…
Jun 25, 2024
9a7072e
changes
Jun 25, 2024
7872a20
changes
Jun 25, 2024
945806d
changes
Jun 26, 2024
be99ccb
changes
Jun 26, 2024
a4de90f
changes
Jun 26, 2024
21c3479
changes
Jun 26, 2024
1bd6546
changes
Jun 26, 2024
6a27dc3
changes
Jun 26, 2024
90173bf
changes
Jun 26, 2024
7930ee1
Update gradio/components/timer.py
aliabid94 Jun 26, 2024
115e7c7
Merge branch 'main' into timer_event_listener
abidlabs Jun 27, 2024
d8db005
changes
Jun 27, 2024
171f085
Merge remote-tracking branch 'origin' into timer_event_listener
Jun 27, 2024
de843f3
changes
Jun 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/hungry-rice-thank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@gradio/app": minor
"@gradio/timer": minor
"gradio": minor
---

feat:Add Timer component
1 change: 1 addition & 0 deletions demo/function_values/run.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: function_values"]}, {"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 gradio as gr\n", "import random\n", "\n", "countries = [\n", " \"Algeria\", \"Argentina\", \"Australia\", \"Brazil\", \"Canada\", \"China\", \"Democratic Republic of the Congo\", \"Greenland (Denmark)\", \"India\", \"Kazakhstan\", \"Mexico\", \"Mongolia\", \"Peru\", \"Russia\", \"Saudi Arabia\", \"Sudan\", \"United States\"\n", "]\n", "\n", "with gr.Blocks() as demo:\n", " with gr.Row():\n", " count = gr.Slider(1, 10, step=1, label=\"Country Count\")\n", " alpha_order = gr.Checkbox(True, label=\"Alphabetical Order\")\n", "\n", " gr.JSON(lambda count, alpha_order: countries[:count] if alpha_order else countries[-count:], inputs=[count, alpha_order])\n", " timer = gr.Timer(1)\n", " with gr.Row():\n", " gr.Textbox(lambda: random.choice(countries), label=\"Random Country\", every=timer)\n", " gr.Textbox(lambda count: \", \".join(random.sample(countries, count)), inputs=count, label=\"Random Countries\", every=timer)\n", " with gr.Row():\n", " gr.Button(\"Start\").click(lambda: gr.Timer(active=True), None, timer)\n", " gr.Button(\"Stop\").click(lambda: gr.Timer(active=False), None, timer)\n", "\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
24 changes: 24 additions & 0 deletions demo/function_values/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import gradio as gr
import random

countries = [
"Algeria", "Argentina", "Australia", "Brazil", "Canada", "China", "Democratic Republic of the Congo", "Greenland (Denmark)", "India", "Kazakhstan", "Mexico", "Mongolia", "Peru", "Russia", "Saudi Arabia", "Sudan", "United States"
]

with gr.Blocks() as demo:
with gr.Row():
count = gr.Slider(1, 10, step=1, label="Country Count")
alpha_order = gr.Checkbox(True, label="Alphabetical Order")

gr.JSON(lambda count, alpha_order: countries[:count] if alpha_order else countries[-count:], inputs=[count, alpha_order])
timer = gr.Timer(1)
with gr.Row():
gr.Textbox(lambda: random.choice(countries), label="Random Country", every=timer)
gr.Textbox(lambda count: ", ".join(random.sample(countries, count)), inputs=count, label="Random Countries", every=timer)
with gr.Row():
gr.Button("Start").click(lambda: gr.Timer(active=True), None, timer)
gr.Button("Stop").click(lambda: gr.Timer(active=False), None, timer)


if __name__ == "__main__":
demo.launch()
1 change: 1 addition & 0 deletions demo/timer/run.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: timer"]}, {"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 gradio as gr\n", "import random\n", "import time\n", "\n", "with gr.Blocks() as demo:\n", " timer = gr.Timer(1)\n", " timestamp = gr.Number(label=\"Time\")\n", " timer.tick(lambda: round(time.time()), outputs=timestamp)\n", "\n", " with gr.Row():\n", " min = gr.Number(1, label=\"Min\")\n", " max = gr.Number(10, label=\"Max\")\n", " timer2 = gr.Timer(1)\n", " number = gr.Number(lambda a, b: random.randint(a, b), inputs=[min, max], every=timer2, label=\"Random Number\")\n", " with gr.Row():\n", " gr.Button(\"Start\").click(lambda: gr.Timer(active=True), None, timer2)\n", " gr.Button(\"Stop\").click(lambda: gr.Timer(active=False), None, timer2)\n", " gr.Button(\"Go Fast\").click(lambda: 0.2, None, timer2)\n", " gr.Button(\"Go Slow\").click(lambda: 2, None, timer2)\n", " \n", "if __name__ == \"__main__\":\n", " demo.launch()"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
22 changes: 22 additions & 0 deletions demo/timer/run.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import gradio as gr
import random
import time

with gr.Blocks() as demo:
timer = gr.Timer(1)
timestamp = gr.Number(label="Time")
timer.tick(lambda: round(time.time()), outputs=timestamp)

with gr.Row():
min = gr.Number(1, label="Min")
max = gr.Number(10, label="Max")
timer2 = gr.Timer(1)
number = gr.Number(lambda a, b: random.randint(a, b), inputs=[min, max], every=timer2, label="Random Number")
with gr.Row():
gr.Button("Start").click(lambda: gr.Timer(active=True), None, timer2)
gr.Button("Stop").click(lambda: gr.Timer(active=False), None, timer2)
gr.Button("Go Fast").click(lambda: 0.2, None, timer2)
gr.Button("Go Slow").click(lambda: 2, None, timer2)

if __name__ == "__main__":
demo.launch()
1 change: 1 addition & 0 deletions gradio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
State,
Text,
Textbox,
Timer,
UploadButton,
Video,
component,
Expand Down
13 changes: 9 additions & 4 deletions gradio/_simple_templates/simpledropdown.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
from __future__ import annotations

import warnings
from typing import Any, Callable
from typing import TYPE_CHECKING, Any, Callable

from gradio.components.base import FormComponent
from gradio.components.base import Component, FormComponent
from gradio.events import Events

if TYPE_CHECKING:
from gradio.components import Timer


class SimpleDropdown(FormComponent):
"""
Expand All @@ -21,7 +24,8 @@ def __init__(
value: str | int | float | Callable | None = None,
label: str | None = None,
info: str | None = None,
every: float | None = None,
every: Timer | None = None,
aliabid94 marked this conversation as resolved.
Show resolved Hide resolved
inputs: Component | list[Component] | set[Component] | None = None,
show_label: bool | None = None,
scale: int | None = None,
min_width: int = 160,
Expand All @@ -38,7 +42,7 @@ def __init__(
value: default value selected in dropdown. If None, no value is selected by default. If callable, the function will be called whenever the app loads to set the initial value of the component.
label: component name in interface.
info: additional component description.
every: If `value` is a callable, run the function 'every' number of seconds while the client connection is open. Has no effect otherwise. The event can be accessed (e.g. to cancel it) via this component's .load_event attribute.
every: If `value` is a callable, run the function every time the provided Timer ticks. Has no effect otherwise.
aliabid94 marked this conversation as resolved.
Show resolved Hide resolved
show_label: if True, will display label.
scale: relative size compared to adjacent Components. For example if Components A and B are in a Row, and A has scale=2, and B has scale=1, A will be twice as wide as B. Should be an integer. scale applies in Rows, and to top-level Components in Blocks where fill_height=True.
min_width: minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.
Expand All @@ -58,6 +62,7 @@ def __init__(
label=label,
info=info,
every=every,
inputs=inputs,
show_label=show_label,
scale=scale,
min_width=min_width,
Expand Down
11 changes: 8 additions & 3 deletions gradio/_simple_templates/simpleimage.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from __future__ import annotations

from pathlib import Path
from typing import Any
from typing import TYPE_CHECKING, Any

from gradio_client import handle_file
from gradio_client.documentation import document
Expand All @@ -12,6 +12,9 @@
from gradio.data_classes import FileData
from gradio.events import Events

if TYPE_CHECKING:
from gradio.components import Timer


@document()
class SimpleImage(Component):
Expand All @@ -32,7 +35,8 @@ def __init__(
value: str | None = None,
*,
label: str | None = None,
every: float | None = None,
every: Timer | None = None,
inputs: Component | list[Component] | set[Component] | None = None,
show_label: bool | None = None,
show_download_button: bool = True,
container: bool = True,
Expand All @@ -49,7 +53,7 @@ def __init__(
Parameters:
value: A path or URL for the default value that SimpleImage component is going to take. If callable, the function will be called whenever the app loads to set the initial value of the component.
label: The label for this component. Appears above the component and is also used as the header if there are a table of examples for this component. If None and used in a `gr.Interface`, the label will be the name of the parameter this component is assigned to.
every: If `value` is a callable, run the function 'every' number of seconds while the client connection is open. Has no effect otherwise. Queue must be enabled. The event can be accessed (e.g. to cancel it) via this component's .load_event attribute.
every: Deprecated, use gr.Timer() instead. If `value` is a callable, run the function 'every' number of seconds while the client connection is open. Has no effect otherwise. Queue must be enabled. The event can be accessed (e.g. to cancel it) via this component's .load_event attribute.
aliabid94 marked this conversation as resolved.
Show resolved Hide resolved
show_label: if True, will display label.
show_download_button: If True, will display button to download image.
container: If True, will place the component in a container - providing some extra padding around the border.
Expand All @@ -66,6 +70,7 @@ def __init__(
super().__init__(
label=label,
every=every,
inputs=inputs,
show_label=show_label,
container=container,
scale=scale,
Expand Down
13 changes: 9 additions & 4 deletions gradio/_simple_templates/simpletextbox.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
from __future__ import annotations

from typing import Any, Callable
from typing import TYPE_CHECKING, Any, Callable

from gradio.components.base import FormComponent
from gradio.components.base import Component, FormComponent
from gradio.events import Events

if TYPE_CHECKING:
from gradio.components import Timer


class SimpleTextbox(FormComponent):
"""
Expand All @@ -23,7 +26,8 @@ def __init__(
*,
placeholder: str | None = None,
label: str | None = None,
every: float | None = None,
every: Timer | None = None,
inputs: Component | list[Component] | set[Component] | None = None,
show_label: bool | None = None,
scale: int | None = None,
min_width: int = 160,
Expand All @@ -40,7 +44,7 @@ def __init__(
value: default text to provide in textbox. If callable, the function will be called whenever the app loads to set the initial value of the component.
placeholder: placeholder hint to provide behind textbox.
label: component name in interface.
every: If `value` is a callable, run the function 'every' number of seconds while the client connection is open. Has no effect otherwise. The event can be accessed (e.g. to cancel it) via this component's .load_event attribute.
every: If `value` is a callable, run the function every time the provided Timer ticks. Has no effect otherwise.
show_label: if True, will display label.
scale: relative size compared to adjacent Components. For example if Components A and B are in a Row, and A has scale=2, and B has scale=1, A will be twice as wide as B. Should be an integer. scale applies in Rows, and to top-level Components in Blocks where fill_height=True.
min_width: minimum pixel width, will wrap if not sufficient screen space to satisfy this value. If a certain scale value results in this Component being narrower than min_width, the min_width parameter will be respected first.
Expand All @@ -57,6 +61,7 @@ def __init__(
super().__init__(
label=label,
every=every,
inputs=inputs,
show_label=show_label,
scale=scale,
min_width=min_width,
Expand Down
22 changes: 15 additions & 7 deletions gradio/blocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,7 @@ def set_event_trigger(
batch: whether this function takes in a batch of inputs
max_batch_size: the maximum batch size to send to the function
cancels: a list of other events to cancel when this event is triggered. For example, setting cancels=[click_event] will cancel the click_event, where click_event is the return value of another components .click method.
every: Run this event 'every' number of seconds while the client connection is open. Interpreted in seconds.
every: Deprecated, use gr.Timer() instead. Run this event 'every' number of seconds while the client connection is open. Interpreted in seconds.
aliabid94 marked this conversation as resolved.
Show resolved Hide resolved
collects_event_data: whether to collect event data for this event
trigger_after: if set, this event will be triggered after 'trigger_after' function index
trigger_only_on_success: if True, this event will only be triggered if the previous event was successful (only applies if `trigger_after` is set)
Expand Down Expand Up @@ -740,6 +740,10 @@ def set_event_trigger(

if fn is not None and not cancels:
check_function_inputs_match(fn, inputs, inputs_as_dict)
if isinstance(every, float):
warnings.warn(
aliabid94 marked this conversation as resolved.
Show resolved Hide resolved
"The 'every' parameter as a float is deprecated. Use gr.Timer() instead.",
)
if every is not None and every <= 0:
raise ValueError("Parameter every must be positive or None")
if every and batch:
Expand Down Expand Up @@ -2678,21 +2682,25 @@ def attach_load_events(self):
isinstance(component, components.Component)
and component.load_event_to_attach
):
load_fn, every = component.load_event_to_attach
load_fn, every_interval, triggers, inputs = (
component.load_event_to_attach
)
has_target = len(triggers) > 0
triggers += [(self, "load")]
# Use set_event_trigger to avoid ambiguity between load class/instance method

dep = self.default_config.set_event_trigger(
[EventListenerMethod(self, "load")],
[EventListenerMethod(*trigger) for trigger in triggers],
load_fn,
None,
inputs,
component,
no_target=True,
no_target=not has_target,
# If every is None, for sure skip the queue
# else, let the enable_queue parameter take precedence
# this will raise a nice error message is every is used
# without queue
queue=every is not None,
every=every,
queue=every_interval is not None,
every=every_interval,
)[0]
component.load_event = dep.get_config()

Expand Down
2 changes: 1 addition & 1 deletion gradio/component_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def {{ event }}(self,
preprocess: If False, will not run preprocessing of component data before running 'fn' (e.g. leaving it as a base64 string if this method is called with the `Image` component).
postprocess: If False, will not run postprocessing of component data before returning 'fn' output to the browser.
cancels: A list of other events to cancel when this listener is triggered. For example, setting cancels=[click_event] will cancel the click_event, where click_event is the return value of another components .click method. Functions that have not yet run (or generators that are iterating) will be cancelled, but functions that are currently running will be allowed to finish.
every: Run this event 'every' number of seconds while the client connection is open. Interpreted in seconds.
every: Deprecated, use gr.Timer() instead. Run this event 'every' number of seconds while the client connection is open. Interpreted in seconds.
trigger_mode: If "once" (default for all events except `.change()`) would not allow any submissions while an event is pending. If set to "multiple", unlimited submissions are allowed while pending, and "always_last" (default for `.change()` and `.key_up()` events) would allow a second submission after the pending event is complete.
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.
concurrency_limit: If set, this is the maximum number of this event that can be running simultaneously. Can be set to None to mean no concurrency_limit (any number of this event can be running simultaneously). Set to "default" to use the default concurrency limit (defined by the `default_concurrency_limit` parameter in `Blocks.queue()`, which itself is 1 by default).
Expand Down
2 changes: 2 additions & 0 deletions gradio/components/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
from gradio.components.slider import Slider
from gradio.components.state import State
from gradio.components.textbox import Textbox
from gradio.components.timer import Timer
from gradio.components.upload_button import UploadButton
from gradio.components.video import Video
from gradio.layouts import Form
Expand Down Expand Up @@ -109,6 +110,7 @@
"ScatterPlot",
"Slider",
"State",
"Timer",
"UploadButton",
"Video",
"StreamingInput",
Expand Down
11 changes: 8 additions & 3 deletions gradio/components/annotated_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from __future__ import annotations

from typing import Any, List
from typing import TYPE_CHECKING, Any, List

import gradio_client.utils as client_utils
import numpy as np
Expand All @@ -15,6 +15,9 @@
from gradio.data_classes import FileData, GradioModel
from gradio.events import Events

if TYPE_CHECKING:
from gradio.components import Timer

PIL.Image.init() # fixes https://github.com/gradio-app/gradio/issues/2843


Expand Down Expand Up @@ -57,7 +60,8 @@ def __init__(
width: int | str | None = None,
color_map: dict[str, str] | None = None,
label: str | None = None,
every: float | None = None,
every: Timer | None = None,
inputs: Component | list[Component] | set[Component] | None = None,
show_label: bool | None = None,
container: bool = True,
scale: int | None = None,
Expand All @@ -77,7 +81,7 @@ def __init__(
width: The width of the image, specified in pixels if a number is passed, or in CSS units if a string is passed.
color_map: A dictionary mapping labels to colors. The colors must be specified as hex codes.
label: The label for this component. Appears above the component and is also used as the header if there are a table of examples for this component. If None and used in a `gr.Interface`, the label will be the name of the parameter this component is assigned to.
every: If `value` is a callable, run the function 'every' number of seconds while the client connection is open. Has no effect otherwise. The event can be accessed (e.g. to cancel it) via this component's .load_event attribute.
every: If `value` is a callable, run the function every time the provided Timer ticks. Has no effect otherwise.
show_label: if True, will display label.
container: If True, will place the component in a container - providing some extra padding around the border.
scale: Relative width compared to adjacent Components in a Row. For example, if Component A has scale=2, and Component B has scale=1, A will be twice as wide as B. Should be an integer.
Expand All @@ -96,6 +100,7 @@ def __init__(
super().__init__(
label=label,
every=every,
inputs=inputs,
show_label=show_label,
container=container,
scale=scale,
Expand Down
Loading