Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/soft-meals-listen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@gradio/client": patch
"@self/app": patch
"@self/spa": patch
"gradio": patch
---

fix:Fix ZeroGPU handling for `gr.Server`
3 changes: 3 additions & 0 deletions client/js/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import {
parse_and_set_cookies
} from "./helpers/init_helpers";
import { check_and_wake_space, check_space_status } from "./helpers/spaces";
import { initialize_zerogpu_handshake } from "./helpers/zerogpu";
import { open_stream, readable_stream, close_stream } from "./utils/stream";
import {
API_INFO_ERROR_MSG,
Expand Down Expand Up @@ -220,6 +221,8 @@ export class Client {
}

private async init(): Promise<void> {
initialize_zerogpu_handshake();

if (this.options.auth) {
await this.resolve_cookies();
}
Expand Down
40 changes: 40 additions & 0 deletions client/js/src/helpers/zerogpu.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
const ZEROGPU_HEADERS_MESSAGE = "supports-zerogpu-headers";

let zerogpu_handshake_initialized = false;

function supports_browser_handshake(): boolean {
return (
typeof window !== "undefined" &&
typeof document !== "undefined" &&
typeof window.addEventListener === "function"
);
}

export function get_zerogpu_origin(hostname: string): string | null {
if (hostname.includes(".dev.")) {
return `https://moon-${hostname.split(".")[1]}.dev.spaces.huggingface.tech`;
}
if (hostname.endsWith(".hf.space")) {
return "https://huggingface.co";
}
return null;
}

export function initialize_zerogpu_handshake(): void {
if (!supports_browser_handshake() || zerogpu_handshake_initialized) {
return;
}

window.addEventListener("message", (event) => {
if (event.data === ZEROGPU_HEADERS_MESSAGE) {
window.supports_zerogpu_headers = true;
}
});

zerogpu_handshake_initialized = true;

const origin = get_zerogpu_origin(window.location.hostname);
if (origin && window.parent !== window) {
window.parent.postMessage(ZEROGPU_HEADERS_MESSAGE, origin);
}
}
7 changes: 3 additions & 4 deletions client/js/src/utils/submit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import type {
} from "../types";

import { skip_queue, post_message, handle_payload } from "../helpers/data";
import { get_zerogpu_origin } from "../helpers/zerogpu";
import {
handle_message,
map_data_to_params,
Expand Down Expand Up @@ -412,15 +413,13 @@ export function submit(
hostname = window?.location?.hostname;
}

let hfhubdev = "dev.spaces.huggingface.tech";
const origin = hostname.includes(".dev.")
? `https://moon-${hostname.split(".")[1]}.${hfhubdev}`
: `https://huggingface.co`;
const origin = get_zerogpu_origin(hostname);

const is_zerogpu_iframe =
typeof window !== "undefined" &&
typeof document !== "undefined" &&
window.parent != window &&
!!origin &&
window.supports_zerogpu_headers;
const zerogpu_auth_promise = is_zerogpu_iframe
? post_message<Map<string, string>>("zerogpu-headers", origin)
Expand Down
16 changes: 14 additions & 2 deletions gradio/queueing.py
Original file line number Diff line number Diff line change
Expand Up @@ -968,13 +968,19 @@ async def process_events(
success = False
error = err or old_err
output = error_payload(error, app.get_blocks().show_error)
used_cache = output.get("used_cache") if success else None
used_cache = (
cast(Literal["full", "partial"], used_cache)
if used_cache in ("full", "partial")
else None
)
for event in awake_events:
self.send_message(
event,
ProcessCompletedMessage(
output=output,
success=success,
used_cache=output.get("used_cache") if success else None,
used_cache=used_cache,
cache_duration=output.get("duration"), # type: ignore[arg-type]
avg_time=output.get("average_duration"), # type: ignore[arg-type]
),
Expand All @@ -988,12 +994,18 @@ async def process_events(
e
]
success = response is not None
used_cache = output.get("used_cache") if success else None
used_cache = (
cast(Literal["full", "partial"], used_cache)
if used_cache in ("full", "partial")
else None
)
self.send_message(
event,
ProcessCompletedMessage(
output=output,
success=success,
used_cache=output.get("used_cache") if success else None,
used_cache=used_cache,
cache_duration=output.get("duration"), # type: ignore[arg-type]
avg_time=output.get("average_duration"), # type: ignore[arg-type]
),
Expand Down
2 changes: 2 additions & 0 deletions guides/09_gradio-clients-and-lite/08_server-mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ python run.py

Then open `http://localhost:7860` in your browser. The custom HTML page uses the `@gradio/client` JavaScript library to call the Gradio API endpoints. Meanwhile, the same endpoints are available as MCP tools and through the REST API at `/gradio_api/call/add` and `/gradio_api/call/multiply`.

Note: if your `Server` app uses ZeroGPU, you _must_ call Gradio API endpoints through `@gradio/client` from the browser. The JavaScript client forwards the Hugging Face iframe auth headers needed for ZeroGPU quota handling.

## Concurrency and Streaming

`app.api()` supports all of the same concurrency and streaming options as `gr.api()`:
Expand Down
16 changes: 0 additions & 16 deletions js/app/src/routes/[...catchall]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -293,22 +293,6 @@

await add_custom_html_head(config.head);

const supports_zerogpu_headers = "supports-zerogpu-headers";
window.addEventListener("message", (event) => {
if (event.data === supports_zerogpu_headers) {
window.supports_zerogpu_headers = true;
}
});
const hostname = window.location.hostname;
const is_hf_host =
hostname.includes(".dev.") || hostname.endsWith(".hf.space");
if (is_hf_host) {
const origin = hostname.includes(".dev.")
? `https://moon-${hostname.split(".")[1]}.dev.spaces.huggingface.tech`
: `https://huggingface.co`;
window.parent.postMessage(supports_zerogpu_headers, origin);
}

if (config.js) {
try {
const script = document.createElement("script");
Expand Down
16 changes: 0 additions & 16 deletions js/spa/src/Index.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -356,22 +356,6 @@
css_ready = true;
window.__is_colab__ = config.is_colab;

const supports_zerogpu_headers = "supports-zerogpu-headers";
window.addEventListener("message", (event) => {
if (event.data === supports_zerogpu_headers) {
window.supports_zerogpu_headers = true;
}
});
const hostname = window.location.hostname;
const is_hf_host =
hostname.includes(".dev.") || hostname.endsWith(".hf.space");
if (is_hf_host) {
const origin = hostname.includes(".dev.")
? `https://moon-${hostname.split(".")[1]}.dev.spaces.huggingface.tech`
: `https://huggingface.co`;
window.parent.postMessage(supports_zerogpu_headers, origin);
}

dispatch("loaded");

pages = config.pages;
Expand Down
Loading