Skip to content

Commit

Permalink
Control Display of Error, Info, Warning (#8489)
Browse files Browse the repository at this point in the history
* 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>
  • Loading branch information
3 people authored Jun 11, 2024
1 parent b03da67 commit c2a0d05
Show file tree
Hide file tree
Showing 18 changed files with 149 additions and 30 deletions.
9 changes: 9 additions & 0 deletions .changeset/neat-roses-tan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
"@gradio/app": minor
"@gradio/client": minor
"@gradio/statustracker": minor
"gradio": minor
"website": minor
---

feat:Control Display of Error, Info, Warning
2 changes: 2 additions & 0 deletions client/js/src/helpers/api_info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions client/js/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down
6 changes: 6 additions & 0 deletions client/js/src/utils/submit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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") {
Expand Down Expand Up @@ -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") {
Expand Down Expand Up @@ -630,6 +634,8 @@ export function submit(
log: data.log,
level: data.level,
endpoint: _endpoint,
duration: data.duration,
visible: data.visible,
fn_index
});
return;
Expand Down
13 changes: 12 additions & 1 deletion gradio/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from __future__ import annotations

from gradio_client.documentation import document


Expand Down Expand Up @@ -73,12 +75,21 @@ def divide(numerator, denominator):
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):
Expand Down
29 changes: 23 additions & 6 deletions gradio/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1226,7 +1226,12 @@ def _animate(_):
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()
Expand All @@ -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():
Expand All @@ -1259,16 +1270,22 @@ def hello_world():
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():
Expand All @@ -1279,4 +1296,4 @@ def hello_world():
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)
20 changes: 14 additions & 6 deletions gradio/queueing.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
from gradio.data_classes import (
PredictBody,
)
from gradio.exceptions import Error
from gradio.helpers import TrackedIterable
from gradio.server_messages import (
EstimationMessage,
Expand All @@ -30,7 +29,13 @@
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
Expand Down Expand Up @@ -376,6 +381,8 @@ def log_message(
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
Expand All @@ -385,6 +392,8 @@ def log_message(
log_message = LogMessage(
log=log,
level=level,
duration=duration,
visible=visible,
)
self.send_message(event, log_message)

Expand Down Expand Up @@ -538,15 +547,15 @@ async def process_events(
)
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,
),
)
Expand Down Expand Up @@ -586,8 +595,7 @@ async def process_events(
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)
Expand Down
5 changes: 2 additions & 3 deletions gradio/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@
ResetBody,
SimplePredictBody,
)
from gradio.exceptions import Error
from gradio.oauth import attach_oauth
from gradio.route_utils import ( # noqa: F401
CustomCORSMiddleware,
Expand Down Expand Up @@ -737,10 +736,10 @@ async def predict(
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
Expand Down
2 changes: 2 additions & 0 deletions gradio/server_messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
14 changes: 14 additions & 0 deletions gradio/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
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).
Expand Down Expand Up @@ -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
6 changes: 6 additions & 0 deletions js/_website/src/lib/assets/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
8 changes: 7 additions & 1 deletion js/_website/src/lib/templates/gradio/05_modals/error.svx
Original file line number Diff line number Diff line change
Expand Up @@ -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).

![modal_control](https://github.com/gradio-app/gradio/assets/41651716/f0977bcd-eaec-4eca-a2fd-ede95fdb8fd2)

<!-- Example Usage -->

{#if obj.example}
Expand Down
2 changes: 1 addition & 1 deletion js/_website/src/lib/templates/gradio/05_modals/info.svx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

<!--- Usage -->
```python
gradio.Info(···)
gradio.Info("Helpful info message ℹ️", duration=5)
```

<!--- Description -->
Expand Down
2 changes: 1 addition & 1 deletion js/_website/src/lib/templates/gradio/05_modals/warning.svx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

<!--- Usage -->
```python
gradio.Warning(···)
gradio.Warning("A warning occured ⛔️!", duration=5)
```

<!--- Description -->
Expand Down
26 changes: 21 additions & 5 deletions js/app/src/Blocks.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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
};
}
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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 (
Expand Down
Loading

0 comments on commit c2a0d05

Please sign in to comment.