@gradio/client 0.16.0 → 0.18.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 +57 -0
- package/README.md +49 -43
- package/dist/client.d.ts +63 -70
- package/dist/client.d.ts.map +1 -1
- package/dist/constants.d.ts +23 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/helpers/api_info.d.ts +25 -0
- package/dist/helpers/api_info.d.ts.map +1 -0
- package/dist/helpers/data.d.ts +8 -0
- package/dist/helpers/data.d.ts.map +1 -0
- package/dist/{utils.d.ts → helpers/init_helpers.d.ts} +6 -18
- package/dist/helpers/init_helpers.d.ts.map +1 -0
- package/dist/helpers/spaces.d.ts +7 -0
- package/dist/helpers/spaces.d.ts.map +1 -0
- package/dist/index.d.ts +8 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1628 -1398
- package/dist/test/handlers.d.ts +3 -0
- package/dist/test/handlers.d.ts.map +1 -0
- package/dist/test/mock_eventsource.d.ts +2 -0
- package/dist/test/mock_eventsource.d.ts.map +1 -0
- package/dist/test/server.d.ts +2 -0
- package/dist/test/server.d.ts.map +1 -0
- package/dist/test/test_data.d.ts +76 -0
- package/dist/test/test_data.d.ts.map +1 -0
- package/dist/types.d.ts +153 -49
- package/dist/types.d.ts.map +1 -1
- package/dist/upload.d.ts +2 -2
- package/dist/upload.d.ts.map +1 -1
- package/dist/utils/duplicate.d.ts +4 -0
- package/dist/utils/duplicate.d.ts.map +1 -0
- package/dist/utils/handle_blob.d.ts +4 -0
- package/dist/utils/handle_blob.d.ts.map +1 -0
- package/dist/utils/post_data.d.ts +4 -0
- package/dist/utils/post_data.d.ts.map +1 -0
- package/dist/utils/predict.d.ts +4 -0
- package/dist/utils/predict.d.ts.map +1 -0
- package/dist/utils/stream.d.ts +8 -0
- package/dist/utils/stream.d.ts.map +1 -0
- package/dist/utils/submit.d.ts +4 -0
- package/dist/utils/submit.d.ts.map +1 -0
- package/dist/utils/upload_files.d.ts +4 -0
- package/dist/utils/upload_files.d.ts.map +1 -0
- package/dist/utils/view_api.d.ts +3 -0
- package/dist/utils/view_api.d.ts.map +1 -0
- package/dist/{wrapper-6f348d45.js → wrapper-CviSselG.js} +259 -17
- package/package.json +10 -3
- package/src/client.ts +314 -1691
- package/src/constants.ts +27 -0
- package/src/globals.d.ts +2 -21
- package/src/helpers/api_info.ts +300 -0
- package/src/helpers/data.ts +133 -0
- package/src/helpers/init_helpers.ts +130 -0
- package/src/helpers/spaces.ts +197 -0
- package/src/index.ts +16 -10
- package/src/test/api_info.test.ts +456 -0
- package/src/test/data.test.ts +281 -0
- package/src/test/handlers.ts +438 -0
- package/src/test/init.test.ts +139 -0
- package/src/test/init_helpers.test.ts +94 -0
- package/src/test/mock_eventsource.ts +11 -0
- package/src/test/post_data.test.ts +45 -0
- package/src/test/server.ts +6 -0
- package/src/test/spaces.test.ts +145 -0
- package/src/test/stream.test.ts +67 -0
- package/src/test/test_data.ts +557 -0
- package/src/test/upload_files.test.ts +42 -0
- package/src/test/view_api.test.ts +53 -0
- package/src/types.ts +201 -59
- package/src/upload.ts +19 -15
- package/src/utils/duplicate.ts +104 -0
- package/src/utils/handle_blob.ts +47 -0
- package/src/utils/post_data.ts +37 -0
- package/src/utils/predict.ts +56 -0
- package/src/utils/stream.ts +175 -0
- package/src/utils/submit.ts +697 -0
- package/src/utils/upload_files.ts +51 -0
- package/src/utils/view_api.ts +67 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +15 -2
- package/vite.config.js +11 -17
- package/dist/utils.d.ts.map +0 -1
- package/src/client.node-test.ts +0 -172
- package/src/utils.ts +0 -314
package/src/client.ts
CHANGED
@@ -1,1769 +1,392 @@
|
|
1
|
-
//@ts-nocheck
|
2
|
-
|
3
|
-
import semiver from "semiver";
|
4
|
-
|
5
|
-
import {
|
6
|
-
process_endpoint,
|
7
|
-
RE_SPACE_NAME,
|
8
|
-
map_names_to_ids,
|
9
|
-
discussions_enabled,
|
10
|
-
get_space_hardware,
|
11
|
-
set_space_hardware,
|
12
|
-
set_space_timeout,
|
13
|
-
hardware_types,
|
14
|
-
resolve_root,
|
15
|
-
apply_diff,
|
16
|
-
post_message
|
17
|
-
} from "./utils.js";
|
18
|
-
|
19
1
|
import type {
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
Status,
|
2
|
+
ApiData,
|
3
|
+
ApiInfo,
|
4
|
+
ClientOptions,
|
5
|
+
Config,
|
6
|
+
DuplicateOptions,
|
7
|
+
EndpointInfo,
|
8
|
+
JsApiData,
|
28
9
|
SpaceStatus,
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
import
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
component_server: (
|
56
|
-
component_id: number,
|
57
|
-
fn_name: string,
|
58
|
-
data: unknown[]
|
59
|
-
) => any;
|
60
|
-
view_api: (c?: Config) => Promise<ApiInfo<JsApiData>>;
|
61
|
-
};
|
62
|
-
|
63
|
-
type SubmitReturn = {
|
64
|
-
on: event;
|
65
|
-
off: event;
|
66
|
-
cancel: () => Promise<void>;
|
67
|
-
destroy: () => void;
|
68
|
-
};
|
69
|
-
|
70
|
-
const QUEUE_FULL_MSG = "This application is too busy. Keep trying!";
|
71
|
-
const BROKEN_CONNECTION_MSG = "Connection errored out.";
|
72
|
-
|
73
|
-
export let NodeBlob;
|
74
|
-
|
75
|
-
export async function duplicate(
|
76
|
-
app_reference: string,
|
77
|
-
options: {
|
78
|
-
hf_token: `hf_${string}`;
|
79
|
-
private?: boolean;
|
80
|
-
status_callback: SpaceStatusCallback;
|
81
|
-
hardware?: (typeof hardware_types)[number];
|
82
|
-
timeout?: number;
|
83
|
-
}
|
84
|
-
): Promise<client_return> {
|
85
|
-
const { hf_token, private: _private, hardware, timeout } = options;
|
86
|
-
|
87
|
-
if (hardware && !hardware_types.includes(hardware)) {
|
88
|
-
throw new Error(
|
89
|
-
`Invalid hardware type provided. Valid types are: ${hardware_types
|
90
|
-
.map((v) => `"${v}"`)
|
91
|
-
.join(",")}.`
|
92
|
-
);
|
10
|
+
Status,
|
11
|
+
SubmitReturn,
|
12
|
+
UploadResponse,
|
13
|
+
client_return
|
14
|
+
} from "./types";
|
15
|
+
import { view_api } from "./utils/view_api";
|
16
|
+
import { upload_files } from "./utils/upload_files";
|
17
|
+
import { upload, FileData } from "./upload";
|
18
|
+
import { handle_blob } from "./utils/handle_blob";
|
19
|
+
import { post_data } from "./utils/post_data";
|
20
|
+
import { predict } from "./utils/predict";
|
21
|
+
import { duplicate } from "./utils/duplicate";
|
22
|
+
import { submit } from "./utils/submit";
|
23
|
+
import { RE_SPACE_NAME, process_endpoint } from "./helpers/api_info";
|
24
|
+
import {
|
25
|
+
map_names_to_ids,
|
26
|
+
resolve_config,
|
27
|
+
get_jwt
|
28
|
+
} from "./helpers/init_helpers";
|
29
|
+
import { check_space_status } from "./helpers/spaces";
|
30
|
+
import { open_stream } from "./utils/stream";
|
31
|
+
import { API_INFO_ERROR_MSG, CONFIG_ERROR_MSG } from "./constants";
|
32
|
+
|
33
|
+
export class NodeBlob extends Blob {
|
34
|
+
constructor(blobParts?: BlobPart[], options?: BlobPropertyBag) {
|
35
|
+
super(blobParts, options);
|
93
36
|
}
|
94
|
-
|
95
|
-
Authorization: `Bearer ${hf_token}`
|
96
|
-
};
|
97
|
-
|
98
|
-
const user = (
|
99
|
-
await (
|
100
|
-
await fetch(`https://huggingface.co/api/whoami-v2`, {
|
101
|
-
headers
|
102
|
-
})
|
103
|
-
).json()
|
104
|
-
).name;
|
105
|
-
|
106
|
-
const space_name = app_reference.split("/")[1];
|
107
|
-
const body: {
|
108
|
-
repository: string;
|
109
|
-
private?: boolean;
|
110
|
-
} = {
|
111
|
-
repository: `${user}/${space_name}`
|
112
|
-
};
|
37
|
+
}
|
113
38
|
|
114
|
-
|
115
|
-
|
39
|
+
export class Client {
|
40
|
+
app_reference: string;
|
41
|
+
options: ClientOptions;
|
42
|
+
|
43
|
+
config: Config | undefined;
|
44
|
+
api_info: ApiInfo<JsApiData> | undefined;
|
45
|
+
api_map: Record<string, number> = {};
|
46
|
+
session_hash: string = Math.random().toString(36).substring(2);
|
47
|
+
jwt: string | false = false;
|
48
|
+
last_status: Record<string, Status["stage"]> = {};
|
49
|
+
|
50
|
+
// streaming
|
51
|
+
stream_status = { open: false };
|
52
|
+
pending_stream_messages: Record<string, any[][]> = {};
|
53
|
+
pending_diff_streams: Record<string, any[][]> = {};
|
54
|
+
event_callbacks: Record<string, (data?: unknown) => Promise<void>> = {};
|
55
|
+
unclosed_events: Set<string> = new Set();
|
56
|
+
heartbeat_event: EventSource | null = null;
|
57
|
+
|
58
|
+
fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
|
59
|
+
return fetch(input, init);
|
116
60
|
}
|
117
61
|
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
return client(`${user}/${space_name}`, options);
|
130
|
-
}
|
131
|
-
const duplicated_space = await response.json();
|
132
|
-
|
133
|
-
let original_hardware;
|
134
|
-
|
135
|
-
if (!hardware) {
|
136
|
-
original_hardware = await get_space_hardware(app_reference, hf_token);
|
62
|
+
stream_factory(url: URL): EventSource | null {
|
63
|
+
if (typeof window === "undefined" || typeof EventSource === "undefined") {
|
64
|
+
import("eventsource")
|
65
|
+
.then((EventSourceModule) => {
|
66
|
+
return new EventSourceModule.default(url.toString());
|
67
|
+
})
|
68
|
+
.catch((error) =>
|
69
|
+
console.error("Failed to load EventSource module:", error)
|
70
|
+
);
|
71
|
+
} else {
|
72
|
+
return new EventSource(url.toString());
|
137
73
|
}
|
138
|
-
|
139
|
-
const requested_hardware = hardware || original_hardware || "cpu-basic";
|
140
|
-
await set_space_hardware(
|
141
|
-
`${user}/${space_name}`,
|
142
|
-
requested_hardware,
|
143
|
-
hf_token
|
144
|
-
);
|
145
|
-
|
146
|
-
await set_space_timeout(`${user}/${space_name}`, timeout || 300, hf_token);
|
147
|
-
return client(duplicated_space.url, options);
|
148
|
-
} catch (e: any) {
|
149
|
-
throw new Error(e);
|
74
|
+
return null;
|
150
75
|
}
|
151
|
-
}
|
152
76
|
|
153
|
-
|
154
|
-
post_data: (
|
155
|
-
url: string,
|
156
|
-
body: unknown,
|
157
|
-
token?: `hf_${string}`
|
158
|
-
) => Promise<[PostResponse, number]>;
|
77
|
+
view_api: () => Promise<ApiInfo<JsApiData>>;
|
159
78
|
upload_files: (
|
160
|
-
|
161
|
-
files: File[],
|
162
|
-
token?: `hf_${string}`,
|
79
|
+
root_url: string,
|
80
|
+
files: (Blob | File)[],
|
163
81
|
upload_id?: string
|
164
82
|
) => Promise<UploadResponse>;
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
) => Promise<client_return>;
|
83
|
+
upload: (
|
84
|
+
file_data: FileData[],
|
85
|
+
root_url: string,
|
86
|
+
upload_id?: string,
|
87
|
+
max_file_size?: number
|
88
|
+
) => Promise<(FileData | null)[] | null>;
|
172
89
|
handle_blob: (
|
173
90
|
endpoint: string,
|
174
91
|
data: unknown[],
|
175
|
-
|
176
|
-
token?: `hf_${string}`
|
92
|
+
endpoint_info: EndpointInfo<ApiData | JsApiData>
|
177
93
|
) => Promise<unknown[]>;
|
178
|
-
|
179
|
-
|
180
|
-
export function api_factory(
|
181
|
-
fetch_implementation: typeof fetch,
|
182
|
-
EventSource_factory: (url: URL) => EventSource
|
183
|
-
): Client {
|
184
|
-
return { post_data, upload_files, client, handle_blob };
|
185
|
-
|
186
|
-
async function post_data(
|
94
|
+
post_data: (
|
187
95
|
url: string,
|
188
96
|
body: unknown,
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
}
|
218
|
-
return [output, status];
|
97
|
+
additional_headers?: any
|
98
|
+
) => Promise<unknown[]>;
|
99
|
+
submit: (
|
100
|
+
endpoint: string | number,
|
101
|
+
data: unknown[],
|
102
|
+
event_data?: unknown,
|
103
|
+
trigger_id?: number | null
|
104
|
+
) => SubmitReturn;
|
105
|
+
predict: (
|
106
|
+
endpoint: string | number,
|
107
|
+
data?: unknown[],
|
108
|
+
event_data?: unknown
|
109
|
+
) => Promise<unknown>;
|
110
|
+
open_stream: () => void;
|
111
|
+
private resolve_config: (endpoint: string) => Promise<Config | undefined>;
|
112
|
+
constructor(app_reference: string, options: ClientOptions = {}) {
|
113
|
+
this.app_reference = app_reference;
|
114
|
+
this.options = options;
|
115
|
+
|
116
|
+
this.view_api = view_api.bind(this);
|
117
|
+
this.upload_files = upload_files.bind(this);
|
118
|
+
this.handle_blob = handle_blob.bind(this);
|
119
|
+
this.post_data = post_data.bind(this);
|
120
|
+
this.submit = submit.bind(this);
|
121
|
+
this.predict = predict.bind(this);
|
122
|
+
this.open_stream = open_stream.bind(this);
|
123
|
+
this.resolve_config = resolve_config.bind(this);
|
124
|
+
this.upload = upload.bind(this);
|
219
125
|
}
|
220
126
|
|
221
|
-
async
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
if (token) {
|
231
|
-
headers.Authorization = `Bearer ${token}`;
|
232
|
-
}
|
233
|
-
const chunkSize = 1000;
|
234
|
-
const uploadResponses = [];
|
235
|
-
for (let i = 0; i < files.length; i += chunkSize) {
|
236
|
-
const chunk = files.slice(i, i + chunkSize);
|
237
|
-
const formData = new FormData();
|
238
|
-
chunk.forEach((file) => {
|
239
|
-
formData.append("files", file);
|
240
|
-
});
|
241
|
-
try {
|
242
|
-
const upload_url = upload_id
|
243
|
-
? `${root}/upload?upload_id=${upload_id}`
|
244
|
-
: `${root}/upload`;
|
245
|
-
var response = await fetch_implementation(upload_url, {
|
246
|
-
method: "POST",
|
247
|
-
body: formData,
|
248
|
-
headers
|
249
|
-
});
|
250
|
-
} catch (e) {
|
251
|
-
return { error: BROKEN_CONNECTION_MSG };
|
252
|
-
}
|
253
|
-
const output: UploadResponse["files"] = await response.json();
|
254
|
-
uploadResponses.push(...output);
|
127
|
+
private async init(): Promise<void> {
|
128
|
+
if (
|
129
|
+
(typeof window === "undefined" || !("WebSocket" in window)) &&
|
130
|
+
!global.WebSocket
|
131
|
+
) {
|
132
|
+
const ws = await import("ws");
|
133
|
+
// @ts-ignore
|
134
|
+
NodeBlob = (await import("node:buffer")).Blob;
|
135
|
+
global.WebSocket = ws.WebSocket as unknown as typeof WebSocket;
|
255
136
|
}
|
256
|
-
return { files: uploadResponses };
|
257
|
-
}
|
258
|
-
|
259
|
-
async function client(
|
260
|
-
app_reference: string,
|
261
|
-
options: {
|
262
|
-
hf_token?: `hf_${string}`;
|
263
|
-
status_callback?: SpaceStatusCallback;
|
264
|
-
} = {}
|
265
|
-
): Promise<client_return> {
|
266
|
-
return new Promise(async (res) => {
|
267
|
-
const { status_callback, hf_token } = options;
|
268
|
-
const return_obj = {
|
269
|
-
predict,
|
270
|
-
submit,
|
271
|
-
view_api,
|
272
|
-
component_server
|
273
|
-
};
|
274
|
-
|
275
|
-
if (
|
276
|
-
(typeof window === "undefined" || !("WebSocket" in window)) &&
|
277
|
-
!global.Websocket
|
278
|
-
) {
|
279
|
-
const ws = await import("ws");
|
280
|
-
NodeBlob = (await import("node:buffer")).Blob;
|
281
|
-
//@ts-ignore
|
282
|
-
global.WebSocket = ws.WebSocket;
|
283
|
-
}
|
284
|
-
|
285
|
-
const { ws_protocol, http_protocol, host, space_id } =
|
286
|
-
await process_endpoint(app_reference, hf_token);
|
287
|
-
|
288
|
-
const session_hash = Math.random().toString(36).substring(2);
|
289
|
-
const last_status: Record<string, Status["stage"]> = {};
|
290
|
-
let stream_open = false;
|
291
|
-
let pending_stream_messages: Record<string, any[]> = {}; // Event messages may be received by the SSE stream before the initial data POST request is complete. To resolve this race condition, we store the messages in a dictionary and process them when the POST request is complete.
|
292
|
-
let pending_diff_streams: Record<string, any[][]> = {};
|
293
|
-
let event_stream: EventSource | null = null;
|
294
|
-
const event_callbacks: Record<string, () => Promise<void>> = {};
|
295
|
-
const unclosed_events: Set<string> = new Set();
|
296
|
-
let config: Config;
|
297
|
-
let api_map: Record<string, number> = {};
|
298
137
|
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
if (window.location.protocol === "https:") {
|
308
|
-
config.root = config.root.replace("http://", "https://");
|
309
|
-
}
|
310
|
-
api_map = map_names_to_ids(_config?.dependencies || []);
|
311
|
-
if (config.auth_required) {
|
312
|
-
return {
|
313
|
-
config,
|
314
|
-
...return_obj
|
315
|
-
};
|
316
|
-
}
|
317
|
-
try {
|
318
|
-
api = await view_api(config);
|
319
|
-
} catch (e) {
|
320
|
-
console.error(`Could not get api details: ${e.message}`);
|
321
|
-
}
|
322
|
-
|
323
|
-
return {
|
324
|
-
config,
|
325
|
-
...return_obj
|
326
|
-
};
|
327
|
-
}
|
328
|
-
let api: ApiInfo<JsApiData>;
|
329
|
-
async function handle_space_sucess(status: SpaceStatus): Promise<void> {
|
330
|
-
if (status_callback) status_callback(status);
|
331
|
-
if (status.status === "running")
|
332
|
-
try {
|
333
|
-
config = await resolve_config(
|
334
|
-
fetch_implementation,
|
335
|
-
`${http_protocol}//${host}`,
|
336
|
-
hf_token
|
138
|
+
try {
|
139
|
+
await this._resolve_config().then(async ({ config }) => {
|
140
|
+
if (config) {
|
141
|
+
this.config = config;
|
142
|
+
if (this.config && this.config.connect_heartbeat) {
|
143
|
+
// connect to the heartbeat endpoint via GET request
|
144
|
+
const heartbeat_url = new URL(
|
145
|
+
`${this.config.root}/heartbeat/${this.session_hash}`
|
337
146
|
);
|
147
|
+
this.heartbeat_event = this.stream_factory(heartbeat_url); // Just connect to the endpoint without parsing the response. Ref: https://github.com/gradio-app/gradio/pull/7974#discussion_r1557717540
|
338
148
|
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
status_callback({
|
345
|
-
status: "error",
|
346
|
-
message: "Could not load this space.",
|
347
|
-
load_status: "error",
|
348
|
-
detail: "NOT_FOUND"
|
349
|
-
});
|
149
|
+
if (this.config.space_id && this.options.hf_token) {
|
150
|
+
this.jwt = await get_jwt(
|
151
|
+
this.config.space_id,
|
152
|
+
this.options.hf_token
|
153
|
+
);
|
350
154
|
}
|
351
155
|
}
|
352
|
-
}
|
353
|
-
|
354
|
-
try {
|
355
|
-
config = await resolve_config(
|
356
|
-
fetch_implementation,
|
357
|
-
`${http_protocol}//${host}`,
|
358
|
-
hf_token
|
359
|
-
);
|
360
|
-
|
361
|
-
const _config = await config_success(config);
|
362
|
-
// connect to the heartbeat endpoint via GET request
|
363
|
-
const heartbeat_url = new URL(
|
364
|
-
`${config.root}/heartbeat/${session_hash}`
|
365
|
-
);
|
366
|
-
EventSource_factory(heartbeat_url); // Just connect to the endpoint without parsing the response. Ref: https://github.com/gradio-app/gradio/pull/7974#discussion_r1557717540
|
367
|
-
res(_config);
|
368
|
-
} catch (e) {
|
369
|
-
console.error(e);
|
370
|
-
if (space_id) {
|
371
|
-
check_space_status(
|
372
|
-
space_id,
|
373
|
-
RE_SPACE_NAME.test(space_id) ? "space_name" : "subdomain",
|
374
|
-
handle_space_sucess
|
375
|
-
);
|
376
|
-
} else {
|
377
|
-
if (status_callback)
|
378
|
-
status_callback({
|
379
|
-
status: "error",
|
380
|
-
message: "Could not load this space.",
|
381
|
-
load_status: "error",
|
382
|
-
detail: "NOT_FOUND"
|
383
|
-
});
|
384
|
-
}
|
385
|
-
}
|
386
|
-
|
387
|
-
function predict(
|
388
|
-
endpoint: string,
|
389
|
-
data: unknown[],
|
390
|
-
event_data?: unknown
|
391
|
-
): Promise<unknown> {
|
392
|
-
let data_returned = false;
|
393
|
-
let status_complete = false;
|
394
|
-
let dependency;
|
395
|
-
if (typeof endpoint === "number") {
|
396
|
-
dependency = config.dependencies[endpoint];
|
397
|
-
} else {
|
398
|
-
const trimmed_endpoint = endpoint.replace(/^\//, "");
|
399
|
-
dependency = config.dependencies[api_map[trimmed_endpoint]];
|
400
156
|
}
|
157
|
+
});
|
158
|
+
} catch (e) {
|
159
|
+
throw Error(CONFIG_ERROR_MSG + (e as Error).message);
|
160
|
+
}
|
401
161
|
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
);
|
406
|
-
}
|
407
|
-
|
408
|
-
return new Promise((res, rej) => {
|
409
|
-
const app = submit(endpoint, data, event_data);
|
410
|
-
let result;
|
411
|
-
|
412
|
-
app
|
413
|
-
.on("data", (d) => {
|
414
|
-
// if complete message comes before data, resolve here
|
415
|
-
if (status_complete) {
|
416
|
-
app.destroy();
|
417
|
-
res(d);
|
418
|
-
}
|
419
|
-
data_returned = true;
|
420
|
-
result = d;
|
421
|
-
})
|
422
|
-
.on("status", (status) => {
|
423
|
-
if (status.stage === "error") rej(status);
|
424
|
-
if (status.stage === "complete") {
|
425
|
-
status_complete = true;
|
426
|
-
// if complete message comes after data, resolve here
|
427
|
-
if (data_returned) {
|
428
|
-
app.destroy();
|
429
|
-
res(result);
|
430
|
-
}
|
431
|
-
}
|
432
|
-
});
|
433
|
-
});
|
434
|
-
}
|
435
|
-
|
436
|
-
function submit(
|
437
|
-
endpoint: string | number,
|
438
|
-
data: unknown[],
|
439
|
-
event_data?: unknown,
|
440
|
-
trigger_id: number | null = null
|
441
|
-
): SubmitReturn {
|
442
|
-
let fn_index: number;
|
443
|
-
let api_info;
|
444
|
-
let dependency;
|
445
|
-
|
446
|
-
if (typeof endpoint === "number") {
|
447
|
-
fn_index = endpoint;
|
448
|
-
api_info = api.unnamed_endpoints[fn_index];
|
449
|
-
dependency = config.dependencies[endpoint];
|
450
|
-
} else {
|
451
|
-
const trimmed_endpoint = endpoint.replace(/^\//, "");
|
452
|
-
|
453
|
-
fn_index = api_map[trimmed_endpoint];
|
454
|
-
api_info = api.named_endpoints[endpoint.trim()];
|
455
|
-
dependency = config.dependencies[api_map[trimmed_endpoint]];
|
456
|
-
}
|
457
|
-
|
458
|
-
if (typeof fn_index !== "number") {
|
459
|
-
throw new Error(
|
460
|
-
"There is no endpoint matching that name of fn_index matching that number."
|
461
|
-
);
|
462
|
-
}
|
463
|
-
|
464
|
-
let websocket: WebSocket;
|
465
|
-
let eventSource: EventSource;
|
466
|
-
let protocol = config.protocol ?? "ws";
|
467
|
-
|
468
|
-
const _endpoint = typeof endpoint === "number" ? "/predict" : endpoint;
|
469
|
-
let payload: Payload;
|
470
|
-
let event_id: string | null = null;
|
471
|
-
let complete: false | Record<string, any> = false;
|
472
|
-
const listener_map: ListenerMap<EventType> = {};
|
473
|
-
let url_params = "";
|
474
|
-
if (typeof window !== "undefined") {
|
475
|
-
url_params = new URLSearchParams(window.location.search).toString();
|
476
|
-
}
|
477
|
-
|
478
|
-
handle_blob(`${config.root}`, data, api_info, hf_token).then(
|
479
|
-
(_payload) => {
|
480
|
-
payload = {
|
481
|
-
data: _payload || [],
|
482
|
-
event_data,
|
483
|
-
fn_index,
|
484
|
-
trigger_id
|
485
|
-
};
|
486
|
-
if (skip_queue(fn_index, config)) {
|
487
|
-
fire_event({
|
488
|
-
type: "status",
|
489
|
-
endpoint: _endpoint,
|
490
|
-
stage: "pending",
|
491
|
-
queue: false,
|
492
|
-
fn_index,
|
493
|
-
time: new Date()
|
494
|
-
});
|
495
|
-
|
496
|
-
post_data(
|
497
|
-
`${config.root}/run${
|
498
|
-
_endpoint.startsWith("/") ? _endpoint : `/${_endpoint}`
|
499
|
-
}${url_params ? "?" + url_params : ""}`,
|
500
|
-
{
|
501
|
-
...payload,
|
502
|
-
session_hash
|
503
|
-
},
|
504
|
-
hf_token
|
505
|
-
)
|
506
|
-
.then(([output, status_code]) => {
|
507
|
-
const data = output.data;
|
508
|
-
if (status_code == 200) {
|
509
|
-
fire_event({
|
510
|
-
type: "data",
|
511
|
-
endpoint: _endpoint,
|
512
|
-
fn_index,
|
513
|
-
data: data,
|
514
|
-
time: new Date()
|
515
|
-
});
|
516
|
-
|
517
|
-
fire_event({
|
518
|
-
type: "status",
|
519
|
-
endpoint: _endpoint,
|
520
|
-
fn_index,
|
521
|
-
stage: "complete",
|
522
|
-
eta: output.average_duration,
|
523
|
-
queue: false,
|
524
|
-
time: new Date()
|
525
|
-
});
|
526
|
-
} else {
|
527
|
-
fire_event({
|
528
|
-
type: "status",
|
529
|
-
stage: "error",
|
530
|
-
endpoint: _endpoint,
|
531
|
-
fn_index,
|
532
|
-
message: output.error,
|
533
|
-
queue: false,
|
534
|
-
time: new Date()
|
535
|
-
});
|
536
|
-
}
|
537
|
-
})
|
538
|
-
.catch((e) => {
|
539
|
-
fire_event({
|
540
|
-
type: "status",
|
541
|
-
stage: "error",
|
542
|
-
message: e.message,
|
543
|
-
endpoint: _endpoint,
|
544
|
-
fn_index,
|
545
|
-
queue: false,
|
546
|
-
time: new Date()
|
547
|
-
});
|
548
|
-
});
|
549
|
-
} else if (protocol == "ws") {
|
550
|
-
fire_event({
|
551
|
-
type: "status",
|
552
|
-
stage: "pending",
|
553
|
-
queue: true,
|
554
|
-
endpoint: _endpoint,
|
555
|
-
fn_index,
|
556
|
-
time: new Date()
|
557
|
-
});
|
558
|
-
let url = new URL(`${ws_protocol}://${resolve_root(
|
559
|
-
host,
|
560
|
-
config.path,
|
561
|
-
true
|
562
|
-
)}
|
563
|
-
/queue/join${url_params ? "?" + url_params : ""}`);
|
564
|
-
|
565
|
-
if (jwt) {
|
566
|
-
url.searchParams.set("__sign", jwt);
|
567
|
-
}
|
568
|
-
|
569
|
-
websocket = new WebSocket(url);
|
570
|
-
|
571
|
-
websocket.onclose = (evt) => {
|
572
|
-
if (!evt.wasClean) {
|
573
|
-
fire_event({
|
574
|
-
type: "status",
|
575
|
-
stage: "error",
|
576
|
-
broken: true,
|
577
|
-
message: BROKEN_CONNECTION_MSG,
|
578
|
-
queue: true,
|
579
|
-
endpoint: _endpoint,
|
580
|
-
fn_index,
|
581
|
-
time: new Date()
|
582
|
-
});
|
583
|
-
}
|
584
|
-
};
|
585
|
-
|
586
|
-
websocket.onmessage = function (event) {
|
587
|
-
const _data = JSON.parse(event.data);
|
588
|
-
const { type, status, data } = handle_message(
|
589
|
-
_data,
|
590
|
-
last_status[fn_index]
|
591
|
-
);
|
592
|
-
|
593
|
-
if (type === "update" && status && !complete) {
|
594
|
-
// call 'status' listeners
|
595
|
-
fire_event({
|
596
|
-
type: "status",
|
597
|
-
endpoint: _endpoint,
|
598
|
-
fn_index,
|
599
|
-
time: new Date(),
|
600
|
-
...status
|
601
|
-
});
|
602
|
-
if (status.stage === "error") {
|
603
|
-
websocket.close();
|
604
|
-
}
|
605
|
-
} else if (type === "hash") {
|
606
|
-
websocket.send(JSON.stringify({ fn_index, session_hash }));
|
607
|
-
return;
|
608
|
-
} else if (type === "data") {
|
609
|
-
websocket.send(JSON.stringify({ ...payload, session_hash }));
|
610
|
-
} else if (type === "complete") {
|
611
|
-
complete = status;
|
612
|
-
} else if (type === "log") {
|
613
|
-
fire_event({
|
614
|
-
type: "log",
|
615
|
-
log: data.log,
|
616
|
-
level: data.level,
|
617
|
-
endpoint: _endpoint,
|
618
|
-
fn_index
|
619
|
-
});
|
620
|
-
} else if (type === "generating") {
|
621
|
-
fire_event({
|
622
|
-
type: "status",
|
623
|
-
time: new Date(),
|
624
|
-
...status,
|
625
|
-
stage: status?.stage!,
|
626
|
-
queue: true,
|
627
|
-
endpoint: _endpoint,
|
628
|
-
fn_index
|
629
|
-
});
|
630
|
-
}
|
631
|
-
if (data) {
|
632
|
-
fire_event({
|
633
|
-
type: "data",
|
634
|
-
time: new Date(),
|
635
|
-
data: data.data,
|
636
|
-
endpoint: _endpoint,
|
637
|
-
fn_index
|
638
|
-
});
|
639
|
-
|
640
|
-
if (complete) {
|
641
|
-
fire_event({
|
642
|
-
type: "status",
|
643
|
-
time: new Date(),
|
644
|
-
...complete,
|
645
|
-
stage: status?.stage!,
|
646
|
-
queue: true,
|
647
|
-
endpoint: _endpoint,
|
648
|
-
fn_index
|
649
|
-
});
|
650
|
-
websocket.close();
|
651
|
-
}
|
652
|
-
}
|
653
|
-
};
|
654
|
-
|
655
|
-
// different ws contract for gradio versions older than 3.6.0
|
656
|
-
//@ts-ignore
|
657
|
-
if (semiver(config.version || "2.0.0", "3.6") < 0) {
|
658
|
-
addEventListener("open", () =>
|
659
|
-
websocket.send(JSON.stringify({ hash: session_hash }))
|
660
|
-
);
|
661
|
-
}
|
662
|
-
} else if (protocol == "sse") {
|
663
|
-
fire_event({
|
664
|
-
type: "status",
|
665
|
-
stage: "pending",
|
666
|
-
queue: true,
|
667
|
-
endpoint: _endpoint,
|
668
|
-
fn_index,
|
669
|
-
time: new Date()
|
670
|
-
});
|
671
|
-
var params = new URLSearchParams({
|
672
|
-
fn_index: fn_index.toString(),
|
673
|
-
session_hash: session_hash
|
674
|
-
}).toString();
|
675
|
-
let url = new URL(
|
676
|
-
`${config.root}/queue/join?${
|
677
|
-
url_params ? url_params + "&" : ""
|
678
|
-
}${params}`
|
679
|
-
);
|
162
|
+
this.api_info = await this.view_api();
|
163
|
+
this.api_map = map_names_to_ids(this.config?.dependencies || []);
|
164
|
+
}
|
680
165
|
|
681
|
-
|
166
|
+
static async connect(
|
167
|
+
app_reference: string,
|
168
|
+
options: ClientOptions = {}
|
169
|
+
): Promise<Client> {
|
170
|
+
const client = new this(app_reference, options); // this refers to the class itself, not the instance
|
171
|
+
await client.init();
|
172
|
+
return client;
|
173
|
+
}
|
682
174
|
|
683
|
-
|
684
|
-
|
685
|
-
|
686
|
-
_data,
|
687
|
-
last_status[fn_index]
|
688
|
-
);
|
175
|
+
close(): void {
|
176
|
+
this.heartbeat_event?.close();
|
177
|
+
}
|
689
178
|
|
690
|
-
|
691
|
-
|
692
|
-
|
693
|
-
|
694
|
-
|
695
|
-
|
696
|
-
time: new Date(),
|
697
|
-
...status
|
698
|
-
});
|
699
|
-
if (status.stage === "error") {
|
700
|
-
eventSource.close();
|
701
|
-
}
|
702
|
-
} else if (type === "data") {
|
703
|
-
event_id = _data.event_id as string;
|
704
|
-
let [_, status] = await post_data(
|
705
|
-
`${config.root}/queue/data`,
|
706
|
-
{
|
707
|
-
...payload,
|
708
|
-
session_hash,
|
709
|
-
event_id
|
710
|
-
},
|
711
|
-
hf_token
|
712
|
-
);
|
713
|
-
if (status !== 200) {
|
714
|
-
fire_event({
|
715
|
-
type: "status",
|
716
|
-
stage: "error",
|
717
|
-
message: BROKEN_CONNECTION_MSG,
|
718
|
-
queue: true,
|
719
|
-
endpoint: _endpoint,
|
720
|
-
fn_index,
|
721
|
-
time: new Date()
|
722
|
-
});
|
723
|
-
eventSource.close();
|
724
|
-
}
|
725
|
-
} else if (type === "complete") {
|
726
|
-
complete = status;
|
727
|
-
} else if (type === "log") {
|
728
|
-
fire_event({
|
729
|
-
type: "log",
|
730
|
-
log: data.log,
|
731
|
-
level: data.level,
|
732
|
-
endpoint: _endpoint,
|
733
|
-
fn_index
|
734
|
-
});
|
735
|
-
} else if (type === "generating") {
|
736
|
-
fire_event({
|
737
|
-
type: "status",
|
738
|
-
time: new Date(),
|
739
|
-
...status,
|
740
|
-
stage: status?.stage!,
|
741
|
-
queue: true,
|
742
|
-
endpoint: _endpoint,
|
743
|
-
fn_index
|
744
|
-
});
|
745
|
-
}
|
746
|
-
if (data) {
|
747
|
-
fire_event({
|
748
|
-
type: "data",
|
749
|
-
time: new Date(),
|
750
|
-
data: data.data,
|
751
|
-
endpoint: _endpoint,
|
752
|
-
fn_index
|
753
|
-
});
|
179
|
+
static async duplicate(
|
180
|
+
app_reference: string,
|
181
|
+
options: DuplicateOptions = {}
|
182
|
+
): Promise<Client> {
|
183
|
+
return duplicate(app_reference, options);
|
184
|
+
}
|
754
185
|
|
755
|
-
|
756
|
-
|
757
|
-
|
758
|
-
|
759
|
-
|
760
|
-
stage: status?.stage!,
|
761
|
-
queue: true,
|
762
|
-
endpoint: _endpoint,
|
763
|
-
fn_index
|
764
|
-
});
|
765
|
-
eventSource.close();
|
766
|
-
}
|
767
|
-
}
|
768
|
-
};
|
769
|
-
} else if (
|
770
|
-
protocol == "sse_v1" ||
|
771
|
-
protocol == "sse_v2" ||
|
772
|
-
protocol == "sse_v2.1" ||
|
773
|
-
protocol == "sse_v3"
|
774
|
-
) {
|
775
|
-
// latest API format. v2 introduces sending diffs for intermediate outputs in generative functions, which makes payloads lighter.
|
776
|
-
// v3 only closes the stream when the backend sends the close stream message.
|
777
|
-
fire_event({
|
778
|
-
type: "status",
|
779
|
-
stage: "pending",
|
780
|
-
queue: true,
|
781
|
-
endpoint: _endpoint,
|
782
|
-
fn_index,
|
783
|
-
time: new Date()
|
784
|
-
});
|
785
|
-
let hostname = window.location.hostname;
|
786
|
-
let hfhubdev = "dev.spaces.huggingface.tech";
|
787
|
-
const origin = hostname.includes(".dev.")
|
788
|
-
? `https://moon-${hostname.split(".")[1]}.${hfhubdev}`
|
789
|
-
: `https://huggingface.co`;
|
790
|
-
const zerogpu_auth_promise =
|
791
|
-
dependency.zerogpu && window.parent != window && config.space_id
|
792
|
-
? post_message<Headers>("zerogpu-headers", origin)
|
793
|
-
: Promise.resolve(null);
|
794
|
-
const post_data_promise = zerogpu_auth_promise.then((headers) => {
|
795
|
-
return post_data(
|
796
|
-
`${config.root}/queue/join?${url_params}`,
|
797
|
-
{
|
798
|
-
...payload,
|
799
|
-
session_hash
|
800
|
-
},
|
801
|
-
hf_token,
|
802
|
-
headers
|
803
|
-
);
|
804
|
-
});
|
805
|
-
post_data_promise.then(([response, status]) => {
|
806
|
-
if (status === 503) {
|
807
|
-
fire_event({
|
808
|
-
type: "status",
|
809
|
-
stage: "error",
|
810
|
-
message: QUEUE_FULL_MSG,
|
811
|
-
queue: true,
|
812
|
-
endpoint: _endpoint,
|
813
|
-
fn_index,
|
814
|
-
time: new Date()
|
815
|
-
});
|
816
|
-
} else if (status !== 200) {
|
817
|
-
fire_event({
|
818
|
-
type: "status",
|
819
|
-
stage: "error",
|
820
|
-
message: BROKEN_CONNECTION_MSG,
|
821
|
-
queue: true,
|
822
|
-
endpoint: _endpoint,
|
823
|
-
fn_index,
|
824
|
-
time: new Date()
|
825
|
-
});
|
826
|
-
} else {
|
827
|
-
event_id = response.event_id as string;
|
828
|
-
let callback = async function (_data: object): void {
|
829
|
-
try {
|
830
|
-
const { type, status, data } = handle_message(
|
831
|
-
_data,
|
832
|
-
last_status[fn_index]
|
833
|
-
);
|
186
|
+
private async _resolve_config(): Promise<any> {
|
187
|
+
const { http_protocol, host, space_id } = await process_endpoint(
|
188
|
+
this.app_reference,
|
189
|
+
this.options.hf_token
|
190
|
+
);
|
834
191
|
|
835
|
-
|
836
|
-
|
837
|
-
}
|
192
|
+
const { status_callback } = this.options;
|
193
|
+
let config: Config | undefined;
|
838
194
|
|
839
|
-
|
840
|
-
|
841
|
-
fire_event({
|
842
|
-
type: "status",
|
843
|
-
endpoint: _endpoint,
|
844
|
-
fn_index,
|
845
|
-
time: new Date(),
|
846
|
-
...status
|
847
|
-
});
|
848
|
-
} else if (type === "complete") {
|
849
|
-
complete = status;
|
850
|
-
} else if (type == "unexpected_error") {
|
851
|
-
console.error("Unexpected error", status?.message);
|
852
|
-
fire_event({
|
853
|
-
type: "status",
|
854
|
-
stage: "error",
|
855
|
-
message:
|
856
|
-
status?.message || "An Unexpected Error Occurred!",
|
857
|
-
queue: true,
|
858
|
-
endpoint: _endpoint,
|
859
|
-
fn_index,
|
860
|
-
time: new Date()
|
861
|
-
});
|
862
|
-
} else if (type === "log") {
|
863
|
-
fire_event({
|
864
|
-
type: "log",
|
865
|
-
log: data.log,
|
866
|
-
level: data.level,
|
867
|
-
endpoint: _endpoint,
|
868
|
-
fn_index
|
869
|
-
});
|
870
|
-
return;
|
871
|
-
} else if (type === "generating") {
|
872
|
-
fire_event({
|
873
|
-
type: "status",
|
874
|
-
time: new Date(),
|
875
|
-
...status,
|
876
|
-
stage: status?.stage!,
|
877
|
-
queue: true,
|
878
|
-
endpoint: _endpoint,
|
879
|
-
fn_index
|
880
|
-
});
|
881
|
-
if (
|
882
|
-
data &&
|
883
|
-
["sse_v2", "sse_v2.1", "sse_v3"].includes(protocol)
|
884
|
-
) {
|
885
|
-
apply_diff_stream(event_id!, data);
|
886
|
-
}
|
887
|
-
}
|
888
|
-
if (data) {
|
889
|
-
fire_event({
|
890
|
-
type: "data",
|
891
|
-
time: new Date(),
|
892
|
-
data: data.data,
|
893
|
-
endpoint: _endpoint,
|
894
|
-
fn_index
|
895
|
-
});
|
195
|
+
try {
|
196
|
+
config = await this.resolve_config(`${http_protocol}//${host}`);
|
896
197
|
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
time: new Date(),
|
901
|
-
...complete,
|
902
|
-
stage: status?.stage!,
|
903
|
-
queue: true,
|
904
|
-
endpoint: _endpoint,
|
905
|
-
fn_index
|
906
|
-
});
|
907
|
-
}
|
908
|
-
}
|
198
|
+
if (!config) {
|
199
|
+
throw new Error(CONFIG_ERROR_MSG);
|
200
|
+
}
|
909
201
|
|
910
|
-
|
911
|
-
|
912
|
-
|
913
|
-
|
914
|
-
|
915
|
-
|
916
|
-
|
917
|
-
|
918
|
-
delete pending_diff_streams[event_id];
|
919
|
-
}
|
920
|
-
}
|
921
|
-
} catch (e) {
|
922
|
-
console.error("Unexpected client exception", e);
|
923
|
-
fire_event({
|
924
|
-
type: "status",
|
925
|
-
stage: "error",
|
926
|
-
message: "An Unexpected Error Occurred!",
|
927
|
-
queue: true,
|
928
|
-
endpoint: _endpoint,
|
929
|
-
fn_index,
|
930
|
-
time: new Date()
|
931
|
-
});
|
932
|
-
if (["sse_v2", "sse_v2.1"].includes(protocol)) {
|
933
|
-
close_stream();
|
934
|
-
}
|
935
|
-
}
|
936
|
-
};
|
937
|
-
if (event_id in pending_stream_messages) {
|
938
|
-
pending_stream_messages[event_id].forEach((msg) =>
|
939
|
-
callback(msg)
|
940
|
-
);
|
941
|
-
delete pending_stream_messages[event_id];
|
942
|
-
}
|
943
|
-
event_callbacks[event_id] = callback;
|
944
|
-
unclosed_events.add(event_id);
|
945
|
-
if (!stream_open) {
|
946
|
-
open_stream();
|
947
|
-
}
|
948
|
-
}
|
949
|
-
});
|
950
|
-
}
|
951
|
-
}
|
202
|
+
return this.config_success(config);
|
203
|
+
} catch (e) {
|
204
|
+
console.error(e);
|
205
|
+
if (space_id) {
|
206
|
+
check_space_status(
|
207
|
+
space_id,
|
208
|
+
RE_SPACE_NAME.test(space_id) ? "space_name" : "subdomain",
|
209
|
+
this.handle_space_success
|
952
210
|
);
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
});
|
961
|
-
} else {
|
962
|
-
data.data.forEach((value: any, i: number) => {
|
963
|
-
let new_data = apply_diff(
|
964
|
-
pending_diff_streams[event_id][i],
|
965
|
-
value
|
966
|
-
);
|
967
|
-
pending_diff_streams[event_id][i] = new_data;
|
968
|
-
data.data[i] = new_data;
|
969
|
-
});
|
970
|
-
}
|
971
|
-
}
|
972
|
-
|
973
|
-
function fire_event<K extends EventType>(event: Event<K>): void {
|
974
|
-
const narrowed_listener_map: ListenerMap<K> = listener_map;
|
975
|
-
const listeners = narrowed_listener_map[event.type] || [];
|
976
|
-
listeners?.forEach((l) => l(event));
|
977
|
-
}
|
978
|
-
|
979
|
-
function on<K extends EventType>(
|
980
|
-
eventType: K,
|
981
|
-
listener: EventListener<K>
|
982
|
-
): SubmitReturn {
|
983
|
-
const narrowed_listener_map: ListenerMap<K> = listener_map;
|
984
|
-
const listeners = narrowed_listener_map[eventType] || [];
|
985
|
-
narrowed_listener_map[eventType] = listeners;
|
986
|
-
listeners?.push(listener);
|
987
|
-
|
988
|
-
return { on, off, cancel, destroy };
|
989
|
-
}
|
990
|
-
|
991
|
-
function off<K extends EventType>(
|
992
|
-
eventType: K,
|
993
|
-
listener: EventListener<K>
|
994
|
-
): SubmitReturn {
|
995
|
-
const narrowed_listener_map: ListenerMap<K> = listener_map;
|
996
|
-
let listeners = narrowed_listener_map[eventType] || [];
|
997
|
-
listeners = listeners?.filter((l) => l !== listener);
|
998
|
-
narrowed_listener_map[eventType] = listeners;
|
999
|
-
|
1000
|
-
return { on, off, cancel, destroy };
|
1001
|
-
}
|
1002
|
-
|
1003
|
-
async function cancel(): Promise<void> {
|
1004
|
-
const _status: Status = {
|
1005
|
-
stage: "complete",
|
1006
|
-
queue: false,
|
1007
|
-
time: new Date()
|
1008
|
-
};
|
1009
|
-
complete = _status;
|
1010
|
-
fire_event({
|
1011
|
-
..._status,
|
1012
|
-
type: "status",
|
1013
|
-
endpoint: _endpoint,
|
1014
|
-
fn_index: fn_index
|
211
|
+
} else {
|
212
|
+
if (status_callback)
|
213
|
+
status_callback({
|
214
|
+
status: "error",
|
215
|
+
message: "Could not load this space.",
|
216
|
+
load_status: "error",
|
217
|
+
detail: "NOT_FOUND"
|
1015
218
|
});
|
1016
|
-
|
1017
|
-
let cancel_request = {};
|
1018
|
-
if (protocol === "ws") {
|
1019
|
-
if (websocket && websocket.readyState === 0) {
|
1020
|
-
websocket.addEventListener("open", () => {
|
1021
|
-
websocket.close();
|
1022
|
-
});
|
1023
|
-
} else {
|
1024
|
-
websocket.close();
|
1025
|
-
}
|
1026
|
-
cancel_request = { fn_index, session_hash };
|
1027
|
-
} else {
|
1028
|
-
eventSource.close();
|
1029
|
-
cancel_request = { event_id };
|
1030
|
-
}
|
1031
|
-
|
1032
|
-
try {
|
1033
|
-
await fetch_implementation(`${config.root}/reset`, {
|
1034
|
-
headers: { "Content-Type": "application/json" },
|
1035
|
-
method: "POST",
|
1036
|
-
body: JSON.stringify(cancel_request)
|
1037
|
-
});
|
1038
|
-
} catch (e) {
|
1039
|
-
console.warn(
|
1040
|
-
"The `/reset` endpoint could not be called. Subsequent endpoint results may be unreliable."
|
1041
|
-
);
|
1042
|
-
}
|
1043
|
-
}
|
1044
|
-
|
1045
|
-
function destroy(): void {
|
1046
|
-
for (const event_type in listener_map) {
|
1047
|
-
listener_map[event_type as "data" | "status"].forEach((fn) => {
|
1048
|
-
off(event_type as "data" | "status", fn);
|
1049
|
-
});
|
1050
|
-
}
|
1051
|
-
}
|
1052
|
-
|
1053
|
-
return {
|
1054
|
-
on,
|
1055
|
-
off,
|
1056
|
-
cancel,
|
1057
|
-
destroy
|
1058
|
-
};
|
1059
219
|
}
|
220
|
+
}
|
221
|
+
}
|
1060
222
|
|
1061
|
-
|
1062
|
-
|
1063
|
-
|
1064
|
-
|
1065
|
-
}).toString();
|
1066
|
-
let url = new URL(`${config.root}/queue/data?${params}`);
|
1067
|
-
event_stream = EventSource_factory(url);
|
1068
|
-
event_stream.onmessage = async function (event) {
|
1069
|
-
let _data = JSON.parse(event.data);
|
1070
|
-
if (_data.msg === "close_stream") {
|
1071
|
-
close_stream();
|
1072
|
-
return;
|
1073
|
-
}
|
1074
|
-
const event_id = _data.event_id;
|
1075
|
-
if (!event_id) {
|
1076
|
-
await Promise.all(
|
1077
|
-
Object.keys(event_callbacks).map((event_id) =>
|
1078
|
-
event_callbacks[event_id](_data)
|
1079
|
-
)
|
1080
|
-
);
|
1081
|
-
} else if (event_callbacks[event_id]) {
|
1082
|
-
if (
|
1083
|
-
_data.msg === "process_completed" &&
|
1084
|
-
["sse", "sse_v1", "sse_v2", "sse_v2.1"].includes(config.protocol)
|
1085
|
-
) {
|
1086
|
-
unclosed_events.delete(event_id);
|
1087
|
-
if (unclosed_events.size === 0) {
|
1088
|
-
close_stream();
|
1089
|
-
}
|
1090
|
-
}
|
1091
|
-
let fn = event_callbacks[event_id];
|
1092
|
-
window.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
|
1093
|
-
} else {
|
1094
|
-
if (!pending_stream_messages[event_id]) {
|
1095
|
-
pending_stream_messages[event_id] = [];
|
1096
|
-
}
|
1097
|
-
pending_stream_messages[event_id].push(_data);
|
1098
|
-
}
|
1099
|
-
};
|
1100
|
-
event_stream.onerror = async function (event) {
|
1101
|
-
await Promise.all(
|
1102
|
-
Object.keys(event_callbacks).map((event_id) =>
|
1103
|
-
event_callbacks[event_id]({
|
1104
|
-
msg: "unexpected_error",
|
1105
|
-
message: BROKEN_CONNECTION_MSG
|
1106
|
-
})
|
1107
|
-
)
|
1108
|
-
);
|
1109
|
-
close_stream();
|
1110
|
-
};
|
1111
|
-
}
|
223
|
+
private async config_success(
|
224
|
+
_config: Config
|
225
|
+
): Promise<Config | client_return> {
|
226
|
+
this.config = _config;
|
1112
227
|
|
1113
|
-
|
1114
|
-
|
1115
|
-
|
228
|
+
if (typeof window !== "undefined") {
|
229
|
+
if (window.location.protocol === "https:") {
|
230
|
+
this.config.root = this.config.root.replace("http://", "https://");
|
1116
231
|
}
|
232
|
+
}
|
1117
233
|
|
1118
|
-
|
1119
|
-
|
1120
|
-
|
1121
|
-
data: unknown[] | { binary: boolean; data: Record<string, any> }
|
1122
|
-
): Promise<any> {
|
1123
|
-
const headers: {
|
1124
|
-
Authorization?: string;
|
1125
|
-
"Content-Type": "application/json";
|
1126
|
-
} = {};
|
1127
|
-
|
1128
|
-
let root_url: string;
|
1129
|
-
let component = config.components.find(
|
1130
|
-
(comp) => comp.id === component_id
|
1131
|
-
);
|
1132
|
-
if (component?.props?.root_url) {
|
1133
|
-
root_url = component.props.root_url;
|
1134
|
-
} else {
|
1135
|
-
root_url = config.root;
|
1136
|
-
}
|
1137
|
-
|
1138
|
-
let body: FormData | string;
|
1139
|
-
if (data.binary) {
|
1140
|
-
body = new FormData();
|
1141
|
-
for (const key in data.data) {
|
1142
|
-
if (key === "binary") continue;
|
1143
|
-
body.append(key, data.data[key]);
|
1144
|
-
}
|
1145
|
-
body.set("component_id", component_id);
|
1146
|
-
body.set("fn_name", fn_name);
|
1147
|
-
body.set("session_hash", session_hash);
|
1148
|
-
} else {
|
1149
|
-
body = JSON.stringify({
|
1150
|
-
data: data,
|
1151
|
-
component_id,
|
1152
|
-
fn_name,
|
1153
|
-
session_hash
|
1154
|
-
});
|
1155
|
-
|
1156
|
-
headers["Content-Type"] = "application/json";
|
1157
|
-
}
|
1158
|
-
if (hf_token) {
|
1159
|
-
headers.Authorization = `Bearer ${hf_token}`;
|
1160
|
-
}
|
234
|
+
if (this.config.auth_required) {
|
235
|
+
return this.prepare_return_obj();
|
236
|
+
}
|
1161
237
|
|
1162
|
-
|
1163
|
-
|
1164
|
-
|
1165
|
-
|
1166
|
-
|
1167
|
-
body: body,
|
1168
|
-
headers
|
1169
|
-
}
|
1170
|
-
);
|
238
|
+
try {
|
239
|
+
this.api_info = await this.view_api();
|
240
|
+
} catch (e) {
|
241
|
+
console.error(API_INFO_ERROR_MSG + (e as Error).message);
|
242
|
+
}
|
1171
243
|
|
1172
|
-
|
1173
|
-
|
1174
|
-
throw new Error(
|
1175
|
-
"Could not connect to component server: " + response.statusText
|
1176
|
-
);
|
1177
|
-
}
|
244
|
+
return this.prepare_return_obj();
|
245
|
+
}
|
1178
246
|
|
1179
|
-
|
1180
|
-
|
1181
|
-
|
1182
|
-
|
247
|
+
async handle_space_success(status: SpaceStatus): Promise<Config | void> {
|
248
|
+
const { status_callback } = this.options;
|
249
|
+
if (status_callback) status_callback(status);
|
250
|
+
if (status.status === "running") {
|
251
|
+
try {
|
252
|
+
this.config = await this._resolve_config();
|
253
|
+
if (!this.config) {
|
254
|
+
throw new Error(CONFIG_ERROR_MSG);
|
1183
255
|
}
|
1184
|
-
}
|
1185
256
|
|
1186
|
-
|
1187
|
-
if (api) return api;
|
257
|
+
const _config = await this.config_success(this.config);
|
1188
258
|
|
1189
|
-
|
1190
|
-
|
1191
|
-
|
1192
|
-
|
1193
|
-
|
1194
|
-
|
1195
|
-
|
1196
|
-
|
1197
|
-
|
1198
|
-
if (semiver(config.version || "2.0.0", "3.30") < 0) {
|
1199
|
-
response = await fetch_implementation(
|
1200
|
-
"https://gradio-space-api-fetcher-v2.hf.space/api",
|
1201
|
-
{
|
1202
|
-
method: "POST",
|
1203
|
-
body: JSON.stringify({
|
1204
|
-
serialize: false,
|
1205
|
-
config: JSON.stringify(config)
|
1206
|
-
}),
|
1207
|
-
headers
|
1208
|
-
}
|
1209
|
-
);
|
1210
|
-
} else {
|
1211
|
-
response = await fetch_implementation(`${config.root}/info`, {
|
1212
|
-
headers
|
259
|
+
return _config as Config;
|
260
|
+
} catch (e) {
|
261
|
+
console.error(e);
|
262
|
+
if (status_callback) {
|
263
|
+
status_callback({
|
264
|
+
status: "error",
|
265
|
+
message: "Could not load this space.",
|
266
|
+
load_status: "error",
|
267
|
+
detail: "NOT_FOUND"
|
1213
268
|
});
|
1214
269
|
}
|
1215
|
-
|
1216
|
-
if (!response.ok) {
|
1217
|
-
throw new Error(BROKEN_CONNECTION_MSG);
|
1218
|
-
}
|
1219
|
-
|
1220
|
-
let api_info = (await response.json()) as
|
1221
|
-
| ApiInfo<ApiData>
|
1222
|
-
| { api: ApiInfo<ApiData> };
|
1223
|
-
if ("api" in api_info) {
|
1224
|
-
api_info = api_info.api;
|
1225
|
-
}
|
1226
|
-
|
1227
|
-
if (
|
1228
|
-
api_info.named_endpoints["/predict"] &&
|
1229
|
-
!api_info.unnamed_endpoints["0"]
|
1230
|
-
) {
|
1231
|
-
api_info.unnamed_endpoints[0] = api_info.named_endpoints["/predict"];
|
1232
|
-
}
|
1233
|
-
|
1234
|
-
const x = transform_api_info(api_info, config, api_map);
|
1235
|
-
return x;
|
1236
270
|
}
|
1237
|
-
});
|
1238
|
-
}
|
1239
|
-
|
1240
|
-
async function handle_blob(
|
1241
|
-
endpoint: string,
|
1242
|
-
data: unknown[],
|
1243
|
-
api_info: ApiInfo<JsApiData>,
|
1244
|
-
token?: `hf_${string}`
|
1245
|
-
): Promise<unknown[]> {
|
1246
|
-
const blob_refs = await walk_and_store_blobs(
|
1247
|
-
data,
|
1248
|
-
undefined,
|
1249
|
-
[],
|
1250
|
-
true,
|
1251
|
-
api_info
|
1252
|
-
);
|
1253
|
-
|
1254
|
-
return Promise.all(
|
1255
|
-
blob_refs.map(async ({ path, blob, type }) => {
|
1256
|
-
if (blob) {
|
1257
|
-
const file_url = (await upload_files(endpoint, [blob], token))
|
1258
|
-
.files[0];
|
1259
|
-
return { path, file_url, type, name: blob?.name };
|
1260
|
-
}
|
1261
|
-
return { path, type };
|
1262
|
-
})
|
1263
|
-
).then((r) => {
|
1264
|
-
r.forEach(({ path, file_url, type, name }) => {
|
1265
|
-
if (type === "Gallery") {
|
1266
|
-
update_object(data, file_url, path);
|
1267
|
-
} else if (file_url) {
|
1268
|
-
const file = new FileData({ path: file_url, orig_name: name });
|
1269
|
-
update_object(data, file, path);
|
1270
|
-
}
|
1271
|
-
});
|
1272
|
-
|
1273
|
-
return data;
|
1274
|
-
});
|
1275
|
-
}
|
1276
|
-
}
|
1277
|
-
|
1278
|
-
export const { post_data, upload_files, client, handle_blob } = api_factory(
|
1279
|
-
fetch,
|
1280
|
-
(...args) => new EventSource(...args)
|
1281
|
-
);
|
1282
|
-
|
1283
|
-
interface ApiData {
|
1284
|
-
label: string;
|
1285
|
-
type: {
|
1286
|
-
type: any;
|
1287
|
-
description: string;
|
1288
|
-
};
|
1289
|
-
component: string;
|
1290
|
-
example_input?: any;
|
1291
|
-
}
|
1292
|
-
|
1293
|
-
interface JsApiData {
|
1294
|
-
label: string;
|
1295
|
-
type: string;
|
1296
|
-
component: string;
|
1297
|
-
example_input: any;
|
1298
|
-
}
|
1299
|
-
|
1300
|
-
interface EndpointInfo<T extends ApiData | JsApiData> {
|
1301
|
-
parameters: T[];
|
1302
|
-
returns: T[];
|
1303
|
-
}
|
1304
|
-
interface ApiInfo<T extends ApiData | JsApiData> {
|
1305
|
-
named_endpoints: {
|
1306
|
-
[key: string]: EndpointInfo<T>;
|
1307
|
-
};
|
1308
|
-
unnamed_endpoints: {
|
1309
|
-
[key: string]: EndpointInfo<T>;
|
1310
|
-
};
|
1311
|
-
}
|
1312
|
-
|
1313
|
-
function get_type(
|
1314
|
-
type: { [key: string]: any },
|
1315
|
-
component: string,
|
1316
|
-
serializer: string,
|
1317
|
-
signature_type: "return" | "parameter"
|
1318
|
-
): string {
|
1319
|
-
switch (type.type) {
|
1320
|
-
case "string":
|
1321
|
-
return "string";
|
1322
|
-
case "boolean":
|
1323
|
-
return "boolean";
|
1324
|
-
case "number":
|
1325
|
-
return "number";
|
1326
|
-
}
|
1327
|
-
|
1328
|
-
if (
|
1329
|
-
serializer === "JSONSerializable" ||
|
1330
|
-
serializer === "StringSerializable"
|
1331
|
-
) {
|
1332
|
-
return "any";
|
1333
|
-
} else if (serializer === "ListStringSerializable") {
|
1334
|
-
return "string[]";
|
1335
|
-
} else if (component === "Image") {
|
1336
|
-
return signature_type === "parameter" ? "Blob | File | Buffer" : "string";
|
1337
|
-
} else if (serializer === "FileSerializable") {
|
1338
|
-
if (type?.type === "array") {
|
1339
|
-
return signature_type === "parameter"
|
1340
|
-
? "(Blob | File | Buffer)[]"
|
1341
|
-
: `{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}[]`;
|
1342
271
|
}
|
1343
|
-
return signature_type === "parameter"
|
1344
|
-
? "Blob | File | Buffer"
|
1345
|
-
: `{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}`;
|
1346
|
-
} else if (serializer === "GallerySerializable") {
|
1347
|
-
return signature_type === "parameter"
|
1348
|
-
? "[(Blob | File | Buffer), (string | null)][]"
|
1349
|
-
: `[{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}, (string | null))][]`;
|
1350
272
|
}
|
1351
|
-
}
|
1352
273
|
|
1353
|
-
|
1354
|
-
|
1355
|
-
|
1356
|
-
|
1357
|
-
|
1358
|
-
|
1359
|
-
|
1360
|
-
|
1361
|
-
} else if (serializer === "FileSerializable") {
|
1362
|
-
return "array of files or single file";
|
1363
|
-
}
|
1364
|
-
return type.description;
|
1365
|
-
}
|
274
|
+
public async component_server(
|
275
|
+
component_id: number,
|
276
|
+
fn_name: string,
|
277
|
+
data: unknown[] | { binary: boolean; data: Record<string, any> }
|
278
|
+
): Promise<unknown> {
|
279
|
+
if (!this.config) {
|
280
|
+
throw new Error(CONFIG_ERROR_MSG);
|
281
|
+
}
|
1366
282
|
|
1367
|
-
|
1368
|
-
|
1369
|
-
|
1370
|
-
|
1371
|
-
): ApiInfo<JsApiData> {
|
1372
|
-
const new_data = {
|
1373
|
-
named_endpoints: {},
|
1374
|
-
unnamed_endpoints: {}
|
1375
|
-
};
|
1376
|
-
for (const key in api_info) {
|
1377
|
-
const cat = api_info[key];
|
283
|
+
const headers: {
|
284
|
+
Authorization?: string;
|
285
|
+
"Content-Type"?: "application/json";
|
286
|
+
} = {};
|
1378
287
|
|
1379
|
-
|
1380
|
-
|
1381
|
-
? endpoint
|
1382
|
-
: api_map[endpoint.replace("/", "")];
|
288
|
+
const { hf_token } = this.options;
|
289
|
+
const { session_hash } = this;
|
1383
290
|
|
1384
|
-
|
1385
|
-
|
1386
|
-
|
1387
|
-
new_data[key][endpoint].returns = {};
|
1388
|
-
new_data[key][endpoint].type = config.dependencies[dep_index].types;
|
1389
|
-
new_data[key][endpoint].parameters = info.parameters.map(
|
1390
|
-
({ label, component, type, serializer }) => ({
|
1391
|
-
label,
|
1392
|
-
component,
|
1393
|
-
type: get_type(type, component, serializer, "parameter"),
|
1394
|
-
description: get_description(type, serializer)
|
1395
|
-
})
|
1396
|
-
);
|
291
|
+
if (hf_token) {
|
292
|
+
headers.Authorization = `Bearer ${this.options.hf_token}`;
|
293
|
+
}
|
1397
294
|
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
|
1404
|
-
|
1405
|
-
|
295
|
+
let root_url: string;
|
296
|
+
let component = this.config.components.find(
|
297
|
+
(comp) => comp.id === component_id
|
298
|
+
);
|
299
|
+
if (component?.props?.root_url) {
|
300
|
+
root_url = component.props.root_url;
|
301
|
+
} else {
|
302
|
+
root_url = this.config.root;
|
1406
303
|
}
|
1407
|
-
}
|
1408
304
|
|
1409
|
-
|
1410
|
-
}
|
305
|
+
let body: FormData | string;
|
1411
306
|
|
1412
|
-
|
1413
|
-
|
1414
|
-
|
1415
|
-
|
1416
|
-
|
1417
|
-
const r = await fetch(`https://huggingface.co/api/spaces/${space}/jwt`, {
|
1418
|
-
headers: {
|
1419
|
-
Authorization: `Bearer ${token}`
|
307
|
+
if ("binary" in data) {
|
308
|
+
body = new FormData();
|
309
|
+
for (const key in data.data) {
|
310
|
+
if (key === "binary") continue;
|
311
|
+
body.append(key, data.data[key]);
|
1420
312
|
}
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
}
|
1431
|
-
|
1432
|
-
function update_object(object, newValue, stack): void {
|
1433
|
-
while (stack.length > 1) {
|
1434
|
-
object = object[stack.shift()];
|
1435
|
-
}
|
1436
|
-
|
1437
|
-
object[stack.shift()] = newValue;
|
1438
|
-
}
|
1439
|
-
|
1440
|
-
export async function walk_and_store_blobs(
|
1441
|
-
param,
|
1442
|
-
type = undefined,
|
1443
|
-
path = [],
|
1444
|
-
root = false,
|
1445
|
-
api_info = undefined
|
1446
|
-
): Promise<
|
1447
|
-
{
|
1448
|
-
path: string[];
|
1449
|
-
type: string;
|
1450
|
-
blob: Blob | false;
|
1451
|
-
}[]
|
1452
|
-
> {
|
1453
|
-
if (Array.isArray(param)) {
|
1454
|
-
let blob_refs = [];
|
313
|
+
body.set("component_id", component_id.toString());
|
314
|
+
body.set("fn_name", fn_name);
|
315
|
+
body.set("session_hash", session_hash);
|
316
|
+
} else {
|
317
|
+
body = JSON.stringify({
|
318
|
+
data: data,
|
319
|
+
component_id,
|
320
|
+
fn_name,
|
321
|
+
session_hash
|
322
|
+
});
|
1455
323
|
|
1456
|
-
|
1457
|
-
|
1458
|
-
let new_path = path.slice();
|
1459
|
-
new_path.push(i);
|
324
|
+
headers["Content-Type"] = "application/json";
|
325
|
+
}
|
1460
326
|
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
new_path,
|
1465
|
-
false,
|
1466
|
-
api_info
|
1467
|
-
);
|
327
|
+
if (hf_token) {
|
328
|
+
headers.Authorization = `Bearer ${hf_token}`;
|
329
|
+
}
|
1468
330
|
|
1469
|
-
|
1470
|
-
}
|
1471
|
-
|
331
|
+
try {
|
332
|
+
const response = await this.fetch(`${root_url}/component_server/`, {
|
333
|
+
method: "POST",
|
334
|
+
body: body,
|
335
|
+
headers
|
336
|
+
});
|
1472
337
|
|
1473
|
-
|
1474
|
-
|
1475
|
-
|
1476
|
-
return [
|
1477
|
-
{
|
1478
|
-
path: path,
|
1479
|
-
blob: is_image ? false : new NodeBlob([param]),
|
1480
|
-
type
|
1481
|
-
}
|
1482
|
-
];
|
1483
|
-
} else if (typeof param === "object") {
|
1484
|
-
let blob_refs = [];
|
1485
|
-
for (let key in param) {
|
1486
|
-
if (param.hasOwnProperty(key)) {
|
1487
|
-
let new_path = path.slice();
|
1488
|
-
new_path.push(key);
|
1489
|
-
blob_refs = blob_refs.concat(
|
1490
|
-
await walk_and_store_blobs(
|
1491
|
-
param[key],
|
1492
|
-
undefined,
|
1493
|
-
new_path,
|
1494
|
-
false,
|
1495
|
-
api_info
|
1496
|
-
)
|
338
|
+
if (!response.ok) {
|
339
|
+
throw new Error(
|
340
|
+
"Could not connect to component server: " + response.statusText
|
1497
341
|
);
|
1498
342
|
}
|
1499
|
-
}
|
1500
|
-
return blob_refs;
|
1501
|
-
}
|
1502
|
-
return [];
|
1503
|
-
}
|
1504
|
-
|
1505
|
-
function image_to_data_uri(blob: Blob): Promise<string | ArrayBuffer> {
|
1506
|
-
return new Promise((resolve, _) => {
|
1507
|
-
const reader = new FileReader();
|
1508
|
-
reader.onloadend = () => resolve(reader.result);
|
1509
|
-
reader.readAsDataURL(blob);
|
1510
|
-
});
|
1511
|
-
}
|
1512
|
-
|
1513
|
-
function skip_queue(id: number, config: Config): boolean {
|
1514
|
-
return (
|
1515
|
-
!(config?.dependencies?.[id]?.queue === null
|
1516
|
-
? config.enable_queue
|
1517
|
-
: config?.dependencies?.[id]?.queue) || false
|
1518
|
-
);
|
1519
|
-
}
|
1520
343
|
|
1521
|
-
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
): Promise<Config> {
|
1526
|
-
const headers: { Authorization?: string } = {};
|
1527
|
-
if (token) {
|
1528
|
-
headers.Authorization = `Bearer ${token}`;
|
1529
|
-
}
|
1530
|
-
if (
|
1531
|
-
typeof window !== "undefined" &&
|
1532
|
-
window.gradio_config &&
|
1533
|
-
location.origin !== "http://localhost:9876" &&
|
1534
|
-
!window.gradio_config.dev_mode
|
1535
|
-
) {
|
1536
|
-
const path = window.gradio_config.root;
|
1537
|
-
const config = window.gradio_config;
|
1538
|
-
config.root = resolve_root(endpoint, config.root, false);
|
1539
|
-
return { ...config, path: path };
|
1540
|
-
} else if (endpoint) {
|
1541
|
-
let response = await fetch_implementation(`${endpoint}/config`, {
|
1542
|
-
headers
|
1543
|
-
});
|
1544
|
-
|
1545
|
-
if (response.status === 200) {
|
1546
|
-
const config = await response.json();
|
1547
|
-
config.path = config.path ?? "";
|
1548
|
-
config.root = endpoint;
|
1549
|
-
return config;
|
344
|
+
const output = await response.json();
|
345
|
+
return output;
|
346
|
+
} catch (e) {
|
347
|
+
console.warn(e);
|
1550
348
|
}
|
1551
|
-
throw new Error("Could not get config.");
|
1552
349
|
}
|
1553
350
|
|
1554
|
-
|
1555
|
-
|
1556
|
-
|
1557
|
-
|
1558
|
-
|
1559
|
-
|
1560
|
-
|
1561
|
-
|
1562
|
-
let endpoint =
|
1563
|
-
type === "subdomain"
|
1564
|
-
? `https://huggingface.co/api/spaces/by-subdomain/${id}`
|
1565
|
-
: `https://huggingface.co/api/spaces/${id}`;
|
1566
|
-
let response;
|
1567
|
-
let _status;
|
1568
|
-
try {
|
1569
|
-
response = await fetch(endpoint);
|
1570
|
-
_status = response.status;
|
1571
|
-
if (_status !== 200) {
|
1572
|
-
throw new Error();
|
1573
|
-
}
|
1574
|
-
response = await response.json();
|
1575
|
-
} catch (e) {
|
1576
|
-
status_callback({
|
1577
|
-
status: "error",
|
1578
|
-
load_status: "error",
|
1579
|
-
message: "Could not get space status",
|
1580
|
-
detail: "NOT_FOUND"
|
1581
|
-
});
|
1582
|
-
return;
|
1583
|
-
}
|
1584
|
-
|
1585
|
-
if (!response || _status !== 200) return;
|
1586
|
-
const {
|
1587
|
-
runtime: { stage },
|
1588
|
-
id: space_name
|
1589
|
-
} = response;
|
1590
|
-
|
1591
|
-
switch (stage) {
|
1592
|
-
case "STOPPED":
|
1593
|
-
case "SLEEPING":
|
1594
|
-
status_callback({
|
1595
|
-
status: "sleeping",
|
1596
|
-
load_status: "pending",
|
1597
|
-
message: "Space is asleep. Waking it up...",
|
1598
|
-
detail: stage
|
1599
|
-
});
|
1600
|
-
|
1601
|
-
setTimeout(() => {
|
1602
|
-
check_space_status(id, type, status_callback);
|
1603
|
-
}, 1000); // poll for status
|
1604
|
-
break;
|
1605
|
-
case "PAUSED":
|
1606
|
-
status_callback({
|
1607
|
-
status: "paused",
|
1608
|
-
load_status: "error",
|
1609
|
-
message:
|
1610
|
-
"This space has been paused by the author. If you would like to try this demo, consider duplicating the space.",
|
1611
|
-
detail: stage,
|
1612
|
-
discussions_enabled: await discussions_enabled(space_name)
|
1613
|
-
});
|
1614
|
-
break;
|
1615
|
-
case "RUNNING":
|
1616
|
-
case "RUNNING_BUILDING":
|
1617
|
-
status_callback({
|
1618
|
-
status: "running",
|
1619
|
-
load_status: "complete",
|
1620
|
-
message: "",
|
1621
|
-
detail: stage
|
1622
|
-
});
|
1623
|
-
// load_config(source);
|
1624
|
-
// launch
|
1625
|
-
break;
|
1626
|
-
case "BUILDING":
|
1627
|
-
status_callback({
|
1628
|
-
status: "building",
|
1629
|
-
load_status: "pending",
|
1630
|
-
message: "Space is building...",
|
1631
|
-
detail: stage
|
1632
|
-
});
|
1633
|
-
|
1634
|
-
setTimeout(() => {
|
1635
|
-
check_space_status(id, type, status_callback);
|
1636
|
-
}, 1000);
|
1637
|
-
break;
|
1638
|
-
default:
|
1639
|
-
status_callback({
|
1640
|
-
status: "space_error",
|
1641
|
-
load_status: "error",
|
1642
|
-
message: "This space is experiencing an issue.",
|
1643
|
-
detail: stage,
|
1644
|
-
discussions_enabled: await discussions_enabled(space_name)
|
1645
|
-
});
|
1646
|
-
break;
|
351
|
+
private prepare_return_obj(): client_return {
|
352
|
+
return {
|
353
|
+
config: this.config,
|
354
|
+
predict: this.predict,
|
355
|
+
submit: this.submit,
|
356
|
+
view_api: this.view_api,
|
357
|
+
component_server: this.component_server
|
358
|
+
};
|
1647
359
|
}
|
1648
360
|
}
|
1649
361
|
|
1650
|
-
|
1651
|
-
|
1652
|
-
|
1653
|
-
|
1654
|
-
|
1655
|
-
|
1656
|
-
|
1657
|
-
|
1658
|
-
|
1659
|
-
|
1660
|
-
|
1661
|
-
|
1662
|
-
|
1663
|
-
|
1664
|
-
case "queue_full":
|
1665
|
-
return {
|
1666
|
-
type: "update",
|
1667
|
-
status: {
|
1668
|
-
queue,
|
1669
|
-
message: QUEUE_FULL_MSG,
|
1670
|
-
stage: "error",
|
1671
|
-
code: data.code,
|
1672
|
-
success: data.success
|
1673
|
-
}
|
1674
|
-
};
|
1675
|
-
case "heartbeat":
|
1676
|
-
return {
|
1677
|
-
type: "heartbeat"
|
1678
|
-
};
|
1679
|
-
case "unexpected_error":
|
1680
|
-
return {
|
1681
|
-
type: "unexpected_error",
|
1682
|
-
status: {
|
1683
|
-
queue,
|
1684
|
-
message: data.message,
|
1685
|
-
stage: "error",
|
1686
|
-
success: false
|
1687
|
-
}
|
1688
|
-
};
|
1689
|
-
case "estimation":
|
1690
|
-
return {
|
1691
|
-
type: "update",
|
1692
|
-
status: {
|
1693
|
-
queue,
|
1694
|
-
stage: last_status || "pending",
|
1695
|
-
code: data.code,
|
1696
|
-
size: data.queue_size,
|
1697
|
-
position: data.rank,
|
1698
|
-
eta: data.rank_eta,
|
1699
|
-
success: data.success
|
1700
|
-
}
|
1701
|
-
};
|
1702
|
-
case "progress":
|
1703
|
-
return {
|
1704
|
-
type: "update",
|
1705
|
-
status: {
|
1706
|
-
queue,
|
1707
|
-
stage: "pending",
|
1708
|
-
code: data.code,
|
1709
|
-
progress_data: data.progress_data,
|
1710
|
-
success: data.success
|
1711
|
-
}
|
1712
|
-
};
|
1713
|
-
case "log":
|
1714
|
-
return { type: "log", data: data };
|
1715
|
-
case "process_generating":
|
1716
|
-
return {
|
1717
|
-
type: "generating",
|
1718
|
-
status: {
|
1719
|
-
queue,
|
1720
|
-
message: !data.success ? data.output.error : null,
|
1721
|
-
stage: data.success ? "generating" : "error",
|
1722
|
-
code: data.code,
|
1723
|
-
progress_data: data.progress_data,
|
1724
|
-
eta: data.average_duration
|
1725
|
-
},
|
1726
|
-
data: data.success ? data.output : null
|
1727
|
-
};
|
1728
|
-
case "process_completed":
|
1729
|
-
if ("error" in data.output) {
|
1730
|
-
return {
|
1731
|
-
type: "update",
|
1732
|
-
status: {
|
1733
|
-
queue,
|
1734
|
-
message: data.output.error as string,
|
1735
|
-
stage: "error",
|
1736
|
-
code: data.code,
|
1737
|
-
success: data.success
|
1738
|
-
}
|
1739
|
-
};
|
1740
|
-
}
|
1741
|
-
return {
|
1742
|
-
type: "complete",
|
1743
|
-
status: {
|
1744
|
-
queue,
|
1745
|
-
message: !data.success ? data.output.error : undefined,
|
1746
|
-
stage: data.success ? "complete" : "error",
|
1747
|
-
code: data.code,
|
1748
|
-
progress_data: data.progress_data
|
1749
|
-
},
|
1750
|
-
data: data.success ? data.output : null
|
1751
|
-
};
|
1752
|
-
|
1753
|
-
case "process_starts":
|
1754
|
-
return {
|
1755
|
-
type: "update",
|
1756
|
-
status: {
|
1757
|
-
queue,
|
1758
|
-
stage: "pending",
|
1759
|
-
code: data.code,
|
1760
|
-
size: data.rank,
|
1761
|
-
position: 0,
|
1762
|
-
success: data.success,
|
1763
|
-
eta: data.eta
|
1764
|
-
}
|
1765
|
-
};
|
1766
|
-
}
|
362
|
+
/**
|
363
|
+
* @deprecated This method will be removed in v1.0. Use `Client.connect()` instead.
|
364
|
+
* Creates a client instance for interacting with Gradio apps.
|
365
|
+
*
|
366
|
+
* @param {string} app_reference - The reference or URL to a Gradio space or app.
|
367
|
+
* @param {ClientOptions} options - Configuration options for the client.
|
368
|
+
* @returns {Promise<Client>} A promise that resolves to a `Client` instance.
|
369
|
+
*/
|
370
|
+
export async function client(
|
371
|
+
app_reference: string,
|
372
|
+
options: ClientOptions = {}
|
373
|
+
): Promise<Client> {
|
374
|
+
return await Client.connect(app_reference, options);
|
375
|
+
}
|
1767
376
|
|
1768
|
-
|
377
|
+
/**
|
378
|
+
* @deprecated This method will be removed in v1.0. Use `Client.duplicate()` instead.
|
379
|
+
* Creates a duplicate of a space and returns a client instance for the duplicated space.
|
380
|
+
*
|
381
|
+
* @param {string} app_reference - The reference or URL to a Gradio space or app to duplicate.
|
382
|
+
* @param {DuplicateOptions} options - Configuration options for the client.
|
383
|
+
* @returns {Promise<Client>} A promise that resolves to a `Client` instance.
|
384
|
+
*/
|
385
|
+
export async function duplicate_space(
|
386
|
+
app_reference: string,
|
387
|
+
options: DuplicateOptions
|
388
|
+
): Promise<Client> {
|
389
|
+
return await Client.duplicate(app_reference, options);
|
1769
390
|
}
|
391
|
+
|
392
|
+
export type ClientInstance = Client;
|