Render decorator 2 (#8110)

* changes

* add changeset

* changes

* changes

* changes

* changes

* changes

* changes

* changeas

* changes

* add changeset

* changes

* add changeset

* changes

* changes

* changes

* changes

* changes

* changes

* changes

* changes

* add changeset

* changes

* cganges

* changes

* changes

* changes

* changes

* add changeset

* changes

* chagnes

* changes

* changes

* changes

* changes

* remove console log

* changes

* changes

* changes

* changes

* changes

---------

Co-authored-by: Ali Abid <aliabid94@gmail.com>
Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: Abubakar Abid <abubakar@huggingface.co>
This commit is contained in:
aliabid94 2024-05-06 08:36:07 -07:00 committed by GitHub
parent be2b1e1261
commit 5436031f92
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
61 changed files with 528 additions and 78 deletions

View File

@ -0,0 +1,7 @@
---
"@gradio/app": minor
"@gradio/client": minor
"gradio": minor
---
feat:Render decorator 2

View File

@ -220,12 +220,13 @@ export interface FileData {
// Event and Listener Types
export type EventType = "data" | "status" | "log";
export type EventType = "data" | "status" | "log" | "render";
export interface EventMap {
data: Payload;
status: Status;
log: LogMessage;
render: RenderMessage;
}
export type Event<K extends EventType> = {
@ -239,6 +240,13 @@ export interface LogMessage {
log: string;
level: "warning" | "info";
}
export interface RenderMessage {
fn_index: number;
data: {
components: any[];
layout: any;
};
}
export interface Status {
queue: boolean;

View File

@ -594,6 +594,14 @@ export function submit(
endpoint: _endpoint,
fn_index
});
if (data.render_config) {
fire_event({
type: "render",
data: data.render_config,
endpoint: _endpoint,
fn_index
});
}
if (complete) {
fire_event({

View File

@ -0,0 +1 @@
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: render_merge"]}, {"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", "\n", "with gr.Blocks() as demo:\n", " text_count = gr.Slider(1, 10, step=1, label=\"Textbox Count\")\n", "\n", " @gr.render(inputs=[text_count], triggers=[text_count.change])\n", " def render_count(count):\n", " for i in range(count):\n", " gr.Textbox(key=i)\n", "\n", " gr.Button(\"Merge\")\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}

14
demo/render_merge/run.py Normal file
View File

@ -0,0 +1,14 @@
import gradio as gr
with gr.Blocks() as demo:
text_count = gr.Slider(1, 10, step=1, label="Textbox Count")
@gr.render(inputs=[text_count], triggers=[text_count.change])
def render_count(count):
for i in range(count):
gr.Textbox(key=i)
gr.Button("Merge")
if __name__ == "__main__":
demo.launch()

View File

@ -0,0 +1 @@
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: render_split"]}, {"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", "\n", "with gr.Blocks() as demo:\n", " input_text = gr.Textbox(label=\"input\")\n", " mode = gr.Radio([\"textbox\", \"button\"], value=\"textbox\")\n", "\n", " @gr.render(inputs=[input_text, mode], triggers=[input_text.submit])\n", " def show_split(text, mode):\n", " if len(text) == 0:\n", " gr.Markdown(\"## No Input Provided\")\n", " else:\n", " for letter in text:\n", " if mode == \"textbox\":\n", " gr.Textbox(letter)\n", " else:\n", " gr.Button(letter)\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}

19
demo/render_split/run.py Normal file
View File

@ -0,0 +1,19 @@
import gradio as gr
with gr.Blocks() as demo:
input_text = gr.Textbox(label="input")
mode = gr.Radio(["textbox", "button"], value="textbox")
@gr.render(inputs=[input_text, mode], triggers=[input_text.submit])
def show_split(text, mode):
if len(text) == 0:
gr.Markdown("## No Input Provided")
else:
for letter in text:
if mode == "textbox":
gr.Textbox(letter)
else:
gr.Button(letter)
if __name__ == "__main__":
demo.launch()

View File

@ -81,6 +81,7 @@ from gradio.helpers import create_examples as Examples # noqa: N812
from gradio.interface import Interface, TabbedInterface, close_all
from gradio.layouts import Accordion, Column, Group, Row, Tab, TabItem, Tabs
from gradio.oauth import OAuthProfile, OAuthToken
from gradio.renderable import render
from gradio.routes import Request, mount_gradio_app
from gradio.templates import (
Files,

View File

@ -30,6 +30,7 @@ class SimpleDropdown(FormComponent):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
):
"""
Parameters:
@ -46,6 +47,7 @@ class SimpleDropdown(FormComponent):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
"""
self.choices = (
[tuple(c) if isinstance(c, (tuple, list)) else (str(c), c) for c in choices]
@ -65,6 +67,7 @@ class SimpleDropdown(FormComponent):
elem_classes=elem_classes,
value=value,
render=render,
key=key,
)
def api_info(self) -> dict[str, Any]:

View File

@ -43,6 +43,7 @@ class SimpleImage(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
):
"""
Parameters:
@ -59,6 +60,7 @@ class SimpleImage(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
"""
self.show_download_button = show_download_button
super().__init__(
@ -73,6 +75,7 @@ class SimpleImage(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -33,6 +33,7 @@ class SimpleTextbox(FormComponent):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
):
"""
Parameters:
@ -49,6 +50,7 @@ class SimpleTextbox(FormComponent):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
"""
self.placeholder = placeholder
self.rtl = rtl
@ -64,6 +66,7 @@ class SimpleTextbox(FormComponent):
elem_classes=elem_classes,
value=value,
render=render,
key=key,
)
def preprocess(self, payload: str | None) -> str | None:

View File

@ -39,7 +39,12 @@ from gradio import (
wasm_utils,
)
from gradio.blocks_events import BlocksEvents, BlocksMeta
from gradio.context import Context
from gradio.context import (
Context,
get_blocks_context,
get_render_context,
set_render_context,
)
from gradio.data_classes import FileData, GradioModel, GradioRootModel
from gradio.events import (
EventData,
@ -82,6 +87,7 @@ if TYPE_CHECKING: # Only import for type checking (is False at runtime).
from fastapi.applications import FastAPI
from gradio.components.base import Component
from gradio.renderable import Renderable
BUILT_IN_THEMES: dict[str, Theme] = {
t.name: t
@ -102,6 +108,7 @@ class Block:
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
visible: bool = True,
proxy_url: str | None = None,
):
@ -120,7 +127,7 @@ class Block:
self.state_session_capacity = 10000
self.temp_files: set[str] = set()
self.GRADIO_CACHE = get_upload_folder()
self.key: int | str | None = None
self.key = key
# Keep tracks of files that should not be deleted when the delete_cache parmaeter is set
# These files are the default value of the component and files that are used in examples
self.keep_in_cache = set()
@ -156,17 +163,19 @@ class Block:
"""
Adds self into appropriate BlockContext
"""
if Context.root_block is not None and self._id in Context.root_block.blocks:
root_context = get_blocks_context()
render_context = get_render_context()
if root_context is not None and self._id in root_context.blocks:
raise DuplicateBlockError(
f"A block with id: {self._id} has already been rendered in the current Blocks."
)
if Context.block is not None:
Context.block.add(self)
if Context.root_block is not None:
Context.root_block.blocks[self._id] = self
if render_context is not None:
render_context.add(self)
if root_context is not None:
root_context.blocks[self._id] = self
self.is_rendered = True
if isinstance(self, components.Component):
Context.root_block.temp_file_sets.append(self.temp_files)
root_context.root_block.temp_file_sets.append(self.temp_files)
return self
def unrender(self):
@ -174,14 +183,16 @@ class Block:
Removes self from BlockContext if it has been rendered (otherwise does nothing).
Removes self from the layout and collection of blocks, but does not delete any event triggers.
"""
if Context.block is not None:
root_context = get_blocks_context()
render_context = get_render_context()
if render_context is not None:
try:
Context.block.children.remove(self)
render_context.children.remove(self)
except ValueError:
pass
if Context.root_block is not None:
if root_context is not None:
try:
del Context.root_block.blocks[self._id]
del root_context.blocks[self._id]
self.is_rendered = False
except KeyError:
pass
@ -404,8 +415,9 @@ class BlockContext(Block):
self.children.append(child)
def __enter__(self):
self.parent = Context.block
Context.block = self
render_context = get_render_context()
self.parent = render_context
set_render_context(self)
return self
def add(self, child: Block):
@ -413,6 +425,7 @@ class BlockContext(Block):
self.children.append(child)
def fill_expected_parents(self):
root_context = get_blocks_context()
children = []
pseudo_parent = None
for child in self.children:
@ -430,13 +443,13 @@ class BlockContext(Block):
pseudo_parent.parent = self
children.append(pseudo_parent)
pseudo_parent.add_child(child)
if Context.root_block:
Context.root_block.blocks[pseudo_parent._id] = pseudo_parent
if root_context:
root_context.blocks[pseudo_parent._id] = pseudo_parent
child.parent = pseudo_parent
self.children = children
def __exit__(self, exc_type: type[BaseException] | None = None, *args):
Context.block = self.parent
set_render_context(self.parent)
if exc_type is not None:
return
if getattr(self, "allow_expected_parents", True):
@ -476,6 +489,7 @@ class BlockFunction:
queue: bool | None = None,
scroll_to_output: bool = False,
show_api: bool = True,
renderable: Renderable | None = None,
):
self.fn = fn
self.inputs = inputs
@ -511,6 +525,8 @@ class BlockFunction:
or inspect.isasyncgenfunction(self.fn)
or bool(self.every)
)
self.renderable = renderable
self.spaces_auto_wrap()
def spaces_auto_wrap(self):
@ -619,10 +635,13 @@ class BlocksConfig:
self.blocks: dict[int, Component | Block] = {}
self.fns: list[BlockFunction] = []
def get_config(self):
def get_config(self, renderable: Renderable | None = None):
config = {}
def get_layout(block):
rendered_ids = []
def get_layout(block: Block):
rendered_ids.append(block._id)
if not isinstance(block, BlockContext):
return {"id": block._id}
children_layout = []
@ -630,10 +649,19 @@ class BlocksConfig:
children_layout.append(get_layout(child))
return {"id": block._id, "children": children_layout}
config["layout"] = get_layout(self.root_block)
if renderable:
root_block = self.blocks[renderable.column_id]
else:
root_block = self.root_block
config["layout"] = get_layout(root_block)
config["components"] = []
for _id, block in self.blocks.items():
if renderable:
if _id not in rendered_ids:
continue
if block.key:
block.key = f"{renderable._id}-{block.key}"
props = block.get_config() if hasattr(block, "get_config") else {}
block_config = {
"id": _id,
@ -643,6 +671,8 @@ class BlocksConfig:
"component_class_id": getattr(block, "component_class_id", None),
"key": block.key,
}
if renderable:
block_config["renderable"] = renderable._id
if not block.skip_api:
block_config["api_info"] = block.api_info() # type: ignore
# .example_inputs() has been renamed .example_payload() but
@ -761,6 +791,7 @@ class Blocks(BlockContext, BlocksEvents, metaclass=BlocksMeta):
self.js = js_file.read()
else:
self.js = js
self.renderables: list[Renderable] = []
# For analytics_enabled and allow_flagging: (1) first check for
# parameter, (2) check for env variable, (3) default to True/"manual"
@ -1009,7 +1040,7 @@ class Blocks(BlockContext, BlocksEvents, metaclass=BlocksMeta):
first_dependency = dependency
# Allows some use of Interface-specific methods with loaded Spaces
if first_dependency and Context.root_block:
if first_dependency and get_blocks_context():
blocks.predict = [fns[0]]
blocks.input_components = first_dependency.inputs
blocks.output_components = first_dependency.outputs
@ -1108,6 +1139,7 @@ class Blocks(BlockContext, BlocksEvents, metaclass=BlocksMeta):
concurrency_limit: int | None | Literal["default"] = "default",
concurrency_id: str | None = None,
show_api: bool = True,
renderable: Renderable | None = None,
) -> tuple[BlockFunction, int]:
"""
Adds an event to the component's dependencies.
@ -1256,18 +1288,20 @@ class Blocks(BlockContext, BlocksEvents, metaclass=BlocksMeta):
queue=queue,
scroll_to_output=scroll_to_output,
show_api=show_api,
renderable=renderable,
)
self.fns.append(block_fn)
return block_fn, len(self.fns) - 1
def render(self):
if Context.root_block is not None:
if self._id in Context.root_block.blocks:
root_context = get_blocks_context()
if root_context is not None and Context.root_block is not None:
if self._id in root_context.blocks:
raise DuplicateBlockError(
f"A block with id: {self._id} has already been rendered in the current Blocks."
)
overlapping_ids = set(Context.root_block.blocks).intersection(self.blocks)
overlapping_ids = set(root_context.blocks).intersection(self.blocks)
for id in overlapping_ids:
# State components are allowed to be reused between Blocks
if not isinstance(self.blocks[id], components.State):
@ -1275,11 +1309,11 @@ class Blocks(BlockContext, BlocksEvents, metaclass=BlocksMeta):
"At least one block in this Blocks has already been rendered."
)
Context.root_block.blocks.update(self.blocks)
dependency_offset = len(Context.root_block.fns)
root_context.blocks.update(self.blocks)
dependency_offset = len(root_context.fns)
existing_api_names = [
dep.api_name
for dep in Context.root_block.fns
for dep in root_context.fns
if isinstance(dep.api_name, str)
]
for dependency in self.fns:
@ -1299,16 +1333,16 @@ class Blocks(BlockContext, BlocksEvents, metaclass=BlocksMeta):
# events in the backend
if dependency.cancels:
updated_cancels = [
Context.root_block.fns[i].get_config()
for i in dependency.cancels
root_context.fns[i].get_config() for i in dependency.cancels
]
dependency.fn = get_cancel_function(updated_cancels)[0]
Context.root_block.fns.append(dependency)
root_context.fns.append(dependency)
Context.root_block.temp_file_sets.extend(self.temp_file_sets)
Context.root_block.proxy_urls.update(self.proxy_urls)
if Context.block is not None:
Context.block.children.extend(self.children)
render_context = get_render_context()
if render_context is not None:
render_context.children.extend(self.children)
return self
def is_callable(self, fn_index: int = 0) -> bool:
@ -1386,6 +1420,7 @@ class Blocks(BlockContext, BlocksEvents, metaclass=BlocksMeta):
event_id: str | None = None,
event_data: EventData | None = None,
in_event_listener: bool = False,
state: SessionState | None = None,
):
"""
Calls function with given index and preprocessed input, and measures process time.
@ -1410,6 +1445,7 @@ class Blocks(BlockContext, BlocksEvents, metaclass=BlocksMeta):
event_id=event_id,
in_event_listener=in_event_listener,
request=request,
state=state,
)
if iterator is None: # If not a generator function that has already run
@ -1825,6 +1861,7 @@ Received outputs:
event_id,
event_data,
in_event_listener,
state,
)
preds = result["prediction"]
data = [
@ -1852,6 +1889,7 @@ Received outputs:
event_id,
event_data,
in_event_listener,
state,
)
data = await self.postprocess_data(fn_index, result["prediction"], state)
if root_path is not None:
@ -1877,13 +1915,20 @@ Received outputs:
block_fn.total_runtime += result["duration"]
block_fn.total_runs += 1
return {
output = {
"data": data,
"is_generating": is_generating,
"iterator": iterator,
"duration": result["duration"],
"average_duration": block_fn.total_runtime / block_fn.total_runs,
"render_config": None,
}
if block_fn.renderable and state:
output["render_config"] = state.blocks_config.get_config(
block_fn.renderable
)
return output
def create_limiter(self):
self.limiter = (
@ -1947,20 +1992,21 @@ Received outputs:
return config
def __enter__(self):
if Context.block is None:
render_context = get_render_context()
if render_context is None:
Context.root_block = self
self.parent = Context.block
Context.block = self
self.parent = render_context
set_render_context(self)
self.exited = False
return self
def __exit__(self, exc_type: type[BaseException] | None = None, *args):
if exc_type is not None:
Context.block = None
set_render_context(None)
Context.root_block = None
return
super().fill_expected_parents()
Context.block = self.parent
set_render_context(self.parent)
# Configure the load events before root_block is reset
self.attach_load_events()
if self.parent is None:
@ -2560,8 +2606,9 @@ Received outputs:
def attach_load_events(self):
"""Add a load event for every component whose initial value should be randomized."""
if Context.root_block:
for component in Context.root_block.blocks.values():
root_context = Context.root_block
if root_context:
for component in root_context.blocks.values():
if (
isinstance(component, components.Component)
and component.load_event_to_attach

View File

@ -128,10 +128,10 @@ def create_or_modify_pyi(
pyi_file.write_text(contents)
def in_event_listener():
def get_local_contexts():
from gradio.context import LocalContext
return LocalContext.in_event_listener.get()
return LocalContext.in_event_listener.get(), LocalContext.is_render.get()
def updateable(fn):
@ -153,7 +153,8 @@ def updateable(fn):
arg_name = fn_args[i]
kwargs[arg_name] = arg
self._constructor_args.append(kwargs)
if in_event_listener() and initialized_before:
in_event_listener, is_render = get_local_contexts()
if in_event_listener and initialized_before and not is_render:
return None
else:
return fn(self, **kwargs)

View File

@ -66,6 +66,7 @@ class AnnotatedImage(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
):
"""
Parameters:
@ -85,6 +86,7 @@ class AnnotatedImage(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
"""
self.format = format
self.show_legend = show_legend
@ -102,6 +104,7 @@ class AnnotatedImage(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -88,6 +88,7 @@ class Audio(
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
format: Literal["wav", "mp3"] = "wav",
autoplay: bool = False,
show_download_button: bool | None = None,
@ -114,6 +115,7 @@ class Audio(
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
format: The file format to save audio files. Either 'wav' or 'mp3'. wav files are lossless but will tend to be larger files. mp3 files tend to be smaller. Default is wav. Applies both when this component is used as an input (when `type` is "format") and when this component is used as an output.
autoplay: Whether to automatically play the audio when the component is used as an output. Note: browsers will not autoplay audio files if the user has not interacted with the page yet.
show_download_button: If True, will show a download button in the corner of the component for saving audio. If False, icon does not appear. By default, it will be True for output components and False for input components.
@ -179,6 +181,7 @@ class Audio(
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -67,6 +67,7 @@ class BarPlot(Plot):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
sort: Literal["x", "y", "-x", "-y"] | None = None,
show_actions_button: bool = False,
):
@ -99,6 +100,7 @@ class BarPlot(Plot):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
sort: Specifies the sorting axis as either "x", "y", "-x" or "-y". If None, no sorting is applied.
show_actions_button: Whether to show the actions button on the top right corner of the plot.
"""
@ -135,6 +137,7 @@ class BarPlot(Plot):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
every=every,
)

View File

@ -143,6 +143,7 @@ class Component(ComponentBase, Block):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
load_fn: Callable | None = None,
every: float | None = None,
):
@ -170,6 +171,7 @@ class Component(ComponentBase, Block):
elem_classes=elem_classes,
visible=visible,
render=render,
key=key,
)
if isinstance(self, StreamingInput):
self.check_streamable()

View File

@ -32,6 +32,7 @@ class Button(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
scale: int | None = None,
min_width: int | None = None,
):
@ -48,6 +49,7 @@ class Button(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
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.
"""
@ -57,6 +59,7 @@ class Button(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
interactive=interactive,
scale=scale,

View File

@ -54,6 +54,7 @@ class Chatbot(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
height: int | str | None = None,
latex_delimiters: list[dict[str, str | bool]] | None = None,
rtl: bool = False,
@ -81,6 +82,7 @@ class Chatbot(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
height: The height of the component, specified in pixels if a number is passed, or in CSS units if a string is passed.
latex_delimiters: A list of dicts of the form {"left": open delimiter (str), "right": close delimiter (str), "display": whether to display in newline (bool)} that will be used to render LaTeX expressions. If not provided, `latex_delimiters` is set to `[{ "left": "$$", "right": "$$", "display": True }]`, so only expressions enclosed in $$ delimiters will be rendered as LaTeX, and in a new line. Pass in an empty list to disable LaTeX rendering. For more information, see the [KaTeX documentation](https://katex.org/docs/autorender.html).
rtl: If True, sets the direction of the rendered text to right-to-left. Default is False, which renders text left-to-right.
@ -123,6 +125,7 @@ class Chatbot(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)
self.avatar_images: list[dict | None] = [None, None]

View File

@ -37,6 +37,7 @@ class Checkbox(FormComponent):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
):
"""
Parameters:
@ -53,6 +54,7 @@ class Checkbox(FormComponent):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
"""
super().__init__(
label=label,
@ -67,6 +69,7 @@ class Checkbox(FormComponent):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -37,6 +37,7 @@ class CheckboxGroup(FormComponent):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
):
"""
Parameters:
@ -55,6 +56,7 @@ class CheckboxGroup(FormComponent):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
"""
self.choices = (
# Although we expect choices to be a list of tuples, it can be a list of tuples if the Gradio app
@ -82,6 +84,7 @@ class CheckboxGroup(FormComponent):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -39,6 +39,7 @@ class ClearButton(Button):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
scale: int | None = None,
min_width: int | None = None,
api_name: str | None | Literal["False"] = None,
@ -56,6 +57,7 @@ class ClearButton(Button):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
scale=scale,
min_width=min_width,
)

View File

@ -95,6 +95,7 @@ class Code(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
):
"""
Parameters:
@ -111,6 +112,7 @@ class Code(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
"""
if language not in Code.languages:
raise ValueError(f"Language {language} not supported.")
@ -129,6 +131,7 @@ class Code(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -35,6 +35,7 @@ class ColorPicker(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
):
"""
Parameters:
@ -51,6 +52,7 @@ class ColorPicker(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
"""
super().__init__(
label=label,
@ -65,6 +67,7 @@ class ColorPicker(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -89,6 +89,7 @@ class Dataframe(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
wrap: bool = False,
line_breaks: bool = True,
column_widths: list[str | int] | None = None,
@ -114,6 +115,7 @@ class Dataframe(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
wrap: If True, the text in table cells will wrap when appropriate. If False and the `column_width` parameter is not set, the column widths will expand based on the cell contents and the table may need to be horizontally scrolled. If `column_width` is set, then any overflow text will be hidden.
line_breaks: If True (default), will enable Github-flavored Markdown line breaks in chatbot messages. If False, single new lines will be ignored. Only applies for columns of type "markdown."
column_widths: An optional list representing the width of each column. The elements of the list should be in the format "100px" (ints are also accepted and converted to pixel values) or "10%". If not provided, the column widths will be automatically determined based on the content of the cells. Setting this parameter will cause the browser to try to fit the table within the page width.
@ -179,6 +181,7 @@ class Dataframe(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -36,6 +36,7 @@ class Dataset(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
container: bool = True,
scale: int | None = None,
min_width: int = 160,
@ -53,6 +54,7 @@ class Dataset(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
container: If True, will place the component in a container - providing some extra padding around the border.
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.
@ -63,6 +65,7 @@ class Dataset(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
)
self.container = container
self.scale = scale

View File

@ -40,6 +40,7 @@ class DownloadButton(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
):
"""
Parameters:
@ -56,6 +57,7 @@ class DownloadButton(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
"""
self.data_model = FileData
self.size = size
@ -68,6 +70,7 @@ class DownloadButton(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
scale=scale,
min_width=min_width,

View File

@ -50,6 +50,7 @@ class Dropdown(FormComponent):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
):
"""
Parameters:
@ -114,6 +115,7 @@ class Dropdown(FormComponent):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -33,6 +33,7 @@ class DuplicateButton(Button):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
scale: int | None = 0,
min_width: int | None = None,
_activate: bool = True,
@ -50,6 +51,7 @@ class DuplicateButton(Button):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
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.
"""
@ -65,6 +67,7 @@ class DuplicateButton(Button):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
scale=scale,
min_width=min_width,
)

View File

@ -47,6 +47,7 @@ class File(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
):
"""
Parameters:
@ -66,6 +67,7 @@ class File(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
"""
self.file_count = file_count
if self.file_count in ["multiple", "directory"]:
@ -101,6 +103,7 @@ class File(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)
self.type = type

View File

@ -50,6 +50,7 @@ class FileExplorer(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
root: None = None,
):
"""
@ -71,6 +72,7 @@ class FileExplorer(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
"""
if root is not None:
warnings.warn(
@ -101,6 +103,7 @@ class FileExplorer(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -61,6 +61,7 @@ class Gallery(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
columns: int | tuple | None = 2,
rows: int | tuple | None = None,
height: int | float | None = None,
@ -89,6 +90,7 @@ class Gallery(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
columns: Represents the number of images that should be shown in one row, for each of the six standard screen sizes (<576px, <768px, <992px, <1200px, <1400px, >1400px). If fewer than 6 are given then the last will be used for all subsequent breakpoints
rows: Represents the number of rows in the image grid, for each of the six standard screen sizes (<576px, <768px, <992px, <1200px, <1400px, >1400px). If fewer than 6 are given then the last will be used for all subsequent breakpoints
height: The height of the gallery component, specified in pixels if a number is passed, or in CSS units if a string is passed. If more images are displayed than can fit in the height, a scrollbar will appear.
@ -132,6 +134,7 @@ class Gallery(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
interactive=interactive,
)

View File

@ -51,6 +51,7 @@ class HighlightedText(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
interactive: bool | None = None,
):
"""
@ -70,6 +71,7 @@ class HighlightedText(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
interactive: If True, the component will be editable, and allow user to select spans of text and label them.
"""
self.color_map = color_map
@ -87,6 +89,7 @@ class HighlightedText(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
interactive=interactive,
)

View File

@ -32,6 +32,7 @@ class HTML(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
):
"""
Parameters:
@ -43,6 +44,7 @@ class HTML(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
"""
super().__init__(
label=label,
@ -52,6 +54,7 @@ class HTML(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -64,6 +64,7 @@ class Image(StreamingInput, Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
mirror_webcam: bool = True,
show_share_button: bool | None = None,
):
@ -89,6 +90,7 @@ class Image(StreamingInput, Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
mirror_webcam: If True webcam will be mirrored. Default is True.
show_share_button: If True, will show a share icon in the corner of the component that allows user to share outputs to Hugging Face Spaces Discussions. If False, icon does not appear. If set to None (default behavior), then the icon appears if this Gradio app is launched on Spaces, but not otherwise.
"""
@ -140,6 +142,7 @@ class Image(StreamingInput, Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -151,6 +151,7 @@ class ImageEditor(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
mirror_webcam: bool = True,
show_share_button: bool | None = None,
_selectable: bool = False,
@ -182,6 +183,7 @@ class ImageEditor(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
mirror_webcam: If True webcam will be mirrored. Default is True.
show_share_button: If True, will show a share icon in the corner of the component that allows user to share outputs to Hugging Face Spaces Discussions. If False, icon does not appear. If set to None (default behavior), then the icon appears if this Gradio app is launched on Spaces, but not otherwise.
crop_size: The size of the crop box in pixels. If a tuple, the first value is the width and the second value is the height. If a string, the value must be a ratio in the form `width:height` (e.g. "16:9").
@ -245,6 +247,7 @@ class ImageEditor(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -36,6 +36,7 @@ class JSON(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
):
"""
Parameters:
@ -50,6 +51,7 @@ class JSON(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
"""
super().__init__(
label=label,
@ -62,6 +64,7 @@ class JSON(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -52,6 +52,7 @@ class Label(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
color: str | None = None,
):
"""
@ -68,6 +69,7 @@ class Label(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
color: The background color of the label (either a valid css color name or hexadecimal string).
"""
self.num_top_classes = num_top_classes
@ -83,6 +85,7 @@ class Label(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -80,6 +80,7 @@ class LinePlot(Plot):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
show_actions_button: bool = False,
):
"""
@ -113,6 +114,7 @@ class LinePlot(Plot):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
show_actions_button: Whether to show the actions button on the top right corner of the plot.
"""
self.x = x
@ -148,6 +150,7 @@ class LinePlot(Plot):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
every=every,
)

View File

@ -38,6 +38,7 @@ class LoginButton(Button):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
scale: int | None = 0,
min_width: int | None = None,
signed_in_value: str = "Signed in as {}",
@ -63,6 +64,7 @@ class LoginButton(Button):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
scale=scale,
min_width=min_width,
)

View File

@ -37,6 +37,7 @@ class LogoutButton(Button):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
scale: int | None = 0,
min_width: int | None = None,
):
@ -55,6 +56,7 @@ class LogoutButton(Button):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
scale=scale,
min_width=min_width,
)

View File

@ -36,6 +36,7 @@ class Markdown(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
sanitize_html: bool = True,
line_breaks: bool = False,
header_links: bool = False,
@ -52,6 +53,7 @@ class Markdown(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
sanitize_html: If False, will disable HTML sanitization when converted from markdown. This is not recommended, as it can lead to security vulnerabilities.
line_breaks: If True, will enable Github-flavored Markdown line breaks in chatbot messages. If False (default), single new lines will be ignored.
header_links: If True, will automatically create anchors for headings, displaying a link icon on hover.
@ -72,6 +74,7 @@ class Markdown(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -51,6 +51,7 @@ class Model3D(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
):
"""
Parameters:
@ -71,6 +72,7 @@ class Model3D(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
"""
self.clear_color = clear_color or [0, 0, 0, 0]
self.camera_position = camera_position
@ -89,6 +91,7 @@ class Model3D(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -72,6 +72,7 @@ class MultimodalTextbox(FormComponent):
autoscroll: bool = True,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
text_align: Literal["left", "right"] | None = None,
rtl: bool = False,
submit_btn: str | Literal[False] | None = None,
@ -96,6 +97,7 @@ class MultimodalTextbox(FormComponent):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
text_align: How to align the text in the textbox, can be: "left", "right", or None (default). If None, the alignment is left if `rtl` is False, or right if `rtl` is True. Can only be changed if `type` is "text".
rtl: If True and `type` is "text", sets the direction of the text to right-to-left (cursor appears on the left of the text). Default is False, which renders cursor on the right.
autoscroll: If True, will automatically scroll to the bottom of the textbox when the value changes, unless the user scrolls up. If False, will not scroll to the bottom of the textbox when the value changes.
@ -128,6 +130,7 @@ class MultimodalTextbox(FormComponent):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)
self.rtl = rtl

View File

@ -37,6 +37,7 @@ class Number(FormComponent):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
precision: int | None = None,
minimum: float | None = None,
maximum: float | None = None,
@ -57,6 +58,7 @@ class Number(FormComponent):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
precision: Precision to round input/output to. If set to 0, will round to nearest integer and convert type to int. If None, no rounding happens.
minimum: Minimum value. Only applied when component is used as an input. If a user provides a smaller value, a gr.Error exception is raised by the backend.
maximum: Maximum value. Only applied when component is used as an input. If a user provides a larger value, a gr.Error exception is raised by the backend.
@ -80,6 +82,7 @@ class Number(FormComponent):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -35,6 +35,7 @@ class ParamViewer(Component):
linkify: list[str] | None = None,
every: float | None = None,
render: bool = True,
key: int | str | None = None,
):
"""
Parameters:
@ -43,6 +44,7 @@ class ParamViewer(Component):
linkify: A list of strings to linkify. If any of these strings is found in the description, it will be rendered as a link.
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.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
"""
self.value = value or {}
self.language = language
@ -51,6 +53,7 @@ class ParamViewer(Component):
every=every,
value=value,
render=render,
key=key,
)
def preprocess(self, payload: dict[str, Parameter]) -> dict[str, Parameter]:

View File

@ -52,6 +52,7 @@ class Plot(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
):
"""
Parameters:
@ -67,6 +68,7 @@ class Plot(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
"""
self.format = format
super().__init__(
@ -80,6 +82,7 @@ class Plot(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -38,6 +38,7 @@ class Radio(FormComponent):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
):
"""
Parameters:
@ -56,6 +57,7 @@ class Radio(FormComponent):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
"""
self.choices = (
# Although we expect choices to be a list of tuples, it can be a list of tuples if the Gradio app
@ -83,6 +85,7 @@ class Radio(FormComponent):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -93,6 +93,7 @@ class ScatterPlot(Plot):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
show_actions_button: bool = False,
):
"""
@ -128,6 +129,7 @@ class ScatterPlot(Plot):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
show_actions_button: Whether to show the actions button on the top right corner of the plot.
"""
self.x = x
@ -166,6 +168,7 @@ class ScatterPlot(Plot):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
)
def get_block_name(self) -> str:

View File

@ -42,6 +42,7 @@ class Slider(FormComponent):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
randomize: bool = False,
):
"""
@ -62,6 +63,7 @@ class Slider(FormComponent):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
randomize: If True, the value of the slider when the app loads is taken uniformly at random from the range given by the minimum and maximum.
"""
self.minimum = minimum
@ -87,6 +89,7 @@ class Slider(FormComponent):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -49,6 +49,7 @@ class Textbox(FormComponent):
autoscroll: bool = True,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
type: Literal["text", "password", "email"] = "text",
text_align: Literal["left", "right"] | None = None,
rtl: bool = False,
@ -73,6 +74,7 @@ class Textbox(FormComponent):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
type: The type of textbox. One of: 'text', 'password', 'email', Default is 'text'.
text_align: How to align the text in the textbox, can be: "left", "right", or None (default). If None, the alignment is left if `rtl` is False, or right if `rtl` is True. Can only be changed if `type` is "text".
rtl: If True and `type` is "text", sets the direction of the text to right-to-left (cursor appears on the left of the text). Default is False, which renders cursor on the right.
@ -104,6 +106,7 @@ class Textbox(FormComponent):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)
self.type = type

View File

@ -44,6 +44,7 @@ class UploadButton(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
type: Literal["filepath", "bytes"] = "filepath",
file_count: Literal["single", "multiple", "directory"] = "single",
file_types: list[str] | None = None,
@ -63,6 +64,7 @@ class UploadButton(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
type: Type of value to be returned by component. "file" returns a temporary file object with the same base name as the uploaded file, whose full path can be retrieved by file_obj.name, "binary" returns an bytes object.
file_count: if single, allows user to upload one file. If "multiple", user uploads multiple files. If "directory", user uploads all files in selected directory. Return type will be list for each file in case of "multiple" or "directory".
file_types: List of type of files to be uploaded. "file" allows any file to be uploaded, "image" allows only image files to be uploaded, "audio" allows only audio files to be uploaded, "video" allows only video files to be uploaded, "text" allows only text files to be uploaded.
@ -100,6 +102,7 @@ class UploadButton(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
scale=scale,
min_width=min_width,

View File

@ -76,6 +76,7 @@ class Video(Component):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
mirror_webcam: bool = True,
include_audio: bool | None = None,
autoplay: bool = False,
@ -102,6 +103,7 @@ class Video(Component):
elem_id: An optional string that is assigned as the id of this component in the HTML DOM. Can be used for targeting CSS styles.
elem_classes: An optional list of strings that are assigned as the classes of this component in the HTML DOM. Can be used for targeting CSS styles.
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
key: if assigned, will be used to assume identity across a re-render. Components that have the same key across a re-render will have their value preserved.
mirror_webcam: If True webcam will be mirrored. Default is True.
include_audio: Whether the component should record/retain the audio track for a video. By default, audio is excluded for webcam videos and included for uploaded videos.
autoplay: Whether to automatically play the video when the component is used as an output. Note: browsers will not autoplay video files if the user has not interacted with the page yet.
@ -154,6 +156,7 @@ class Video(Component):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
value=value,
)

View File

@ -6,7 +6,7 @@ from contextvars import ContextVar
from typing import TYPE_CHECKING
if TYPE_CHECKING: # Only import for type checking (is False at runtime).
from gradio.blocks import BlockContext, Blocks
from gradio.blocks import BlockContext, Blocks, BlocksConfig
from gradio.helpers import Progress
from gradio.routes import Request
@ -21,7 +21,35 @@ class Context:
class LocalContext:
blocks: ContextVar[Blocks | None] = ContextVar("blocks", default=None)
blocks_config: ContextVar[BlocksConfig | None] = ContextVar(
"blocks_config", default=None
)
is_render: ContextVar[bool] = ContextVar("is_render", default=False)
render_block: ContextVar[BlockContext | None] = ContextVar(
"render_block", default=None
)
in_event_listener: ContextVar[bool] = ContextVar("in_event_listener", default=False)
event_id: ContextVar[str | None] = ContextVar("event_id", default=None)
request: ContextVar[Request | None] = ContextVar("request", default=None)
progress: ContextVar[Progress | None] = ContextVar("progress", default=None)
def get_render_context() -> BlockContext | None:
if LocalContext.is_render.get():
return LocalContext.render_block.get()
else:
return Context.block
def set_render_context(block: BlockContext | None):
if LocalContext.is_render.get():
LocalContext.render_block.set(block)
else:
Context.block = block
def get_blocks_context() -> BlocksConfig | None:
if LocalContext.is_render.get():
return LocalContext.blocks_config.get()
elif Context.root_block:
return Context.root_block.default_config

79
gradio/renderable.py Normal file
View File

@ -0,0 +1,79 @@
from __future__ import annotations
from typing import Callable, Literal, Sequence
from gradio.components import Component
from gradio.context import Context, LocalContext
from gradio.events import EventListener, EventListenerMethod
from gradio.layouts import Column
class Renderable:
def __init__(
self,
fn: Callable,
inputs: list[Component] | Component | None = None,
triggers: EventListener | Sequence[EventListener] | None = None,
concurrency_limit: int | None | Literal["default"] = "default",
concurrency_id: str | None = None,
):
if Context.root_block is None:
raise ValueError("Reactive render must be inside a Blocks context.")
self._id = len(Context.root_block.renderables)
Context.root_block.renderables.append(self)
self.column = Column()
self.column_id = Column()._id
self.fn = fn
self.inputs = [inputs] if isinstance(inputs, Component) else inputs
self.triggers: list[EventListenerMethod] = []
if isinstance(triggers, EventListener):
triggers = [triggers]
if triggers:
self.triggers = [
EventListenerMethod(
getattr(t, "__self__", None) if t.has_trigger else None,
t.event_name,
)
for t in triggers
]
Context.root_block.set_event_trigger(
self.triggers,
self.apply,
self.inputs,
None,
show_api=False,
concurrency_limit=concurrency_limit,
concurrency_id=concurrency_id,
renderable=self,
)
def apply(self, *args, **kwargs):
column_copy = Column(render=False)
column_copy._id = self.column_id
LocalContext.is_render.set(True)
LocalContext.render_block.set(column_copy)
try:
self.fn(*args, **kwargs)
blocks_config = LocalContext.blocks_config.get()
if blocks_config is None:
raise ValueError("Reactive render must be inside a LocalContext.")
blocks_config.blocks[self.column_id] = column_copy
finally:
LocalContext.is_render.set(False)
LocalContext.render_block.set(None)
def render(
inputs: list[Component] | None = None,
triggers: list[EventListener] | None = None,
concurrency_limit: int | None | Literal["default"] = None,
concurrency_id: str | None = None,
):
def wrapper_function(fn):
Renderable(fn, inputs, triggers, concurrency_limit, concurrency_id)
return fn
return wrapper_function

View File

@ -39,6 +39,7 @@ class TextArea(components.Textbox):
autoscroll: bool = True,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
type: Literal["text", "password", "email"] = "text",
text_align: Literal["left", "right"] | None = None,
rtl: bool = False,
@ -63,6 +64,7 @@ class TextArea(components.Textbox):
autoscroll=autoscroll,
elem_classes=elem_classes,
render=render,
key=key,
type=type,
text_align=text_align,
rtl=rtl,
@ -100,6 +102,7 @@ class Sketchpad(components.ImageEditor):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
mirror_webcam: bool = True,
show_share_button: bool | None = None,
_selectable: bool = False,
@ -132,6 +135,7 @@ class Sketchpad(components.ImageEditor):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
mirror_webcam=mirror_webcam,
show_share_button=show_share_button,
_selectable=_selectable,
@ -175,6 +179,7 @@ class Paint(components.ImageEditor):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
mirror_webcam: bool = True,
show_share_button: bool | None = None,
_selectable: bool = False,
@ -205,6 +210,7 @@ class Paint(components.ImageEditor):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
mirror_webcam=mirror_webcam,
show_share_button=show_share_button,
_selectable=_selectable,
@ -252,6 +258,7 @@ class ImageMask(components.ImageEditor):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
mirror_webcam: bool = True,
show_share_button: bool | None = None,
_selectable: bool = False,
@ -284,6 +291,7 @@ class ImageMask(components.ImageEditor):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
mirror_webcam=mirror_webcam,
show_share_button=show_share_button,
_selectable=_selectable,
@ -325,6 +333,7 @@ class PlayableVideo(components.Video):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
mirror_webcam: bool = True,
include_audio: bool | None = None,
autoplay: bool = False,
@ -351,6 +360,7 @@ class PlayableVideo(components.Video):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
mirror_webcam=mirror_webcam,
include_audio=include_audio,
autoplay=autoplay,
@ -386,6 +396,7 @@ class Microphone(components.Audio):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
format: Literal["wav", "mp3"] = "wav",
autoplay: bool = False,
show_download_button: bool | None = None,
@ -412,6 +423,7 @@ class Microphone(components.Audio):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
format=format,
autoplay=autoplay,
show_download_button=show_download_button,
@ -449,6 +461,7 @@ class Files(components.File):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
):
super().__init__(
value,
@ -467,6 +480,7 @@ class Files(components.File):
elem_id=elem_id,
elem_classes=elem_classes,
render=render,
key=key,
)
@ -498,6 +512,7 @@ class Numpy(components.Dataframe):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
wrap: bool = False,
line_breaks: bool = True,
column_widths: list[str | int] | None = None,
@ -517,6 +532,7 @@ class Numpy(components.Dataframe):
wrap=wrap,
elem_classes=elem_classes,
render=render,
key=key,
line_breaks=line_breaks,
column_widths=column_widths,
every=every,
@ -555,6 +571,7 @@ class Matrix(components.Dataframe):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
wrap: bool = False,
line_breaks: bool = True,
column_widths: list[str | int] | None = None,
@ -574,6 +591,7 @@ class Matrix(components.Dataframe):
wrap=wrap,
elem_classes=elem_classes,
render=render,
key=key,
line_breaks=line_breaks,
column_widths=column_widths,
every=every,
@ -612,6 +630,7 @@ class List(components.Dataframe):
elem_id: str | None = None,
elem_classes: list[str] | str | None = None,
render: bool = True,
key: int | str | None = None,
wrap: bool = False,
line_breaks: bool = True,
column_widths: list[str | int] | None = None,
@ -631,6 +650,7 @@ class List(components.Dataframe):
wrap=wrap,
elem_classes=elem_classes,
render=render,
key=key,
line_breaks=line_breaks,
column_widths=column_widths,
every=every,

View File

@ -58,6 +58,7 @@ if TYPE_CHECKING: # Only import for type checking (is False at runtime).
from gradio.blocks import BlockContext, Blocks
from gradio.components import Component
from gradio.routes import App, Request
from gradio.state_holder import SessionState
JSON_PATH = os.path.join(os.path.dirname(gradio.__file__), "launches.json")
@ -816,6 +817,7 @@ def get_function_with_locals(
event_id: str | None,
in_event_listener: bool,
request: Request | None,
state: SessionState | None,
):
def before_fn(blocks, event_id):
from gradio.context import LocalContext
@ -824,12 +826,15 @@ def get_function_with_locals(
LocalContext.in_event_listener.set(in_event_listener)
LocalContext.event_id.set(event_id)
LocalContext.request.set(request)
if state:
LocalContext.blocks_config.set(state.blocks_config)
def after_fn():
from gradio.context import LocalContext
LocalContext.in_event_listener.set(False)
LocalContext.request.set(None)
LocalContext.blocks_config.set(None)
return function_wrapper(
fn,

View File

@ -17,11 +17,7 @@
import logo from "./images/logo.svg";
import api_logo from "./api_docs/img/api-logo.svg";
import {
create_components,
AsyncFunction,
restore_keyed_values
} from "./init";
import { create_components, AsyncFunction } from "./init";
setupi18n();
@ -53,7 +49,8 @@
get_data,
loading_status,
scheduled_updates,
create_layout
create_layout,
rerender_layout
} = create_components();
$: create_layout({
@ -64,8 +61,7 @@
app,
options: {
fill_height
},
callback: () => restore_keyed_values(old_components, components)
}
});
$: {
@ -303,6 +299,16 @@
handle_update(data, fn_index);
set_status($loading_status);
})
.on("render", ({ data, fn_index }) => {
let _components: ComponentMeta[] = data.components;
let render_layout: LayoutNode = data.layout;
rerender_layout({
components: _components,
layout: render_layout,
root: root
});
})
.on("status", ({ fn_index, ...status }) => {
//@ts-ignore
loading_status.update({

View File

@ -1,4 +1,4 @@
import { writable, type Writable } from "svelte/store";
import { writable, type Writable, get } from "svelte/store";
import type {
ComponentMeta,
Dependency,
@ -9,6 +9,7 @@ import type {
import { load_component } from "virtual:component-loader";
import type { client_return } from "@gradio/client";
import { create_loading_status_store } from "./stores";
import { _ } from "svelte-i18n";
export interface UpdateTransaction {
id: number;
@ -40,6 +41,11 @@ export function create_components(): {
};
callback?: () => void;
}) => void;
rerender_layout: (args: {
components: ComponentMeta[];
layout: LayoutNode;
root: string;
}) => void;
} {
let _component_map: Map<number, ComponentMeta>;
@ -53,8 +59,9 @@ export function create_components(): {
create_loading_status_store();
const layout_store: Writable<ComponentMeta> = writable();
let root: string;
let _components: ComponentMeta[];
let _components: ComponentMeta[] = [];
let app: client_return;
let keyed_component_values: Record<string | number, any> = {};
function create_layout({
app: _app,
@ -76,6 +83,8 @@ export function create_components(): {
callback?: () => void;
}): void {
app = _app;
store_keyed_values(_components);
_components = components;
inputs = new Set();
outputs = new Set();
@ -130,15 +139,62 @@ export function create_components(): {
});
}
/**
* Rerender the layout when the config has been modified to attach new components
*/
function rerender_layout({
components,
layout,
root
}: {
components: ComponentMeta[];
layout: LayoutNode;
root: string;
}): void {
target_map.set(_target_map);
let _constructor_map = preload_all_components(components, root);
_constructor_map.forEach((v, k) => {
constructor_map.set(k, v);
});
let current_element = instance_map[layout.id];
let all_current_children: ComponentMeta[] = [];
const add_to_current_children = (component: ComponentMeta): void => {
all_current_children.push(component);
if (component.children) {
component.children.forEach((child) => {
add_to_current_children(child);
});
}
};
add_to_current_children(current_element);
store_keyed_values(all_current_children);
components.forEach((c) => {
instance_map[c.id] = c;
_component_map.set(c.id, c);
});
if (current_element.parent) {
current_element.parent.children![
current_element.parent.children!.indexOf(current_element)
] = instance_map[layout.id];
}
walk_layout(layout, root, current_element.parent);
}
async function walk_layout(
node: LayoutNode,
root: string
root: string,
parent?: ComponentMeta
): Promise<ComponentMeta> {
const instance = instance_map[node.id];
instance.component = (await constructor_map.get(
instance.component_class_id
))!?.default;
instance.parent = parent;
if (instance.type === "dataset") {
instance.props.component_map = get_component(
@ -168,11 +224,18 @@ export function create_components(): {
app
);
if (
instance.key != null &&
keyed_component_values[instance.key] !== undefined
) {
instance.props.value = keyed_component_values[instance.key];
}
_component_map.set(instance.id, instance);
if (node.children) {
instance.children = await Promise.all(
node.children.map((v) => walk_layout(v, root))
node.children.map((v) => walk_layout(v, root, instance))
);
}
@ -182,6 +245,14 @@ export function create_components(): {
let update_scheduled = false;
let update_scheduled_store = writable(false);
function store_keyed_values(components: ComponentMeta[]): void {
components.forEach((c) => {
if (c.key != null) {
keyed_component_values[c.key] = c.props.value;
}
});
}
function flush(): void {
layout_store.update((layout) => {
for (let i = 0; i < pending_updates.length; i++) {
@ -239,7 +310,8 @@ export function create_components(): {
loading_status,
scheduled_updates: update_scheduled_store,
create_layout: (...args) =>
requestAnimationFrame(() => create_layout(...args))
requestAnimationFrame(() => create_layout(...args)),
rerender_layout
};
}
@ -488,23 +560,3 @@ export function preload_all_components(
return constructor_map;
}
export const restore_keyed_values = (
old_components: ComponentMeta[],
new_components: ComponentMeta[]
): void => {
let component_values_by_key: Record<string | number, ComponentMeta> = {};
old_components.forEach((component) => {
if (component.key) {
component_values_by_key[component.key] = component;
}
});
new_components.forEach((component) => {
if (component.key) {
const old_component = component_values_by_key[component.key];
if (old_component) {
component.props.value = old_component.props.value;
}
}
});
};

View File

@ -24,6 +24,7 @@ export interface ComponentMeta {
component: ComponentType<SvelteComponent>;
documentation?: Documentation;
children?: ComponentMeta[];
parent?: ComponentMeta;
value?: any;
component_class_id: string;
key: string | number | null;

View File

@ -102,6 +102,7 @@ class TestTextbox:
"text_align": None,
"autofocus": False,
"_selectable": False,
"key": None,
"info": None,
"autoscroll": True,
}
@ -187,6 +188,7 @@ class TestNumber:
"info": None,
"precision": None,
"_selectable": False,
"key": None,
}
def test_component_functions_integer(self):
@ -220,6 +222,7 @@ class TestNumber:
"info": None,
"precision": 0,
"_selectable": False,
"key": None,
}
def test_component_functions_precision(self):
@ -316,6 +319,7 @@ class TestSlider:
"proxy_url": None,
"info": None,
"_selectable": False,
"key": None,
}
def test_in_interface(self):
@ -374,6 +378,7 @@ class TestCheckbox:
"interactive": None,
"proxy_url": None,
"_selectable": False,
"key": None,
"info": None,
}
@ -424,6 +429,7 @@ class TestCheckboxGroup:
"interactive": None,
"proxy_url": None,
"_selectable": False,
"key": None,
"type": "value",
"info": None,
}
@ -473,6 +479,7 @@ class TestRadio:
"interactive": None,
"proxy_url": None,
"_selectable": False,
"key": None,
"type": "value",
"info": None,
}
@ -557,6 +564,7 @@ class TestDropdown:
"filterable": True,
"max_choices": 2,
"_selectable": False,
"key": None,
"type": "value",
"info": None,
}
@ -621,6 +629,7 @@ class TestImageEditor:
"mirror_webcam": True,
"show_share_button": False,
"_selectable": False,
"key": None,
"crop_size": None,
"transforms": ("crop",),
"eraser": {"default_size": "auto"},
@ -692,6 +701,7 @@ class TestImage:
"proxy_url": None,
"mirror_webcam": True,
"_selectable": False,
"key": None,
"streamable": False,
"type": "pil",
}
@ -887,6 +897,7 @@ class TestAudio:
"trim_region_color": None,
},
"_selectable": False,
"key": None,
}
assert audio_input.preprocess(None) is None
@ -941,6 +952,7 @@ class TestAudio:
"trim_region_color": None,
},
"_selectable": False,
"key": None,
}
output1 = audio_output.postprocess(y_audio.name).model_dump()
@ -1037,6 +1049,7 @@ class TestFile:
"interactive": None,
"proxy_url": None,
"_selectable": False,
"key": None,
"height": None,
"type": "filepath",
}
@ -1152,6 +1165,7 @@ class TestDataframe:
"metadata": None,
},
"_selectable": False,
"key": None,
"headers": ["Name", "Age", "Member"],
"row_count": (1, "dynamic"),
"col_count": (3, "dynamic"),
@ -1195,6 +1209,7 @@ class TestDataframe:
"metadata": None,
},
"_selectable": False,
"key": None,
"headers": ["1", "2", "3"],
"row_count": (1, "dynamic"),
"col_count": (3, "dynamic"),
@ -1546,6 +1561,7 @@ class TestVideo:
"min_length": None,
"max_length": None,
"_selectable": False,
"key": None,
}
assert video_input.preprocess(None) is None
video_input = gr.Video(format="avi")
@ -1765,6 +1781,7 @@ class TestLabel:
"proxy_url": None,
"color": None,
"_selectable": False,
"key": None,
}
def test_color_argument(self):
@ -1920,6 +1937,7 @@ class TestHighlightedText:
"value": None,
"proxy_url": None,
"_selectable": False,
"key": None,
"combine_adjacent": False,
"adjacent_separator": "",
"interactive": None,
@ -2008,6 +2026,7 @@ class TestAnnotatedImage:
"value": None,
"proxy_url": None,
"_selectable": False,
"key": None,
}
def test_in_interface(self):
@ -2069,6 +2088,7 @@ class TestChatbot:
"height": None,
"proxy_url": None,
"_selectable": False,
"key": None,
"latex_delimiters": [{"display": True, "left": "$$", "right": "$$"}],
"likeable": False,
"rtl": False,
@ -2110,6 +2130,7 @@ class TestJSON:
"name": "json",
"proxy_url": None,
"_selectable": False,
"key": None,
}
def test_chatbot_selectable_in_config(self):
@ -2181,6 +2202,7 @@ class TestHTML:
"proxy_url": None,
"name": "html",
"_selectable": False,
"key": None,
}
def test_in_interface(self):
@ -2235,6 +2257,7 @@ class TestModel3D:
"zoom_speed": 1,
"pan_speed": 1,
"_selectable": False,
"key": None,
}
file = "test/test_files/Box.gltf"
@ -2280,6 +2303,7 @@ class TestColorPicker:
"name": "colorpicker",
"info": None,
"_selectable": False,
"key": None,
}
def test_in_interface_as_input(self):
@ -2562,6 +2586,7 @@ class TestScatterPlot:
"x_label_angle": None,
"y_label_angle": None,
"_selectable": False,
"key": None,
}
def test_no_color(self):
@ -2720,6 +2745,7 @@ class TestLinePlot:
"x_label_angle": None,
"y_label_angle": None,
"_selectable": False,
"key": None,
}
def test_no_color(self):
@ -2824,6 +2850,7 @@ class TestBarPlot:
"y_label_angle": None,
"sort": None,
"_selectable": False,
"key": None,
}
def test_no_color(self):
@ -2937,6 +2964,7 @@ class TestCode:
"interactive": None,
"proxy_url": None,
"_selectable": False,
"key": None,
}
def test_process_example(self):