@gradio/client 0.1.2 → 0.1.4
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 +12 -0
- package/dist/client.d.ts +47 -10
- package/dist/client.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +426 -401
- package/dist/types.d.ts +10 -10
- package/dist/types.d.ts.map +1 -1
- package/dist/{wrapper-b7460963.js → wrapper-6f348d45.js} +16 -27
- package/package.json +3 -3
- package/src/client.ts +521 -491
- package/src/globals.d.ts +1 -1
- package/src/index.ts +7 -1
- package/src/types.ts +8 -3
package/src/client.ts
CHANGED
@@ -45,7 +45,7 @@ type client_return = {
|
|
45
45
|
data?: unknown[],
|
46
46
|
event_data?: unknown
|
47
47
|
) => SubmitReturn;
|
48
|
-
view_api: (c?: Config) => Promise<
|
48
|
+
view_api: (c?: Config) => Promise<ApiInfo<JsApiData>>;
|
49
49
|
};
|
50
50
|
|
51
51
|
type SubmitReturn = {
|
@@ -58,62 +58,8 @@ type SubmitReturn = {
|
|
58
58
|
const QUEUE_FULL_MSG = "This application is too busy. Keep trying!";
|
59
59
|
const BROKEN_CONNECTION_MSG = "Connection errored out.";
|
60
60
|
|
61
|
-
export async function post_data(
|
62
|
-
url: string,
|
63
|
-
body: unknown,
|
64
|
-
token?: `hf_${string}`
|
65
|
-
): Promise<[PostResponse, number]> {
|
66
|
-
const headers: {
|
67
|
-
Authorization?: string;
|
68
|
-
"Content-Type": "application/json";
|
69
|
-
} = { "Content-Type": "application/json" };
|
70
|
-
if (token) {
|
71
|
-
headers.Authorization = `Bearer ${token}`;
|
72
|
-
}
|
73
|
-
try {
|
74
|
-
var response = await fetch(url, {
|
75
|
-
method: "POST",
|
76
|
-
body: JSON.stringify(body),
|
77
|
-
headers
|
78
|
-
});
|
79
|
-
} catch (e) {
|
80
|
-
return [{ error: BROKEN_CONNECTION_MSG }, 500];
|
81
|
-
}
|
82
|
-
const output: PostResponse = await response.json();
|
83
|
-
return [output, response.status];
|
84
|
-
}
|
85
|
-
|
86
61
|
export let NodeBlob;
|
87
62
|
|
88
|
-
export async function upload_files(
|
89
|
-
root: string,
|
90
|
-
files: Array<File>,
|
91
|
-
token?: `hf_${string}`
|
92
|
-
): Promise<UploadResponse> {
|
93
|
-
const headers: {
|
94
|
-
Authorization?: string;
|
95
|
-
} = {};
|
96
|
-
if (token) {
|
97
|
-
headers.Authorization = `Bearer ${token}`;
|
98
|
-
}
|
99
|
-
|
100
|
-
const formData = new FormData();
|
101
|
-
files.forEach((file) => {
|
102
|
-
formData.append("files", file);
|
103
|
-
});
|
104
|
-
try {
|
105
|
-
var response = await fetch(`${root}/upload`, {
|
106
|
-
method: "POST",
|
107
|
-
body: formData,
|
108
|
-
headers
|
109
|
-
});
|
110
|
-
} catch (e) {
|
111
|
-
return { error: BROKEN_CONNECTION_MSG };
|
112
|
-
}
|
113
|
-
const output: UploadResponse["files"] = await response.json();
|
114
|
-
return { files: output };
|
115
|
-
}
|
116
|
-
|
117
63
|
export async function duplicate(
|
118
64
|
app_reference: string,
|
119
65
|
options: {
|
@@ -197,453 +143,526 @@ export async function duplicate(
|
|
197
143
|
}
|
198
144
|
}
|
199
145
|
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
146
|
+
/**
|
147
|
+
* We need to inject a customized fetch implementation for the Wasm version.
|
148
|
+
*/
|
149
|
+
export function api_factory(fetch_implementation: typeof fetch) {
|
150
|
+
return { post_data, upload_files, client, handle_blob };
|
151
|
+
|
152
|
+
async function post_data(
|
153
|
+
url: string,
|
154
|
+
body: unknown,
|
155
|
+
token?: `hf_${string}`
|
156
|
+
): Promise<[PostResponse, number]> {
|
157
|
+
const headers: {
|
158
|
+
Authorization?: string;
|
159
|
+
"Content-Type": "application/json";
|
160
|
+
} = { "Content-Type": "application/json" };
|
161
|
+
if (token) {
|
162
|
+
headers.Authorization = `Bearer ${token}`;
|
163
|
+
}
|
164
|
+
try {
|
165
|
+
var response = await fetch_implementation(url, {
|
166
|
+
method: "POST",
|
167
|
+
body: JSON.stringify(body),
|
168
|
+
headers
|
169
|
+
});
|
170
|
+
} catch (e) {
|
171
|
+
return [{ error: BROKEN_CONNECTION_MSG }, 500];
|
172
|
+
}
|
173
|
+
const output: PostResponse = await response.json();
|
174
|
+
return [output, response.status];
|
175
|
+
}
|
216
176
|
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
177
|
+
async function upload_files(
|
178
|
+
root: string,
|
179
|
+
files: Array<File>,
|
180
|
+
token?: `hf_${string}`
|
181
|
+
): Promise<UploadResponse> {
|
182
|
+
const headers: {
|
183
|
+
Authorization?: string;
|
184
|
+
} = {};
|
185
|
+
if (token) {
|
186
|
+
headers.Authorization = `Bearer ${token}`;
|
223
187
|
}
|
224
188
|
|
225
|
-
const
|
226
|
-
|
189
|
+
const formData = new FormData();
|
190
|
+
files.forEach((file) => {
|
191
|
+
formData.append("files", file);
|
192
|
+
});
|
193
|
+
try {
|
194
|
+
var response = await fetch_implementation(`${root}/upload`, {
|
195
|
+
method: "POST",
|
196
|
+
body: formData,
|
197
|
+
headers
|
198
|
+
});
|
199
|
+
} catch (e) {
|
200
|
+
return { error: BROKEN_CONNECTION_MSG };
|
201
|
+
}
|
202
|
+
const output: UploadResponse["files"] = await response.json();
|
203
|
+
return { files: output };
|
204
|
+
}
|
205
|
+
|
206
|
+
async function client(
|
207
|
+
app_reference: string,
|
208
|
+
options: {
|
209
|
+
hf_token?: `hf_${string}`;
|
210
|
+
status_callback?: SpaceStatusCallback;
|
211
|
+
normalise_files?: boolean;
|
212
|
+
} = { normalise_files: true }
|
213
|
+
): Promise<client_return> {
|
214
|
+
return new Promise(async (res) => {
|
215
|
+
const { status_callback, hf_token, normalise_files } = options;
|
216
|
+
const return_obj = {
|
217
|
+
predict,
|
218
|
+
submit,
|
219
|
+
view_api
|
220
|
+
// duplicate
|
221
|
+
};
|
227
222
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
223
|
+
const transform_files = normalise_files ?? true;
|
224
|
+
if (typeof window === "undefined" || !("WebSocket" in window)) {
|
225
|
+
const ws = await import("ws");
|
226
|
+
NodeBlob = (await import("node:buffer")).Blob;
|
227
|
+
//@ts-ignore
|
228
|
+
global.WebSocket = ws.WebSocket;
|
229
|
+
}
|
232
230
|
|
233
|
-
|
231
|
+
const { ws_protocol, http_protocol, host, space_id } =
|
232
|
+
await process_endpoint(app_reference, hf_token);
|
234
233
|
|
235
|
-
|
236
|
-
|
237
|
-
|
234
|
+
const session_hash = Math.random().toString(36).substring(2);
|
235
|
+
const last_status: Record<string, Status["stage"]> = {};
|
236
|
+
let config: Config;
|
237
|
+
let api_map: Record<string, number> = {};
|
238
238
|
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
api = await view_api(config);
|
244
|
-
} catch (e) {
|
245
|
-
console.error(`Could not get api details: ${e.message}`);
|
239
|
+
let jwt: false | string = false;
|
240
|
+
|
241
|
+
if (hf_token && space_id) {
|
242
|
+
jwt = await get_jwt(space_id, hf_token);
|
246
243
|
}
|
247
244
|
|
248
|
-
|
249
|
-
config
|
250
|
-
|
251
|
-
};
|
252
|
-
}
|
253
|
-
let api;
|
254
|
-
async function handle_space_sucess(status: SpaceStatus) {
|
255
|
-
if (status_callback) status_callback(status);
|
256
|
-
if (status.status === "running")
|
245
|
+
async function config_success(_config: Config) {
|
246
|
+
config = _config;
|
247
|
+
api_map = map_names_to_ids(_config?.dependencies || []);
|
257
248
|
try {
|
258
|
-
|
259
|
-
|
260
|
-
const _config = await config_success(config);
|
261
|
-
res(_config);
|
249
|
+
api = await view_api(config);
|
262
250
|
} catch (e) {
|
263
|
-
|
264
|
-
status_callback({
|
265
|
-
status: "error",
|
266
|
-
message: "Could not load this space.",
|
267
|
-
load_status: "error",
|
268
|
-
detail: "NOT_FOUND"
|
269
|
-
});
|
270
|
-
}
|
251
|
+
console.error(`Could not get api details: ${e.message}`);
|
271
252
|
}
|
272
|
-
}
|
273
|
-
|
274
|
-
try {
|
275
|
-
config = await resolve_config(`${http_protocol}//${host}`, hf_token);
|
276
253
|
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
check_space_status(
|
282
|
-
space_id,
|
283
|
-
RE_SPACE_NAME.test(space_id) ? "space_name" : "subdomain",
|
284
|
-
handle_space_sucess
|
285
|
-
);
|
286
|
-
} else {
|
287
|
-
if (status_callback)
|
288
|
-
status_callback({
|
289
|
-
status: "error",
|
290
|
-
message: "Could not load this space.",
|
291
|
-
load_status: "error",
|
292
|
-
detail: "NOT_FOUND"
|
293
|
-
});
|
254
|
+
return {
|
255
|
+
config,
|
256
|
+
...return_obj
|
257
|
+
};
|
294
258
|
}
|
295
|
-
|
259
|
+
let api: ApiInfo<JsApiData>;
|
260
|
+
async function handle_space_sucess(status: SpaceStatus) {
|
261
|
+
if (status_callback) status_callback(status);
|
262
|
+
if (status.status === "running")
|
263
|
+
try {
|
264
|
+
config = await resolve_config(
|
265
|
+
fetch_implementation,
|
266
|
+
`${http_protocol}//${host}`,
|
267
|
+
hf_token
|
268
|
+
);
|
296
269
|
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
app
|
310
|
-
.on("data", (d) => {
|
311
|
-
data_returned = true;
|
312
|
-
if (status_complete) {
|
313
|
-
app.destroy();
|
314
|
-
}
|
315
|
-
res(d);
|
316
|
-
})
|
317
|
-
.on("status", (status) => {
|
318
|
-
if (status.stage === "error") rej(status);
|
319
|
-
if (status.stage === "complete" && data_returned) {
|
320
|
-
app.destroy();
|
321
|
-
}
|
322
|
-
if (status.stage === "complete") {
|
323
|
-
status_complete = true;
|
270
|
+
const _config = await config_success(config);
|
271
|
+
res(_config);
|
272
|
+
} catch (e) {
|
273
|
+
console.error(e);
|
274
|
+
if (status_callback) {
|
275
|
+
status_callback({
|
276
|
+
status: "error",
|
277
|
+
message: "Could not load this space.",
|
278
|
+
load_status: "error",
|
279
|
+
detail: "NOT_FOUND"
|
280
|
+
});
|
324
281
|
}
|
325
|
-
}
|
326
|
-
}
|
327
|
-
}
|
282
|
+
}
|
283
|
+
}
|
328
284
|
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
let api_info;
|
336
|
-
|
337
|
-
if (typeof endpoint === "number") {
|
338
|
-
fn_index = endpoint;
|
339
|
-
api_info = api.unnamed_endpoints[fn_index];
|
340
|
-
} else {
|
341
|
-
const trimmed_endpoint = endpoint.replace(/^\//, "");
|
285
|
+
try {
|
286
|
+
config = await resolve_config(
|
287
|
+
fetch_implementation,
|
288
|
+
`${http_protocol}//${host}`,
|
289
|
+
hf_token
|
290
|
+
);
|
342
291
|
|
343
|
-
|
344
|
-
|
292
|
+
const _config = await config_success(config);
|
293
|
+
res(_config);
|
294
|
+
} catch (e) {
|
295
|
+
console.error(e);
|
296
|
+
if (space_id) {
|
297
|
+
check_space_status(
|
298
|
+
space_id,
|
299
|
+
RE_SPACE_NAME.test(space_id) ? "space_name" : "subdomain",
|
300
|
+
handle_space_sucess
|
301
|
+
);
|
302
|
+
} else {
|
303
|
+
if (status_callback)
|
304
|
+
status_callback({
|
305
|
+
status: "error",
|
306
|
+
message: "Could not load this space.",
|
307
|
+
load_status: "error",
|
308
|
+
detail: "NOT_FOUND"
|
309
|
+
});
|
310
|
+
}
|
345
311
|
}
|
346
312
|
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
313
|
+
/**
|
314
|
+
* Run a prediction.
|
315
|
+
* @param endpoint - The prediction endpoint to use.
|
316
|
+
* @param status_callback - A function that is called with the current status of the prediction immediately and every time it updates.
|
317
|
+
* @return Returns the data for the prediction or an error message.
|
318
|
+
*/
|
319
|
+
function predict(
|
320
|
+
endpoint: string,
|
321
|
+
data: unknown[],
|
322
|
+
event_data?: unknown
|
323
|
+
) {
|
324
|
+
let data_returned = false;
|
325
|
+
let status_complete = false;
|
326
|
+
return new Promise((res, rej) => {
|
327
|
+
const app = submit(endpoint, data, event_data);
|
328
|
+
|
329
|
+
app
|
330
|
+
.on("data", (d) => {
|
331
|
+
data_returned = true;
|
332
|
+
if (status_complete) {
|
333
|
+
app.destroy();
|
334
|
+
}
|
335
|
+
res(d);
|
336
|
+
})
|
337
|
+
.on("status", (status) => {
|
338
|
+
if (status.stage === "error") rej(status);
|
339
|
+
if (status.stage === "complete" && data_returned) {
|
340
|
+
app.destroy();
|
341
|
+
}
|
342
|
+
if (status.stage === "complete") {
|
343
|
+
status_complete = true;
|
344
|
+
}
|
345
|
+
});
|
346
|
+
});
|
351
347
|
}
|
352
348
|
|
353
|
-
|
349
|
+
function submit(
|
350
|
+
endpoint: string | number,
|
351
|
+
data: unknown[],
|
352
|
+
event_data?: unknown
|
353
|
+
): SubmitReturn {
|
354
|
+
let fn_index: number;
|
355
|
+
let api_info;
|
356
|
+
|
357
|
+
if (typeof endpoint === "number") {
|
358
|
+
fn_index = endpoint;
|
359
|
+
api_info = api.unnamed_endpoints[fn_index];
|
360
|
+
} else {
|
361
|
+
const trimmed_endpoint = endpoint.replace(/^\//, "");
|
354
362
|
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
const listener_map: ListenerMap<EventType> = {};
|
363
|
+
fn_index = api_map[trimmed_endpoint];
|
364
|
+
api_info = api.named_endpoints[endpoint.trim()];
|
365
|
+
}
|
359
366
|
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
hf_token
|
366
|
-
).then((_payload) => {
|
367
|
-
payload = { data: _payload || [], event_data, fn_index };
|
368
|
-
if (skip_queue(fn_index, config)) {
|
369
|
-
fire_event({
|
370
|
-
type: "status",
|
371
|
-
endpoint: _endpoint,
|
372
|
-
stage: "pending",
|
373
|
-
queue: false,
|
374
|
-
fn_index,
|
375
|
-
time: new Date()
|
376
|
-
});
|
367
|
+
if (typeof fn_index !== "number") {
|
368
|
+
throw new Error(
|
369
|
+
"There is no endpoint matching that name of fn_index matching that number."
|
370
|
+
);
|
371
|
+
}
|
377
372
|
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
fn_index,
|
402
|
-
data: data,
|
403
|
-
time: new Date()
|
404
|
-
});
|
373
|
+
let websocket: WebSocket;
|
374
|
+
|
375
|
+
const _endpoint = typeof endpoint === "number" ? "/predict" : endpoint;
|
376
|
+
let payload: Payload;
|
377
|
+
let complete: false | Record<string, any> = false;
|
378
|
+
const listener_map: ListenerMap<EventType> = {};
|
379
|
+
|
380
|
+
handle_blob(
|
381
|
+
`${http_protocol}//${host + config.path}`,
|
382
|
+
data,
|
383
|
+
api_info,
|
384
|
+
hf_token
|
385
|
+
).then((_payload) => {
|
386
|
+
payload = { data: _payload || [], event_data, fn_index };
|
387
|
+
if (skip_queue(fn_index, config)) {
|
388
|
+
fire_event({
|
389
|
+
type: "status",
|
390
|
+
endpoint: _endpoint,
|
391
|
+
stage: "pending",
|
392
|
+
queue: false,
|
393
|
+
fn_index,
|
394
|
+
time: new Date()
|
395
|
+
});
|
405
396
|
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
397
|
+
post_data(
|
398
|
+
`${http_protocol}//${host + config.path}/run${
|
399
|
+
_endpoint.startsWith("/") ? _endpoint : `/${_endpoint}`
|
400
|
+
}`,
|
401
|
+
{
|
402
|
+
...payload,
|
403
|
+
session_hash
|
404
|
+
},
|
405
|
+
hf_token
|
406
|
+
)
|
407
|
+
.then(([output, status_code]) => {
|
408
|
+
const data = transform_files
|
409
|
+
? transform_output(
|
410
|
+
output.data,
|
411
|
+
api_info,
|
412
|
+
config.root,
|
413
|
+
config.root_url
|
414
|
+
)
|
415
|
+
: output.data;
|
416
|
+
if (status_code == 200) {
|
417
|
+
fire_event({
|
418
|
+
type: "data",
|
419
|
+
endpoint: _endpoint,
|
420
|
+
fn_index,
|
421
|
+
data: data,
|
422
|
+
time: new Date()
|
423
|
+
});
|
424
|
+
|
425
|
+
fire_event({
|
426
|
+
type: "status",
|
427
|
+
endpoint: _endpoint,
|
428
|
+
fn_index,
|
429
|
+
stage: "complete",
|
430
|
+
eta: output.average_duration,
|
431
|
+
queue: false,
|
432
|
+
time: new Date()
|
433
|
+
});
|
434
|
+
} else {
|
435
|
+
fire_event({
|
436
|
+
type: "status",
|
437
|
+
stage: "error",
|
438
|
+
endpoint: _endpoint,
|
439
|
+
fn_index,
|
440
|
+
message: output.error,
|
441
|
+
queue: false,
|
442
|
+
time: new Date()
|
443
|
+
});
|
444
|
+
}
|
445
|
+
})
|
446
|
+
.catch((e) => {
|
416
447
|
fire_event({
|
417
448
|
type: "status",
|
418
449
|
stage: "error",
|
450
|
+
message: e.message,
|
419
451
|
endpoint: _endpoint,
|
420
452
|
fn_index,
|
421
|
-
message: output.error,
|
422
453
|
queue: false,
|
423
454
|
time: new Date()
|
424
455
|
});
|
425
|
-
}
|
426
|
-
})
|
427
|
-
.catch((e) => {
|
428
|
-
fire_event({
|
429
|
-
type: "status",
|
430
|
-
stage: "error",
|
431
|
-
message: e.message,
|
432
|
-
endpoint: _endpoint,
|
433
|
-
fn_index,
|
434
|
-
queue: false,
|
435
|
-
time: new Date()
|
436
456
|
});
|
457
|
+
} else {
|
458
|
+
fire_event({
|
459
|
+
type: "status",
|
460
|
+
stage: "pending",
|
461
|
+
queue: true,
|
462
|
+
endpoint: _endpoint,
|
463
|
+
fn_index,
|
464
|
+
time: new Date()
|
437
465
|
});
|
438
|
-
} else {
|
439
|
-
fire_event({
|
440
|
-
type: "status",
|
441
|
-
stage: "pending",
|
442
|
-
queue: true,
|
443
|
-
endpoint: _endpoint,
|
444
|
-
fn_index,
|
445
|
-
time: new Date()
|
446
|
-
});
|
447
|
-
|
448
|
-
let url = new URL(`${ws_protocol}://${host}${config.path}
|
449
|
-
/queue/join`);
|
450
466
|
|
451
|
-
|
452
|
-
|
453
|
-
}
|
467
|
+
let url = new URL(`${ws_protocol}://${host}${config.path}
|
468
|
+
/queue/join`);
|
454
469
|
|
455
|
-
|
456
|
-
|
457
|
-
websocket.onclose = (evt) => {
|
458
|
-
if (!evt.wasClean) {
|
459
|
-
fire_event({
|
460
|
-
type: "status",
|
461
|
-
stage: "error",
|
462
|
-
message: BROKEN_CONNECTION_MSG,
|
463
|
-
queue: true,
|
464
|
-
endpoint: _endpoint,
|
465
|
-
fn_index,
|
466
|
-
time: new Date()
|
467
|
-
});
|
470
|
+
if (jwt) {
|
471
|
+
url.searchParams.set("__sign", jwt);
|
468
472
|
}
|
469
|
-
};
|
470
473
|
|
471
|
-
|
472
|
-
const _data = JSON.parse(event.data);
|
473
|
-
const { type, status, data } = handle_message(
|
474
|
-
_data,
|
475
|
-
last_status[fn_index]
|
476
|
-
);
|
474
|
+
websocket = new WebSocket(url);
|
477
475
|
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
476
|
+
websocket.onclose = (evt) => {
|
477
|
+
if (!evt.wasClean) {
|
478
|
+
fire_event({
|
479
|
+
type: "status",
|
480
|
+
stage: "error",
|
481
|
+
message: BROKEN_CONNECTION_MSG,
|
482
|
+
queue: true,
|
483
|
+
endpoint: _endpoint,
|
484
|
+
fn_index,
|
485
|
+
time: new Date()
|
486
|
+
});
|
489
487
|
}
|
490
|
-
}
|
491
|
-
|
492
|
-
|
493
|
-
|
494
|
-
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
fire_event({
|
499
|
-
type: "status",
|
500
|
-
time: new Date(),
|
501
|
-
...status,
|
502
|
-
stage: status?.stage!,
|
503
|
-
queue: true,
|
504
|
-
endpoint: _endpoint,
|
505
|
-
fn_index
|
506
|
-
});
|
507
|
-
}
|
508
|
-
if (data) {
|
509
|
-
fire_event({
|
510
|
-
type: "data",
|
511
|
-
time: new Date(),
|
512
|
-
data: transform_files
|
513
|
-
? transform_output(
|
514
|
-
data.data,
|
515
|
-
api_info,
|
516
|
-
config.root,
|
517
|
-
config.root_url
|
518
|
-
)
|
519
|
-
: data.data,
|
520
|
-
endpoint: _endpoint,
|
521
|
-
fn_index
|
522
|
-
});
|
488
|
+
};
|
489
|
+
|
490
|
+
websocket.onmessage = function (event) {
|
491
|
+
const _data = JSON.parse(event.data);
|
492
|
+
const { type, status, data } = handle_message(
|
493
|
+
_data,
|
494
|
+
last_status[fn_index]
|
495
|
+
);
|
523
496
|
|
524
|
-
if (complete) {
|
497
|
+
if (type === "update" && status && !complete) {
|
498
|
+
// call 'status' listeners
|
499
|
+
fire_event({
|
500
|
+
type: "status",
|
501
|
+
endpoint: _endpoint,
|
502
|
+
fn_index,
|
503
|
+
time: new Date(),
|
504
|
+
...status
|
505
|
+
});
|
506
|
+
if (status.stage === "error") {
|
507
|
+
websocket.close();
|
508
|
+
}
|
509
|
+
} else if (type === "hash") {
|
510
|
+
websocket.send(JSON.stringify({ fn_index, session_hash }));
|
511
|
+
return;
|
512
|
+
} else if (type === "data") {
|
513
|
+
websocket.send(JSON.stringify({ ...payload, session_hash }));
|
514
|
+
} else if (type === "complete") {
|
515
|
+
complete = status;
|
516
|
+
} else if (type === "generating") {
|
525
517
|
fire_event({
|
526
518
|
type: "status",
|
527
519
|
time: new Date(),
|
528
|
-
...
|
520
|
+
...status,
|
529
521
|
stage: status?.stage!,
|
530
522
|
queue: true,
|
531
523
|
endpoint: _endpoint,
|
532
524
|
fn_index
|
533
525
|
});
|
534
|
-
websocket.close();
|
535
526
|
}
|
536
|
-
|
537
|
-
|
527
|
+
if (data) {
|
528
|
+
fire_event({
|
529
|
+
type: "data",
|
530
|
+
time: new Date(),
|
531
|
+
data: transform_files
|
532
|
+
? transform_output(
|
533
|
+
data.data,
|
534
|
+
api_info,
|
535
|
+
config.root,
|
536
|
+
config.root_url
|
537
|
+
)
|
538
|
+
: data.data,
|
539
|
+
endpoint: _endpoint,
|
540
|
+
fn_index
|
541
|
+
});
|
538
542
|
|
539
|
-
|
540
|
-
|
541
|
-
|
542
|
-
|
543
|
-
|
544
|
-
|
543
|
+
if (complete) {
|
544
|
+
fire_event({
|
545
|
+
type: "status",
|
546
|
+
time: new Date(),
|
547
|
+
...complete,
|
548
|
+
stage: status?.stage!,
|
549
|
+
queue: true,
|
550
|
+
endpoint: _endpoint,
|
551
|
+
fn_index
|
552
|
+
});
|
553
|
+
websocket.close();
|
554
|
+
}
|
555
|
+
}
|
556
|
+
};
|
557
|
+
|
558
|
+
// different ws contract for gradio versions older than 3.6.0
|
559
|
+
//@ts-ignore
|
560
|
+
if (semiver(config.version || "2.0.0", "3.6") < 0) {
|
561
|
+
addEventListener("open", () =>
|
562
|
+
websocket.send(JSON.stringify({ hash: session_hash }))
|
563
|
+
);
|
564
|
+
}
|
545
565
|
}
|
546
|
-
}
|
547
|
-
});
|
566
|
+
});
|
548
567
|
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
568
|
+
function fire_event<K extends EventType>(event: Event<K>) {
|
569
|
+
const narrowed_listener_map: ListenerMap<K> = listener_map;
|
570
|
+
const listeners = narrowed_listener_map[event.type] || [];
|
571
|
+
listeners?.forEach((l) => l(event));
|
572
|
+
}
|
554
573
|
|
555
|
-
|
556
|
-
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
574
|
+
function on<K extends EventType>(
|
575
|
+
eventType: K,
|
576
|
+
listener: EventListener<K>
|
577
|
+
) {
|
578
|
+
const narrowed_listener_map: ListenerMap<K> = listener_map;
|
579
|
+
const listeners = narrowed_listener_map[eventType] || [];
|
580
|
+
narrowed_listener_map[eventType] = listeners;
|
581
|
+
listeners?.push(listener);
|
563
582
|
|
564
|
-
|
565
|
-
|
583
|
+
return { on, off, cancel, destroy };
|
584
|
+
}
|
566
585
|
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
586
|
+
function off<K extends EventType>(
|
587
|
+
eventType: K,
|
588
|
+
listener: EventListener<K>
|
589
|
+
) {
|
590
|
+
const narrowed_listener_map: ListenerMap<K> = listener_map;
|
591
|
+
let listeners = narrowed_listener_map[eventType] || [];
|
592
|
+
listeners = listeners?.filter((l) => l !== listener);
|
593
|
+
narrowed_listener_map[eventType] = listeners;
|
575
594
|
|
576
|
-
|
577
|
-
|
595
|
+
return { on, off, cancel, destroy };
|
596
|
+
}
|
578
597
|
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
598
|
+
async function cancel() {
|
599
|
+
const _status: Status = {
|
600
|
+
stage: "complete",
|
601
|
+
queue: false,
|
602
|
+
time: new Date()
|
603
|
+
};
|
604
|
+
complete = _status;
|
605
|
+
fire_event({
|
606
|
+
..._status,
|
607
|
+
type: "status",
|
608
|
+
endpoint: _endpoint,
|
609
|
+
fn_index: fn_index
|
610
|
+
});
|
592
611
|
|
593
|
-
|
594
|
-
|
612
|
+
if (websocket && websocket.readyState === 0) {
|
613
|
+
websocket.addEventListener("open", () => {
|
614
|
+
websocket.close();
|
615
|
+
});
|
616
|
+
} else {
|
595
617
|
websocket.close();
|
596
|
-
}
|
597
|
-
} else {
|
598
|
-
websocket.close();
|
599
|
-
}
|
618
|
+
}
|
600
619
|
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
)
|
620
|
+
try {
|
621
|
+
await fetch_implementation(
|
622
|
+
`${http_protocol}//${host + config.path}/reset`,
|
623
|
+
{
|
624
|
+
headers: { "Content-Type": "application/json" },
|
625
|
+
method: "POST",
|
626
|
+
body: JSON.stringify({ fn_index, session_hash })
|
627
|
+
}
|
628
|
+
);
|
629
|
+
} catch (e) {
|
630
|
+
console.warn(
|
631
|
+
"The `/reset` endpoint could not be called. Subsequent endpoint results may be unreliable."
|
632
|
+
);
|
633
|
+
}
|
611
634
|
}
|
612
|
-
}
|
613
635
|
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
636
|
+
function destroy() {
|
637
|
+
for (const event_type in listener_map) {
|
638
|
+
listener_map[event_type as "data" | "status"].forEach((fn) => {
|
639
|
+
off(event_type as "data" | "status", fn);
|
640
|
+
});
|
641
|
+
}
|
619
642
|
}
|
643
|
+
|
644
|
+
return {
|
645
|
+
on,
|
646
|
+
off,
|
647
|
+
cancel,
|
648
|
+
destroy
|
649
|
+
};
|
620
650
|
}
|
621
651
|
|
622
|
-
|
623
|
-
|
624
|
-
off,
|
625
|
-
cancel,
|
626
|
-
destroy
|
627
|
-
};
|
628
|
-
}
|
652
|
+
async function view_api(config?: Config): Promise<ApiInfo<JsApiData>> {
|
653
|
+
if (api) return api;
|
629
654
|
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
"Content-Type": "application/json";
|
638
|
-
} = { "Content-Type": "application/json" };
|
639
|
-
if (hf_token) {
|
640
|
-
headers.Authorization = `Bearer ${hf_token}`;
|
641
|
-
}
|
642
|
-
try {
|
655
|
+
const headers: {
|
656
|
+
Authorization?: string;
|
657
|
+
"Content-Type": "application/json";
|
658
|
+
} = { "Content-Type": "application/json" };
|
659
|
+
if (hf_token) {
|
660
|
+
headers.Authorization = `Bearer ${hf_token}`;
|
661
|
+
}
|
643
662
|
let response: Response;
|
644
663
|
// @ts-ignore
|
645
664
|
if (semiver(config.version || "2.0.0", "3.30") < 0) {
|
646
|
-
response = await
|
665
|
+
response = await fetch_implementation(
|
647
666
|
"https://gradio-space-api-fetcher-v2.hf.space/api",
|
648
667
|
{
|
649
668
|
method: "POST",
|
@@ -655,11 +674,15 @@ export async function client(
|
|
655
674
|
}
|
656
675
|
);
|
657
676
|
} else {
|
658
|
-
response = await
|
677
|
+
response = await fetch_implementation(`${config.root}/info`, {
|
659
678
|
headers
|
660
679
|
});
|
661
680
|
}
|
662
681
|
|
682
|
+
if (!response.ok) {
|
683
|
+
throw new Error(BROKEN_CONNECTION_MSG);
|
684
|
+
}
|
685
|
+
|
663
686
|
let api_info = (await response.json()) as
|
664
687
|
| ApiInfo<ApiData>
|
665
688
|
| { api: ApiInfo<ApiData> };
|
@@ -676,20 +699,66 @@ export async function client(
|
|
676
699
|
|
677
700
|
const x = transform_api_info(api_info, config, api_map);
|
678
701
|
return x;
|
679
|
-
} catch (e) {
|
680
|
-
return [{ error: BROKEN_CONNECTION_MSG }, 500];
|
681
702
|
}
|
682
|
-
}
|
683
|
-
}
|
703
|
+
});
|
704
|
+
}
|
705
|
+
|
706
|
+
async function handle_blob(
|
707
|
+
endpoint: string,
|
708
|
+
data: unknown[],
|
709
|
+
api_info,
|
710
|
+
token?: `hf_${string}`
|
711
|
+
): Promise<unknown[]> {
|
712
|
+
const blob_refs = await walk_and_store_blobs(
|
713
|
+
data,
|
714
|
+
undefined,
|
715
|
+
[],
|
716
|
+
true,
|
717
|
+
api_info
|
718
|
+
);
|
719
|
+
|
720
|
+
return Promise.all(
|
721
|
+
blob_refs.map(async ({ path, blob, data, type }) => {
|
722
|
+
if (blob) {
|
723
|
+
const file_url = (await upload_files(endpoint, [blob], token))
|
724
|
+
.files[0];
|
725
|
+
return { path, file_url, type };
|
726
|
+
} else {
|
727
|
+
return { path, base64: data, type };
|
728
|
+
}
|
729
|
+
})
|
730
|
+
).then((r) => {
|
731
|
+
r.forEach(({ path, file_url, base64, type }) => {
|
732
|
+
if (base64) {
|
733
|
+
update_object(data, base64, path);
|
734
|
+
} else if (type === "Gallery") {
|
735
|
+
update_object(data, file_url, path);
|
736
|
+
} else if (file_url) {
|
737
|
+
const o = {
|
738
|
+
is_file: true,
|
739
|
+
name: `${file_url}`,
|
740
|
+
data: null
|
741
|
+
// orig_name: "file.csv"
|
742
|
+
};
|
743
|
+
update_object(data, o, path);
|
744
|
+
}
|
745
|
+
});
|
746
|
+
|
747
|
+
return data;
|
748
|
+
});
|
749
|
+
}
|
684
750
|
}
|
685
751
|
|
752
|
+
export const { post_data, upload_files, client, handle_blob } =
|
753
|
+
api_factory(fetch);
|
754
|
+
|
686
755
|
function transform_output(
|
687
756
|
data: any[],
|
688
757
|
api_info: any,
|
689
758
|
root_url: string,
|
690
759
|
remote_url?: string
|
691
760
|
): unknown[] {
|
692
|
-
|
761
|
+
return data.map((d, i) => {
|
693
762
|
if (api_info.returns?.[i]?.component === "File") {
|
694
763
|
return normalise_file(d, root_url, remote_url);
|
695
764
|
} else if (api_info.returns?.[i]?.component === "Gallery") {
|
@@ -704,8 +773,6 @@ function transform_output(
|
|
704
773
|
return d;
|
705
774
|
}
|
706
775
|
});
|
707
|
-
|
708
|
-
return transformed_data;
|
709
776
|
}
|
710
777
|
|
711
778
|
function normalise_file(
|
@@ -750,7 +817,7 @@ function normalise_file(
|
|
750
817
|
if (!root_url) {
|
751
818
|
file.data = root + "/file=" + file.name;
|
752
819
|
} else {
|
753
|
-
file.data = "/proxy=" + root_url + "
|
820
|
+
file.data = "/proxy=" + root_url + "file=" + file.name;
|
754
821
|
}
|
755
822
|
}
|
756
823
|
return file;
|
@@ -907,55 +974,6 @@ async function get_jwt(
|
|
907
974
|
}
|
908
975
|
}
|
909
976
|
|
910
|
-
export async function handle_blob(
|
911
|
-
endpoint: string,
|
912
|
-
data: unknown[],
|
913
|
-
api_info,
|
914
|
-
token?: `hf_${string}`
|
915
|
-
): Promise<unknown[]> {
|
916
|
-
const blob_refs = await walk_and_store_blobs(
|
917
|
-
data,
|
918
|
-
undefined,
|
919
|
-
[],
|
920
|
-
true,
|
921
|
-
api_info
|
922
|
-
);
|
923
|
-
|
924
|
-
return new Promise((res) => {
|
925
|
-
Promise.all(
|
926
|
-
blob_refs.map(async ({ path, blob, data, type }) => {
|
927
|
-
if (blob) {
|
928
|
-
const file_url = (await upload_files(endpoint, [blob], token))
|
929
|
-
.files[0];
|
930
|
-
return { path, file_url, type };
|
931
|
-
} else {
|
932
|
-
return { path, base64: data, type };
|
933
|
-
}
|
934
|
-
})
|
935
|
-
)
|
936
|
-
.then((r) => {
|
937
|
-
r.forEach(({ path, file_url, base64, type }) => {
|
938
|
-
if (base64) {
|
939
|
-
update_object(data, base64, path);
|
940
|
-
} else if (type === "Gallery") {
|
941
|
-
update_object(data, file_url, path);
|
942
|
-
} else if (file_url) {
|
943
|
-
const o = {
|
944
|
-
is_file: true,
|
945
|
-
name: `${file_url}`,
|
946
|
-
data: null
|
947
|
-
// orig_name: "file.csv"
|
948
|
-
};
|
949
|
-
update_object(data, o, path);
|
950
|
-
}
|
951
|
-
});
|
952
|
-
|
953
|
-
res(data);
|
954
|
-
})
|
955
|
-
.catch(console.log);
|
956
|
-
});
|
957
|
-
}
|
958
|
-
|
959
977
|
function update_object(object, newValue, stack) {
|
960
978
|
while (stack.length > 1) {
|
961
979
|
object = object[stack.shift()];
|
@@ -1061,6 +1079,7 @@ function skip_queue(id: number, config: Config) {
|
|
1061
1079
|
}
|
1062
1080
|
|
1063
1081
|
async function resolve_config(
|
1082
|
+
fetch_implementation: typeof fetch,
|
1064
1083
|
endpoint?: string,
|
1065
1084
|
token?: `hf_${string}`
|
1066
1085
|
): Promise<Config> {
|
@@ -1078,7 +1097,9 @@ async function resolve_config(
|
|
1078
1097
|
config.root = endpoint + config.root;
|
1079
1098
|
return { ...config, path: path };
|
1080
1099
|
} else if (endpoint) {
|
1081
|
-
let response = await
|
1100
|
+
let response = await fetch_implementation(`${endpoint}/config`, {
|
1101
|
+
headers
|
1102
|
+
});
|
1082
1103
|
|
1083
1104
|
if (response.status === 200) {
|
1084
1105
|
const config = await response.json();
|
@@ -1139,9 +1160,18 @@ async function check_space_status(
|
|
1139
1160
|
|
1140
1161
|
setTimeout(() => {
|
1141
1162
|
check_space_status(id, type, status_callback);
|
1142
|
-
}, 1000);
|
1163
|
+
}, 1000); // poll for status
|
1164
|
+
break;
|
1165
|
+
case "PAUSED":
|
1166
|
+
status_callback({
|
1167
|
+
status: "paused",
|
1168
|
+
load_status: "error",
|
1169
|
+
message:
|
1170
|
+
"This space has been paused by the author. If you would like to try this demo, consider duplicating the space.",
|
1171
|
+
detail: stage,
|
1172
|
+
discussions_enabled: await discussions_enabled(space_name)
|
1173
|
+
});
|
1143
1174
|
break;
|
1144
|
-
// poll for status
|
1145
1175
|
case "RUNNING":
|
1146
1176
|
case "RUNNING_BUILDING":
|
1147
1177
|
status_callback({
|