@gradio/client 0.20.1 → 1.1.1
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/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 +490 -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 +94 -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/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 +111 -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;
|
@@ -151,6 +173,46 @@ export interface Config {
|
|
151
173
|
path: string;
|
152
174
|
protocol: "sse_v3" | "sse_v2.1" | "sse_v2" | "sse_v1" | "sse" | "ws";
|
153
175
|
max_file_size?: number;
|
176
|
+
theme_hash?: number;
|
177
|
+
}
|
178
|
+
|
179
|
+
// todo: DRY up types
|
180
|
+
export interface ComponentMeta {
|
181
|
+
type: string;
|
182
|
+
id: number;
|
183
|
+
has_modes: boolean;
|
184
|
+
props: SharedProps;
|
185
|
+
instance: SvelteComponent;
|
186
|
+
component: ComponentType<SvelteComponent>;
|
187
|
+
documentation?: Documentation;
|
188
|
+
children?: ComponentMeta[];
|
189
|
+
parent?: ComponentMeta;
|
190
|
+
value?: any;
|
191
|
+
component_class_id: string;
|
192
|
+
key: string | number | null;
|
193
|
+
rendered_in?: number;
|
194
|
+
}
|
195
|
+
|
196
|
+
interface SharedProps {
|
197
|
+
elem_id?: string;
|
198
|
+
elem_classes?: string[];
|
199
|
+
components?: string[];
|
200
|
+
server_fns?: string[];
|
201
|
+
interactive: boolean;
|
202
|
+
[key: string]: unknown;
|
203
|
+
root_url?: string;
|
204
|
+
}
|
205
|
+
|
206
|
+
export interface Documentation {
|
207
|
+
type?: TypeDescription;
|
208
|
+
description?: TypeDescription;
|
209
|
+
example_data?: string;
|
210
|
+
}
|
211
|
+
|
212
|
+
interface TypeDescription {
|
213
|
+
input_payload?: string;
|
214
|
+
response_object?: string;
|
215
|
+
payload?: string;
|
154
216
|
}
|
155
217
|
|
156
218
|
export interface Dependency {
|
@@ -186,6 +248,7 @@ export interface Dependency {
|
|
186
248
|
export interface DependencyTypes {
|
187
249
|
continuous: boolean;
|
188
250
|
generator: boolean;
|
251
|
+
cancel: boolean;
|
189
252
|
}
|
190
253
|
|
191
254
|
export interface Payload {
|
@@ -218,6 +281,8 @@ export interface ClientOptions {
|
|
218
281
|
hf_token?: `hf_${string}`;
|
219
282
|
status_callback?: SpaceStatusCallback | null;
|
220
283
|
auth?: [string, string] | null;
|
284
|
+
with_null_state?: boolean;
|
285
|
+
events?: EventType[];
|
221
286
|
}
|
222
287
|
|
223
288
|
export interface FileData {
|
@@ -236,25 +301,21 @@ export interface FileData {
|
|
236
301
|
export type EventType = "data" | "status" | "log" | "render";
|
237
302
|
|
238
303
|
export interface EventMap {
|
239
|
-
data:
|
240
|
-
status:
|
304
|
+
data: PayloadMessage;
|
305
|
+
status: StatusMessage;
|
241
306
|
log: LogMessage;
|
242
307
|
render: RenderMessage;
|
243
308
|
}
|
244
309
|
|
245
|
-
export type
|
246
|
-
[P in
|
247
|
-
}[
|
248
|
-
|
249
|
-
export
|
250
|
-
[P in K]?: EventListener<K>[];
|
251
|
-
};
|
252
|
-
export interface LogMessage {
|
310
|
+
export type GradioEvent = {
|
311
|
+
[P in EventType]: EventMap[P];
|
312
|
+
}[EventType];
|
313
|
+
|
314
|
+
export interface Log {
|
253
315
|
log: string;
|
254
316
|
level: "warning" | "info";
|
255
317
|
}
|
256
|
-
export interface
|
257
|
-
fn_index: number;
|
318
|
+
export interface Render {
|
258
319
|
data: {
|
259
320
|
components: any[];
|
260
321
|
layout: any;
|
@@ -283,3 +344,27 @@ export interface Status {
|
|
283
344
|
time?: Date;
|
284
345
|
changed_state_ids?: number[];
|
285
346
|
}
|
347
|
+
|
348
|
+
export interface StatusMessage extends Status {
|
349
|
+
type: "status";
|
350
|
+
endpoint: string;
|
351
|
+
fn_index: number;
|
352
|
+
}
|
353
|
+
|
354
|
+
export interface PayloadMessage extends Payload {
|
355
|
+
type: "data";
|
356
|
+
endpoint: string;
|
357
|
+
fn_index: number;
|
358
|
+
}
|
359
|
+
|
360
|
+
export interface LogMessage extends Log {
|
361
|
+
type: "log";
|
362
|
+
endpoint: string;
|
363
|
+
fn_index: number;
|
364
|
+
}
|
365
|
+
|
366
|
+
export interface RenderMessage extends Render {
|
367
|
+
type: "render";
|
368
|
+
endpoint: string;
|
369
|
+
fn_index: number;
|
370
|
+
}
|
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
|
+
}
|