1148 loading status (#1164)

* update loader

* fix for non queued statuses

* remove logs

* Update demo/fake_gan/run.py
This commit is contained in:
pngwn 2022-05-05 20:05:05 +01:00 committed by GitHub
parent a9610a4c9b
commit 56222fbe2b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 387 additions and 164 deletions

View File

@ -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__":

View File

@ -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>

View File

@ -82,6 +82,7 @@
node.props.form_position = "single";
}
}
children =
children &&
children.filter((v) => instance_map[v.id].type !== "statustracker");

View File

@ -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;
}
};

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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}

View File

@ -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

View File

@ -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}

View File

@ -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

View File

@ -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

View File

@ -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">

View File

@ -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>

View File

@ -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}

View File

@ -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>

View File

@ -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} />

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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}

View File

@ -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

View File

@ -38,7 +38,7 @@
});
</script>
<div class="m-12">
<div class="m-12 z-20">
<svg
class="text-xl"
width="7em"

View File

@ -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>

View File

@ -0,0 +1,5 @@
export interface LoadingStatus {
eta: number;
queue_position: number;
status: "pending" | "error" | "complete";
}

View File

@ -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

View File

@ -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}

View File

@ -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} />

View 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();