mirror of
https://github.com/gradio-app/gradio.git
synced 2025-04-06 12:30:29 +08:00
1148 loading status (#1164)
* update loader * fix for non queued statuses * remove logs * Update demo/fake_gan/run.py
This commit is contained in:
parent
a9610a4c9b
commit
56222fbe2b
@ -24,6 +24,8 @@ def fake_gan(count, *args):
|
||||
return images
|
||||
|
||||
|
||||
cheetah = os.path.join(os.path.dirname(__file__), "files/cheetah1.jpg")
|
||||
|
||||
demo = gr.Interface(
|
||||
fn=fake_gan,
|
||||
inputs=[
|
||||
@ -38,21 +40,22 @@ demo = gr.Interface(
|
||||
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"), 12, 12, 4, 4],
|
||||
[os.path.join(os.path.dirname(__file__), "files/cheetah1.jpg"), 12, 12, 4, 4],
|
||||
[os.path.join(os.path.dirname(__file__), "files/cheetah1.jpg"), 12, 12, 4, 4],
|
||||
[os.path.join(os.path.dirname(__file__), "files/cheetah1.jpg"), 12, 12, 4, 4],
|
||||
[os.path.join(os.path.dirname(__file__), "files/cheetah1.jpg"), 12, 12, 4, 4],
|
||||
[os.path.join(os.path.dirname(__file__), "files/cheetah1.jpg"), 12, 12, 4, 4],
|
||||
[os.path.join(os.path.dirname(__file__), "files/cheetah1.jpg"), 12, 12, 4, 4],
|
||||
[os.path.join(os.path.dirname(__file__), "files/cheetah1.jpg"), 12, 12, 4, 4],
|
||||
[os.path.join(os.path.dirname(__file__), "files/cheetah1.jpg"), 12, 12, 4, 4],
|
||||
[os.path.join(os.path.dirname(__file__), "files/cheetah1.jpg"), 12, 12, 4, 4],
|
||||
[os.path.join(os.path.dirname(__file__), "files/cheetah1.jpg"), 12, 12, 4, 4],
|
||||
[os.path.join(os.path.dirname(__file__), "files/cheetah1.jpg"), 12, 12, 4, 4],
|
||||
[os.path.join(os.path.dirname(__file__), "files/cheetah1.jpg"), 12, 12, 4, 4],
|
||||
[os.path.join(os.path.dirname(__file__), "files/cheetah1.jpg"), 12, 12, 4, 4],
|
||||
[2, cheetah, 12, 12, 4, 4],
|
||||
[2, cheetah, 12, 12, 4, 4],
|
||||
[2, cheetah, 12, 12, 4, 4],
|
||||
[2, cheetah, 12, 12, 4, 4],
|
||||
[2, cheetah, 12, 12, 4, 4],
|
||||
[2, cheetah, 12, 12, 4, 4],
|
||||
[2, cheetah, 12, 12, 4, 4],
|
||||
[2, cheetah, 12, 12, 4, 4],
|
||||
[2, cheetah, 12, 12, 4, 4],
|
||||
[2, cheetah, 12, 12, 4, 4],
|
||||
[2, cheetah, 12, 12, 4, 4],
|
||||
[2, cheetah, 12, 12, 4, 4],
|
||||
[2, cheetah, 12, 12, 4, 4],
|
||||
[2, cheetah, 12, 12, 4, 4],
|
||||
],
|
||||
enable_queue=True,
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
@ -1,6 +1,9 @@
|
||||
<script lang="ts">
|
||||
import type { SvelteComponentTyped } from "svelte";
|
||||
import { component_map } from "./components/directory";
|
||||
import { loading_status } from "./stores";
|
||||
import type { LoadingStatus } from "./stores";
|
||||
|
||||
import { _ } from "svelte-i18n";
|
||||
import { setupi18n } from "./i18n";
|
||||
import Render from "./Render.svelte";
|
||||
@ -83,7 +86,6 @@
|
||||
}
|
||||
};
|
||||
}, {} as { [id: number]: Instance });
|
||||
console.log(JSON.stringify(components));
|
||||
|
||||
function load_component<T extends keyof typeof component_map>(
|
||||
name: T
|
||||
@ -145,7 +147,7 @@
|
||||
let handled_dependencies: Array<number[]> = [];
|
||||
let status_tracker_values: Record<number, string> = {};
|
||||
|
||||
async function handle_mount({ detail }) {
|
||||
async function handle_mount() {
|
||||
await tick();
|
||||
dependencies.forEach(
|
||||
(
|
||||
@ -166,18 +168,16 @@
|
||||
outputs.every((v) => instance_map[v].instance) &&
|
||||
inputs.every((v) => instance_map[v].instance)
|
||||
) {
|
||||
fn(
|
||||
"predict",
|
||||
fn({
|
||||
action: "predict",
|
||||
backend_fn,
|
||||
frontend_fn,
|
||||
{
|
||||
payload: {
|
||||
fn_index: i,
|
||||
data: inputs.map((id) => instance_map[id].value)
|
||||
},
|
||||
outputs.map((id) => instance_map[id].value),
|
||||
queue === null ? enable_queue : queue,
|
||||
() => {}
|
||||
)
|
||||
queue: queue === null ? enable_queue : queue
|
||||
})
|
||||
.then((output) => {
|
||||
output.data.forEach((value, i) => {
|
||||
instance_map[outputs[i]].value = value;
|
||||
@ -193,40 +193,30 @@
|
||||
target_instances.forEach(([id, { instance }]: [number, Instance]) => {
|
||||
if (handled_dependencies[i]?.includes(id) || !instance) return;
|
||||
instance?.$on(trigger, () => {
|
||||
if (status === "pending") {
|
||||
console.log(loading_status.get_status_for_fn(i));
|
||||
|
||||
if (loading_status.get_status_for_fn(i) === "pending") {
|
||||
return;
|
||||
}
|
||||
outputs.forEach((_id) =>
|
||||
set_prop(instance_map[_id], "loading_status", "pending")
|
||||
);
|
||||
|
||||
fn(
|
||||
"predict",
|
||||
// page events
|
||||
fn({
|
||||
action: "predict",
|
||||
backend_fn,
|
||||
frontend_fn,
|
||||
{
|
||||
payload: {
|
||||
fn_index: i,
|
||||
data: inputs.map((id) => instance_map[id].value)
|
||||
},
|
||||
outputs.map((id) => instance_map[id].value),
|
||||
queue === null ? enable_queue : queue,
|
||||
() => {}
|
||||
)
|
||||
output_data: outputs.map((id) => instance_map[id].value),
|
||||
queue: queue === null ? enable_queue : queue
|
||||
})
|
||||
.then((output) => {
|
||||
output.data.forEach((value, i) => {
|
||||
instance_map[outputs[i]].value = value;
|
||||
set_prop(
|
||||
instance_map[outputs[i]],
|
||||
"loading_status",
|
||||
"complete"
|
||||
);
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
outputs.forEach((_id) =>
|
||||
set_prop(instance_map[_id], "loading_status", "error")
|
||||
);
|
||||
|
||||
console.error(error);
|
||||
});
|
||||
});
|
||||
@ -243,6 +233,20 @@
|
||||
return dep.filter((_id) => _id !== id);
|
||||
});
|
||||
}
|
||||
|
||||
$: set_status($loading_status);
|
||||
|
||||
dependencies.forEach((v, i) => {
|
||||
loading_status.register(i, v.outputs);
|
||||
});
|
||||
|
||||
function set_status(
|
||||
statuses: Record<number, Omit<LoadingStatus, "outputs">>
|
||||
) {
|
||||
for (const id in statuses) {
|
||||
set_prop(instance_map[id], "loading_status", statuses[id]);
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
|
@ -82,6 +82,7 @@
|
||||
node.props.form_position = "single";
|
||||
}
|
||||
}
|
||||
|
||||
children =
|
||||
children &&
|
||||
children.filter((v) => instance_map[v.id].type !== "statustracker");
|
||||
|
@ -1,71 +1,136 @@
|
||||
import { LoadingStatus, loading_status } from "./stores";
|
||||
|
||||
type StatusResponse =
|
||||
| {
|
||||
status: "COMPLETE";
|
||||
data: { duration: number; average_duration: number; data: unknown };
|
||||
}
|
||||
| {
|
||||
status: "QUEUED";
|
||||
data: number;
|
||||
}
|
||||
| {
|
||||
status: "PENDING";
|
||||
data: null;
|
||||
}
|
||||
| {
|
||||
status: "FAILED";
|
||||
data: Record<string, unknown>;
|
||||
};
|
||||
|
||||
interface Payload {
|
||||
data: Record<string, unknown>;
|
||||
fn_index: number;
|
||||
}
|
||||
|
||||
function delay(n: number) {
|
||||
return new Promise(function (resolve) {
|
||||
setTimeout(resolve, n * 1000);
|
||||
});
|
||||
}
|
||||
|
||||
let postData = async (url: string, body: unknown) => {
|
||||
const output = await fetch(url, {
|
||||
async function post_data<
|
||||
Return extends Record<string, unknown> = Record<string, unknown>
|
||||
>(url: string, body: unknown): Promise<Return> {
|
||||
const response = await fetch(url, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(body),
|
||||
headers: { "Content-Type": "application/json" }
|
||||
});
|
||||
|
||||
if (response.status !== 200) {
|
||||
throw new Error(response.statusText);
|
||||
}
|
||||
|
||||
const output: Return = await response.json();
|
||||
|
||||
return output;
|
||||
};
|
||||
}
|
||||
|
||||
export const fn = async (
|
||||
session_hash: string,
|
||||
api_endpoint: string,
|
||||
action: string,
|
||||
backend_fn: boolean,
|
||||
frontend_fn: Function | undefined,
|
||||
data: Record<string, unknown>,
|
||||
output_data: Array<any>,
|
||||
queue: boolean,
|
||||
queue_callback: (pos: number | null, is_initial?: boolean) => void
|
||||
{
|
||||
action,
|
||||
payload,
|
||||
queue,
|
||||
backend_fn,
|
||||
frontend_fn,
|
||||
output_data
|
||||
}: {
|
||||
action: string;
|
||||
payload: Payload;
|
||||
queue: boolean;
|
||||
backend_fn: boolean;
|
||||
frontend_fn: Function | undefined;
|
||||
output_data: Array<any>;
|
||||
}
|
||||
) => {
|
||||
const fn_index = payload.fn_index;
|
||||
|
||||
if (frontend_fn !== undefined) {
|
||||
data.data = frontend_fn(data.data.concat(output_data));
|
||||
payload.data = frontend_fn(payload.data.concat(output_data));
|
||||
}
|
||||
if (backend_fn == false) {
|
||||
return data;
|
||||
return payload;
|
||||
}
|
||||
data["session_hash"] = session_hash;
|
||||
|
||||
if (queue && ["predict", "interpret"].includes(action)) {
|
||||
data["action"] = action;
|
||||
const output = await postData(api_endpoint + "queue/push/", data);
|
||||
const output_json = await output.json();
|
||||
let [hash, queue_position] = [
|
||||
output_json["hash"],
|
||||
output_json["queue_position"]
|
||||
];
|
||||
queue_callback(queue_position, /*is_initial=*/ true);
|
||||
let status = "UNKNOWN";
|
||||
while (status != "COMPLETE" && status != "FAILED") {
|
||||
if (status != "UNKNOWN") {
|
||||
await delay(1);
|
||||
}
|
||||
const status_response = await postData(api_endpoint + "queue/status/", {
|
||||
hash: hash
|
||||
});
|
||||
var status_obj = await status_response.json();
|
||||
status = status_obj["status"];
|
||||
loading_status.update(fn_index as number, "pending", null, null);
|
||||
|
||||
const { hash, queue_position } = await post_data<{
|
||||
hash: string;
|
||||
queue_position: number;
|
||||
}>(api_endpoint + "queue/push/", { ...payload, action, session_hash });
|
||||
|
||||
loading_status.update(fn_index, "pending", queue_position, null);
|
||||
|
||||
for (;;) {
|
||||
await delay(1);
|
||||
|
||||
const { status, data } = await post_data<StatusResponse>(
|
||||
api_endpoint + "queue/status/",
|
||||
{
|
||||
hash: hash
|
||||
}
|
||||
);
|
||||
|
||||
if (status === "QUEUED") {
|
||||
queue_callback(status_obj["data"]);
|
||||
loading_status.update(fn_index, "pending", data, null);
|
||||
} else if (status === "PENDING") {
|
||||
queue_callback(null);
|
||||
loading_status.update(fn_index, "pending", 0, null);
|
||||
} else if (status === "FAILED") {
|
||||
loading_status.update(fn_index, "error", null, null);
|
||||
|
||||
throw new Error(status);
|
||||
} else {
|
||||
loading_status.update(
|
||||
fn_index,
|
||||
"complete",
|
||||
null,
|
||||
data.average_duration
|
||||
);
|
||||
|
||||
return data;
|
||||
}
|
||||
}
|
||||
if (status == "FAILED") {
|
||||
throw new Error(status);
|
||||
} else {
|
||||
return status_obj["data"];
|
||||
}
|
||||
} else {
|
||||
const output = await postData(api_endpoint + action + "/", data);
|
||||
if (output.status !== 200) {
|
||||
throw new Error(output.statusText);
|
||||
}
|
||||
return await output.json();
|
||||
loading_status.update(fn_index as number, "pending", null, null);
|
||||
|
||||
const output = await post_data(api_endpoint + action + "/", {
|
||||
...payload,
|
||||
session_hash
|
||||
});
|
||||
|
||||
console.log();
|
||||
|
||||
loading_status.update(
|
||||
fn_index,
|
||||
"complete",
|
||||
null,
|
||||
output.average_duration as number
|
||||
);
|
||||
|
||||
return await output;
|
||||
}
|
||||
};
|
||||
|
@ -5,6 +5,8 @@
|
||||
import { Block } from "@gradio/atoms";
|
||||
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
|
||||
import { _ } from "svelte-i18n";
|
||||
|
||||
export let mode: "static" | "dynamic";
|
||||
@ -18,7 +20,7 @@
|
||||
export let root: string;
|
||||
export let show_label: boolean;
|
||||
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
|
||||
if (default_value) value = default_value;
|
||||
|
||||
@ -35,7 +37,7 @@
|
||||
color={dragging ? "green" : "grey"}
|
||||
padding={false}
|
||||
>
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
|
||||
{#if mode === "dynamic"}
|
||||
<Audio
|
||||
|
@ -1,13 +1,14 @@
|
||||
<script lang="ts">
|
||||
import { Carousel } from "@gradio/carousel";
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
|
||||
export let style: string = "";
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
</script>
|
||||
|
||||
<Carousel {style} on:change>
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
|
||||
<slot />
|
||||
</Carousel>
|
||||
|
@ -2,18 +2,19 @@
|
||||
import { ChatBot } from "@gradio/chatbot";
|
||||
import { Block } from "@gradio/atoms";
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
|
||||
export let value: Array<[string, string]> = [];
|
||||
export let default_value: Array<[string, string]>;
|
||||
export let style: string = "";
|
||||
export let color_map: Array<[string, string]>;
|
||||
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
|
||||
if (default_value) value = default_value;
|
||||
</script>
|
||||
|
||||
<Block padding={false}>
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
<ChatBot {value} {style} {color_map} on:change />
|
||||
</Block>
|
||||
|
@ -2,6 +2,7 @@
|
||||
import { Checkbox } from "@gradio/form";
|
||||
import { Block } from "@gradio/atoms";
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
|
||||
export let value: boolean = false;
|
||||
export let default_value: boolean = false;
|
||||
@ -11,13 +12,13 @@
|
||||
export let form_position: "first" | "last" | "mid" | "single" = "single";
|
||||
export let show_label: boolean;
|
||||
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
|
||||
if (default_value) value = default_value;
|
||||
</script>
|
||||
|
||||
<Block {form_position}>
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
|
||||
<Checkbox
|
||||
{style}
|
||||
|
@ -2,6 +2,7 @@
|
||||
import { CheckboxGroup } from "@gradio/form";
|
||||
import { Block } from "@gradio/atoms";
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
|
||||
export let value: Array<string> = [];
|
||||
export let default_value: Array<string> = [];
|
||||
@ -13,13 +14,13 @@
|
||||
export let form_position: "first" | "last" | "mid" | "single" = "single";
|
||||
export let show_label: boolean;
|
||||
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
|
||||
if (default_value) value = default_value;
|
||||
</script>
|
||||
|
||||
<Block {form_position} type="fieldset">
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
|
||||
<CheckboxGroup
|
||||
bind:value
|
||||
|
@ -1,6 +1,7 @@
|
||||
<script lang="ts">
|
||||
import { Table } from "@gradio/table";
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
import { createEventDispatcher, tick } from "svelte";
|
||||
|
||||
type Headers = Array<string>;
|
||||
@ -26,7 +27,7 @@
|
||||
|
||||
const dispatch = createEventDispatcher();
|
||||
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
|
||||
async function handle_change({ detail }) {
|
||||
value = detail;
|
||||
@ -36,7 +37,7 @@
|
||||
</script>
|
||||
|
||||
<div class="relative">
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
<Table
|
||||
values={value}
|
||||
{headers}
|
||||
|
@ -2,6 +2,7 @@
|
||||
import { Dropdown } from "@gradio/form";
|
||||
import { Block } from "@gradio/atoms";
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
|
||||
export let label: string = "Dropdown";
|
||||
export let value: string = "";
|
||||
@ -11,7 +12,7 @@
|
||||
export let form_position: "first" | "last" | "mid" | "single" = "single";
|
||||
export let show_label: boolean;
|
||||
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
|
||||
export let mode: "static" | "dynamic";
|
||||
|
||||
@ -19,7 +20,7 @@
|
||||
</script>
|
||||
|
||||
<Block {form_position}>
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
|
||||
<Dropdown
|
||||
bind:value
|
||||
|
@ -5,6 +5,7 @@
|
||||
import { Block } from "@gradio/atoms";
|
||||
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
import { _ } from "svelte-i18n";
|
||||
|
||||
export let value: null | FileData = null;
|
||||
@ -15,7 +16,7 @@
|
||||
export let label: string;
|
||||
export let show_label: boolean;
|
||||
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
|
||||
if (default_value) value = default_value;
|
||||
|
||||
@ -30,7 +31,7 @@
|
||||
color={dragging ? "green" : "grey"}
|
||||
padding={false}
|
||||
>
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
|
||||
{#if mode === "dynamic"}
|
||||
<FileUpload
|
||||
|
@ -2,10 +2,11 @@
|
||||
import { Block, BlockLabel } from "@gradio/atoms";
|
||||
import { ModifyUpload } from "@gradio/upload";
|
||||
import { tick } from "svelte";
|
||||
import { Component as StatusTracker } from "../StatusTracker/";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import image_icon from "./image.svg";
|
||||
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
export let show_label: boolean;
|
||||
export let label: string;
|
||||
export let value: Array<string> | null = null;
|
||||
@ -66,7 +67,7 @@
|
||||
<svelte:window />
|
||||
|
||||
<Block variant="solid" color="grey" padding={false}>
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
<BlockLabel {show_label} image={image_icon} label={label || "Gallery"} />
|
||||
{#if value === null}
|
||||
<div class="min-h-[16rem] flex justify-center items-center">
|
||||
|
@ -3,6 +3,7 @@
|
||||
import { HighlightedText } from "@gradio/highlighted-text";
|
||||
import { Block } from "@gradio/atoms";
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
|
||||
export let value: Array<[string, string | number]>;
|
||||
export let default_value: Array<[string, string | number]>;
|
||||
@ -10,7 +11,7 @@
|
||||
export let show_legend: boolean;
|
||||
export let color_map: Record<string, string> = {};
|
||||
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
|
||||
const dispatch = createEventDispatcher<{ change: undefined }>();
|
||||
|
||||
@ -20,7 +21,7 @@
|
||||
</script>
|
||||
|
||||
<Block>
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
|
||||
<HighlightedText {value} {style} {show_legend} {color_map} />
|
||||
</Block>
|
||||
|
@ -13,7 +13,7 @@
|
||||
export let label: string;
|
||||
export let show_label: boolean;
|
||||
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
|
||||
export let mode: "static" | "dynamic";
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
color={dragging ? "green" : "grey"}
|
||||
padding={false}
|
||||
>
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
{#if mode === "static"}
|
||||
<StaticImage {value} {label} {style} {show_label} />
|
||||
{:else}
|
||||
|
@ -4,11 +4,12 @@
|
||||
import { Block } from "@gradio/atoms";
|
||||
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
|
||||
export let value: any = {};
|
||||
export let default_value: any;
|
||||
export let style: string = "";
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
|
||||
const dispatch = createEventDispatcher<{ change: undefined }>();
|
||||
|
||||
@ -18,7 +19,7 @@
|
||||
</script>
|
||||
|
||||
<Block test_id="json">
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
|
||||
<JSON {style} {value} />
|
||||
</Block>
|
||||
|
@ -3,6 +3,7 @@
|
||||
import { Label } from "@gradio/label";
|
||||
import { Block } from "@gradio/atoms";
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
|
||||
export let value: {
|
||||
label: string;
|
||||
@ -15,7 +16,7 @@
|
||||
};
|
||||
|
||||
export let style: string = "";
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
export let show_label: boolean;
|
||||
|
||||
const dispatch = createEventDispatcher<{ change: undefined }>();
|
||||
@ -26,7 +27,7 @@
|
||||
</script>
|
||||
|
||||
<Block>
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
|
||||
{#if value !== undefined && value !== null}
|
||||
<Label {style} {value} {show_label} />
|
||||
|
@ -5,6 +5,7 @@
|
||||
import { Block } from "@gradio/atoms";
|
||||
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
import { _ } from "svelte-i18n";
|
||||
|
||||
export let value: null | FileData = null;
|
||||
@ -14,7 +15,7 @@
|
||||
export let root: string;
|
||||
export let clearColor: Array<number>;
|
||||
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
export let label: string;
|
||||
export let show_label: boolean;
|
||||
|
||||
@ -31,7 +32,7 @@
|
||||
color={dragging ? "green" : "grey"}
|
||||
padding={false}
|
||||
>
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
|
||||
{#if mode === "dynamic"}
|
||||
<Model3DUpload
|
||||
|
@ -2,6 +2,7 @@
|
||||
import { Number } from "@gradio/form";
|
||||
import { Block } from "@gradio/atoms";
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
|
||||
export let label: string = "Number";
|
||||
export let value: number = 0;
|
||||
@ -9,7 +10,7 @@
|
||||
export let form_position: "first" | "last" | "mid" | "single" = "single";
|
||||
export let show_label: boolean;
|
||||
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
|
||||
export let style: string = "";
|
||||
|
||||
@ -19,7 +20,7 @@
|
||||
</script>
|
||||
|
||||
<Block {form_position}>
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
|
||||
<Number
|
||||
bind:value
|
||||
|
@ -5,7 +5,7 @@
|
||||
export let default_value: null | string = null;
|
||||
export let style: string = "";
|
||||
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
|
||||
if (default_value) value = default_value;
|
||||
</script>
|
||||
|
@ -2,6 +2,7 @@
|
||||
import { Radio } from "@gradio/form";
|
||||
import { Block } from "@gradio/atoms";
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
|
||||
export let label: string = "Radio";
|
||||
export let value: string = "";
|
||||
@ -12,13 +13,13 @@
|
||||
export let form_position: "first" | "last" | "mid" | "single" = "single";
|
||||
export let show_label: boolean;
|
||||
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
|
||||
if (default_value) value = default_value;
|
||||
</script>
|
||||
|
||||
<Block {form_position} type="fieldset">
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
|
||||
<Radio
|
||||
{form_position}
|
||||
|
@ -2,6 +2,7 @@
|
||||
import { Range } from "@gradio/form";
|
||||
import { Block } from "@gradio/atoms";
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
|
||||
export let value: number = 0;
|
||||
|
||||
@ -16,13 +17,13 @@
|
||||
export let form_position: "first" | "last" | "mid" | "single" = "single";
|
||||
export let show_label: boolean;
|
||||
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
|
||||
if (default_value) value = default_value;
|
||||
</script>
|
||||
|
||||
<Block {form_position}>
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
|
||||
<Range
|
||||
bind:value
|
||||
|
@ -38,7 +38,7 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<div class="m-12">
|
||||
<div class="m-12 z-20">
|
||||
<svg
|
||||
class="text-xl"
|
||||
width="7em"
|
||||
|
@ -34,62 +34,99 @@
|
||||
</script>
|
||||
|
||||
<script lang="ts">
|
||||
// import { onDestroy, onMount } from "svelte";
|
||||
import { onDestroy, onMount } from "svelte";
|
||||
import Loader from "./Loader.svelte";
|
||||
|
||||
export let style: string = "";
|
||||
// export let eta: number | null = null;
|
||||
// export let duration: number = 8.2;
|
||||
// export let queue_pos: number | null = 0;
|
||||
export let tracked_status: "complete" | "pending" | "error";
|
||||
export let eta: number | null = null;
|
||||
export let queue_position: number | null;
|
||||
export let status: "complete" | "pending" | "error";
|
||||
|
||||
let el: HTMLDivElement;
|
||||
|
||||
// $: progress = eta === null ? null : Math.min(duration / eta, 1);
|
||||
let timer: boolean = false;
|
||||
let timer_start = 0;
|
||||
let timer_diff = 0;
|
||||
|
||||
// let timer: NodeJS.Timeout | null = null;
|
||||
// let timer_start = 0;
|
||||
// let timer_diff = 0;
|
||||
let initial_queue_pos = queue_position;
|
||||
|
||||
// const start_timer = () => {
|
||||
// timer_start = performance.now();
|
||||
// timer_diff = 0;
|
||||
// timer = setInterval(() => {
|
||||
// timer_diff = (performance.now() - timer_start) / 1000;
|
||||
// }, 100);
|
||||
// };
|
||||
$: if (
|
||||
queue_position &&
|
||||
(!initial_queue_pos || queue_position > initial_queue_pos)
|
||||
) {
|
||||
initial_queue_pos = queue_position;
|
||||
}
|
||||
|
||||
// const stop_timer = () => {
|
||||
// if (!timer) return;
|
||||
// clearInterval(timer);
|
||||
// };
|
||||
$: progress =
|
||||
eta === null || !timer_diff
|
||||
? null
|
||||
: Math.min(timer_diff / (eta * ((initial_queue_pos || 0) + 1)), 1);
|
||||
|
||||
// onDestroy(() => {
|
||||
// if (timer) stop_timer();
|
||||
// });
|
||||
const start_timer = () => {
|
||||
timer_start = performance.now();
|
||||
timer_diff = 0;
|
||||
timer = true;
|
||||
run();
|
||||
// timer = setInterval(, 100);
|
||||
};
|
||||
|
||||
// $: {
|
||||
// if (tracked_status === "pending") {
|
||||
// start_timer();
|
||||
// } else {
|
||||
// stop_timer();
|
||||
// }
|
||||
// }
|
||||
function run() {
|
||||
requestAnimationFrame(() => {
|
||||
timer_diff = (performance.now() - timer_start) / 1000;
|
||||
if (timer) run();
|
||||
});
|
||||
}
|
||||
|
||||
const stop_timer = () => {
|
||||
timer_diff = 0;
|
||||
|
||||
if (!timer) return;
|
||||
timer = false;
|
||||
};
|
||||
|
||||
onDestroy(() => {
|
||||
if (timer) stop_timer();
|
||||
});
|
||||
|
||||
$: {
|
||||
if (status === "pending") {
|
||||
start_timer();
|
||||
} else {
|
||||
stop_timer();
|
||||
}
|
||||
}
|
||||
|
||||
$: el &&
|
||||
(tracked_status === "pending" || tracked_status === "complete") &&
|
||||
(status === "pending" || status === "complete") &&
|
||||
scroll_into_view(el);
|
||||
|
||||
$: formatted_eta = eta && (eta * ((initial_queue_pos || 0) + 1)).toFixed(1);
|
||||
$: formatted_timer = timer_diff.toFixed(1);
|
||||
</script>
|
||||
|
||||
<div
|
||||
class=" absolute top-0 left-0 w-full h-full z-10 flex flex-col justify-center items-center bg-white pointer-events-none transition-opacity"
|
||||
class:opacity-0={!tracked_status || tracked_status === "complete"}
|
||||
class=" absolute inset-0 z-10 flex flex-col justify-center items-center bg-white pointer-events-none transition-opacity"
|
||||
class:opacity-0={!status || status === "complete"}
|
||||
{style}
|
||||
bind:this={el}
|
||||
>
|
||||
{#if tracked_status === "pending"}
|
||||
{#if status === "pending"}
|
||||
<div
|
||||
class="absolute inset-0 origin-left bg-slate-100 top-0 left-0 z-10 opacity-80"
|
||||
style:transform="scaleX({progress || 0})"
|
||||
/>
|
||||
<div class="absolute top-0 right-0 py-1 px-2 font-mono z-20 text-xs">
|
||||
{#if queue_position !== null && queue_position > 0}
|
||||
queue: {queue_position}/{initial_queue_pos} |
|
||||
{:else if queue_position === 0}
|
||||
processing |
|
||||
{/if}
|
||||
|
||||
{formatted_timer}{eta ? `/${formatted_eta}` : ""}
|
||||
</div>
|
||||
|
||||
<Loader />
|
||||
{:else if tracked_status === "error"}
|
||||
{:else if status === "error"}
|
||||
<span class="text-red-400 font-mono font-semibold text-lg">ERROR</span>
|
||||
{/if}
|
||||
</div>
|
||||
|
5
ui/packages/app/src/components/StatusTracker/types.ts
Normal file
5
ui/packages/app/src/components/StatusTracker/types.ts
Normal file
@ -0,0 +1,5 @@
|
||||
export interface LoadingStatus {
|
||||
eta: number;
|
||||
queue_position: number;
|
||||
status: "pending" | "error" | "complete";
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
import { TextBox } from "@gradio/form";
|
||||
import { Block } from "@gradio/atoms";
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
|
||||
export let label: string = "Textbox";
|
||||
export let value: string = "";
|
||||
@ -15,7 +16,7 @@
|
||||
export let show_label: boolean;
|
||||
export let max_lines: number | false;
|
||||
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
|
||||
export let mode: "static" | "dynamic";
|
||||
|
||||
@ -23,7 +24,7 @@
|
||||
</script>
|
||||
|
||||
<Block {form_position}>
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
|
||||
<TextBox
|
||||
bind:value
|
||||
|
@ -6,6 +6,7 @@
|
||||
import { Chart } from "@gradio/chart";
|
||||
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
import { _ } from "svelte-i18n";
|
||||
|
||||
import chart_icon from "./chart.svg";
|
||||
@ -37,7 +38,7 @@
|
||||
export let show_label: boolean;
|
||||
export let colors: Array<string>;
|
||||
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
|
||||
let _value: string | null;
|
||||
|
||||
@ -121,7 +122,7 @@
|
||||
padding={false}
|
||||
>
|
||||
<BlockLabel {show_label} image={chart_icon} label={label || "TimeSeries"} />
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
|
||||
{#if mode === "static"}
|
||||
{#if static_data}
|
||||
|
@ -5,6 +5,7 @@
|
||||
import { Video, StaticVideo } from "@gradio/video";
|
||||
|
||||
import StatusTracker from "../StatusTracker/StatusTracker.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
import { _ } from "svelte-i18n";
|
||||
|
||||
export let value: FileData | null | string = null;
|
||||
@ -14,7 +15,7 @@
|
||||
export let source: string;
|
||||
export let root: string;
|
||||
export let show_label: boolean;
|
||||
export let loading_status: "complete" | "pending" | "error";
|
||||
export let loading_status: LoadingStatus;
|
||||
|
||||
export let mode: "static" | "dynamic";
|
||||
|
||||
@ -33,7 +34,7 @@
|
||||
color={dragging ? "green" : "grey"}
|
||||
padding={false}
|
||||
>
|
||||
<StatusTracker tracked_status={loading_status} />
|
||||
<StatusTracker {...loading_status} />
|
||||
|
||||
{#if mode === "static"}
|
||||
<StaticVideo value={_value} {label} {show_label} {style} />
|
||||
|
88
ui/packages/app/src/stores.ts
Normal file
88
ui/packages/app/src/stores.ts
Normal file
@ -0,0 +1,88 @@
|
||||
import { writable } from "svelte/store";
|
||||
|
||||
export interface LoadingStatus {
|
||||
eta: number | null;
|
||||
status: "pending" | "error" | "complete";
|
||||
queue_position: number | null;
|
||||
outputs: Array<number>;
|
||||
}
|
||||
|
||||
function create_loading_status_store() {
|
||||
const store = writable<Record<string, Omit<LoadingStatus, "outputs">>>({});
|
||||
|
||||
const fn_outputs: Array<Array<number>> = [];
|
||||
const pending_outputs = new Map<number, number>();
|
||||
const fn_status: Array<LoadingStatus["status"]> = [];
|
||||
|
||||
function update(
|
||||
fn_index: number,
|
||||
status: LoadingStatus["status"],
|
||||
position: LoadingStatus["queue_position"],
|
||||
eta: LoadingStatus["eta"]
|
||||
) {
|
||||
const outputs = fn_outputs[fn_index];
|
||||
const last_status = fn_status[fn_index];
|
||||
|
||||
const outputs_to_update = outputs.map((id) => {
|
||||
let new_status: LoadingStatus["status"];
|
||||
|
||||
const pending_count = pending_outputs.get(id) || 0;
|
||||
|
||||
// from (pending -> error) | complete - decrement pending count
|
||||
if (last_status === "pending" && status !== "pending") {
|
||||
let new_count = pending_count - 1;
|
||||
|
||||
pending_outputs.set(id, new_count < 0 ? 0 : new_count);
|
||||
|
||||
new_status = new_count > 0 ? "pending" : status;
|
||||
|
||||
// from pending -> pending - do nothing
|
||||
} else if (last_status === "pending" && status === "pending") {
|
||||
new_status = "pending";
|
||||
|
||||
// (error | complete) -> pending - - increment pending count
|
||||
} else if (last_status !== "pending" && status === "pending") {
|
||||
new_status = "pending";
|
||||
pending_outputs.set(id, pending_count + 1);
|
||||
} else {
|
||||
new_status = status;
|
||||
}
|
||||
|
||||
return {
|
||||
id,
|
||||
queue_position: position,
|
||||
eta: eta,
|
||||
status: new_status
|
||||
};
|
||||
});
|
||||
|
||||
store.update((outputs) => {
|
||||
outputs_to_update.forEach(({ id, queue_position, eta, status }) => {
|
||||
outputs[id] = {
|
||||
queue_position,
|
||||
eta: eta || outputs[id]?.eta,
|
||||
status
|
||||
};
|
||||
});
|
||||
|
||||
return outputs;
|
||||
});
|
||||
|
||||
fn_status[fn_index] = status;
|
||||
}
|
||||
|
||||
function register(index: number, outputs: Array<number>) {
|
||||
fn_outputs[index] = outputs;
|
||||
}
|
||||
|
||||
return {
|
||||
update,
|
||||
register,
|
||||
subscribe: store.subscribe,
|
||||
get_status_for_fn(i: number) {
|
||||
return fn_status[i];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const loading_status = create_loading_status_store();
|
Loading…
x
Reference in New Issue
Block a user