@gradio/client 0.20.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +201 -0
- package/README.md +21 -36
- package/dist/client.d.ts +6 -7
- package/dist/client.d.ts.map +1 -1
- package/dist/constants.d.ts +3 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/helpers/data.d.ts +15 -1
- package/dist/helpers/data.d.ts.map +1 -1
- package/dist/helpers/init_helpers.d.ts.map +1 -1
- package/dist/helpers/spaces.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +496 -114
- package/dist/test/handlers.d.ts +1 -0
- package/dist/test/handlers.d.ts.map +1 -1
- package/dist/test/test_data.d.ts.map +1 -1
- package/dist/types.d.ts +93 -24
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/handle_blob.d.ts +2 -1
- package/dist/utils/handle_blob.d.ts.map +1 -1
- package/dist/utils/predict.d.ts +2 -2
- package/dist/utils/predict.d.ts.map +1 -1
- package/dist/utils/stream.d.ts +2 -1
- package/dist/utils/stream.d.ts.map +1 -1
- package/dist/utils/submit.d.ts +2 -2
- package/dist/utils/submit.d.ts.map +1 -1
- package/index.html +39 -0
- package/package.json +5 -2
- package/src/client.ts +40 -35
- package/src/constants.ts +4 -0
- package/src/helpers/api_info.ts +1 -1
- package/src/helpers/data.ts +124 -10
- package/src/helpers/init_helpers.ts +5 -0
- package/src/helpers/spaces.ts +2 -1
- package/src/index.ts +6 -1
- package/src/test/api_info.test.ts +0 -1
- package/src/test/data.test.ts +201 -26
- package/src/test/handlers.ts +9 -1
- package/src/test/stream.test.ts +12 -10
- package/src/test/test_data.ts +8 -5
- package/src/test/upload_files.test.ts +1 -1
- package/src/types.ts +110 -26
- package/src/utils/handle_blob.ts +91 -1
- package/src/utils/predict.ts +15 -16
- package/src/utils/stream.ts +66 -13
- package/src/utils/submit.ts +156 -63
- package/src/utils/upload_files.ts +1 -1
- package/vite.config.js +37 -24
package/src/types.ts
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
// API Data Types
|
2
2
|
|
3
3
|
import { hardware_types } from "./helpers/spaces";
|
4
|
+
import type { SvelteComponent } from "svelte";
|
5
|
+
import type { ComponentType } from "svelte";
|
4
6
|
|
5
7
|
export interface ApiData {
|
6
8
|
label: string;
|
@@ -49,6 +51,27 @@ export interface BlobRef {
|
|
49
51
|
|
50
52
|
export type DataType = string | Buffer | Record<string, any> | any[];
|
51
53
|
|
54
|
+
// custom class used for uploading local files
|
55
|
+
export class Command {
|
56
|
+
type: string;
|
57
|
+
command: string;
|
58
|
+
meta: {
|
59
|
+
path: string;
|
60
|
+
name: string;
|
61
|
+
orig_path: string;
|
62
|
+
};
|
63
|
+
fileData?: FileData;
|
64
|
+
|
65
|
+
constructor(
|
66
|
+
command: string,
|
67
|
+
meta: { path: string; name: string; orig_path: string }
|
68
|
+
) {
|
69
|
+
this.type = "command";
|
70
|
+
this.command = command;
|
71
|
+
this.meta = meta;
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
52
75
|
// Function Signature Types
|
53
76
|
|
54
77
|
export type SubmitFunction = (
|
@@ -56,20 +79,13 @@ export type SubmitFunction = (
|
|
56
79
|
data: unknown[] | Record<string, unknown>,
|
57
80
|
event_data?: unknown,
|
58
81
|
trigger_id?: number | null
|
59
|
-
) =>
|
82
|
+
) => SubmitIterable<GradioEvent>;
|
60
83
|
|
61
84
|
export type PredictFunction = (
|
62
85
|
endpoint: string | number,
|
63
86
|
data: unknown[] | Record<string, unknown>,
|
64
87
|
event_data?: unknown
|
65
|
-
) => Promise<
|
66
|
-
|
67
|
-
// Event and Submission Types
|
68
|
-
|
69
|
-
type event = <K extends EventType>(
|
70
|
-
eventType: K,
|
71
|
-
listener: EventListener<K>
|
72
|
-
) => SubmitReturn;
|
88
|
+
) => Promise<PredictReturn>;
|
73
89
|
|
74
90
|
export type client_return = {
|
75
91
|
config: Config | undefined;
|
@@ -83,11 +99,17 @@ export type client_return = {
|
|
83
99
|
view_api: (_fetch: typeof fetch) => Promise<ApiInfo<JsApiData>>;
|
84
100
|
};
|
85
101
|
|
86
|
-
export
|
87
|
-
|
88
|
-
off: event;
|
102
|
+
export interface SubmitIterable<T> extends AsyncIterable<T> {
|
103
|
+
[Symbol.asyncIterator](): AsyncIterator<T>;
|
89
104
|
cancel: () => Promise<void>;
|
90
|
-
|
105
|
+
}
|
106
|
+
|
107
|
+
export type PredictReturn = {
|
108
|
+
type: EventType;
|
109
|
+
time: Date;
|
110
|
+
data: unknown;
|
111
|
+
endpoint: string;
|
112
|
+
fn_index: number;
|
91
113
|
};
|
92
114
|
|
93
115
|
// Space Status Types
|
@@ -128,7 +150,7 @@ export interface Config {
|
|
128
150
|
analytics_enabled: boolean;
|
129
151
|
connect_heartbeat: boolean;
|
130
152
|
auth_message: string;
|
131
|
-
components:
|
153
|
+
components: ComponentMeta[];
|
132
154
|
css: string | null;
|
133
155
|
js: string | null;
|
134
156
|
head: string | null;
|
@@ -153,6 +175,45 @@ export interface Config {
|
|
153
175
|
max_file_size?: number;
|
154
176
|
}
|
155
177
|
|
178
|
+
// todo: DRY up types
|
179
|
+
export interface ComponentMeta {
|
180
|
+
type: string;
|
181
|
+
id: number;
|
182
|
+
has_modes: boolean;
|
183
|
+
props: SharedProps;
|
184
|
+
instance: SvelteComponent;
|
185
|
+
component: ComponentType<SvelteComponent>;
|
186
|
+
documentation?: Documentation;
|
187
|
+
children?: ComponentMeta[];
|
188
|
+
parent?: ComponentMeta;
|
189
|
+
value?: any;
|
190
|
+
component_class_id: string;
|
191
|
+
key: string | number | null;
|
192
|
+
rendered_in?: number;
|
193
|
+
}
|
194
|
+
|
195
|
+
interface SharedProps {
|
196
|
+
elem_id?: string;
|
197
|
+
elem_classes?: string[];
|
198
|
+
components?: string[];
|
199
|
+
server_fns?: string[];
|
200
|
+
interactive: boolean;
|
201
|
+
[key: string]: unknown;
|
202
|
+
root_url?: string;
|
203
|
+
}
|
204
|
+
|
205
|
+
export interface Documentation {
|
206
|
+
type?: TypeDescription;
|
207
|
+
description?: TypeDescription;
|
208
|
+
example_data?: string;
|
209
|
+
}
|
210
|
+
|
211
|
+
interface TypeDescription {
|
212
|
+
input_payload?: string;
|
213
|
+
response_object?: string;
|
214
|
+
payload?: string;
|
215
|
+
}
|
216
|
+
|
156
217
|
export interface Dependency {
|
157
218
|
id: number;
|
158
219
|
targets: [number, string][];
|
@@ -186,6 +247,7 @@ export interface Dependency {
|
|
186
247
|
export interface DependencyTypes {
|
187
248
|
continuous: boolean;
|
188
249
|
generator: boolean;
|
250
|
+
cancel: boolean;
|
189
251
|
}
|
190
252
|
|
191
253
|
export interface Payload {
|
@@ -218,6 +280,8 @@ export interface ClientOptions {
|
|
218
280
|
hf_token?: `hf_${string}`;
|
219
281
|
status_callback?: SpaceStatusCallback | null;
|
220
282
|
auth?: [string, string] | null;
|
283
|
+
with_null_state?: boolean;
|
284
|
+
events?: EventType[];
|
221
285
|
}
|
222
286
|
|
223
287
|
export interface FileData {
|
@@ -236,25 +300,21 @@ export interface FileData {
|
|
236
300
|
export type EventType = "data" | "status" | "log" | "render";
|
237
301
|
|
238
302
|
export interface EventMap {
|
239
|
-
data:
|
240
|
-
status:
|
303
|
+
data: PayloadMessage;
|
304
|
+
status: StatusMessage;
|
241
305
|
log: LogMessage;
|
242
306
|
render: RenderMessage;
|
243
307
|
}
|
244
308
|
|
245
|
-
export type
|
246
|
-
[P in
|
247
|
-
}[
|
248
|
-
|
249
|
-
export
|
250
|
-
[P in K]?: EventListener<K>[];
|
251
|
-
};
|
252
|
-
export interface LogMessage {
|
309
|
+
export type GradioEvent = {
|
310
|
+
[P in EventType]: EventMap[P];
|
311
|
+
}[EventType];
|
312
|
+
|
313
|
+
export interface Log {
|
253
314
|
log: string;
|
254
315
|
level: "warning" | "info";
|
255
316
|
}
|
256
|
-
export interface
|
257
|
-
fn_index: number;
|
317
|
+
export interface Render {
|
258
318
|
data: {
|
259
319
|
components: any[];
|
260
320
|
layout: any;
|
@@ -283,3 +343,27 @@ export interface Status {
|
|
283
343
|
time?: Date;
|
284
344
|
changed_state_ids?: number[];
|
285
345
|
}
|
346
|
+
|
347
|
+
export interface StatusMessage extends Status {
|
348
|
+
type: "status";
|
349
|
+
endpoint: string;
|
350
|
+
fn_index: number;
|
351
|
+
}
|
352
|
+
|
353
|
+
export interface PayloadMessage extends Payload {
|
354
|
+
type: "data";
|
355
|
+
endpoint: string;
|
356
|
+
fn_index: number;
|
357
|
+
}
|
358
|
+
|
359
|
+
export interface LogMessage extends Log {
|
360
|
+
type: "log";
|
361
|
+
endpoint: string;
|
362
|
+
fn_index: number;
|
363
|
+
}
|
364
|
+
|
365
|
+
export interface RenderMessage extends Render {
|
366
|
+
type: "render";
|
367
|
+
endpoint: string;
|
368
|
+
fn_index: number;
|
369
|
+
}
|
package/src/utils/handle_blob.ts
CHANGED
@@ -1,7 +1,17 @@
|
|
1
1
|
import { update_object, walk_and_store_blobs } from "../helpers/data";
|
2
|
-
import
|
2
|
+
import {
|
3
|
+
Command,
|
4
|
+
type ApiData,
|
5
|
+
type EndpointInfo,
|
6
|
+
type JsApiData
|
7
|
+
} from "../types";
|
3
8
|
import { FileData } from "../upload";
|
4
9
|
import type { Client } from "..";
|
10
|
+
import {
|
11
|
+
FILE_PROCESSING_ERROR_MSG,
|
12
|
+
NODEJS_FS_ERROR_MSG,
|
13
|
+
ROOT_URL_ERROR_MSG
|
14
|
+
} from "../constants";
|
5
15
|
|
6
16
|
export async function handle_blob(
|
7
17
|
this: Client,
|
@@ -11,6 +21,8 @@ export async function handle_blob(
|
|
11
21
|
): Promise<unknown[]> {
|
12
22
|
const self = this;
|
13
23
|
|
24
|
+
await process_local_file_commands(self, data);
|
25
|
+
|
14
26
|
const blobRefs = await walk_and_store_blobs(
|
15
27
|
data,
|
16
28
|
undefined,
|
@@ -45,3 +57,81 @@ export async function handle_blob(
|
|
45
57
|
|
46
58
|
return data;
|
47
59
|
}
|
60
|
+
|
61
|
+
export async function process_local_file_commands(
|
62
|
+
client: Client,
|
63
|
+
data: unknown[]
|
64
|
+
): Promise<void> {
|
65
|
+
const root = client.config?.root || client.config?.root_url;
|
66
|
+
|
67
|
+
if (!root) {
|
68
|
+
throw new Error(ROOT_URL_ERROR_MSG);
|
69
|
+
}
|
70
|
+
|
71
|
+
await recursively_process_commands(client, data);
|
72
|
+
}
|
73
|
+
|
74
|
+
async function recursively_process_commands(
|
75
|
+
client: Client,
|
76
|
+
data: any,
|
77
|
+
path: string[] = []
|
78
|
+
): Promise<void> {
|
79
|
+
for (const key in data) {
|
80
|
+
if (data[key] instanceof Command) {
|
81
|
+
await process_single_command(client, data, key);
|
82
|
+
} else if (typeof data[key] === "object" && data[key] !== null) {
|
83
|
+
await recursively_process_commands(client, data[key], [...path, key]);
|
84
|
+
}
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
async function process_single_command(
|
89
|
+
client: Client,
|
90
|
+
data: any,
|
91
|
+
key: string
|
92
|
+
): Promise<void> {
|
93
|
+
let cmd_item = data[key] as Command;
|
94
|
+
const root = client.config?.root || client.config?.root_url;
|
95
|
+
|
96
|
+
if (!root) {
|
97
|
+
throw new Error(ROOT_URL_ERROR_MSG);
|
98
|
+
}
|
99
|
+
|
100
|
+
try {
|
101
|
+
let fileBuffer: Buffer;
|
102
|
+
let fullPath: string;
|
103
|
+
|
104
|
+
// check if running in a Node.js environment
|
105
|
+
if (
|
106
|
+
typeof process !== "undefined" &&
|
107
|
+
process.versions &&
|
108
|
+
process.versions.node
|
109
|
+
) {
|
110
|
+
const fs = await import("fs/promises");
|
111
|
+
const path = await import("path");
|
112
|
+
|
113
|
+
fullPath = path.resolve(process.cwd(), cmd_item.meta.path);
|
114
|
+
fileBuffer = await fs.readFile(fullPath); // Read file from disk
|
115
|
+
} else {
|
116
|
+
throw new Error(NODEJS_FS_ERROR_MSG);
|
117
|
+
}
|
118
|
+
|
119
|
+
const file = new Blob([fileBuffer], { type: "application/octet-stream" });
|
120
|
+
|
121
|
+
const response = await client.upload_files(root, [file]);
|
122
|
+
|
123
|
+
const file_url = response.files && response.files[0];
|
124
|
+
|
125
|
+
if (file_url) {
|
126
|
+
const fileData = new FileData({
|
127
|
+
path: file_url,
|
128
|
+
orig_name: cmd_item.meta.name || ""
|
129
|
+
});
|
130
|
+
|
131
|
+
// replace the command object with the fileData object
|
132
|
+
data[key] = fileData;
|
133
|
+
}
|
134
|
+
} catch (error) {
|
135
|
+
console.error(FILE_PROCESSING_ERROR_MSG, error);
|
136
|
+
}
|
137
|
+
}
|
package/src/utils/predict.ts
CHANGED
@@ -1,11 +1,11 @@
|
|
1
1
|
import { Client } from "../client";
|
2
|
-
import type { Dependency,
|
2
|
+
import type { Dependency, PredictReturn } from "../types";
|
3
3
|
|
4
4
|
export async function predict(
|
5
5
|
this: Client,
|
6
6
|
endpoint: string | number,
|
7
7
|
data: unknown[] | Record<string, unknown>
|
8
|
-
): Promise<
|
8
|
+
): Promise<PredictReturn> {
|
9
9
|
let data_returned = false;
|
10
10
|
let status_complete = false;
|
11
11
|
let dependency: Dependency;
|
@@ -30,29 +30,28 @@ export async function predict(
|
|
30
30
|
}
|
31
31
|
|
32
32
|
return new Promise(async (resolve, reject) => {
|
33
|
-
const app = this.submit(endpoint, data);
|
33
|
+
const app = this.submit(endpoint, data, null, null, true);
|
34
34
|
let result: unknown;
|
35
35
|
|
36
|
-
app
|
37
|
-
.
|
38
|
-
// if complete message comes before data, resolve here
|
36
|
+
for await (const message of app) {
|
37
|
+
if (message.type === "data") {
|
39
38
|
if (status_complete) {
|
40
|
-
|
41
|
-
resolve(d as SubmitReturn);
|
39
|
+
resolve(result as PredictReturn);
|
42
40
|
}
|
43
41
|
data_returned = true;
|
44
|
-
result =
|
45
|
-
}
|
46
|
-
|
47
|
-
|
48
|
-
if (
|
42
|
+
result = message;
|
43
|
+
}
|
44
|
+
|
45
|
+
if (message.type === "status") {
|
46
|
+
if (message.stage === "error") reject(message);
|
47
|
+
if (message.stage === "complete") {
|
49
48
|
status_complete = true;
|
50
49
|
// if complete message comes after data, resolve here
|
51
50
|
if (data_returned) {
|
52
|
-
|
53
|
-
resolve(result as SubmitReturn);
|
51
|
+
resolve(result as PredictReturn);
|
54
52
|
}
|
55
53
|
}
|
56
|
-
}
|
54
|
+
}
|
55
|
+
}
|
57
56
|
});
|
58
57
|
}
|
package/src/utils/stream.ts
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import { BROKEN_CONNECTION_MSG } from "../constants";
|
2
2
|
import type { Client } from "../client";
|
3
|
+
import { stream } from "fetch-event-stream";
|
3
4
|
|
4
5
|
export async function open_stream(this: Client): Promise<void> {
|
5
6
|
let {
|
@@ -11,6 +12,8 @@ export async function open_stream(this: Client): Promise<void> {
|
|
11
12
|
jwt
|
12
13
|
} = this;
|
13
14
|
|
15
|
+
const that = this;
|
16
|
+
|
14
17
|
if (!config) {
|
15
18
|
throw new Error("Could not resolve app config");
|
16
19
|
}
|
@@ -28,7 +31,7 @@ export async function open_stream(this: Client): Promise<void> {
|
|
28
31
|
url.searchParams.set("__sign", jwt);
|
29
32
|
}
|
30
33
|
|
31
|
-
stream =
|
34
|
+
stream = this.stream(url);
|
32
35
|
|
33
36
|
if (!stream) {
|
34
37
|
console.warn("Cannot connect to SSE endpoint: " + url.toString());
|
@@ -38,7 +41,7 @@ export async function open_stream(this: Client): Promise<void> {
|
|
38
41
|
stream.onmessage = async function (event: MessageEvent) {
|
39
42
|
let _data = JSON.parse(event.data);
|
40
43
|
if (_data.msg === "close_stream") {
|
41
|
-
close_stream(stream_status,
|
44
|
+
close_stream(stream_status, that.abort_controller);
|
42
45
|
return;
|
43
46
|
}
|
44
47
|
const event_id = _data.event_id;
|
@@ -51,19 +54,19 @@ export async function open_stream(this: Client): Promise<void> {
|
|
51
54
|
} else if (event_callbacks[event_id] && config) {
|
52
55
|
if (
|
53
56
|
_data.msg === "process_completed" &&
|
54
|
-
["sse", "sse_v1", "sse_v2", "sse_v2.1"].includes(
|
57
|
+
["sse", "sse_v1", "sse_v2", "sse_v2.1", "sse_v3"].includes(
|
58
|
+
config.protocol
|
59
|
+
)
|
55
60
|
) {
|
56
61
|
unclosed_events.delete(event_id);
|
57
|
-
if (unclosed_events.size === 0) {
|
58
|
-
close_stream(stream_status, stream);
|
59
|
-
}
|
60
62
|
}
|
61
63
|
let fn: (data: any) => void = event_callbacks[event_id];
|
62
64
|
|
63
|
-
if (typeof window !== "undefined") {
|
64
|
-
|
65
|
+
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
66
|
+
// fn(_data); // need to do this to put the event on the end of the event loop, so the browser can refresh between callbacks and not freeze in case of quick generations. See
|
67
|
+
setTimeout(fn, 0, _data); // need to do this to put the event on the end of the event loop, so the browser can refresh between callbacks and not freeze in case of quick generations. See https://github.com/gradio-app/gradio/pull/7055
|
65
68
|
} else {
|
66
|
-
|
69
|
+
fn(_data);
|
67
70
|
}
|
68
71
|
} else {
|
69
72
|
if (!pending_stream_messages[event_id]) {
|
@@ -81,17 +84,16 @@ export async function open_stream(this: Client): Promise<void> {
|
|
81
84
|
})
|
82
85
|
)
|
83
86
|
);
|
84
|
-
close_stream(stream_status, stream);
|
85
87
|
};
|
86
88
|
}
|
87
89
|
|
88
90
|
export function close_stream(
|
89
91
|
stream_status: { open: boolean },
|
90
|
-
|
92
|
+
abort_controller: AbortController | null
|
91
93
|
): void {
|
92
|
-
if (stream_status
|
94
|
+
if (stream_status) {
|
93
95
|
stream_status.open = false;
|
94
|
-
|
96
|
+
abort_controller?.abort();
|
95
97
|
}
|
96
98
|
}
|
97
99
|
|
@@ -173,3 +175,54 @@ function apply_edit(
|
|
173
175
|
}
|
174
176
|
return target;
|
175
177
|
}
|
178
|
+
|
179
|
+
export function readable_stream(
|
180
|
+
input: RequestInfo | URL,
|
181
|
+
init: RequestInit = {}
|
182
|
+
): EventSource {
|
183
|
+
const instance: EventSource & { readyState: number } = {
|
184
|
+
close: () => {
|
185
|
+
throw new Error("Method not implemented.");
|
186
|
+
},
|
187
|
+
onerror: null,
|
188
|
+
onmessage: null,
|
189
|
+
onopen: null,
|
190
|
+
readyState: 0,
|
191
|
+
url: input.toString(),
|
192
|
+
withCredentials: false,
|
193
|
+
CONNECTING: 0,
|
194
|
+
OPEN: 1,
|
195
|
+
CLOSED: 2,
|
196
|
+
addEventListener: () => {
|
197
|
+
throw new Error("Method not implemented.");
|
198
|
+
},
|
199
|
+
dispatchEvent: () => {
|
200
|
+
throw new Error("Method not implemented.");
|
201
|
+
},
|
202
|
+
removeEventListener: () => {
|
203
|
+
throw new Error("Method not implemented.");
|
204
|
+
}
|
205
|
+
};
|
206
|
+
|
207
|
+
stream(input, init)
|
208
|
+
.then(async (res) => {
|
209
|
+
instance.readyState = instance.OPEN;
|
210
|
+
try {
|
211
|
+
for await (const chunk of res) {
|
212
|
+
//@ts-ignore
|
213
|
+
instance.onmessage && instance.onmessage(chunk);
|
214
|
+
}
|
215
|
+
instance.readyState = instance.CLOSED;
|
216
|
+
} catch (e) {
|
217
|
+
instance.onerror && instance.onerror(e as Event);
|
218
|
+
instance.readyState = instance.CLOSED;
|
219
|
+
}
|
220
|
+
})
|
221
|
+
.catch((e) => {
|
222
|
+
console.error(e);
|
223
|
+
instance.onerror && instance.onerror(e as Event);
|
224
|
+
instance.readyState = instance.CLOSED;
|
225
|
+
});
|
226
|
+
|
227
|
+
return instance as EventSource;
|
228
|
+
}
|