Queue error fix & custom errors (#2047)

* changes

* format

* changes

* changes

* custom error

* change

* change

* change

* changes

* change

* fe fix

* changes

* changes
This commit is contained in:
aliabid94 2022-08-22 11:05:55 -07:00 committed by GitHub
parent e9b4584ffb
commit 1510cb73cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 86 additions and 53 deletions

View File

@ -8,6 +8,8 @@ def calculator(num1, operation, num2):
elif operation == "multiply":
return num1 * num2
elif operation == "divide":
if num2 == 0:
raise gr.Error("Cannot divide by zero!")
return num1 / num2
demo = gr.Interface(
@ -28,4 +30,4 @@ demo = gr.Interface(
description="Here's a sample toy calculator. Enjoy!",
)
if __name__ == "__main__":
demo.launch(show_error=True)
demo.launch()

View File

@ -7,8 +7,10 @@ import time
import gradio as gr
def fake_gan(*args):
time.sleep(15)
def fake_gan(desc):
if desc == "NSFW":
raise gr.Error("NSFW - banned content.")
time.sleep(5)
image = random.choice(
[
"https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=387&q=80",
@ -23,20 +25,12 @@ def fake_gan(*args):
demo = gr.Interface(
fn=fake_gan,
inputs=[
gr.Image(label="Initial Image (optional)"),
],
inputs=gr.Textbox(),
outputs=gr.Image(label="Generated Image"),
title="FD-GAN",
description="This is a fake demo of a GAN. In reality, the images are randomly chosen from Unsplash.",
examples=[
[os.path.join(os.path.dirname(__file__), "files/cheetah1.jpg")],
[os.path.join(os.path.dirname(__file__), "files/elephant.jpg")],
[os.path.join(os.path.dirname(__file__), "files/tiger.jpg")],
[os.path.join(os.path.dirname(__file__), "files/zebra.jpg")],
],
)
demo.queue(max_size=3)
if __name__ == "__main__":
demo.launch()
demo.launch(show_error=True)

View File

@ -44,6 +44,7 @@ from gradio.components import (
component,
)
from gradio.examples import create_examples as Examples
from gradio.exceptions import Error
from gradio.flagging import (
CSVLogger,
FlaggingCallback,

View File

@ -33,6 +33,7 @@ from gradio.documentation import (
document_component_api,
set_documentation_group,
)
from gradio.exceptions import Error
from gradio.utils import component_or_layout_class, delete_none
set_documentation_group("blocks")
@ -813,7 +814,7 @@ class Blocks(BlockContext):
auth: Optional[Callable | Tuple[str, str] | List[Tuple[str, str]]] = None,
auth_message: Optional[str] = None,
prevent_thread_lock: bool = False,
show_error: bool = True,
show_error: bool = False,
server_name: Optional[str] = None,
server_port: Optional[int] = None,
show_tips: bool = False,
@ -839,7 +840,7 @@ class Blocks(BlockContext):
auth: If provided, username and password (or list of username-password tuples) required to access interface. Can also provide function that takes username and password and returns True if valid login.
auth_message: If provided, HTML message provided on login page.
prevent_thread_lock: If True, the interface will block the main thread while the server is running.
show_error: If True, any errors in the interface will be printed in the browser console log
show_error: If True, any errors in the interface will be displayed in an alert modal and printed in the browser console log
server_port: will start gradio app on this port (if available). Can be set by environment variable GRADIO_SERVER_PORT. If None, will search for an available port starting at 7860.
server_name: to make app accessible on local network, set this to "0.0.0.0". Can be set by environment variable GRADIO_SERVER_NAME. If None, will use "127.0.0.1".
show_tips: if True, will occasionally show tips about new Gradio features
@ -886,9 +887,9 @@ class Blocks(BlockContext):
DeprecationWarning,
)
if self.is_space:
self.enable_queue = enable_queue is not False
self.enable_queue = self.enable_queue is not False
else:
self.enable_queue = enable_queue is True
self.enable_queue = self.enable_queue is True
self.config = self.get_config_file()
self.share = share

View File

@ -258,9 +258,15 @@ class Queue:
json=event.data,
)
end_time = time.time()
cls.update_estimation(end_time - begin_time)
success = response.status == 200
if success:
cls.update_estimation(end_time - begin_time)
client_awake = await event.send_message(
{"msg": "process_completed", "output": response.json}
{
"msg": "process_completed",
"output": response.json,
"success": success,
}
)
if client_awake:
run_coro_in_background(cls.wait_in_inactive, event)

7
gradio/exceptions.py Normal file
View File

@ -0,0 +1,7 @@
class Error(Exception):
def __init__(self, message: str):
self.message = message
super().__init__(self.message)
def __str__(self):
return repr(self.message)

View File

@ -29,6 +29,7 @@ from starlette.websockets import WebSocket, WebSocketState
import gradio
from gradio import encryptor
from gradio.event_queue import Estimation, Event, Queue
from gradio.exceptions import Error
STATIC_TEMPLATE_LIB = pkg_resources.resource_filename("gradio", "templates/")
STATIC_PATH_LIB = pkg_resources.resource_filename("gradio", "templates/frontend/static")
@ -241,18 +242,21 @@ class App(FastAPI):
session_state = app.state_holder[body.session_hash]
else:
session_state = {}
raw_input = body.data
fn_index = body.fn_index
try:
raw_input = body.data
fn_index = body.fn_index
output = await app.blocks.process_api(
fn_index, raw_input, username, session_state
)
if isinstance(output, Error):
raise output
except BaseException as error:
if app.blocks.show_error:
traceback.print_exc()
return JSONResponse(content={"error": str(error)}, status_code=500)
else:
raise error
show_error = app.blocks.show_error or isinstance(error, Error)
traceback.print_exc()
return JSONResponse(
content={"error": str(error) if show_error else None},
status_code=500,
)
return output
@app.post("/api/{api_name}", dependencies=[Depends(login_check)])

View File

@ -1 +1 @@
3.1.6
3.1.6b1

View File

@ -11,6 +11,10 @@ $demo_calculator
You can load a large dataset into the examples to browse and interact with the dataset through Gradio. The examples will be automatically paginated (you can configure this through the `examples_per_page` argument of `Interface`).
## Errors
You wish to pass custom error messages to the user. To do so, raise a `gr.Error("custom message")` to display an error message. If you try to divide by zero in the the calculator demo above, a popup modal will display the custom error message.
## Decriptive Content
In the previous example, you may have noticed the `title=` and `description=` keyword arguments in the `Interface` constructor that helps users understand your app.

View File

@ -35,7 +35,6 @@
export let target: HTMLElement;
export let id: number = 0;
export let autoscroll: boolean = false;
export let show_error: boolean = false;
let app_mode = window.__gradio_mode__ === "app";
let loading_status = create_loading_status_store();

View File

@ -46,7 +46,6 @@ async function post_data(
body: JSON.stringify(body),
headers: { "Content-Type": "application/json" }
});
const output: PostResponse = await response.json();
return [output, response.status];
}
@ -64,12 +63,7 @@ type Output = {
const ws_map = new Map();
export const fn =
(
session_hash: string,
api_endpoint: string,
is_space: boolean,
show_error: boolean
) =>
(session_hash: string, api_endpoint: string, is_space: boolean) =>
async ({
action,
payload,
@ -177,14 +171,16 @@ export const fn =
case "process_completed":
loading_status.update(
fn_index,
"complete",
data.success ? "complete" : "error",
queue,
null,
null,
data.output.average_duration,
null
!data.success ? data.output.error : null
);
queue_callback(data.output);
if (data.success) {
queue_callback(data.output);
}
websocket_data.connection.close();
break;
case "process_starts":
@ -233,8 +229,9 @@ export const fn =
null,
null,
null,
show_error ? output.error : null
output.error
);
throw output.error || "API Error";
}
return output;
}

View File

@ -64,6 +64,7 @@
let timer_start = 0;
let timer_diff = 0;
let old_eta: number | null = null;
let message_visible: boolean = false;
$: progress =
eta === null || eta <= 0 || !timer_diff
@ -121,6 +122,19 @@
old_eta = eta;
}
}
let show_message_timeout: NodeJS.Timeout | null = null;
const close_message = () => {
message_visible = false;
if (show_message_timeout !== null) {
clearTimeout(show_message_timeout);
}
};
$: {
if (status === "error" && message) {
message_visible = true;
show_message_timeout = setTimeout(close_message, 8000);
}
}
$: formatted_timer = timer_diff.toFixed(1);
</script>
@ -151,8 +165,22 @@
{/if}
{:else if status === "error"}
<span class="error">ERROR</span>
{#if message}
<span class="status-message dark:text-gray-100">{message}</span>
{#if message_visible}
<div
class="flex flex-col items-center fixed z-[100] w-full left-0 top-12 mx-auto font-mono whitespace-pre-wrap pointer-events-auto"
>
<div
class="p-3 w-4/5 text-xl rounded-t bg-red-300 text-red-700 status-title flex justify-between items-center"
>
<span>Error</span>
<button on:click={close_message}>✖</button>
</div>
<div
class="px-3 w-4/5 py-4 rounded-b bg-gray-200 border-gray-100 dark:bg-gray-700 dark:border-gray-800 dark:text-gray-100"
>
{message}
</div>
</div>
{/if}
{/if}
</div>
@ -181,8 +209,4 @@
.error {
@apply text-red-400 font-mono font-semibold text-lg;
}
.status-message {
@apply font-mono p-2 whitespace-pre;
}
</style>

View File

@ -34,7 +34,6 @@ interface Config {
title: string;
version: string;
is_space: boolean;
show_error: boolean;
// allow_flagging: string;
// allow_interpretation: boolean;
// article: string;
@ -184,12 +183,7 @@ function mount_app(
});
} else {
let session_hash = Math.random().toString(36).substring(2);
config.fn = fn(
session_hash,
config.root + "api/",
config.is_space,
config.show_error
);
config.fn = fn(session_hash, config.root + "api/", config.is_space);
new Blocks({
target: wrapper,

View File

@ -69,7 +69,7 @@
}
.gr-button-primary {
@apply from-orange-200/70 to-orange-300/80 hover:from-orange-200/90 text-orange-600 border-orange-200
@apply from-orange-200/70 to-orange-300/80 hover:to-orange-200/90 text-orange-600 border-orange-200
dark:from-orange-700 dark:to-orange-700 dark:hover:to-orange-500 dark:text-white dark:border-orange-600;
}