mirror of
https://github.com/gradio-app/gradio.git
synced 2025-04-06 12:30:29 +08:00
Control Display of Error, Info, Warning (#8489)
* first draft * handle animation * No animation * Add code * add changeset * Only use duration * lint * lint * Add docs * add changeset * Fix default * sample usage * formatting * Add visible parameters * float --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: aliabd <ali.si3luwa@gmail.com>
This commit is contained in:
parent
b03da67d8f
commit
c2a0d056d6
9
.changeset/neat-roses-tan.md
Normal file
9
.changeset/neat-roses-tan.md
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
"@gradio/app": minor
|
||||
"@gradio/client": minor
|
||||
"@gradio/statustracker": minor
|
||||
"gradio": minor
|
||||
"website": minor
|
||||
---
|
||||
|
||||
feat:Control Display of Error, Info, Warning
|
@ -318,6 +318,8 @@ export function handle_message(
|
||||
status: {
|
||||
queue,
|
||||
message: data.output.error as string,
|
||||
visible: data.output.visible as boolean,
|
||||
duration: data.output.duration as number,
|
||||
stage: "error",
|
||||
code: data.code,
|
||||
success: data.success
|
||||
|
@ -329,6 +329,8 @@ export interface Status {
|
||||
code?: string;
|
||||
success?: boolean;
|
||||
stage: "pending" | "error" | "complete" | "generating";
|
||||
duration?: number;
|
||||
visible?: boolean;
|
||||
broken?: boolean;
|
||||
size?: number;
|
||||
position?: number;
|
||||
@ -361,6 +363,8 @@ export interface LogMessage extends Log {
|
||||
type: "log";
|
||||
endpoint: string;
|
||||
fn_index: number;
|
||||
duration: number | null;
|
||||
visible: boolean;
|
||||
}
|
||||
|
||||
export interface RenderMessage extends Render {
|
||||
|
@ -343,6 +343,8 @@ export function submit(
|
||||
log: data.log,
|
||||
level: data.level,
|
||||
endpoint: _endpoint,
|
||||
duration: data.duration,
|
||||
visible: data.visible,
|
||||
fn_index
|
||||
});
|
||||
} else if (type === "generating") {
|
||||
@ -474,6 +476,8 @@ export function submit(
|
||||
log: data.log,
|
||||
level: data.level,
|
||||
endpoint: _endpoint,
|
||||
duration: data.duration,
|
||||
visible: data.visible,
|
||||
fn_index
|
||||
});
|
||||
} else if (type === "generating") {
|
||||
@ -630,6 +634,8 @@ export function submit(
|
||||
log: data.log,
|
||||
level: data.level,
|
||||
endpoint: _endpoint,
|
||||
duration: data.duration,
|
||||
visible: data.visible,
|
||||
fn_index
|
||||
});
|
||||
return;
|
||||
|
@ -1,3 +1,5 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from gradio_client.documentation import document
|
||||
|
||||
|
||||
@ -73,12 +75,21 @@ class Error(Exception):
|
||||
Demos: calculator, blocks_chained_events
|
||||
"""
|
||||
|
||||
def __init__(self, message: str = "Error raised."):
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Error raised.",
|
||||
duration: float | None = 10,
|
||||
visible: bool = True,
|
||||
):
|
||||
"""
|
||||
Parameters:
|
||||
message: The error message to be displayed to the user.
|
||||
duration: The duration in seconds to display the error message. If None or 0, the error message will be displayed until the user closes it.
|
||||
visible: Whether the error message should be displayed in the UI.
|
||||
"""
|
||||
self.message = message
|
||||
self.duration = duration
|
||||
self.visible = visible
|
||||
super().__init__(self.message)
|
||||
|
||||
def __str__(self):
|
||||
|
@ -1226,7 +1226,12 @@ def make_waveform(
|
||||
return output_mp4.name
|
||||
|
||||
|
||||
def log_message(message: str, level: Literal["info", "warning"] = "info"):
|
||||
def log_message(
|
||||
message: str,
|
||||
level: Literal["info", "warning"] = "info",
|
||||
duration: float | None = 10,
|
||||
visible: bool = True,
|
||||
):
|
||||
from gradio.context import LocalContext
|
||||
|
||||
blocks = LocalContext.blocks.get()
|
||||
@ -1239,16 +1244,22 @@ def log_message(message: str, level: Literal["info", "warning"] = "info"):
|
||||
elif level == "warning":
|
||||
warnings.warn(message)
|
||||
return
|
||||
blocks._queue.log_message(event_id=event_id, log=message, level=level)
|
||||
blocks._queue.log_message(
|
||||
event_id=event_id, log=message, level=level, duration=duration, visible=visible
|
||||
)
|
||||
|
||||
|
||||
@document(documentation_group="modals")
|
||||
def Warning(message: str = "Warning issued."): # noqa: N802
|
||||
def Warning( # noqa: N802
|
||||
message: str = "Warning issued.", duration: float | None = 10, visible: bool = True
|
||||
):
|
||||
"""
|
||||
This function allows you to pass custom warning messages to the user. You can do so simply by writing `gr.Warning('message here')` in your function, and when that line is executed the custom message will appear in a modal on the demo. The modal is yellow by default and has the heading: "Warning." Queue must be enabled for this behavior; otherwise, the warning will be printed to the console using the `warnings` library.
|
||||
Demos: blocks_chained_events
|
||||
Parameters:
|
||||
message: The warning message to be displayed to the user.
|
||||
duration: The duration in seconds that the warning message should be displayed for. If None or 0, the message will be displayed indefinitely until the user closes it.
|
||||
visible: Whether the error message should be displayed in the UI.
|
||||
Example:
|
||||
import gradio as gr
|
||||
def hello_world():
|
||||
@ -1259,16 +1270,22 @@ def Warning(message: str = "Warning issued."): # noqa: N802
|
||||
demo.load(hello_world, inputs=None, outputs=[md])
|
||||
demo.queue().launch()
|
||||
"""
|
||||
log_message(message, level="warning")
|
||||
log_message(message, level="warning", duration=duration, visible=visible)
|
||||
|
||||
|
||||
@document(documentation_group="modals")
|
||||
def Info(message: str = "Info issued."): # noqa: N802
|
||||
def Info( # noqa: N802
|
||||
message: str = "Info issued.",
|
||||
duration: float | None = 10,
|
||||
visible: bool = True,
|
||||
):
|
||||
"""
|
||||
This function allows you to pass custom info messages to the user. You can do so simply by writing `gr.Info('message here')` in your function, and when that line is executed the custom message will appear in a modal on the demo. The modal is gray by default and has the heading: "Info." Queue must be enabled for this behavior; otherwise, the message will be printed to the console.
|
||||
Demos: blocks_chained_events
|
||||
Parameters:
|
||||
message: The info message to be displayed to the user.
|
||||
duration: The duration in seconds that the info message should be displayed for. If None or 0, the message will be displayed indefinitely until the user closes it.
|
||||
visible: Whether the error message should be displayed in the UI.
|
||||
Example:
|
||||
import gradio as gr
|
||||
def hello_world():
|
||||
@ -1279,4 +1296,4 @@ def Info(message: str = "Info issued."): # noqa: N802
|
||||
demo.load(hello_world, inputs=None, outputs=[md])
|
||||
demo.queue().launch()
|
||||
"""
|
||||
log_message(message, level="info")
|
||||
log_message(message, level="info", duration=duration, visible=visible)
|
||||
|
@ -18,7 +18,6 @@ from gradio import route_utils, routes
|
||||
from gradio.data_classes import (
|
||||
PredictBody,
|
||||
)
|
||||
from gradio.exceptions import Error
|
||||
from gradio.helpers import TrackedIterable
|
||||
from gradio.server_messages import (
|
||||
EstimationMessage,
|
||||
@ -30,7 +29,13 @@ from gradio.server_messages import (
|
||||
ProgressMessage,
|
||||
ProgressUnit,
|
||||
)
|
||||
from gradio.utils import LRUCache, run_coro_in_background, safe_get_lock, set_task_name
|
||||
from gradio.utils import (
|
||||
LRUCache,
|
||||
error_payload,
|
||||
run_coro_in_background,
|
||||
safe_get_lock,
|
||||
set_task_name,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from gradio.blocks import BlockFunction, Blocks
|
||||
@ -376,6 +381,8 @@ class Queue:
|
||||
event_id: str,
|
||||
log: str,
|
||||
level: Literal["info", "warning"],
|
||||
duration: float | None = 10,
|
||||
visible: bool = True,
|
||||
):
|
||||
events = [
|
||||
evt for job in self.active_jobs if job is not None for evt in job
|
||||
@ -385,6 +392,8 @@ class Queue:
|
||||
log_message = LogMessage(
|
||||
log=log,
|
||||
level=level,
|
||||
duration=duration,
|
||||
visible=visible,
|
||||
)
|
||||
self.send_message(event, log_message)
|
||||
|
||||
@ -538,15 +547,15 @@ class Queue:
|
||||
)
|
||||
err = None
|
||||
except Exception as e:
|
||||
show_error = app.get_blocks().show_error or isinstance(e, Error)
|
||||
traceback.print_exc()
|
||||
response = None
|
||||
err = e
|
||||
for event in awake_events:
|
||||
content = error_payload(err, app.get_blocks().show_error)
|
||||
self.send_message(
|
||||
event,
|
||||
ProcessCompletedMessage(
|
||||
output={"error": str(e) if show_error else None},
|
||||
output=content,
|
||||
success=False,
|
||||
),
|
||||
)
|
||||
@ -586,8 +595,7 @@ class Queue:
|
||||
else:
|
||||
success = False
|
||||
error = err or old_err
|
||||
show_error = app.get_blocks().show_error or isinstance(error, Error)
|
||||
output = {"error": str(error) if show_error else None}
|
||||
output = error_payload(error, app.get_blocks().show_error)
|
||||
for event in awake_events:
|
||||
self.send_message(
|
||||
event, ProcessCompletedMessage(output=output, success=success)
|
||||
|
@ -76,7 +76,6 @@ from gradio.data_classes import (
|
||||
ResetBody,
|
||||
SimplePredictBody,
|
||||
)
|
||||
from gradio.exceptions import Error
|
||||
from gradio.oauth import attach_oauth
|
||||
from gradio.route_utils import ( # noqa: F401
|
||||
CustomCORSMiddleware,
|
||||
@ -737,10 +736,10 @@ class App(FastAPI):
|
||||
root_path=root_path,
|
||||
)
|
||||
except BaseException as error:
|
||||
show_error = app.get_blocks().show_error or isinstance(error, Error)
|
||||
content = utils.error_payload(error, app.get_blocks().show_error)
|
||||
traceback.print_exc()
|
||||
return JSONResponse(
|
||||
content={"error": str(error) if show_error else None},
|
||||
content=content,
|
||||
status_code=500,
|
||||
)
|
||||
return output
|
||||
|
@ -31,6 +31,8 @@ class LogMessage(BaseMessage):
|
||||
msg: Literal[ServerMessage.log] = ServerMessage.log
|
||||
log: str
|
||||
level: Literal["info", "warning"]
|
||||
duration: Optional[float] = 10
|
||||
visible: bool = True
|
||||
|
||||
|
||||
class EstimationMessage(BaseMessage):
|
||||
|
@ -53,6 +53,7 @@ from typing_extensions import ParamSpec
|
||||
import gradio
|
||||
from gradio.context import get_blocks_context
|
||||
from gradio.data_classes import FileData
|
||||
from gradio.exceptions import Error
|
||||
from gradio.strings import en
|
||||
|
||||
if TYPE_CHECKING: # Only import for type checking (is False at runtime).
|
||||
@ -1417,3 +1418,16 @@ def deep_hash(obj):
|
||||
items = str(id(obj)).encode("utf-8")
|
||||
hasher.update(repr(items).encode("utf-8"))
|
||||
return hasher.hexdigest()
|
||||
|
||||
|
||||
def error_payload(
|
||||
error: BaseException | None, show_error: bool
|
||||
) -> dict[str, bool | str | float | None]:
|
||||
content: dict[str, bool | str | float | None] = {"error": None}
|
||||
show_error = show_error or isinstance(error, Error)
|
||||
if show_error:
|
||||
content["error"] = str(error)
|
||||
if isinstance(error, Error):
|
||||
content["duration"] = error.duration
|
||||
content["visible"] = error.visible
|
||||
return content
|
||||
|
@ -278,6 +278,12 @@ strong {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.obj a {
|
||||
color: var(--tw-prose-links);
|
||||
text-decoration: underline;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.codeblock > pre {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
@ -17,13 +17,19 @@
|
||||
|
||||
<!--- Usage -->
|
||||
```python
|
||||
gradio.Error(···)
|
||||
raise gradio.Error("An error occured 💥!", duration=5)
|
||||
```
|
||||
|
||||
<!--- Description -->
|
||||
### Description
|
||||
## {@html style_formatted_text(obj.description)}
|
||||
|
||||
## You can control for how long the error message is displayed with the `duration` parameter. If it's `None`, the message will be displayed forever until the user closes it. If it's a number, it will be shown for that many seconds.
|
||||
## You can also hide the error modal from being shown in the UI by setting `visible=False`.
|
||||
## Below is a demo of how different values of duration control the error, info, and warning messages. You can see the code [here](https://huggingface.co/spaces/freddyaboulton/gradio-error-duration/blob/244331cf53f6b5fa2fd406ece3bf55c6ccb9f5f2/app.py#L17).
|
||||
|
||||

|
||||
|
||||
<!-- Example Usage -->
|
||||
|
||||
{#if obj.example}
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
<!--- Usage -->
|
||||
```python
|
||||
gradio.Info(···)
|
||||
gradio.Info("Helpful info message ℹ️", duration=5)
|
||||
```
|
||||
|
||||
<!--- Description -->
|
||||
|
@ -17,7 +17,7 @@
|
||||
|
||||
<!--- Usage -->
|
||||
```python
|
||||
gradio.Warning(···)
|
||||
gradio.Warning("A warning occured ⛔️!", duration=5)
|
||||
```
|
||||
|
||||
<!--- Description -->
|
||||
|
@ -141,13 +141,17 @@
|
||||
function new_message(
|
||||
message: string,
|
||||
fn_index: number,
|
||||
type: ToastMessage["type"]
|
||||
type: ToastMessage["type"],
|
||||
duration: number | null = 10,
|
||||
visible = true
|
||||
): ToastMessage & { fn_index: number } {
|
||||
return {
|
||||
message,
|
||||
fn_index,
|
||||
type,
|
||||
id: ++_error_id
|
||||
id: ++_error_id,
|
||||
duration,
|
||||
visible
|
||||
};
|
||||
}
|
||||
|
||||
@ -344,8 +348,11 @@
|
||||
}
|
||||
|
||||
function handle_log(msg: LogMessage): void {
|
||||
const { log, fn_index, level } = msg;
|
||||
messages = [new_message(log, fn_index, level), ...messages];
|
||||
const { log, fn_index, level, duration, visible } = msg;
|
||||
messages = [
|
||||
new_message(log, fn_index, level, duration, visible),
|
||||
...messages
|
||||
];
|
||||
}
|
||||
|
||||
function handle_status_update(message: StatusMessage): void {
|
||||
@ -416,7 +423,16 @@
|
||||
MESSAGE_QUOTE_RE,
|
||||
(_, b) => b
|
||||
);
|
||||
messages = [new_message(_message, fn_index, "error"), ...messages];
|
||||
messages = [
|
||||
new_message(
|
||||
_message,
|
||||
fn_index,
|
||||
"error",
|
||||
status.duration,
|
||||
status.visible
|
||||
),
|
||||
...messages
|
||||
];
|
||||
}
|
||||
dependencies.map(async (dep) => {
|
||||
if (
|
||||
|
@ -17,9 +17,9 @@
|
||||
</script>
|
||||
|
||||
<div class="toast-wrap">
|
||||
{#each messages as { type, message, id } (id)}
|
||||
{#each messages as { type, message, id, duration, visible } (id)}
|
||||
<div animate:flip={{ duration: 300 }} style:width="100%">
|
||||
<ToastContent {type} {message} on:close {id} />
|
||||
<ToastContent {type} {message} {duration} {visible} on:close {id} />
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
|
@ -7,6 +7,11 @@
|
||||
export let message = "";
|
||||
export let type: ToastMessage["type"];
|
||||
export let id: number;
|
||||
export let duration: number | null = 10;
|
||||
export let visible = true;
|
||||
|
||||
$: display = visible;
|
||||
$: duration = duration || null;
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
@ -15,10 +20,14 @@
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
setTimeout(() => {
|
||||
close_message();
|
||||
}, 10000);
|
||||
if (duration !== null) {
|
||||
setTimeout(() => {
|
||||
close_message();
|
||||
}, duration * 1000);
|
||||
}
|
||||
});
|
||||
|
||||
$: timer_animation_duration = `${duration || 0}s`;
|
||||
</script>
|
||||
|
||||
<!-- TODO: fix-->
|
||||
@ -27,6 +36,7 @@
|
||||
class="toast-body {type}"
|
||||
role="alert"
|
||||
data-testid="toast-body"
|
||||
class:hidden={!display}
|
||||
on:click|stopPropagation
|
||||
on:keydown|stopPropagation
|
||||
in:fade={{ duration: 200, delay: 100 }}
|
||||
@ -59,7 +69,10 @@
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
|
||||
<div class="timer {type}" />
|
||||
<div
|
||||
class="timer {type}"
|
||||
style={`animation-duration: ${timer_animation_duration};`}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@ -275,4 +288,8 @@
|
||||
:global(.dark) .timer.info {
|
||||
background: var(--color-grey-500);
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
@ -21,4 +21,6 @@ export interface ToastMessage {
|
||||
type: "error" | "warning" | "info";
|
||||
message: string;
|
||||
id: number;
|
||||
duration: number | null;
|
||||
visible: boolean;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user