@gradio/client 2.3.1 → 2.5.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 +21 -0
- package/README.md +4 -2
- package/dist/__vite-browser-external-Cgmn0awE.js +7 -0
- package/dist/browser.js +1949 -1963
- package/dist/client.d.ts +5 -0
- package/dist/client.d.ts.map +1 -1
- package/dist/constants.d.ts +4 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/helpers/api_info.d.ts.map +1 -1
- package/dist/helpers/data.d.ts.map +1 -1
- package/dist/helpers/init_helpers.d.ts +11 -2
- package/dist/helpers/init_helpers.d.ts.map +1 -1
- package/dist/index.cjs +2584 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2471 -2466
- package/dist/index.min.js +1962 -0
- package/dist/types.d.ts +29 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/duplicate.d.ts.map +1 -1
- package/dist/utils/predict.d.ts.map +1 -1
- package/dist/utils/run_history.d.ts +64 -0
- package/dist/utils/run_history.d.ts.map +1 -0
- package/dist/utils/stream.d.ts.map +1 -1
- package/dist/utils/submit.d.ts.map +1 -1
- package/package.json +11 -4
- package/scripts/verify_dist.mjs +46 -0
- package/src/client.ts +54 -5
- package/src/constants.ts +10 -0
- package/src/helpers/api_info.ts +46 -19
- package/src/helpers/data.ts +8 -3
- package/src/helpers/init_helpers.ts +54 -7
- package/src/index.ts +12 -0
- package/src/test/api_info.test.ts +77 -12
- package/src/test/data.test.ts +26 -3
- package/src/test/init.test.ts +21 -3
- package/src/test/init_helpers.test.ts +67 -1
- package/src/test/refresh.test.ts +31 -0
- package/src/test/run_history.test.ts +345 -0
- package/src/test/submit.test.ts +1 -3
- package/src/types.ts +29 -0
- package/src/utils/duplicate.ts +2 -0
- package/src/utils/predict.ts +14 -1
- package/src/utils/run_history.ts +520 -0
- package/src/utils/stream.ts +17 -4
- package/src/utils/submit.ts +105 -12
- package/vite.config.ts +20 -4
- package/dist/__vite-browser-external-DYxpcVy9.js +0 -4
package/dist/index.js
CHANGED
|
@@ -1,2561 +1,2566 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
1
|
+
//#region src/constants.ts
|
|
2
|
+
var HOST_URL = `host`;
|
|
3
|
+
var SSE_URL = `queue/data`;
|
|
4
|
+
var SSE_DATA_URL = `queue/join`;
|
|
5
|
+
var UPLOAD_URL = `upload`;
|
|
6
|
+
var LOGIN_URL = `login`;
|
|
7
|
+
var CONFIG_URL = `config`;
|
|
8
|
+
var API_INFO_URL = `info`;
|
|
9
|
+
var RUNTIME_URL = `runtime`;
|
|
10
|
+
var SLEEPTIME_URL = `sleeptime`;
|
|
11
|
+
var HEARTBEAT_URL = `heartbeat`;
|
|
12
|
+
var COMPONENT_SERVER_URL = `component_server`;
|
|
13
|
+
var RESET_URL = `reset`;
|
|
14
|
+
var CANCEL_URL = `cancel`;
|
|
15
|
+
var APP_ID_URL = `app_id`;
|
|
16
|
+
var QUEUE_FULL_MSG = "This application is currently busy. Please try again. ";
|
|
17
|
+
var BROKEN_CONNECTION_MSG = "Connection errored out. ";
|
|
18
|
+
var CONFIG_ERROR_MSG = "Could not resolve app config. ";
|
|
19
|
+
var SPACE_STATUS_ERROR_MSG = "Could not get space status. ";
|
|
20
|
+
var API_INFO_ERROR_MSG = "Could not get API info. ";
|
|
21
|
+
var SPACE_METADATA_ERROR_MSG = "Space metadata could not be loaded. ";
|
|
22
|
+
var INVALID_URL_MSG = "Invalid URL. A full URL path is required.";
|
|
23
|
+
var UNAUTHORIZED_MSG = "Not authorized to access this space. ";
|
|
24
|
+
var INVALID_CREDENTIALS_MSG = "Invalid credentials. Could not login. ";
|
|
25
|
+
var MISSING_CREDENTIALS_MSG = "Login credentials are required to access this space.";
|
|
26
|
+
var PRIVATE_SPACE_MSG = "Could not access this app (received a 401 response). If it is a private Hugging Face Space, pass a valid Hugging Face token to the `token` option of `Client.connect`. You can generate a token at https://huggingface.co/settings/tokens.";
|
|
27
|
+
var SPACE_NOT_FOUND_MSG = (space, status) => `Space "${space}" could not be accessed (received a ${status} response from the Hugging Face API). Check that the Space name is spelled correctly and that the Space exists. If the Space is private, pass a valid Hugging Face token to the \`token\` option of \`Client.connect\`. You can generate a token at https://huggingface.co/settings/tokens.`;
|
|
28
|
+
var NO_API_INFO_MSG = "No API information is available for this app. This can happen when the app's `/info` endpoint cannot be reached, or when the app is running a legacy version of Gradio that is not supported by this client. ";
|
|
29
|
+
var WS_PROTOCOL_MSG = "This app appears to be running a legacy version of Gradio (3.x or earlier) that communicates over WebSockets, which is not supported by this version of @gradio/client. Please upgrade the app to a newer version of Gradio, or connect to it with @gradio/client version 0.x.";
|
|
30
|
+
var NODEJS_FS_ERROR_MSG = "File system access is only available in Node.js environments";
|
|
31
|
+
var ROOT_URL_ERROR_MSG = "Root URL not found in client config";
|
|
32
|
+
var FILE_PROCESSING_ERROR_MSG = "Error uploading file";
|
|
33
|
+
//#endregion
|
|
34
|
+
//#region src/helpers/init_helpers.ts
|
|
28
35
|
async function get_jwt(space, token, cookies) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
36
|
+
try {
|
|
37
|
+
return (await (await fetch(`https://huggingface.co/api/spaces/${space}/jwt`, { headers: {
|
|
38
|
+
Authorization: `Bearer ${token}`,
|
|
39
|
+
...cookies ? { Cookie: cookies } : {}
|
|
40
|
+
} })).json()).token || false;
|
|
41
|
+
} catch (e) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The `hf_token` option was renamed to `token`, but a lot of existing code
|
|
47
|
+
* (and the Python client) still uses `hf_token`. Accept it as an alias so
|
|
48
|
+
* that authenticated requests are not silently sent without credentials,
|
|
49
|
+
* which previously surfaced as "Could not resolve app config" errors when
|
|
50
|
+
* connecting to private Spaces.
|
|
51
|
+
*/
|
|
52
|
+
function normalise_token_option(options) {
|
|
53
|
+
if (options.hf_token && !options.token) {
|
|
54
|
+
options.token = options.hf_token;
|
|
55
|
+
console.warn("The `hf_token` option has been renamed to `token`. Support for `hf_token` will be removed in a future version of @gradio/client.");
|
|
56
|
+
}
|
|
41
57
|
}
|
|
42
58
|
function map_names_to_ids(fns) {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
}
|
|
87
|
-
throw new Error(CONFIG_ERROR_MSG);
|
|
59
|
+
let apis = {};
|
|
60
|
+
fns.forEach(({ api_name, id }) => {
|
|
61
|
+
if (api_name) apis[api_name] = id;
|
|
62
|
+
});
|
|
63
|
+
return apis;
|
|
64
|
+
}
|
|
65
|
+
function resolve_config_root(root, current_location) {
|
|
66
|
+
const root_url = new URL(root, current_location);
|
|
67
|
+
const current_url = new URL(current_location);
|
|
68
|
+
if (root_url.hostname !== current_url.hostname) return root;
|
|
69
|
+
root_url.protocol = current_url.protocol;
|
|
70
|
+
root_url.host = current_url.host;
|
|
71
|
+
return root_url.toString().replace(/\/$/, "");
|
|
72
|
+
}
|
|
73
|
+
async function resolve_config(endpoint, strip_current_page = true) {
|
|
74
|
+
const headers = this.options.token ? { Authorization: `Bearer ${this.options.token}` } : {};
|
|
75
|
+
if (typeof window !== "undefined" && window.gradio_config && location.origin !== "http://localhost:9876") {
|
|
76
|
+
if (strip_current_page && window.gradio_config.current_page) endpoint = endpoint.substring(0, endpoint.lastIndexOf("/"));
|
|
77
|
+
if (window.gradio_config.dev_mode || typeof window !== "undefined" && window?.BUILD_MODE === "dev") {
|
|
78
|
+
let config_url = join_urls(endpoint, this.deep_link ? CONFIG_URL + "?deep_link=" + this.deep_link : CONFIG_URL);
|
|
79
|
+
const config = await handleConfigResponse(await this.fetch(config_url, {
|
|
80
|
+
headers,
|
|
81
|
+
credentials: this.options.credentials ?? "same-origin"
|
|
82
|
+
}), !!this.options.auth);
|
|
83
|
+
config.root = endpoint || config.root;
|
|
84
|
+
window.gradio_config = {
|
|
85
|
+
...config,
|
|
86
|
+
current_page: window.gradio_config.current_page
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
const config = { ...window.gradio_config };
|
|
90
|
+
config.root = resolve_config_root(config.root, location.href);
|
|
91
|
+
return config;
|
|
92
|
+
} else if (endpoint) {
|
|
93
|
+
let config_url = join_urls(endpoint, this.deep_link ? CONFIG_URL + "?deep_link=" + this.deep_link : CONFIG_URL);
|
|
94
|
+
const config = await handleConfigResponse(await this.fetch(config_url, {
|
|
95
|
+
headers,
|
|
96
|
+
credentials: this.options.credentials ?? "same-origin"
|
|
97
|
+
}), !!this.options.auth);
|
|
98
|
+
if (!config.root) config.root = endpoint;
|
|
99
|
+
return config;
|
|
100
|
+
}
|
|
101
|
+
throw new Error(CONFIG_ERROR_MSG);
|
|
88
102
|
}
|
|
89
103
|
async function handleConfigResponse(response, authorized) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
throw new Error(CONFIG_ERROR_MSG);
|
|
104
|
+
if (response?.status === 401 && !authorized) {
|
|
105
|
+
let error_data = null;
|
|
106
|
+
try {
|
|
107
|
+
error_data = await response.json();
|
|
108
|
+
} catch (e) {
|
|
109
|
+
throw new Error(PRIVATE_SPACE_MSG);
|
|
110
|
+
}
|
|
111
|
+
const auth_message = error_data?.detail?.auth_message;
|
|
112
|
+
throw new Error(auth_message || "Login credentials are required to access this space.");
|
|
113
|
+
} else if (response?.status === 401 && authorized) throw new Error(INVALID_CREDENTIALS_MSG);
|
|
114
|
+
if (response?.status === 200) {
|
|
115
|
+
let config = await response.json();
|
|
116
|
+
config.dependencies?.forEach((dep, i) => {
|
|
117
|
+
if (dep.id === void 0) dep.id = i;
|
|
118
|
+
});
|
|
119
|
+
return config;
|
|
120
|
+
} else if (response?.status === 401) throw new Error(UNAUTHORIZED_MSG);
|
|
121
|
+
throw new Error(`${CONFIG_ERROR_MSG}(received status ${response?.status} when fetching the app config)`);
|
|
109
122
|
}
|
|
110
123
|
async function resolve_cookies() {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
this.options.auth,
|
|
121
|
-
this.fetch,
|
|
122
|
-
this.options.token,
|
|
123
|
-
this.options.credentials
|
|
124
|
-
);
|
|
125
|
-
if (cookie_header) this.set_cookies(cookie_header);
|
|
126
|
-
}
|
|
127
|
-
} catch (e) {
|
|
128
|
-
throw Error(e.message);
|
|
129
|
-
}
|
|
124
|
+
const { http_protocol, host } = await process_endpoint(this.app_reference, this.options.token);
|
|
125
|
+
try {
|
|
126
|
+
if (this.options.auth) {
|
|
127
|
+
const cookie_header = await get_cookie_header(http_protocol, host, this.options.auth, this.fetch, this.options.token, this.options.credentials);
|
|
128
|
+
if (cookie_header) this.set_cookies(cookie_header);
|
|
129
|
+
}
|
|
130
|
+
} catch (e) {
|
|
131
|
+
throw Error(e.message);
|
|
132
|
+
}
|
|
130
133
|
}
|
|
131
134
|
async function get_cookie_header(http_protocol, host, auth, _fetch, token, credentials) {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
return res.headers.get("set-cookie");
|
|
147
|
-
} else if (res.status === 401) {
|
|
148
|
-
throw new Error(INVALID_CREDENTIALS_MSG);
|
|
149
|
-
} else {
|
|
150
|
-
throw new Error(SPACE_METADATA_ERROR_MSG);
|
|
151
|
-
}
|
|
135
|
+
const formData = new FormData();
|
|
136
|
+
formData.append("username", auth?.[0]);
|
|
137
|
+
formData.append("password", auth?.[1]);
|
|
138
|
+
let headers = {};
|
|
139
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
140
|
+
const res = await _fetch(`${http_protocol}//${host}/${LOGIN_URL}`, {
|
|
141
|
+
headers,
|
|
142
|
+
method: "POST",
|
|
143
|
+
body: formData,
|
|
144
|
+
credentials: credentials ?? "same-origin"
|
|
145
|
+
});
|
|
146
|
+
if (res.status === 200) return res.headers.get("set-cookie");
|
|
147
|
+
else if (res.status === 401) throw new Error(INVALID_CREDENTIALS_MSG);
|
|
148
|
+
else throw new Error(SPACE_METADATA_ERROR_MSG);
|
|
152
149
|
}
|
|
153
150
|
function determine_protocol(endpoint) {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
}
|
|
176
|
-
});
|
|
177
|
-
return cookies;
|
|
151
|
+
if (endpoint.startsWith("http")) {
|
|
152
|
+
const { protocol, host, pathname } = new URL(endpoint);
|
|
153
|
+
return {
|
|
154
|
+
ws_protocol: protocol === "https:" ? "wss" : "ws",
|
|
155
|
+
http_protocol: protocol,
|
|
156
|
+
host: host + (pathname !== "/" ? pathname : "")
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
return {
|
|
160
|
+
ws_protocol: "wss",
|
|
161
|
+
http_protocol: "https:",
|
|
162
|
+
host: new URL(endpoint).host
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
var parse_and_set_cookies = (cookie_header) => {
|
|
166
|
+
let cookies = [];
|
|
167
|
+
cookie_header.split(/,(?=\s*[^\s=;]+=[^\s=;]+)/).forEach((cookie) => {
|
|
168
|
+
const [cookie_name, cookie_value] = cookie.split(";")[0].split("=");
|
|
169
|
+
if (cookie_name && cookie_value) cookies.push(`${cookie_name.trim()}=${cookie_value.trim()}`);
|
|
170
|
+
});
|
|
171
|
+
return cookies;
|
|
178
172
|
};
|
|
179
|
-
|
|
180
|
-
|
|
173
|
+
//#endregion
|
|
174
|
+
//#region src/helpers/api_info.ts
|
|
175
|
+
var RE_SPACE_NAME = /^[a-zA-Z0-9_\-\.]+\/[a-zA-Z0-9_\-\.]+$/;
|
|
176
|
+
var RE_SPACE_DOMAIN = /.*hf\.space\/{0,1}.*$/;
|
|
181
177
|
async function process_endpoint(app_reference, token) {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
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
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
178
|
+
const headers = {};
|
|
179
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
180
|
+
const _app_reference = app_reference.trim().replace(/\/$/, "");
|
|
181
|
+
if (RE_SPACE_NAME.test(_app_reference)) {
|
|
182
|
+
let res;
|
|
183
|
+
try {
|
|
184
|
+
res = await fetch(`https://huggingface.co/api/spaces/${_app_reference}/${HOST_URL}`, { headers });
|
|
185
|
+
} catch (e) {
|
|
186
|
+
throw new Error(SPACE_METADATA_ERROR_MSG);
|
|
187
|
+
}
|
|
188
|
+
if (res.status === 401 || res.status === 404) throw new Error(SPACE_NOT_FOUND_MSG(_app_reference, res.status));
|
|
189
|
+
let _host;
|
|
190
|
+
try {
|
|
191
|
+
_host = (await res.json()).host;
|
|
192
|
+
} catch (e) {
|
|
193
|
+
throw new Error(SPACE_METADATA_ERROR_MSG);
|
|
194
|
+
}
|
|
195
|
+
if (!_host) throw new Error(SPACE_METADATA_ERROR_MSG);
|
|
196
|
+
return {
|
|
197
|
+
space_id: _app_reference,
|
|
198
|
+
...determine_protocol(_host)
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
if (RE_SPACE_DOMAIN.test(_app_reference)) {
|
|
202
|
+
const { ws_protocol, http_protocol, host } = determine_protocol(_app_reference);
|
|
203
|
+
return {
|
|
204
|
+
space_id: host.split("/")[0].replace(".hf.space", ""),
|
|
205
|
+
ws_protocol,
|
|
206
|
+
http_protocol,
|
|
207
|
+
host
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
space_id: false,
|
|
212
|
+
...determine_protocol(_app_reference)
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
var join_urls = (...urls) => {
|
|
216
|
+
try {
|
|
217
|
+
return urls.reduce((base_url, part) => {
|
|
218
|
+
base_url = base_url.replace(/\/+$/, "");
|
|
219
|
+
part = part.replace(/^\/+/, "");
|
|
220
|
+
return new URL(part, base_url + "/").toString();
|
|
221
|
+
});
|
|
222
|
+
} catch (e) {
|
|
223
|
+
throw new Error(INVALID_URL_MSG);
|
|
224
|
+
}
|
|
226
225
|
};
|
|
227
226
|
function transform_api_info(api_info, config, api_map) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
};
|
|
277
|
-
}
|
|
278
|
-
);
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
return transformed_info;
|
|
227
|
+
const transformed_info = {
|
|
228
|
+
named_endpoints: {},
|
|
229
|
+
unnamed_endpoints: {}
|
|
230
|
+
};
|
|
231
|
+
Object.keys(api_info).forEach((category) => {
|
|
232
|
+
if (category === "named_endpoints" || category === "unnamed_endpoints") {
|
|
233
|
+
transformed_info[category] = {};
|
|
234
|
+
Object.entries(api_info[category]).forEach(([endpoint, endpoint_info]) => {
|
|
235
|
+
const parameters = endpoint_info?.parameters ?? [];
|
|
236
|
+
const returns = endpoint_info?.returns ?? [];
|
|
237
|
+
const dependencyIndex = config.dependencies.find((dep) => dep.api_name === endpoint || dep.api_name === endpoint.replace("/", ""))?.id || api_map[endpoint.replace("/", "")] || -1;
|
|
238
|
+
const dependency = dependencyIndex !== -1 ? config.dependencies.find((dep) => dep.id == dependencyIndex) : void 0;
|
|
239
|
+
const dependencyTypes = dependencyIndex !== -1 ? dependency?.types : {
|
|
240
|
+
generator: false,
|
|
241
|
+
cancel: false
|
|
242
|
+
};
|
|
243
|
+
if (dependency && Array.isArray(dependency.inputs) && dependency.inputs.length !== parameters.length) {
|
|
244
|
+
const components = dependency.inputs.map((input) => config.components.find((c) => c.id === input)?.type);
|
|
245
|
+
try {
|
|
246
|
+
components.forEach((comp, idx) => {
|
|
247
|
+
if (comp === "state") parameters.splice(idx, 0, {
|
|
248
|
+
component: "state",
|
|
249
|
+
example: null,
|
|
250
|
+
parameter_default: null,
|
|
251
|
+
parameter_has_default: true,
|
|
252
|
+
parameter_name: null,
|
|
253
|
+
hidden: true
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
} catch (e) {
|
|
257
|
+
console.error(e);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
const transform_type = (data, component, serializer, signature_type) => ({
|
|
261
|
+
...data,
|
|
262
|
+
description: get_description(data?.type, serializer),
|
|
263
|
+
type: get_type(data?.type, component, serializer, signature_type) || ""
|
|
264
|
+
});
|
|
265
|
+
transformed_info[category][endpoint] = {
|
|
266
|
+
parameters: parameters.map((p) => transform_type(p, p?.component, p?.serializer, "parameter")),
|
|
267
|
+
returns: returns.map((r) => transform_type(r, r?.component, r?.serializer, "return")),
|
|
268
|
+
type: dependencyTypes,
|
|
269
|
+
...endpoint_info?.oauth_token ? { oauth_token: endpoint_info.oauth_token } : {}
|
|
270
|
+
};
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
return transformed_info;
|
|
282
275
|
}
|
|
283
276
|
function get_type(type, component, serializer, signature_type) {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
} else if (component === "Image") {
|
|
298
|
-
return signature_type === "parameter" ? "Blob | File | Buffer" : "string";
|
|
299
|
-
} else if (serializer === "FileSerializable") {
|
|
300
|
-
if (type?.type === "array") {
|
|
301
|
-
return signature_type === "parameter" ? "(Blob | File | Buffer)[]" : `{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}[]`;
|
|
302
|
-
}
|
|
303
|
-
return signature_type === "parameter" ? "Blob | File | Buffer" : `{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}`;
|
|
304
|
-
} else if (serializer === "GallerySerializable") {
|
|
305
|
-
return signature_type === "parameter" ? "[(Blob | File | Buffer), (string | null)][]" : `[{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}, (string | null))][]`;
|
|
306
|
-
}
|
|
277
|
+
if (component === "Api") return type.type;
|
|
278
|
+
switch (type?.type) {
|
|
279
|
+
case "string": return "string";
|
|
280
|
+
case "boolean": return "boolean";
|
|
281
|
+
case "number": return "number";
|
|
282
|
+
}
|
|
283
|
+
if (serializer === "JSONSerializable" || serializer === "StringSerializable") return "any";
|
|
284
|
+
else if (serializer === "ListStringSerializable") return "string[]";
|
|
285
|
+
else if (component === "Image") return signature_type === "parameter" ? "Blob | File | Buffer" : "string";
|
|
286
|
+
else if (serializer === "FileSerializable") {
|
|
287
|
+
if (type?.type === "array") return signature_type === "parameter" ? "(Blob | File | Buffer)[]" : `{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}[]`;
|
|
288
|
+
return signature_type === "parameter" ? "Blob | File | Buffer" : `{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}`;
|
|
289
|
+
} else if (serializer === "GallerySerializable") return signature_type === "parameter" ? "[(Blob | File | Buffer), (string | null)][]" : `[{ name: string; data: string; size?: number; is_file?: boolean; orig_name?: string}, (string | null))][]`;
|
|
307
290
|
}
|
|
308
291
|
function get_description(type, serializer) {
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
} else if (serializer === "FileSerializable") {
|
|
314
|
-
return "array of files or single file";
|
|
315
|
-
}
|
|
316
|
-
return type?.description;
|
|
292
|
+
if (serializer === "GallerySerializable") return "array of [file, label] tuples";
|
|
293
|
+
else if (serializer === "ListStringSerializable") return "array of strings";
|
|
294
|
+
else if (serializer === "FileSerializable") return "array of files or single file";
|
|
295
|
+
return type?.description;
|
|
317
296
|
}
|
|
318
297
|
function handle_message(data, last_status) {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
});
|
|
499
|
-
return resolved_data;
|
|
298
|
+
const queue = true;
|
|
299
|
+
switch (data.msg) {
|
|
300
|
+
case "send_data": return { type: "data" };
|
|
301
|
+
case "send_hash": return { type: "hash" };
|
|
302
|
+
case "queue_full": return {
|
|
303
|
+
type: "update",
|
|
304
|
+
status: {
|
|
305
|
+
queue,
|
|
306
|
+
message: QUEUE_FULL_MSG,
|
|
307
|
+
stage: "error",
|
|
308
|
+
code: data.code,
|
|
309
|
+
success: data.success
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
case "heartbeat": return { type: "heartbeat" };
|
|
313
|
+
case "unexpected_error": return {
|
|
314
|
+
type: "unexpected_error",
|
|
315
|
+
status: {
|
|
316
|
+
queue,
|
|
317
|
+
message: data.message,
|
|
318
|
+
session_not_found: data.session_not_found,
|
|
319
|
+
stage: "error",
|
|
320
|
+
success: false
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
case "broken_connection": return {
|
|
324
|
+
type: "broken_connection",
|
|
325
|
+
status: {
|
|
326
|
+
queue,
|
|
327
|
+
message: data.message,
|
|
328
|
+
stage: "error",
|
|
329
|
+
success: false
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
case "estimation": return {
|
|
333
|
+
type: "update",
|
|
334
|
+
status: {
|
|
335
|
+
queue,
|
|
336
|
+
stage: last_status || "pending",
|
|
337
|
+
code: data.code,
|
|
338
|
+
size: data.queue_size,
|
|
339
|
+
position: data.rank,
|
|
340
|
+
eta: data.rank_eta,
|
|
341
|
+
success: data.success
|
|
342
|
+
}
|
|
343
|
+
};
|
|
344
|
+
case "progress": return {
|
|
345
|
+
type: "update",
|
|
346
|
+
status: {
|
|
347
|
+
queue,
|
|
348
|
+
stage: "pending",
|
|
349
|
+
code: data.code,
|
|
350
|
+
progress_data: data.progress_data,
|
|
351
|
+
success: data.success
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
case "log": return {
|
|
355
|
+
type: "log",
|
|
356
|
+
data
|
|
357
|
+
};
|
|
358
|
+
case "process_generating": return {
|
|
359
|
+
type: "generating",
|
|
360
|
+
status: {
|
|
361
|
+
queue,
|
|
362
|
+
message: !data.success ? data.output.error : null,
|
|
363
|
+
stage: data.success ? "generating" : "error",
|
|
364
|
+
code: data.code,
|
|
365
|
+
progress_data: data.progress_data,
|
|
366
|
+
eta: data.average_duration,
|
|
367
|
+
changed_state_ids: data.success ? data.output.changed_state_ids : void 0
|
|
368
|
+
},
|
|
369
|
+
data: data.success ? data.output : null
|
|
370
|
+
};
|
|
371
|
+
case "process_streaming": return {
|
|
372
|
+
type: "streaming",
|
|
373
|
+
status: {
|
|
374
|
+
queue,
|
|
375
|
+
message: data.output.error,
|
|
376
|
+
stage: "streaming",
|
|
377
|
+
time_limit: data.time_limit,
|
|
378
|
+
code: data.code,
|
|
379
|
+
progress_data: data.progress_data,
|
|
380
|
+
changed_state_ids: data.output.changed_state_ids,
|
|
381
|
+
eta: data.eta
|
|
382
|
+
},
|
|
383
|
+
data: data.output
|
|
384
|
+
};
|
|
385
|
+
case "process_completed":
|
|
386
|
+
if ("error" in data.output) return {
|
|
387
|
+
type: "update",
|
|
388
|
+
status: {
|
|
389
|
+
queue,
|
|
390
|
+
title: data.output.title ?? "Error",
|
|
391
|
+
message: data.output.error ?? "An error occurred",
|
|
392
|
+
visible: data.output.visible,
|
|
393
|
+
duration: data.output.duration,
|
|
394
|
+
stage: "error",
|
|
395
|
+
code: data.code,
|
|
396
|
+
success: data.success
|
|
397
|
+
}
|
|
398
|
+
};
|
|
399
|
+
return {
|
|
400
|
+
type: "complete",
|
|
401
|
+
status: {
|
|
402
|
+
queue,
|
|
403
|
+
message: !data.success ? data.output.error : void 0,
|
|
404
|
+
stage: data.success ? "complete" : "error",
|
|
405
|
+
code: data.code,
|
|
406
|
+
progress_data: data.progress_data,
|
|
407
|
+
changed_state_ids: data.success ? data.output.changed_state_ids : void 0,
|
|
408
|
+
used_cache: data.used_cache,
|
|
409
|
+
cache_duration: data.cache_duration,
|
|
410
|
+
avg_time: data.avg_time
|
|
411
|
+
},
|
|
412
|
+
data: data.success ? data.output : null
|
|
413
|
+
};
|
|
414
|
+
case "process_starts": return {
|
|
415
|
+
type: "update",
|
|
416
|
+
status: {
|
|
417
|
+
queue,
|
|
418
|
+
stage: "pending",
|
|
419
|
+
code: data.code,
|
|
420
|
+
size: data.rank,
|
|
421
|
+
position: 0,
|
|
422
|
+
success: data.success,
|
|
423
|
+
eta: data.eta
|
|
424
|
+
},
|
|
425
|
+
original_msg: "process_starts"
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
return {
|
|
429
|
+
type: "none",
|
|
430
|
+
status: {
|
|
431
|
+
stage: "error",
|
|
432
|
+
queue
|
|
433
|
+
}
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Maps the provided `data` to the parameters defined by the `/info` endpoint response.
|
|
438
|
+
* This allows us to support both positional and keyword arguments passed to the client
|
|
439
|
+
* and ensures that all parameters are either directly provided or have default values assigned.
|
|
440
|
+
*
|
|
441
|
+
* @param {unknown[] | Record<string, unknown>} data - The input data for the function,
|
|
442
|
+
* which can be either an array of values for positional arguments or an object
|
|
443
|
+
* with key-value pairs for keyword arguments.
|
|
444
|
+
* @param {JsApiData[]} parameters - Array of parameter descriptions retrieved from the
|
|
445
|
+
* `/info` endpoint.
|
|
446
|
+
*
|
|
447
|
+
* @returns {unknown[]} - Returns an array of resolved data where each element corresponds
|
|
448
|
+
* to the expected parameter from the API. The `parameter_default` value is used where
|
|
449
|
+
* a value is not provided for a parameter, and optional parameters without defaults are
|
|
450
|
+
* set to `undefined`.
|
|
451
|
+
*
|
|
452
|
+
* @throws {Error} - Throws an error:
|
|
453
|
+
* - If more arguments are provided than are defined in the parameters.
|
|
454
|
+
* * - If no parameter value is provided for a required parameter and no default value is defined.
|
|
455
|
+
* - If an argument is provided that does not match any defined parameter.
|
|
456
|
+
*/
|
|
457
|
+
var map_data_to_params = (data = [], endpoint_info) => {
|
|
458
|
+
const parameters = endpoint_info ? endpoint_info.parameters : [];
|
|
459
|
+
if (Array.isArray(data)) {
|
|
460
|
+
if (endpoint_info && parameters.length > 0 && data.length > parameters.length) console.warn("Too many arguments provided for the endpoint.");
|
|
461
|
+
return data;
|
|
462
|
+
}
|
|
463
|
+
const resolved_data = [];
|
|
464
|
+
const provided_keys = Object.keys(data);
|
|
465
|
+
parameters.forEach((param, index) => {
|
|
466
|
+
if (data.hasOwnProperty(param.parameter_name)) resolved_data[index] = data[param.parameter_name];
|
|
467
|
+
else if (param.parameter_has_default) resolved_data[index] = param.parameter_default;
|
|
468
|
+
else throw new Error(`No value provided for required parameter: ${param.parameter_name}`);
|
|
469
|
+
});
|
|
470
|
+
provided_keys.forEach((key) => {
|
|
471
|
+
if (!parameters.some((param) => param.parameter_name === key)) throw new Error(`Parameter \`${key}\` is not a valid keyword argument. Please refer to the API for usage.`);
|
|
472
|
+
});
|
|
473
|
+
resolved_data.forEach((value, idx) => {
|
|
474
|
+
if (value === void 0 && !parameters[idx].parameter_has_default) throw new Error(`No value provided for required parameter: ${parameters[idx].parameter_name}`);
|
|
475
|
+
});
|
|
476
|
+
return resolved_data;
|
|
500
477
|
};
|
|
478
|
+
//#endregion
|
|
479
|
+
//#region src/utils/view_api.ts
|
|
501
480
|
async function view_api() {
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
}
|
|
528
|
-
if ("api" in api_info) {
|
|
529
|
-
api_info = api_info.api;
|
|
530
|
-
}
|
|
531
|
-
if (api_info.named_endpoints["/predict"] && !api_info.unnamed_endpoints["0"]) {
|
|
532
|
-
api_info.unnamed_endpoints[0] = api_info.named_endpoints["/predict"];
|
|
533
|
-
}
|
|
534
|
-
return transform_api_info(api_info, config, this.api_map);
|
|
535
|
-
} catch (e) {
|
|
536
|
-
throw new Error("Could not get API info. " + e.message);
|
|
537
|
-
}
|
|
481
|
+
if (this.api_info) return this.api_info;
|
|
482
|
+
const { token } = this.options;
|
|
483
|
+
const { config } = this;
|
|
484
|
+
const headers = {};
|
|
485
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
486
|
+
if (!config) return;
|
|
487
|
+
try {
|
|
488
|
+
let response;
|
|
489
|
+
let api_info;
|
|
490
|
+
if (typeof window !== "undefined" && window.gradio_api_info) api_info = window.gradio_api_info;
|
|
491
|
+
else {
|
|
492
|
+
const url = join_urls(config.root, this.api_prefix, API_INFO_URL);
|
|
493
|
+
response = await this.fetch(url, {
|
|
494
|
+
headers,
|
|
495
|
+
credentials: this.options.credentials ?? "same-origin"
|
|
496
|
+
});
|
|
497
|
+
if (!response.ok) throw new Error(BROKEN_CONNECTION_MSG);
|
|
498
|
+
api_info = await response.json();
|
|
499
|
+
}
|
|
500
|
+
if ("api" in api_info) api_info = api_info.api;
|
|
501
|
+
if (api_info.named_endpoints["/predict"] && !api_info.unnamed_endpoints["0"]) api_info.unnamed_endpoints[0] = api_info.named_endpoints["/predict"];
|
|
502
|
+
return transform_api_info(api_info, config, this.api_map);
|
|
503
|
+
} catch (e) {
|
|
504
|
+
throw new Error("Could not get API info. " + e.message);
|
|
505
|
+
}
|
|
538
506
|
}
|
|
507
|
+
//#endregion
|
|
508
|
+
//#region src/utils/upload_files.ts
|
|
539
509
|
async function upload_files(root_url, files, upload_id) {
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
510
|
+
const headers = {};
|
|
511
|
+
if (this?.options?.token) headers.Authorization = `Bearer ${this.options.token}`;
|
|
512
|
+
const chunkSize = 1e3;
|
|
513
|
+
const uploadResponses = [];
|
|
514
|
+
let response;
|
|
515
|
+
for (let i = 0; i < files.length; i += chunkSize) {
|
|
516
|
+
const chunk = files.slice(i, i + chunkSize);
|
|
517
|
+
const formData = new FormData();
|
|
518
|
+
chunk.forEach((file) => {
|
|
519
|
+
formData.append("files", file);
|
|
520
|
+
});
|
|
521
|
+
try {
|
|
522
|
+
const upload_url = upload_id ? `${root_url}${this.api_prefix}/${UPLOAD_URL}?upload_id=${upload_id}` : `${root_url}${this.api_prefix}/${UPLOAD_URL}`;
|
|
523
|
+
response = await this.fetch(upload_url, {
|
|
524
|
+
method: "POST",
|
|
525
|
+
body: formData,
|
|
526
|
+
headers,
|
|
527
|
+
credentials: this.options.credentials ?? "same-origin"
|
|
528
|
+
});
|
|
529
|
+
} catch (e) {
|
|
530
|
+
throw new Error(BROKEN_CONNECTION_MSG + e.message);
|
|
531
|
+
}
|
|
532
|
+
if (!response.ok) {
|
|
533
|
+
const error_text = await response.text();
|
|
534
|
+
return { error: `HTTP ${response.status}: ${error_text}` };
|
|
535
|
+
}
|
|
536
|
+
const output = await response.json();
|
|
537
|
+
if (output) uploadResponses.push(...output);
|
|
538
|
+
}
|
|
539
|
+
return { files: uploadResponses };
|
|
540
|
+
}
|
|
541
|
+
var SPECS = {
|
|
542
|
+
si: {
|
|
543
|
+
radix: 1e3,
|
|
544
|
+
unit: [
|
|
545
|
+
"b",
|
|
546
|
+
"kb",
|
|
547
|
+
"Mb",
|
|
548
|
+
"Gb",
|
|
549
|
+
"Tb",
|
|
550
|
+
"Pb",
|
|
551
|
+
"Eb",
|
|
552
|
+
"Zb",
|
|
553
|
+
"Yb"
|
|
554
|
+
]
|
|
555
|
+
},
|
|
556
|
+
iec: {
|
|
557
|
+
radix: 1024,
|
|
558
|
+
unit: [
|
|
559
|
+
"b",
|
|
560
|
+
"Kib",
|
|
561
|
+
"Mib",
|
|
562
|
+
"Gib",
|
|
563
|
+
"Tib",
|
|
564
|
+
"Pib",
|
|
565
|
+
"Eib",
|
|
566
|
+
"Zib",
|
|
567
|
+
"Yib"
|
|
568
|
+
]
|
|
569
|
+
},
|
|
570
|
+
jedec: {
|
|
571
|
+
radix: 1024,
|
|
572
|
+
unit: [
|
|
573
|
+
"b",
|
|
574
|
+
"Kb",
|
|
575
|
+
"Mb",
|
|
576
|
+
"Gb",
|
|
577
|
+
"Tb",
|
|
578
|
+
"Pb",
|
|
579
|
+
"Eb",
|
|
580
|
+
"Zb",
|
|
581
|
+
"Yb"
|
|
582
|
+
]
|
|
583
|
+
}
|
|
591
584
|
};
|
|
585
|
+
/**
|
|
586
|
+
* file size from https://github.com/hustcc/filesize.js
|
|
587
|
+
* @param bytes - The number of bytes to convert to human-readable format
|
|
588
|
+
* @param fixed - Number of decimal places to display (default: 1)
|
|
589
|
+
* @param spec - Size specification to use: "si", "iec", or "jedec" (default: "jedec")
|
|
590
|
+
* @returns Human-readable file size string
|
|
591
|
+
*/
|
|
592
592
|
function filesize(bytes, fixed = 1, spec = "jedec") {
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
593
|
+
bytes = Math.abs(bytes);
|
|
594
|
+
const { radix, unit } = SPECS[spec] || SPECS.jedec;
|
|
595
|
+
let loop = 0;
|
|
596
|
+
while (bytes >= radix) {
|
|
597
|
+
bytes /= radix;
|
|
598
|
+
++loop;
|
|
599
|
+
}
|
|
600
|
+
return `${bytes.toFixed(fixed)} ${unit[loop]}`;
|
|
601
601
|
}
|
|
602
|
+
//#endregion
|
|
603
|
+
//#region src/upload.ts
|
|
602
604
|
async function upload(file_data, root_url, upload_id, max_file_size) {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
} else {
|
|
620
|
-
if (response.files) {
|
|
621
|
-
return response.files.map((f, i) => {
|
|
622
|
-
const file = new FileData({
|
|
623
|
-
...file_data[i],
|
|
624
|
-
path: f,
|
|
625
|
-
url: `${root_url}${this.api_prefix}/file=${f}`
|
|
626
|
-
});
|
|
627
|
-
return file;
|
|
628
|
-
});
|
|
629
|
-
}
|
|
630
|
-
return [];
|
|
631
|
-
}
|
|
632
|
-
}
|
|
633
|
-
)
|
|
634
|
-
);
|
|
605
|
+
let files = (Array.isArray(file_data) ? file_data : [file_data]).map((file_data) => file_data.blob);
|
|
606
|
+
const oversized_files = files.filter((f) => f.size > (max_file_size ?? Infinity));
|
|
607
|
+
if (oversized_files.length) throw new Error(`File(s) exceed the maximum allowed size of ${filesize(max_file_size || Infinity)}: ${oversized_files.map((f) => `"${f.name}"`).join(", ")}`);
|
|
608
|
+
return await Promise.all(await this.upload_files(root_url, files, upload_id).then(async (response) => {
|
|
609
|
+
if (response.error) throw new Error(response.error);
|
|
610
|
+
else {
|
|
611
|
+
if (response.files) return response.files.map((f, i) => {
|
|
612
|
+
return new FileData({
|
|
613
|
+
...file_data[i],
|
|
614
|
+
path: f,
|
|
615
|
+
url: `${root_url}${this.api_prefix}/file=${f}`
|
|
616
|
+
});
|
|
617
|
+
});
|
|
618
|
+
return [];
|
|
619
|
+
}
|
|
620
|
+
}));
|
|
635
621
|
}
|
|
636
622
|
async function prepare_files(files, is_stream) {
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
}
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
fileData;
|
|
686
|
-
constructor(command, meta) {
|
|
687
|
-
this.type = "command";
|
|
688
|
-
this.command = command;
|
|
689
|
-
this.meta = meta;
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
const is_node = typeof process !== "undefined" && process.versions && process.versions.node;
|
|
623
|
+
return files.map((f) => new FileData({
|
|
624
|
+
path: f.name,
|
|
625
|
+
orig_name: f.name,
|
|
626
|
+
blob: f,
|
|
627
|
+
size: f.size,
|
|
628
|
+
mime_type: f.type,
|
|
629
|
+
is_stream
|
|
630
|
+
}));
|
|
631
|
+
}
|
|
632
|
+
var FileData = class {
|
|
633
|
+
path;
|
|
634
|
+
url;
|
|
635
|
+
orig_name;
|
|
636
|
+
size;
|
|
637
|
+
blob;
|
|
638
|
+
is_stream;
|
|
639
|
+
mime_type;
|
|
640
|
+
alt_text;
|
|
641
|
+
b64;
|
|
642
|
+
meta = { _type: "gradio.FileData" };
|
|
643
|
+
constructor({ path, url, orig_name, size, blob, is_stream, mime_type, alt_text, b64 }) {
|
|
644
|
+
this.path = path;
|
|
645
|
+
this.url = url;
|
|
646
|
+
this.orig_name = orig_name;
|
|
647
|
+
this.size = size;
|
|
648
|
+
this.blob = url ? void 0 : blob;
|
|
649
|
+
this.is_stream = is_stream;
|
|
650
|
+
this.mime_type = mime_type;
|
|
651
|
+
this.alt_text = alt_text;
|
|
652
|
+
this.b64 = b64;
|
|
653
|
+
}
|
|
654
|
+
};
|
|
655
|
+
//#endregion
|
|
656
|
+
//#region src/types.ts
|
|
657
|
+
var Command = class {
|
|
658
|
+
type;
|
|
659
|
+
command;
|
|
660
|
+
meta;
|
|
661
|
+
fileData;
|
|
662
|
+
constructor(command, meta) {
|
|
663
|
+
this.type = "command";
|
|
664
|
+
this.command = command;
|
|
665
|
+
this.meta = meta;
|
|
666
|
+
}
|
|
667
|
+
};
|
|
668
|
+
//#endregion
|
|
669
|
+
//#region src/helpers/data.ts
|
|
670
|
+
var is_node = typeof process !== "undefined" && process.versions && process.versions.node;
|
|
693
671
|
function update_object(object, newValue, stack) {
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
const key = stack.shift();
|
|
703
|
-
if (typeof key === "string" || typeof key === "number") {
|
|
704
|
-
object[key] = newValue;
|
|
705
|
-
} else {
|
|
706
|
-
throw new Error("Invalid key type");
|
|
707
|
-
}
|
|
672
|
+
while (stack.length > 1) {
|
|
673
|
+
const key = stack.shift();
|
|
674
|
+
if (typeof key === "string" || typeof key === "number") object = object[key];
|
|
675
|
+
else throw new Error("Invalid key type");
|
|
676
|
+
}
|
|
677
|
+
const key = stack.shift();
|
|
678
|
+
if (typeof key === "string" || typeof key === "number") object[key] = newValue;
|
|
679
|
+
else throw new Error("Invalid key type");
|
|
708
680
|
}
|
|
709
681
|
async function walk_and_store_blobs(data, type = void 0, path = [], root = false, endpoint_info = void 0) {
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
];
|
|
735
|
-
} else if (typeof data === "object" && data !== null) {
|
|
736
|
-
let blob_refs = [];
|
|
737
|
-
for (const key of Object.keys(data)) {
|
|
738
|
-
const new_path = [...path, key];
|
|
739
|
-
const value = data[key];
|
|
740
|
-
blob_refs = blob_refs.concat(
|
|
741
|
-
await walk_and_store_blobs(
|
|
742
|
-
value,
|
|
743
|
-
void 0,
|
|
744
|
-
new_path,
|
|
745
|
-
false,
|
|
746
|
-
endpoint_info
|
|
747
|
-
)
|
|
748
|
-
);
|
|
749
|
-
}
|
|
750
|
-
return blob_refs;
|
|
751
|
-
}
|
|
752
|
-
return [];
|
|
682
|
+
if (Array.isArray(data)) {
|
|
683
|
+
let blob_refs = [];
|
|
684
|
+
await Promise.all(data.map(async (_, index) => {
|
|
685
|
+
let new_path = path.slice();
|
|
686
|
+
new_path.push(String(index));
|
|
687
|
+
const array_refs = await walk_and_store_blobs(data[index], root ? endpoint_info?.parameters[index]?.component || void 0 : type, new_path, false, endpoint_info);
|
|
688
|
+
blob_refs = blob_refs.concat(array_refs);
|
|
689
|
+
}));
|
|
690
|
+
return blob_refs;
|
|
691
|
+
} else if (globalThis.Buffer && data instanceof globalThis.Buffer || data instanceof Blob) return [{
|
|
692
|
+
path,
|
|
693
|
+
blob: data instanceof Blob ? data : new Blob([data]),
|
|
694
|
+
type
|
|
695
|
+
}];
|
|
696
|
+
else if (typeof data === "object" && data !== null) {
|
|
697
|
+
let blob_refs = [];
|
|
698
|
+
for (const key of Object.keys(data)) {
|
|
699
|
+
const new_path = [...path, key];
|
|
700
|
+
const value = data[key];
|
|
701
|
+
blob_refs = blob_refs.concat(await walk_and_store_blobs(value, void 0, new_path, false, endpoint_info));
|
|
702
|
+
}
|
|
703
|
+
return blob_refs;
|
|
704
|
+
}
|
|
705
|
+
return [];
|
|
753
706
|
}
|
|
754
707
|
function skip_queue(id, config) {
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
}
|
|
759
|
-
return !config.enable_queue;
|
|
708
|
+
let fn_queue = config?.dependencies?.find((dep) => dep.id == id)?.queue;
|
|
709
|
+
if (fn_queue != null) return !fn_queue;
|
|
710
|
+
return !config.enable_queue;
|
|
760
711
|
}
|
|
761
712
|
function post_message(message, origin) {
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
713
|
+
return new Promise((res, _rej) => {
|
|
714
|
+
const channel = new MessageChannel();
|
|
715
|
+
channel.port1.onmessage = (({ data }) => {
|
|
716
|
+
channel.port1.close();
|
|
717
|
+
res(data);
|
|
718
|
+
});
|
|
719
|
+
window.parent.postMessage(message, origin, [channel.port2]);
|
|
720
|
+
});
|
|
770
721
|
}
|
|
771
722
|
function handle_file(file_or_url) {
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
} else if (typeof File !== "undefined" && file_or_url instanceof File) {
|
|
789
|
-
return new Blob([file_or_url]);
|
|
790
|
-
} else if (file_or_url instanceof Buffer) {
|
|
791
|
-
return new Blob([file_or_url]);
|
|
792
|
-
} else if (file_or_url instanceof Blob) {
|
|
793
|
-
return file_or_url;
|
|
794
|
-
}
|
|
795
|
-
throw new Error(
|
|
796
|
-
"Invalid input: must be a URL, File, Blob, or Buffer object."
|
|
797
|
-
);
|
|
723
|
+
if (typeof file_or_url === "string") {
|
|
724
|
+
if (file_or_url.startsWith("http://") || file_or_url.startsWith("https://")) return {
|
|
725
|
+
path: file_or_url,
|
|
726
|
+
url: file_or_url,
|
|
727
|
+
orig_name: file_or_url.split("/").pop() ?? "unknown",
|
|
728
|
+
meta: { _type: "gradio.FileData" }
|
|
729
|
+
};
|
|
730
|
+
if (is_node) return new Command("upload_file", {
|
|
731
|
+
path: file_or_url,
|
|
732
|
+
name: file_or_url,
|
|
733
|
+
orig_path: file_or_url
|
|
734
|
+
});
|
|
735
|
+
} else if (typeof File !== "undefined" && file_or_url instanceof File) return file_or_url;
|
|
736
|
+
else if (globalThis.Buffer && file_or_url instanceof globalThis.Buffer) return new Blob([file_or_url]);
|
|
737
|
+
else if (file_or_url instanceof Blob) return file_or_url;
|
|
738
|
+
throw new Error("Invalid input: must be a URL, File, Blob, or Buffer object.");
|
|
798
739
|
}
|
|
740
|
+
/**
|
|
741
|
+
* Handles the payload by filtering out state inputs and returning an array of resolved payload values.
|
|
742
|
+
* We send null values for state inputs to the server, but we don't want to include them in the resolved payload.
|
|
743
|
+
*
|
|
744
|
+
* @param resolved_payload - The resolved payload values received from the client or the server
|
|
745
|
+
* @param dependency - The dependency object.
|
|
746
|
+
* @param components - The array of component metadata.
|
|
747
|
+
* @param with_null_state - Optional. Specifies whether to include null values for state inputs. Default is false.
|
|
748
|
+
* @returns An array of resolved payload values, filtered based on the dependency and component metadata.
|
|
749
|
+
*/
|
|
799
750
|
function handle_payload(resolved_payload, dependency, components, type, with_null_state = false) {
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
continue;
|
|
826
|
-
} else {
|
|
827
|
-
const value = resolved_payload[payload_index];
|
|
828
|
-
updated_payload.push(value);
|
|
829
|
-
payload_index++;
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
return updated_payload;
|
|
751
|
+
if (type === "input" && !with_null_state) throw new Error("Invalid code path. Cannot skip state inputs for input.");
|
|
752
|
+
if (type === "output" && with_null_state) return resolved_payload;
|
|
753
|
+
let updated_payload = [];
|
|
754
|
+
let payload_index = 0;
|
|
755
|
+
const deps = type === "input" ? dependency.inputs : dependency.outputs;
|
|
756
|
+
for (let i = 0; i < deps.length; i++) {
|
|
757
|
+
const input_id = deps[i];
|
|
758
|
+
if (components.find((c) => c.id === input_id)?.type === "state") {
|
|
759
|
+
if (with_null_state) if (resolved_payload.length === deps.length) {
|
|
760
|
+
const value = resolved_payload[payload_index];
|
|
761
|
+
updated_payload.push(value);
|
|
762
|
+
payload_index++;
|
|
763
|
+
} else updated_payload.push(null);
|
|
764
|
+
else {
|
|
765
|
+
payload_index++;
|
|
766
|
+
continue;
|
|
767
|
+
}
|
|
768
|
+
continue;
|
|
769
|
+
} else {
|
|
770
|
+
const value = resolved_payload[payload_index];
|
|
771
|
+
updated_payload.push(value);
|
|
772
|
+
payload_index++;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
return updated_payload;
|
|
833
776
|
}
|
|
777
|
+
//#endregion
|
|
778
|
+
//#region src/utils/handle_blob.ts
|
|
834
779
|
async function handle_blob(endpoint, data, api_info) {
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
update_object(data, file, path);
|
|
863
|
-
}
|
|
864
|
-
});
|
|
865
|
-
return data;
|
|
866
|
-
}
|
|
867
|
-
async function process_local_file_commands(client2, data) {
|
|
868
|
-
const root = client2.config?.root || client2.config?.root_url;
|
|
869
|
-
if (!root) {
|
|
870
|
-
throw new Error(ROOT_URL_ERROR_MSG);
|
|
871
|
-
}
|
|
872
|
-
await recursively_process_commands(client2, data);
|
|
873
|
-
}
|
|
874
|
-
async function recursively_process_commands(client2, data, path = []) {
|
|
875
|
-
for (const key in data) {
|
|
876
|
-
if (data[key] instanceof Command) {
|
|
877
|
-
await process_single_command(client2, data, key);
|
|
878
|
-
} else if (typeof data[key] === "object" && data[key] !== null) {
|
|
879
|
-
await recursively_process_commands(client2, data[key], [...path, key]);
|
|
880
|
-
}
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
async function process_single_command(client2, data, key) {
|
|
884
|
-
let cmd_item = data[key];
|
|
885
|
-
const root = client2.config?.root || client2.config?.root_url;
|
|
886
|
-
if (!root) {
|
|
887
|
-
throw new Error(ROOT_URL_ERROR_MSG);
|
|
888
|
-
}
|
|
889
|
-
try {
|
|
890
|
-
let fileBuffer;
|
|
891
|
-
let fullPath;
|
|
892
|
-
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
893
|
-
const fs = await import("fs/promises");
|
|
894
|
-
const path = await import("path");
|
|
895
|
-
fullPath = path.resolve(process.cwd(), cmd_item.meta.path);
|
|
896
|
-
fileBuffer = await fs.readFile(fullPath);
|
|
897
|
-
} else {
|
|
898
|
-
throw new Error(NODEJS_FS_ERROR_MSG);
|
|
899
|
-
}
|
|
900
|
-
const file = new Blob([fileBuffer], {
|
|
901
|
-
type: "application/octet-stream"
|
|
902
|
-
});
|
|
903
|
-
const response = await client2.upload_files(root, [file]);
|
|
904
|
-
const file_url = response.files && response.files[0];
|
|
905
|
-
if (file_url) {
|
|
906
|
-
const fileData = new FileData({
|
|
907
|
-
path: file_url,
|
|
908
|
-
orig_name: cmd_item.meta.name || ""
|
|
909
|
-
});
|
|
910
|
-
data[key] = fileData;
|
|
911
|
-
}
|
|
912
|
-
} catch (error) {
|
|
913
|
-
console.error(FILE_PROCESSING_ERROR_MSG, error);
|
|
914
|
-
}
|
|
780
|
+
const self = this;
|
|
781
|
+
await process_local_file_commands(self, data);
|
|
782
|
+
const blobRefs = await walk_and_store_blobs(data, void 0, [], true, api_info);
|
|
783
|
+
(await Promise.all(blobRefs.map(async ({ path, blob, type }) => {
|
|
784
|
+
if (!blob) return {
|
|
785
|
+
path,
|
|
786
|
+
type
|
|
787
|
+
};
|
|
788
|
+
const response = await self.upload_files(endpoint, [blob]);
|
|
789
|
+
return {
|
|
790
|
+
path,
|
|
791
|
+
file_url: response.files && response.files[0],
|
|
792
|
+
type,
|
|
793
|
+
name: typeof File !== "undefined" && blob instanceof File ? blob?.name : void 0
|
|
794
|
+
};
|
|
795
|
+
}))).forEach(({ path, file_url, type, name }) => {
|
|
796
|
+
if (type === "Gallery") update_object(data, file_url, path);
|
|
797
|
+
else if (file_url) update_object(data, new FileData({
|
|
798
|
+
path: file_url,
|
|
799
|
+
orig_name: name
|
|
800
|
+
}), path);
|
|
801
|
+
});
|
|
802
|
+
return data;
|
|
803
|
+
}
|
|
804
|
+
async function process_local_file_commands(client, data) {
|
|
805
|
+
if (!(client.config?.root || client.config?.root_url)) throw new Error(ROOT_URL_ERROR_MSG);
|
|
806
|
+
await recursively_process_commands(client, data);
|
|
915
807
|
}
|
|
808
|
+
async function recursively_process_commands(client, data, path = []) {
|
|
809
|
+
for (const key in data) if (data[key] instanceof Command) await process_single_command(client, data, key);
|
|
810
|
+
else if (typeof data[key] === "object" && data[key] !== null) await recursively_process_commands(client, data[key], [...path, key]);
|
|
811
|
+
}
|
|
812
|
+
async function process_single_command(client, data, key) {
|
|
813
|
+
let cmd_item = data[key];
|
|
814
|
+
const root = client.config?.root || client.config?.root_url;
|
|
815
|
+
if (!root) throw new Error(ROOT_URL_ERROR_MSG);
|
|
816
|
+
try {
|
|
817
|
+
let fileBuffer;
|
|
818
|
+
let fullPath;
|
|
819
|
+
if (typeof process !== "undefined" && process.versions && process.versions.node) {
|
|
820
|
+
const fs = await import("fs/promises");
|
|
821
|
+
fullPath = (await import("path")).resolve(process.cwd(), cmd_item.meta.path);
|
|
822
|
+
fileBuffer = await fs.readFile(fullPath);
|
|
823
|
+
} else throw new Error(NODEJS_FS_ERROR_MSG);
|
|
824
|
+
const file = new Blob([fileBuffer], { type: "application/octet-stream" });
|
|
825
|
+
const response = await client.upload_files(root, [file]);
|
|
826
|
+
const file_url = response.files && response.files[0];
|
|
827
|
+
if (file_url) data[key] = new FileData({
|
|
828
|
+
path: file_url,
|
|
829
|
+
orig_name: cmd_item.meta.name || ""
|
|
830
|
+
});
|
|
831
|
+
} catch (error) {
|
|
832
|
+
console.error(FILE_PROCESSING_ERROR_MSG, error);
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
//#endregion
|
|
836
|
+
//#region src/utils/post_data.ts
|
|
916
837
|
async function post_data(url, body, additional_headers) {
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
838
|
+
const headers = { "Content-Type": "application/json" };
|
|
839
|
+
if (this.options.token) headers.Authorization = `Bearer ${this.options.token}`;
|
|
840
|
+
try {
|
|
841
|
+
var response = await this.fetch(url, {
|
|
842
|
+
method: "POST",
|
|
843
|
+
body: JSON.stringify(body),
|
|
844
|
+
headers: {
|
|
845
|
+
...headers,
|
|
846
|
+
...additional_headers
|
|
847
|
+
},
|
|
848
|
+
credentials: this.options.credentials ?? "same-origin"
|
|
849
|
+
});
|
|
850
|
+
} catch (e) {
|
|
851
|
+
return [{ error: BROKEN_CONNECTION_MSG }, 500];
|
|
852
|
+
}
|
|
853
|
+
let output;
|
|
854
|
+
let status;
|
|
855
|
+
try {
|
|
856
|
+
output = await response.json();
|
|
857
|
+
status = response.status;
|
|
858
|
+
} catch (e) {
|
|
859
|
+
output = { error: `Could not parse server response: ${e}` };
|
|
860
|
+
status = 500;
|
|
861
|
+
}
|
|
862
|
+
return [output, status];
|
|
941
863
|
}
|
|
864
|
+
//#endregion
|
|
865
|
+
//#region src/utils/predict.ts
|
|
942
866
|
async function predict(endpoint, data = {}) {
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
return result;
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
return result;
|
|
867
|
+
let data_returned = false;
|
|
868
|
+
let status_complete = false;
|
|
869
|
+
if (!this.config) throw new Error("Could not resolve app config");
|
|
870
|
+
if (typeof endpoint === "number") this.config.dependencies.find((dep) => dep.id == endpoint);
|
|
871
|
+
else {
|
|
872
|
+
const trimmed_endpoint = endpoint.replace(/^\//, "");
|
|
873
|
+
this.config.dependencies.find((dep) => dep.id == this.api_map[trimmed_endpoint]);
|
|
874
|
+
}
|
|
875
|
+
const app = this.submit(endpoint, data, null, null, true);
|
|
876
|
+
let result;
|
|
877
|
+
for await (const message of app) {
|
|
878
|
+
if (message.type === "data") {
|
|
879
|
+
data_returned = true;
|
|
880
|
+
result = message;
|
|
881
|
+
if (status_complete) return result;
|
|
882
|
+
}
|
|
883
|
+
if (message.type === "status") {
|
|
884
|
+
if (message.stage === "error") {
|
|
885
|
+
const { message: error_message, ...status } = message;
|
|
886
|
+
const error = new Error((typeof error_message === "string" ? error_message : error_message && JSON.stringify(error_message)) || "An unknown error occurred while making a prediction.");
|
|
887
|
+
Object.assign(error, status);
|
|
888
|
+
throw error;
|
|
889
|
+
}
|
|
890
|
+
if (message.stage === "complete") {
|
|
891
|
+
status_complete = true;
|
|
892
|
+
if (data_returned) return result;
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
return result;
|
|
979
897
|
}
|
|
898
|
+
//#endregion
|
|
899
|
+
//#region src/helpers/spaces.ts
|
|
980
900
|
async function check_space_status(id, type, status_callback) {
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
} else if (status.status === "error" || status.status === "paused" || status.status === "space_error") {
|
|
1082
|
-
resolve();
|
|
1083
|
-
} else if (status.status === "sleeping" || status.status === "building") {
|
|
1084
|
-
if (retries < max_retries) {
|
|
1085
|
-
retries++;
|
|
1086
|
-
setTimeout(() => {
|
|
1087
|
-
check_and_wake_space(space_id, status_callback).then(resolve);
|
|
1088
|
-
}, check_interval);
|
|
1089
|
-
} else {
|
|
1090
|
-
resolve();
|
|
1091
|
-
}
|
|
1092
|
-
}
|
|
1093
|
-
}
|
|
1094
|
-
);
|
|
1095
|
-
});
|
|
901
|
+
let endpoint = type === "subdomain" ? `https://huggingface.co/api/spaces/by-subdomain/${id}` : `https://huggingface.co/api/spaces/${id}`;
|
|
902
|
+
let response;
|
|
903
|
+
let _status;
|
|
904
|
+
try {
|
|
905
|
+
response = await fetch(endpoint);
|
|
906
|
+
_status = response.status;
|
|
907
|
+
if (_status !== 200) throw new Error();
|
|
908
|
+
response = await response.json();
|
|
909
|
+
} catch (e) {
|
|
910
|
+
status_callback({
|
|
911
|
+
status: "error",
|
|
912
|
+
load_status: "error",
|
|
913
|
+
message: SPACE_STATUS_ERROR_MSG,
|
|
914
|
+
detail: "NOT_FOUND"
|
|
915
|
+
});
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
if (!response || _status !== 200) return;
|
|
919
|
+
const { runtime: { stage }, id: space_name } = response;
|
|
920
|
+
switch (stage) {
|
|
921
|
+
case "STOPPED":
|
|
922
|
+
case "SLEEPING":
|
|
923
|
+
status_callback({
|
|
924
|
+
status: "sleeping",
|
|
925
|
+
load_status: "pending",
|
|
926
|
+
message: "Space is asleep. Waking it up...",
|
|
927
|
+
detail: stage
|
|
928
|
+
});
|
|
929
|
+
setTimeout(() => {
|
|
930
|
+
check_space_status(id, type, status_callback);
|
|
931
|
+
}, 1e3);
|
|
932
|
+
break;
|
|
933
|
+
case "PAUSED":
|
|
934
|
+
status_callback({
|
|
935
|
+
status: "paused",
|
|
936
|
+
load_status: "error",
|
|
937
|
+
message: "This space has been paused by the author. If you would like to try this demo, consider duplicating the space.",
|
|
938
|
+
detail: stage,
|
|
939
|
+
discussions_enabled: await discussions_enabled(space_name)
|
|
940
|
+
});
|
|
941
|
+
break;
|
|
942
|
+
case "RUNNING":
|
|
943
|
+
case "RUNNING_BUILDING":
|
|
944
|
+
status_callback({
|
|
945
|
+
status: "running",
|
|
946
|
+
load_status: "complete",
|
|
947
|
+
message: "Space is running.",
|
|
948
|
+
detail: stage
|
|
949
|
+
});
|
|
950
|
+
break;
|
|
951
|
+
case "BUILDING":
|
|
952
|
+
status_callback({
|
|
953
|
+
status: "building",
|
|
954
|
+
load_status: "pending",
|
|
955
|
+
message: "Space is building...",
|
|
956
|
+
detail: stage
|
|
957
|
+
});
|
|
958
|
+
setTimeout(() => {
|
|
959
|
+
check_space_status(id, type, status_callback);
|
|
960
|
+
}, 1e3);
|
|
961
|
+
break;
|
|
962
|
+
case "APP_STARTING":
|
|
963
|
+
status_callback({
|
|
964
|
+
status: "starting",
|
|
965
|
+
load_status: "pending",
|
|
966
|
+
message: "Space is starting...",
|
|
967
|
+
detail: stage
|
|
968
|
+
});
|
|
969
|
+
setTimeout(() => {
|
|
970
|
+
check_space_status(id, type, status_callback);
|
|
971
|
+
}, 1e3);
|
|
972
|
+
break;
|
|
973
|
+
default:
|
|
974
|
+
status_callback({
|
|
975
|
+
status: "space_error",
|
|
976
|
+
load_status: "error",
|
|
977
|
+
message: "This space is experiencing an issue.",
|
|
978
|
+
detail: stage,
|
|
979
|
+
discussions_enabled: await discussions_enabled(space_name)
|
|
980
|
+
});
|
|
981
|
+
break;
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
var check_and_wake_space = async (space_id, status_callback) => {
|
|
985
|
+
let retries = 0;
|
|
986
|
+
const max_retries = 12;
|
|
987
|
+
const check_interval = 5e3;
|
|
988
|
+
return new Promise((resolve) => {
|
|
989
|
+
check_space_status(space_id, RE_SPACE_NAME.test(space_id) ? "space_name" : "subdomain", (status) => {
|
|
990
|
+
status_callback(status);
|
|
991
|
+
if (status.status === "running") resolve();
|
|
992
|
+
else if (status.status === "error" || status.status === "paused" || status.status === "space_error") resolve();
|
|
993
|
+
else if (status.status === "sleeping" || status.status === "building") if (retries < max_retries) {
|
|
994
|
+
retries++;
|
|
995
|
+
setTimeout(() => {
|
|
996
|
+
check_and_wake_space(space_id, status_callback).then(resolve);
|
|
997
|
+
}, check_interval);
|
|
998
|
+
} else resolve();
|
|
999
|
+
});
|
|
1000
|
+
});
|
|
1096
1001
|
};
|
|
1097
|
-
|
|
1002
|
+
var RE_DISABLED_DISCUSSION = /^(?=[^]*\b[dD]iscussions{0,1}\b)(?=[^]*\b[dD]isabled\b)[^]*$/;
|
|
1098
1003
|
async function discussions_enabled(space_id) {
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
if (!r.ok || error && RE_DISABLED_DISCUSSION.test(error)) return false;
|
|
1108
|
-
return true;
|
|
1109
|
-
} catch (e) {
|
|
1110
|
-
return false;
|
|
1111
|
-
}
|
|
1004
|
+
try {
|
|
1005
|
+
const r = await fetch(`https://huggingface.co/api/spaces/${space_id}/discussions`, { method: "HEAD" });
|
|
1006
|
+
const error = r.headers.get("x-error-message");
|
|
1007
|
+
if (!r.ok || error && RE_DISABLED_DISCUSSION.test(error)) return false;
|
|
1008
|
+
return true;
|
|
1009
|
+
} catch (e) {
|
|
1010
|
+
return false;
|
|
1011
|
+
}
|
|
1112
1012
|
}
|
|
1113
1013
|
async function get_space_hardware(space_id, token) {
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
throw new Error("Space hardware could not be obtained.");
|
|
1125
|
-
const { hardware } = await res.json();
|
|
1126
|
-
return hardware.current;
|
|
1127
|
-
} catch (e) {
|
|
1128
|
-
throw new Error(e.message);
|
|
1129
|
-
}
|
|
1014
|
+
const headers = {};
|
|
1015
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
1016
|
+
try {
|
|
1017
|
+
const res = await fetch(`https://huggingface.co/api/spaces/${space_id}/${RUNTIME_URL}`, { headers });
|
|
1018
|
+
if (res.status !== 200) throw new Error("Space hardware could not be obtained.");
|
|
1019
|
+
const { hardware } = await res.json();
|
|
1020
|
+
return hardware.current;
|
|
1021
|
+
} catch (e) {
|
|
1022
|
+
throw new Error(e.message);
|
|
1023
|
+
}
|
|
1130
1024
|
}
|
|
1131
1025
|
async function set_space_timeout(space_id, timeout, token) {
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
"t4-medium",
|
|
1165
|
-
"a10g-small",
|
|
1166
|
-
"a10g-large",
|
|
1167
|
-
"a10g-largex2",
|
|
1168
|
-
"a10g-largex4",
|
|
1169
|
-
"a100-large",
|
|
1170
|
-
"zero-a10g",
|
|
1171
|
-
"h100",
|
|
1172
|
-
"h100x8"
|
|
1026
|
+
const headers = {};
|
|
1027
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
1028
|
+
const body = { seconds: timeout };
|
|
1029
|
+
try {
|
|
1030
|
+
const res = await fetch(`https://huggingface.co/api/spaces/${space_id}/${SLEEPTIME_URL}`, {
|
|
1031
|
+
method: "POST",
|
|
1032
|
+
headers: {
|
|
1033
|
+
"Content-Type": "application/json",
|
|
1034
|
+
...headers
|
|
1035
|
+
},
|
|
1036
|
+
body: JSON.stringify(body)
|
|
1037
|
+
});
|
|
1038
|
+
if (res.status !== 200) throw new Error("Could not set sleep timeout on duplicated Space. Please visit *ADD HF LINK TO SETTINGS* to set a timeout manually to reduce billing charges.");
|
|
1039
|
+
return await res.json();
|
|
1040
|
+
} catch (e) {
|
|
1041
|
+
throw new Error(e.message);
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
var hardware_types = [
|
|
1045
|
+
"cpu-basic",
|
|
1046
|
+
"cpu-upgrade",
|
|
1047
|
+
"cpu-xl",
|
|
1048
|
+
"t4-small",
|
|
1049
|
+
"t4-medium",
|
|
1050
|
+
"a10g-small",
|
|
1051
|
+
"a10g-large",
|
|
1052
|
+
"a10g-largex2",
|
|
1053
|
+
"a10g-largex4",
|
|
1054
|
+
"a100-large",
|
|
1055
|
+
"zero-a10g",
|
|
1056
|
+
"h100",
|
|
1057
|
+
"h100x8"
|
|
1173
1058
|
];
|
|
1059
|
+
//#endregion
|
|
1060
|
+
//#region src/utils/duplicate.ts
|
|
1174
1061
|
async function duplicate(app_reference, options) {
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
try {
|
|
1220
|
-
const response = await fetch(
|
|
1221
|
-
`https://huggingface.co/api/spaces/${app_reference}/duplicate`,
|
|
1222
|
-
{
|
|
1223
|
-
method: "POST",
|
|
1224
|
-
headers,
|
|
1225
|
-
body: JSON.stringify(body)
|
|
1226
|
-
}
|
|
1227
|
-
);
|
|
1228
|
-
if (response.status === 409) {
|
|
1229
|
-
try {
|
|
1230
|
-
const client2 = await Client.connect(`${user}/${space_name}`, options);
|
|
1231
|
-
return client2;
|
|
1232
|
-
} catch (error) {
|
|
1233
|
-
console.error("Failed to connect Client instance:", error);
|
|
1234
|
-
throw error;
|
|
1235
|
-
}
|
|
1236
|
-
} else if (response.status !== 200) {
|
|
1237
|
-
throw new Error(response.statusText);
|
|
1238
|
-
}
|
|
1239
|
-
const duplicated_space = await response.json();
|
|
1240
|
-
await set_space_timeout(`${user}/${space_name}`, timeout || 300, token);
|
|
1241
|
-
return await Client.connect(
|
|
1242
|
-
get_space_reference(duplicated_space.url),
|
|
1243
|
-
options
|
|
1244
|
-
);
|
|
1245
|
-
} catch (e) {
|
|
1246
|
-
throw new Error(e);
|
|
1247
|
-
}
|
|
1062
|
+
normalise_token_option(options);
|
|
1063
|
+
const { token, private: _private, hardware, timeout, auth } = options;
|
|
1064
|
+
if (hardware && !hardware_types.includes(hardware)) throw new Error(`Invalid hardware type provided. Valid types are: ${hardware_types.map((v) => `"${v}"`).join(",")}.`);
|
|
1065
|
+
const { http_protocol, host } = await process_endpoint(app_reference, token);
|
|
1066
|
+
let cookies = null;
|
|
1067
|
+
if (auth) {
|
|
1068
|
+
const cookie_header = await get_cookie_header(http_protocol, host, auth, fetch, void 0, options.credentials);
|
|
1069
|
+
if (cookie_header) cookies = parse_and_set_cookies(cookie_header);
|
|
1070
|
+
}
|
|
1071
|
+
const headers = {
|
|
1072
|
+
Authorization: `Bearer ${token}`,
|
|
1073
|
+
"Content-Type": "application/json",
|
|
1074
|
+
...cookies ? { Cookie: cookies.join("; ") } : {}
|
|
1075
|
+
};
|
|
1076
|
+
const user = (await (await fetch(`https://huggingface.co/api/whoami-v2`, { headers })).json()).name;
|
|
1077
|
+
const space_name = app_reference.split("/")[1];
|
|
1078
|
+
const body = { repository: `${user}/${space_name}` };
|
|
1079
|
+
if (_private) body.private = true;
|
|
1080
|
+
let original_hardware;
|
|
1081
|
+
try {
|
|
1082
|
+
if (!hardware) original_hardware = await get_space_hardware(app_reference, token);
|
|
1083
|
+
} catch (e) {
|
|
1084
|
+
throw Error(SPACE_METADATA_ERROR_MSG + e.message);
|
|
1085
|
+
}
|
|
1086
|
+
body.hardware = hardware || original_hardware || "cpu-basic";
|
|
1087
|
+
try {
|
|
1088
|
+
const response = await fetch(`https://huggingface.co/api/spaces/${app_reference}/duplicate`, {
|
|
1089
|
+
method: "POST",
|
|
1090
|
+
headers,
|
|
1091
|
+
body: JSON.stringify(body)
|
|
1092
|
+
});
|
|
1093
|
+
if (response.status === 409) try {
|
|
1094
|
+
return await Client.connect(`${user}/${space_name}`, options);
|
|
1095
|
+
} catch (error) {
|
|
1096
|
+
console.error("Failed to connect Client instance:", error);
|
|
1097
|
+
throw error;
|
|
1098
|
+
}
|
|
1099
|
+
else if (response.status !== 200) throw new Error(response.statusText);
|
|
1100
|
+
const duplicated_space = await response.json();
|
|
1101
|
+
await set_space_timeout(`${user}/${space_name}`, timeout || 300, token);
|
|
1102
|
+
return await Client.connect(get_space_reference(duplicated_space.url), options);
|
|
1103
|
+
} catch (e) {
|
|
1104
|
+
throw new Error(e);
|
|
1105
|
+
}
|
|
1248
1106
|
}
|
|
1249
1107
|
function get_space_reference(url) {
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
let zerogpu_handshake_initialized = false;
|
|
1108
|
+
const match = url.match(/https:\/\/huggingface.co\/spaces\/([^/]+\/[^/]+)/);
|
|
1109
|
+
if (match) return match[1];
|
|
1110
|
+
}
|
|
1111
|
+
//#endregion
|
|
1112
|
+
//#region src/helpers/zerogpu.ts
|
|
1113
|
+
var ZEROGPU_HEADERS_MESSAGE = "supports-zerogpu-headers";
|
|
1114
|
+
var zerogpu_handshake_initialized = false;
|
|
1258
1115
|
function supports_browser_handshake() {
|
|
1259
|
-
|
|
1116
|
+
return typeof window !== "undefined" && typeof document !== "undefined" && typeof window.addEventListener === "function";
|
|
1260
1117
|
}
|
|
1261
1118
|
function get_zerogpu_origin(hostname) {
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
if (hostname.endsWith(".hf.space")) {
|
|
1266
|
-
return "https://huggingface.co";
|
|
1267
|
-
}
|
|
1268
|
-
return null;
|
|
1119
|
+
if (hostname.includes(".dev.")) return `https://moon-${hostname.split(".")[1]}.dev.spaces.huggingface.tech`;
|
|
1120
|
+
if (hostname.endsWith(".hf.space")) return "https://huggingface.co";
|
|
1121
|
+
return null;
|
|
1269
1122
|
}
|
|
1270
1123
|
function initialize_zerogpu_handshake() {
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
});
|
|
1279
|
-
zerogpu_handshake_initialized = true;
|
|
1280
|
-
const origin = get_zerogpu_origin(window.location.hostname);
|
|
1281
|
-
if (origin && window.parent !== window) {
|
|
1282
|
-
window.parent.postMessage(ZEROGPU_HEADERS_MESSAGE, origin);
|
|
1283
|
-
}
|
|
1284
|
-
}
|
|
1285
|
-
class TextLineStream extends TransformStream {
|
|
1286
|
-
#currentLine = "";
|
|
1287
|
-
/** Constructs a new instance. */
|
|
1288
|
-
constructor(options = { allowCR: false }) {
|
|
1289
|
-
super({
|
|
1290
|
-
transform: (chars, controller) => {
|
|
1291
|
-
chars = this.#currentLine + chars;
|
|
1292
|
-
while (true) {
|
|
1293
|
-
const lfIndex = chars.indexOf("\n");
|
|
1294
|
-
const crIndex = options.allowCR ? chars.indexOf("\r") : -1;
|
|
1295
|
-
if (crIndex !== -1 && crIndex !== chars.length - 1 && (lfIndex === -1 || lfIndex - 1 > crIndex)) {
|
|
1296
|
-
controller.enqueue(chars.slice(0, crIndex));
|
|
1297
|
-
chars = chars.slice(crIndex + 1);
|
|
1298
|
-
continue;
|
|
1299
|
-
}
|
|
1300
|
-
if (lfIndex === -1)
|
|
1301
|
-
break;
|
|
1302
|
-
const endIndex = chars[lfIndex - 1] === "\r" ? lfIndex - 1 : lfIndex;
|
|
1303
|
-
controller.enqueue(chars.slice(0, endIndex));
|
|
1304
|
-
chars = chars.slice(lfIndex + 1);
|
|
1305
|
-
}
|
|
1306
|
-
this.#currentLine = chars;
|
|
1307
|
-
},
|
|
1308
|
-
flush: (controller) => {
|
|
1309
|
-
if (this.#currentLine === "")
|
|
1310
|
-
return;
|
|
1311
|
-
const currentLine = options.allowCR && this.#currentLine.endsWith("\r") ? this.#currentLine.slice(0, -1) : this.#currentLine;
|
|
1312
|
-
controller.enqueue(currentLine);
|
|
1313
|
-
}
|
|
1314
|
-
});
|
|
1315
|
-
}
|
|
1124
|
+
if (!supports_browser_handshake() || zerogpu_handshake_initialized) return;
|
|
1125
|
+
window.addEventListener("message", (event) => {
|
|
1126
|
+
if (event.data === ZEROGPU_HEADERS_MESSAGE) window.supports_zerogpu_headers = true;
|
|
1127
|
+
});
|
|
1128
|
+
zerogpu_handshake_initialized = true;
|
|
1129
|
+
const origin = get_zerogpu_origin(window.location.hostname);
|
|
1130
|
+
if (origin && window.parent !== window) window.parent.postMessage(ZEROGPU_HEADERS_MESSAGE, origin);
|
|
1316
1131
|
}
|
|
1132
|
+
//#endregion
|
|
1133
|
+
//#region ../../node_modules/.pnpm/fetch-event-stream@0.1.6/node_modules/fetch-event-stream/esm/deps/jsr.io/@std/streams/0.221.0/text_line_stream.js
|
|
1134
|
+
/**
|
|
1135
|
+
* Transform a stream into a stream where each chunk is divided by a newline,
|
|
1136
|
+
* be it `\n` or `\r\n`. `\r` can be enabled via the `allowCR` option.
|
|
1137
|
+
*
|
|
1138
|
+
* @example
|
|
1139
|
+
* ```ts
|
|
1140
|
+
* import { TextLineStream } from "@std/streams/text-line-stream";
|
|
1141
|
+
*
|
|
1142
|
+
* const res = await fetch("https://example.com");
|
|
1143
|
+
* const lines = res.body!
|
|
1144
|
+
* .pipeThrough(new TextDecoderStream())
|
|
1145
|
+
* .pipeThrough(new TextLineStream());
|
|
1146
|
+
* ```
|
|
1147
|
+
*/
|
|
1148
|
+
var TextLineStream = class extends TransformStream {
|
|
1149
|
+
#currentLine = "";
|
|
1150
|
+
/** Constructs a new instance. */
|
|
1151
|
+
constructor(options = { allowCR: false }) {
|
|
1152
|
+
super({
|
|
1153
|
+
transform: (chars, controller) => {
|
|
1154
|
+
chars = this.#currentLine + chars;
|
|
1155
|
+
while (true) {
|
|
1156
|
+
const lfIndex = chars.indexOf("\n");
|
|
1157
|
+
const crIndex = options.allowCR ? chars.indexOf("\r") : -1;
|
|
1158
|
+
if (crIndex !== -1 && crIndex !== chars.length - 1 && (lfIndex === -1 || lfIndex - 1 > crIndex)) {
|
|
1159
|
+
controller.enqueue(chars.slice(0, crIndex));
|
|
1160
|
+
chars = chars.slice(crIndex + 1);
|
|
1161
|
+
continue;
|
|
1162
|
+
}
|
|
1163
|
+
if (lfIndex === -1) break;
|
|
1164
|
+
const endIndex = chars[lfIndex - 1] === "\r" ? lfIndex - 1 : lfIndex;
|
|
1165
|
+
controller.enqueue(chars.slice(0, endIndex));
|
|
1166
|
+
chars = chars.slice(lfIndex + 1);
|
|
1167
|
+
}
|
|
1168
|
+
this.#currentLine = chars;
|
|
1169
|
+
},
|
|
1170
|
+
flush: (controller) => {
|
|
1171
|
+
if (this.#currentLine === "") return;
|
|
1172
|
+
const currentLine = options.allowCR && this.#currentLine.endsWith("\r") ? this.#currentLine.slice(0, -1) : this.#currentLine;
|
|
1173
|
+
controller.enqueue(currentLine);
|
|
1174
|
+
}
|
|
1175
|
+
});
|
|
1176
|
+
}
|
|
1177
|
+
};
|
|
1178
|
+
//#endregion
|
|
1179
|
+
//#region ../../node_modules/.pnpm/fetch-event-stream@0.1.6/node_modules/fetch-event-stream/esm/utils.js
|
|
1317
1180
|
function stream$1(input) {
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1181
|
+
let decoder = new TextDecoderStream();
|
|
1182
|
+
let split = new TextLineStream({ allowCR: true });
|
|
1183
|
+
return input.pipeThrough(decoder).pipeThrough(split);
|
|
1321
1184
|
}
|
|
1322
1185
|
function split(input) {
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
if (idx) {
|
|
1327
|
-
return [
|
|
1328
|
-
input.substring(0, idx),
|
|
1329
|
-
input.substring(idx + match[0].length)
|
|
1330
|
-
];
|
|
1331
|
-
}
|
|
1186
|
+
let match = /[:]\s*/.exec(input);
|
|
1187
|
+
let idx = match && match.index;
|
|
1188
|
+
if (idx) return [input.substring(0, idx), input.substring(idx + match[0].length)];
|
|
1332
1189
|
}
|
|
1333
1190
|
function fallback(headers, key, value) {
|
|
1334
|
-
|
|
1335
|
-
if (!tmp)
|
|
1336
|
-
headers.set(key, value);
|
|
1191
|
+
if (!headers.get(key)) headers.set(key, value);
|
|
1337
1192
|
}
|
|
1193
|
+
//#endregion
|
|
1194
|
+
//#region ../../node_modules/.pnpm/fetch-event-stream@0.1.6/node_modules/fetch-event-stream/esm/mod.js
|
|
1195
|
+
/**
|
|
1196
|
+
* Convert a `Response` body containing Server Sent Events (SSE) into an Async Iterator that yields {@linkcode ServerSentEventMessage} objects.
|
|
1197
|
+
*
|
|
1198
|
+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events}
|
|
1199
|
+
*
|
|
1200
|
+
* @example
|
|
1201
|
+
* ```js
|
|
1202
|
+
* // Optional
|
|
1203
|
+
* let abort = new AbortController;
|
|
1204
|
+
*
|
|
1205
|
+
* // Manually fetch a Response
|
|
1206
|
+
* let res = await fetch('https://...', {
|
|
1207
|
+
* method: 'POST',
|
|
1208
|
+
* signal: abort.signal,
|
|
1209
|
+
* headers: {
|
|
1210
|
+
* 'api-key': 'token <value>',
|
|
1211
|
+
* 'content-type': 'application/json',
|
|
1212
|
+
* },
|
|
1213
|
+
* body: JSON.stringify({
|
|
1214
|
+
* stream: true, // <- hypothetical
|
|
1215
|
+
* // ...
|
|
1216
|
+
* })
|
|
1217
|
+
* });
|
|
1218
|
+
*
|
|
1219
|
+
* if (res.ok) {
|
|
1220
|
+
* let stream = events(res, abort.signal);
|
|
1221
|
+
* for await (let event of stream) {
|
|
1222
|
+
* console.log('<<', event.data);
|
|
1223
|
+
* }
|
|
1224
|
+
* }
|
|
1225
|
+
* ```
|
|
1226
|
+
*/
|
|
1338
1227
|
async function* events(res, signal) {
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
} else if (field === "retry") {
|
|
1368
|
-
event ||= {};
|
|
1369
|
-
event[field] = +value || void 0;
|
|
1370
|
-
}
|
|
1371
|
-
}
|
|
1228
|
+
if (!res.body) return;
|
|
1229
|
+
let iter = stream$1(res.body);
|
|
1230
|
+
let line, reader = iter.getReader();
|
|
1231
|
+
let event;
|
|
1232
|
+
for (;;) {
|
|
1233
|
+
if (signal && signal.aborted) return reader.cancel();
|
|
1234
|
+
line = await reader.read();
|
|
1235
|
+
if (line.done) return;
|
|
1236
|
+
if (!line.value) {
|
|
1237
|
+
if (event) yield event;
|
|
1238
|
+
event = void 0;
|
|
1239
|
+
continue;
|
|
1240
|
+
}
|
|
1241
|
+
let [field, value] = split(line.value) || [];
|
|
1242
|
+
if (field === "data") {
|
|
1243
|
+
event ||= {};
|
|
1244
|
+
event[field] = event[field] ? event[field] + "\n" + value : value;
|
|
1245
|
+
} else if (field === "event") {
|
|
1246
|
+
event ||= {};
|
|
1247
|
+
event[field] = value;
|
|
1248
|
+
} else if (field === "id") {
|
|
1249
|
+
event ||= {};
|
|
1250
|
+
event[field] = String(+value) === value ? +value : value;
|
|
1251
|
+
} else if (field === "retry") {
|
|
1252
|
+
event ||= {};
|
|
1253
|
+
event[field] = +value || void 0;
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1372
1256
|
}
|
|
1257
|
+
/**
|
|
1258
|
+
* Convenience function that will `fetch` with the given arguments and, if ok, will return the {@linkcode events} async iterator.
|
|
1259
|
+
*
|
|
1260
|
+
* If the response is not ok (status 200-299), the `Response` is thrown.
|
|
1261
|
+
*
|
|
1262
|
+
* @example
|
|
1263
|
+
* ```js
|
|
1264
|
+
* // NOTE: throws `Response` if not 2xx status
|
|
1265
|
+
* let events = await stream('https://api.openai.com/...', {
|
|
1266
|
+
* method: 'POST',
|
|
1267
|
+
* headers: {
|
|
1268
|
+
* 'Authorization': 'Bearer <token>',
|
|
1269
|
+
* 'Content-Type': 'application/json',
|
|
1270
|
+
* },
|
|
1271
|
+
* body: JSON.stringify({
|
|
1272
|
+
* stream: true,
|
|
1273
|
+
* // ...
|
|
1274
|
+
* })
|
|
1275
|
+
* });
|
|
1276
|
+
*
|
|
1277
|
+
* for await (let event of events) {
|
|
1278
|
+
* console.log('<<', JSON.parse(event.data));
|
|
1279
|
+
* }
|
|
1280
|
+
* ```
|
|
1281
|
+
*/
|
|
1373
1282
|
async function stream(input, init) {
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
return events(r, req.signal);
|
|
1283
|
+
let req = new Request(input, init);
|
|
1284
|
+
fallback(req.headers, "Accept", "text/event-stream");
|
|
1285
|
+
fallback(req.headers, "Content-Type", "application/json");
|
|
1286
|
+
let r = await fetch(req);
|
|
1287
|
+
if (!r.ok) throw r;
|
|
1288
|
+
return events(r, req.signal);
|
|
1381
1289
|
}
|
|
1290
|
+
//#endregion
|
|
1291
|
+
//#region src/utils/stream.ts
|
|
1382
1292
|
async function open_stream() {
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
}
|
|
1428
|
-
let fn = event_callbacks[event_id];
|
|
1429
|
-
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
1430
|
-
setTimeout(fn, 0, _data);
|
|
1431
|
-
} else {
|
|
1432
|
-
fn(_data);
|
|
1433
|
-
}
|
|
1434
|
-
} else {
|
|
1435
|
-
if (!pending_stream_messages[event_id]) {
|
|
1436
|
-
pending_stream_messages[event_id] = [];
|
|
1437
|
-
}
|
|
1438
|
-
pending_stream_messages[event_id].push(_data);
|
|
1439
|
-
}
|
|
1440
|
-
};
|
|
1441
|
-
stream2.onerror = async function(e) {
|
|
1442
|
-
console.error(e);
|
|
1443
|
-
await Promise.all(
|
|
1444
|
-
Object.keys(event_callbacks).map(
|
|
1445
|
-
(event_id) => event_callbacks[event_id]({
|
|
1446
|
-
msg: "broken_connection",
|
|
1447
|
-
message: BROKEN_CONNECTION_MSG
|
|
1448
|
-
})
|
|
1449
|
-
)
|
|
1450
|
-
);
|
|
1451
|
-
};
|
|
1293
|
+
let { event_callbacks, unclosed_events, pending_stream_messages, stream_status, config, jwt } = this;
|
|
1294
|
+
const that = this;
|
|
1295
|
+
if (!config) throw new Error("Could not resolve app config");
|
|
1296
|
+
stream_status.open = true;
|
|
1297
|
+
let stream = null;
|
|
1298
|
+
let params = new URLSearchParams({ session_hash: this.session_hash }).toString();
|
|
1299
|
+
let url = new URL(`${config.root}${this.api_prefix}/${SSE_URL}?${params}`);
|
|
1300
|
+
if (jwt) url.searchParams.set("__sign", jwt);
|
|
1301
|
+
stream = this.stream(url);
|
|
1302
|
+
if (!stream) {
|
|
1303
|
+
console.warn("Cannot connect to SSE endpoint: " + url.toString());
|
|
1304
|
+
return;
|
|
1305
|
+
}
|
|
1306
|
+
stream.onmessage = async function(event) {
|
|
1307
|
+
let _data = JSON.parse(event.data);
|
|
1308
|
+
if (_data.msg === "close_stream") {
|
|
1309
|
+
close_stream(stream_status, that.abort_controller);
|
|
1310
|
+
return;
|
|
1311
|
+
}
|
|
1312
|
+
const event_id = _data.event_id;
|
|
1313
|
+
if (!event_id) await Promise.all(Object.keys(event_callbacks).map((event_id) => event_callbacks[event_id](_data)));
|
|
1314
|
+
else if (event_callbacks[event_id] && config) {
|
|
1315
|
+
if (_data.msg === "process_completed" && [
|
|
1316
|
+
"sse",
|
|
1317
|
+
"sse_v1",
|
|
1318
|
+
"sse_v2",
|
|
1319
|
+
"sse_v2.1",
|
|
1320
|
+
"sse_v3"
|
|
1321
|
+
].includes(config.protocol)) unclosed_events.delete(event_id);
|
|
1322
|
+
let fn = event_callbacks[event_id];
|
|
1323
|
+
if (typeof window !== "undefined" && typeof document !== "undefined" && document.visibilityState !== "hidden") setTimeout(fn, 0, _data);
|
|
1324
|
+
else fn(_data);
|
|
1325
|
+
} else {
|
|
1326
|
+
if (!pending_stream_messages[event_id]) pending_stream_messages[event_id] = [];
|
|
1327
|
+
pending_stream_messages[event_id].push(_data);
|
|
1328
|
+
}
|
|
1329
|
+
};
|
|
1330
|
+
stream.onerror = async function(e) {
|
|
1331
|
+
console.error(e);
|
|
1332
|
+
await Promise.all(Object.keys(event_callbacks).map((event_id) => event_callbacks[event_id]({
|
|
1333
|
+
msg: "broken_connection",
|
|
1334
|
+
message: BROKEN_CONNECTION_MSG
|
|
1335
|
+
})));
|
|
1336
|
+
};
|
|
1452
1337
|
}
|
|
1453
1338
|
function close_stream(stream_status, abort_controller) {
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1339
|
+
if (stream_status) {
|
|
1340
|
+
stream_status.open = false;
|
|
1341
|
+
abort_controller?.abort();
|
|
1342
|
+
}
|
|
1458
1343
|
}
|
|
1459
1344
|
function apply_diff_stream(pending_diff_streams, event_id, data) {
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
data.data[i] = new_data;
|
|
1471
|
-
});
|
|
1472
|
-
}
|
|
1345
|
+
if (!pending_diff_streams[event_id]) {
|
|
1346
|
+
pending_diff_streams[event_id] = [];
|
|
1347
|
+
data.data.forEach((value, i) => {
|
|
1348
|
+
pending_diff_streams[event_id][i] = value;
|
|
1349
|
+
});
|
|
1350
|
+
} else data.data.forEach((value, i) => {
|
|
1351
|
+
let new_data = apply_diff(i < pending_diff_streams[event_id].length ? pending_diff_streams[event_id][i] : null, value);
|
|
1352
|
+
pending_diff_streams[event_id][i] = new_data;
|
|
1353
|
+
data.data[i] = new_data;
|
|
1354
|
+
});
|
|
1473
1355
|
}
|
|
1474
1356
|
function apply_diff(obj, diff) {
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1357
|
+
diff.forEach(([action, path, value]) => {
|
|
1358
|
+
obj = apply_edit(obj, path, action, value);
|
|
1359
|
+
});
|
|
1360
|
+
return obj;
|
|
1479
1361
|
}
|
|
1480
1362
|
function apply_edit(target, path, action, value) {
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
break;
|
|
1508
|
-
case "delete":
|
|
1509
|
-
if (Array.isArray(current)) {
|
|
1510
|
-
current.splice(Number(last_path), 1);
|
|
1511
|
-
} else {
|
|
1512
|
-
delete current[last_path];
|
|
1513
|
-
}
|
|
1514
|
-
break;
|
|
1515
|
-
default:
|
|
1516
|
-
throw new Error(`Unknown action: ${action}`);
|
|
1517
|
-
}
|
|
1518
|
-
return target;
|
|
1363
|
+
if (path.length === 0) {
|
|
1364
|
+
if (action === "replace") return value;
|
|
1365
|
+
else if (action === "append") return target + value;
|
|
1366
|
+
throw new Error(`Unsupported action: ${action}`);
|
|
1367
|
+
}
|
|
1368
|
+
let current = target;
|
|
1369
|
+
for (let i = 0; i < path.length - 1; i++) current = current[path[i]];
|
|
1370
|
+
const last_path = path[path.length - 1];
|
|
1371
|
+
switch (action) {
|
|
1372
|
+
case "replace":
|
|
1373
|
+
current[last_path] = value;
|
|
1374
|
+
break;
|
|
1375
|
+
case "append":
|
|
1376
|
+
current[last_path] += value;
|
|
1377
|
+
break;
|
|
1378
|
+
case "add":
|
|
1379
|
+
if (Array.isArray(current)) current.splice(Number(last_path), 0, value);
|
|
1380
|
+
else current[last_path] = value;
|
|
1381
|
+
break;
|
|
1382
|
+
case "delete":
|
|
1383
|
+
if (Array.isArray(current)) current.splice(Number(last_path), 1);
|
|
1384
|
+
else delete current[last_path];
|
|
1385
|
+
break;
|
|
1386
|
+
default: throw new Error(`Unknown action: ${action}`);
|
|
1387
|
+
}
|
|
1388
|
+
return target;
|
|
1519
1389
|
}
|
|
1520
1390
|
function readable_stream(input, init = {}) {
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1391
|
+
const instance = {
|
|
1392
|
+
close: () => {
|
|
1393
|
+
console.warn("Method not implemented.");
|
|
1394
|
+
},
|
|
1395
|
+
onerror: null,
|
|
1396
|
+
onmessage: null,
|
|
1397
|
+
onopen: null,
|
|
1398
|
+
readyState: 0,
|
|
1399
|
+
url: input.toString(),
|
|
1400
|
+
withCredentials: false,
|
|
1401
|
+
CONNECTING: 0,
|
|
1402
|
+
OPEN: 1,
|
|
1403
|
+
CLOSED: 2,
|
|
1404
|
+
addEventListener: () => {
|
|
1405
|
+
throw new Error("Method not implemented.");
|
|
1406
|
+
},
|
|
1407
|
+
dispatchEvent: () => {
|
|
1408
|
+
throw new Error("Method not implemented.");
|
|
1409
|
+
},
|
|
1410
|
+
removeEventListener: () => {
|
|
1411
|
+
throw new Error("Method not implemented.");
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1414
|
+
stream(input, init).then(async (res) => {
|
|
1415
|
+
instance.readyState = instance.OPEN;
|
|
1416
|
+
try {
|
|
1417
|
+
for await (const chunk of res) instance.onmessage && instance.onmessage(chunk);
|
|
1418
|
+
instance.readyState = instance.CLOSED;
|
|
1419
|
+
} catch (e) {
|
|
1420
|
+
instance.onerror && instance.onerror(e);
|
|
1421
|
+
instance.readyState = instance.CLOSED;
|
|
1422
|
+
}
|
|
1423
|
+
}).catch((e) => {
|
|
1424
|
+
console.error(e);
|
|
1425
|
+
instance.onerror && instance.onerror(e);
|
|
1426
|
+
instance.readyState = instance.CLOSED;
|
|
1427
|
+
});
|
|
1428
|
+
return instance;
|
|
1429
|
+
}
|
|
1430
|
+
//#endregion
|
|
1431
|
+
//#region src/utils/run_history.ts
|
|
1432
|
+
var KEY_ROOT = "gradio:run-history:";
|
|
1433
|
+
var STORAGE_PREFIX = `${KEY_ROOT}v2:`;
|
|
1434
|
+
var REPLAY_PREFIX = `${KEY_ROOT}replay:v2:`;
|
|
1435
|
+
var MAX_RUNS = 100;
|
|
1436
|
+
var MAX_APPS = 8;
|
|
1437
|
+
/**
|
|
1438
|
+
* Run history is a side effect of submitting, never the point of it, so no
|
|
1439
|
+
* failure in here may propagate into the caller and break the app. Every
|
|
1440
|
+
* exported function routes through this.
|
|
1441
|
+
*/
|
|
1442
|
+
function safely(operation, fallback) {
|
|
1443
|
+
try {
|
|
1444
|
+
return operation();
|
|
1445
|
+
} catch (error) {
|
|
1446
|
+
console.warn("Could not update the run history.", error);
|
|
1447
|
+
return fallback;
|
|
1448
|
+
}
|
|
1449
|
+
}
|
|
1450
|
+
/**
|
|
1451
|
+
* The URL of the run history page for an app. `root` never carries a trailing
|
|
1452
|
+
* slash, so it cannot simply be concatenated with the path.
|
|
1453
|
+
*/
|
|
1454
|
+
function run_history_url(root, api_prefix = "/gradio_api") {
|
|
1455
|
+
return `${root.replace(/\/+$/, "")}${api_prefix}/runs`;
|
|
1456
|
+
}
|
|
1457
|
+
function storage_key(scope) {
|
|
1458
|
+
if (typeof window === "undefined") return null;
|
|
1459
|
+
const app_id = scope?.app_id;
|
|
1460
|
+
if (app_id === null || app_id === void 0 || app_id === "") return null;
|
|
1461
|
+
try {
|
|
1462
|
+
if (!window.localStorage) return null;
|
|
1463
|
+
return `${STORAGE_PREFIX}${app_id}${scope?.username ? `:user:${encodeURIComponent(scope.username)}` : ""}`;
|
|
1464
|
+
} catch {
|
|
1465
|
+
return null;
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
function replay_key(scope) {
|
|
1469
|
+
const key = storage_key(scope);
|
|
1470
|
+
return key ? key.replace(STORAGE_PREFIX, REPLAY_PREFIX) : null;
|
|
1471
|
+
}
|
|
1472
|
+
/** When a run was most recently saved under a key, for deciding what to drop. */
|
|
1473
|
+
function last_saved_at(key) {
|
|
1474
|
+
try {
|
|
1475
|
+
const runs = JSON.parse(window.localStorage.getItem(key) || "[]");
|
|
1476
|
+
return Array.isArray(runs) && runs.length ? Date.parse(runs[0]?.started_at) || 0 : 0;
|
|
1477
|
+
} catch {
|
|
1478
|
+
return 0;
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
/**
|
|
1482
|
+
* Drops the histories of long-gone app instances. Every restart mints a new app
|
|
1483
|
+
* id, so without this the browser would keep every history an app ever had and
|
|
1484
|
+
* eventually run out of room for the current one.
|
|
1485
|
+
*/
|
|
1486
|
+
function prune_apps(current_key) {
|
|
1487
|
+
const keys = Object.keys(window.localStorage).filter((key) => key.startsWith(KEY_ROOT));
|
|
1488
|
+
const stale = [...keys.filter((key) => !key.startsWith(STORAGE_PREFIX) && !key.startsWith(REPLAY_PREFIX)), ...keys.filter((key) => key.startsWith(STORAGE_PREFIX) && key !== current_key).sort((a, b) => last_saved_at(b) - last_saved_at(a)).slice(MAX_APPS - 1)];
|
|
1489
|
+
for (const key of stale) try {
|
|
1490
|
+
window.localStorage.removeItem(key);
|
|
1491
|
+
window.sessionStorage.removeItem(key.replace(STORAGE_PREFIX, REPLAY_PREFIX));
|
|
1492
|
+
} catch {}
|
|
1493
|
+
}
|
|
1494
|
+
function make_id() {
|
|
1495
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) return crypto.randomUUID();
|
|
1496
|
+
return `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
1561
1497
|
}
|
|
1498
|
+
function clone_for_storage(value) {
|
|
1499
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
1500
|
+
try {
|
|
1501
|
+
return JSON.parse(JSON.stringify(value, (_key, item) => {
|
|
1502
|
+
if (typeof item === "bigint") return item.toString();
|
|
1503
|
+
if (typeof item === "object" && item !== null) {
|
|
1504
|
+
if (seen.has(item)) return "[Circular]";
|
|
1505
|
+
seen.add(item);
|
|
1506
|
+
}
|
|
1507
|
+
return item;
|
|
1508
|
+
}));
|
|
1509
|
+
} catch {
|
|
1510
|
+
return "[Unserializable value]";
|
|
1511
|
+
}
|
|
1512
|
+
}
|
|
1513
|
+
function read_run_history_impl(scope) {
|
|
1514
|
+
const key = storage_key(scope);
|
|
1515
|
+
if (!key) return [];
|
|
1516
|
+
try {
|
|
1517
|
+
const value = JSON.parse(window.localStorage.getItem(key) || "[]");
|
|
1518
|
+
return Array.isArray(value) ? value : [];
|
|
1519
|
+
} catch {
|
|
1520
|
+
return [];
|
|
1521
|
+
}
|
|
1522
|
+
}
|
|
1523
|
+
function write_run_history(scope, runs) {
|
|
1524
|
+
const key = storage_key(scope);
|
|
1525
|
+
if (!key) return;
|
|
1526
|
+
let next = runs.slice(0, MAX_RUNS);
|
|
1527
|
+
let pruned = false;
|
|
1528
|
+
while (next.length > 0) try {
|
|
1529
|
+
window.localStorage.setItem(key, JSON.stringify(next));
|
|
1530
|
+
return;
|
|
1531
|
+
} catch {
|
|
1532
|
+
if (!pruned) {
|
|
1533
|
+
pruned = true;
|
|
1534
|
+
prune_apps(key);
|
|
1535
|
+
continue;
|
|
1536
|
+
}
|
|
1537
|
+
next = next.slice(0, -1);
|
|
1538
|
+
}
|
|
1539
|
+
try {
|
|
1540
|
+
window.localStorage.removeItem(key);
|
|
1541
|
+
} catch {}
|
|
1542
|
+
}
|
|
1543
|
+
function clear_run_history_impl(scope) {
|
|
1544
|
+
const key = storage_key(scope);
|
|
1545
|
+
if (!key) return;
|
|
1546
|
+
try {
|
|
1547
|
+
window.localStorage.removeItem(key);
|
|
1548
|
+
} catch {}
|
|
1549
|
+
notify_run_history_change();
|
|
1550
|
+
}
|
|
1551
|
+
function delete_run_history_impl(scope, id) {
|
|
1552
|
+
write_run_history(scope, read_run_history_impl(scope).filter((run) => run.id !== id));
|
|
1553
|
+
notify_run_history_change();
|
|
1554
|
+
}
|
|
1555
|
+
var CHANGE_EVENT = "gradio:run-history-change";
|
|
1556
|
+
function notify_run_history_change() {
|
|
1557
|
+
if (typeof window === "undefined") return;
|
|
1558
|
+
try {
|
|
1559
|
+
window.dispatchEvent(new Event(CHANGE_EVENT));
|
|
1560
|
+
} catch {}
|
|
1561
|
+
}
|
|
1562
|
+
/**
|
|
1563
|
+
* Subscribes to runs being added, deleted or cleared. `storage` covers other
|
|
1564
|
+
* tabs; the custom event covers this one, which `storage` never fires for.
|
|
1565
|
+
* Only counts change, not per-run progress, so listeners stay cheap.
|
|
1566
|
+
*
|
|
1567
|
+
* @returns a function that unsubscribes.
|
|
1568
|
+
*/
|
|
1569
|
+
function on_run_history_change_impl(listener) {
|
|
1570
|
+
if (typeof window === "undefined") return () => {};
|
|
1571
|
+
window.addEventListener(CHANGE_EVENT, listener);
|
|
1572
|
+
window.addEventListener("storage", listener);
|
|
1573
|
+
return () => {
|
|
1574
|
+
window.removeEventListener(CHANGE_EVENT, listener);
|
|
1575
|
+
window.removeEventListener("storage", listener);
|
|
1576
|
+
};
|
|
1577
|
+
}
|
|
1578
|
+
function stage_run_history_replay_impl(scope, run) {
|
|
1579
|
+
const key = replay_key(scope);
|
|
1580
|
+
if (!key) return;
|
|
1581
|
+
try {
|
|
1582
|
+
window.sessionStorage.setItem(key, JSON.stringify(run));
|
|
1583
|
+
} catch {}
|
|
1584
|
+
}
|
|
1585
|
+
function consume_run_history_replay_impl(scope) {
|
|
1586
|
+
const key = replay_key(scope);
|
|
1587
|
+
if (!key) return null;
|
|
1588
|
+
try {
|
|
1589
|
+
const value = window.sessionStorage.getItem(key);
|
|
1590
|
+
window.sessionStorage.removeItem(key);
|
|
1591
|
+
return value ? JSON.parse(value) : null;
|
|
1592
|
+
} catch {
|
|
1593
|
+
return null;
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
function start_run_history_impl(options) {
|
|
1597
|
+
const key = storage_key(options);
|
|
1598
|
+
if (!key) return null;
|
|
1599
|
+
prune_apps(key);
|
|
1600
|
+
const run = {
|
|
1601
|
+
id: make_id(),
|
|
1602
|
+
endpoint: options.endpoint,
|
|
1603
|
+
api_name: options.api_name,
|
|
1604
|
+
fn_index: options.fn_index,
|
|
1605
|
+
page: `${window.location.pathname}${window.location.search}`,
|
|
1606
|
+
inputs: clone_for_storage(options.inputs),
|
|
1607
|
+
outputs: null,
|
|
1608
|
+
...options.input_components ? { input_components: clone_for_storage(options.input_components) } : {},
|
|
1609
|
+
...options.output_components ? { output_components: clone_for_storage(options.output_components) } : {},
|
|
1610
|
+
status: "running",
|
|
1611
|
+
started_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
1612
|
+
};
|
|
1613
|
+
write_run_history(options, [run, ...read_run_history_impl(options)]);
|
|
1614
|
+
notify_run_history_change();
|
|
1615
|
+
return run.id;
|
|
1616
|
+
}
|
|
1617
|
+
function update_run_inputs_impl(scope, id, inputs) {
|
|
1618
|
+
if (!id) return;
|
|
1619
|
+
const runs = read_run_history_impl(scope);
|
|
1620
|
+
const run = runs.find((item) => item.id === id);
|
|
1621
|
+
if (!run) return;
|
|
1622
|
+
run.inputs = clone_for_storage(inputs);
|
|
1623
|
+
write_run_history(scope, runs);
|
|
1624
|
+
}
|
|
1625
|
+
function update_run_history_impl(scope, id, event) {
|
|
1626
|
+
if (!id) return;
|
|
1627
|
+
const runs = read_run_history_impl(scope);
|
|
1628
|
+
const run = runs.find((item) => item.id === id);
|
|
1629
|
+
if (!run) return;
|
|
1630
|
+
let finished = false;
|
|
1631
|
+
if (event.type === "data") {
|
|
1632
|
+
run.outputs = clone_for_storage(event.data);
|
|
1633
|
+
deferred_outputs.set(id, run.outputs);
|
|
1634
|
+
} else if (event.type === "status" && event.original_msg === "process_starts") mark_process_start(run, event.time);
|
|
1635
|
+
else if (event.type === "status" && (event.stage === "generating" || event.stage === "streaming")) run.streamed = true;
|
|
1636
|
+
else if (event.type === "status" && event.stage === "complete") {
|
|
1637
|
+
run.status = "completed";
|
|
1638
|
+
mark_complete(run, event);
|
|
1639
|
+
finished = true;
|
|
1640
|
+
} else if (event.type === "status" && event.stage === "error") {
|
|
1641
|
+
run.status = "failed";
|
|
1642
|
+
run.error = typeof event.message === "string" ? event.message : JSON.stringify(event.message || "Unknown error");
|
|
1643
|
+
mark_complete(run, event);
|
|
1644
|
+
finished = true;
|
|
1645
|
+
} else return;
|
|
1646
|
+
if (finished) {
|
|
1647
|
+
if (deferred_outputs.has(id)) run.outputs = deferred_outputs.get(id);
|
|
1648
|
+
deferred_outputs.delete(id);
|
|
1649
|
+
last_write.delete(id);
|
|
1650
|
+
} else if (run.streamed) {
|
|
1651
|
+
if (Date.now() - (last_write.get(id) ?? 0) < STREAM_WRITE_INTERVAL_MS) return;
|
|
1652
|
+
last_write.set(id, Date.now());
|
|
1653
|
+
deferred_outputs.delete(id);
|
|
1654
|
+
}
|
|
1655
|
+
write_run_history(scope, runs);
|
|
1656
|
+
}
|
|
1657
|
+
var STREAM_WRITE_INTERVAL_MS = 500;
|
|
1658
|
+
/** When each in-flight streamed run was last written. */
|
|
1659
|
+
var last_write = /* @__PURE__ */ new Map();
|
|
1660
|
+
/** The newest output of a streamed run that has not been written yet. */
|
|
1661
|
+
var deferred_outputs = /* @__PURE__ */ new Map();
|
|
1662
|
+
function mark_process_start(run, time) {
|
|
1663
|
+
if (run.process_started_at) return;
|
|
1664
|
+
const started = time || /* @__PURE__ */ new Date();
|
|
1665
|
+
run.process_started_at = started.toISOString();
|
|
1666
|
+
run.queued_ms = Math.max(0, started.getTime() - Date.parse(run.started_at));
|
|
1667
|
+
}
|
|
1668
|
+
function mark_complete(run, event) {
|
|
1669
|
+
const completed = event.time || /* @__PURE__ */ new Date();
|
|
1670
|
+
run.completed_at = completed.toISOString();
|
|
1671
|
+
run.duration_ms = (!run.streamed && typeof event.cache_duration === "number" && event.cache_duration >= 0 ? event.cache_duration * 1e3 : null) ?? Math.max(0, completed.getTime() - Date.parse(run.process_started_at || run.started_at));
|
|
1672
|
+
}
|
|
1673
|
+
function read_run_history(scope) {
|
|
1674
|
+
return safely(() => read_run_history_impl(scope), []);
|
|
1675
|
+
}
|
|
1676
|
+
function clear_run_history(scope) {
|
|
1677
|
+
safely(() => clear_run_history_impl(scope), void 0);
|
|
1678
|
+
}
|
|
1679
|
+
function delete_run_history(scope, id) {
|
|
1680
|
+
safely(() => delete_run_history_impl(scope, id), void 0);
|
|
1681
|
+
}
|
|
1682
|
+
function stage_run_history_replay(scope, run) {
|
|
1683
|
+
safely(() => stage_run_history_replay_impl(scope, run), void 0);
|
|
1684
|
+
}
|
|
1685
|
+
function consume_run_history_replay(scope) {
|
|
1686
|
+
return safely(() => consume_run_history_replay_impl(scope), null);
|
|
1687
|
+
}
|
|
1688
|
+
function start_run_history(options) {
|
|
1689
|
+
return safely(() => start_run_history_impl(options), null);
|
|
1690
|
+
}
|
|
1691
|
+
function update_run_inputs(scope, id, inputs) {
|
|
1692
|
+
safely(() => update_run_inputs_impl(scope, id, inputs), void 0);
|
|
1693
|
+
}
|
|
1694
|
+
function update_run_history(scope, id, event) {
|
|
1695
|
+
safely(() => update_run_history_impl(scope, id, event), void 0);
|
|
1696
|
+
}
|
|
1697
|
+
function on_run_history_change(listener) {
|
|
1698
|
+
return safely(() => on_run_history_change_impl(() => safely(listener, void 0)), () => {});
|
|
1699
|
+
}
|
|
1700
|
+
//#endregion
|
|
1701
|
+
//#region src/utils/submit.ts
|
|
1562
1702
|
function submit(endpoint, data = {}, event_data, trigger_id, all_events, additional_headers) {
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
queue: true,
|
|
2084
|
-
endpoint: _endpoint,
|
|
2085
|
-
fn_index,
|
|
2086
|
-
time: /* @__PURE__ */ new Date()
|
|
2087
|
-
});
|
|
2088
|
-
if (["sse_v2", "sse_v2.1", "sse_v3"].includes(protocol)) {
|
|
2089
|
-
close_stream(stream_status, that.abort_controller);
|
|
2090
|
-
stream_status.open = false;
|
|
2091
|
-
close();
|
|
2092
|
-
}
|
|
2093
|
-
}
|
|
2094
|
-
};
|
|
2095
|
-
if (event_id in pending_stream_messages) {
|
|
2096
|
-
pending_stream_messages[event_id].forEach((msg) => callback(msg));
|
|
2097
|
-
delete pending_stream_messages[event_id];
|
|
2098
|
-
}
|
|
2099
|
-
event_callbacks[event_id] = callback;
|
|
2100
|
-
unclosed_events.add(event_id);
|
|
2101
|
-
if (!stream_status.open) {
|
|
2102
|
-
await this.open_stream();
|
|
2103
|
-
}
|
|
2104
|
-
}
|
|
2105
|
-
});
|
|
2106
|
-
}
|
|
2107
|
-
});
|
|
2108
|
-
let done = false;
|
|
2109
|
-
const values = [];
|
|
2110
|
-
const resolvers = [];
|
|
2111
|
-
const iterator = {
|
|
2112
|
-
[Symbol.asyncIterator]: () => iterator,
|
|
2113
|
-
next,
|
|
2114
|
-
throw: async (value) => {
|
|
2115
|
-
push_error(value);
|
|
2116
|
-
return next();
|
|
2117
|
-
},
|
|
2118
|
-
return: async () => {
|
|
2119
|
-
close();
|
|
2120
|
-
return { value: void 0, done: true };
|
|
2121
|
-
},
|
|
2122
|
-
cancel,
|
|
2123
|
-
send_chunk: (payload2) => {
|
|
2124
|
-
this.post_data(`${config.root}${api_prefix}/stream/${event_id_final}`, {
|
|
2125
|
-
...payload2,
|
|
2126
|
-
session_hash: this.session_hash
|
|
2127
|
-
});
|
|
2128
|
-
},
|
|
2129
|
-
close_stream: () => {
|
|
2130
|
-
this.post_data(
|
|
2131
|
-
`${config.root}${api_prefix}/stream/${event_id_final}/close`,
|
|
2132
|
-
{}
|
|
2133
|
-
);
|
|
2134
|
-
close();
|
|
2135
|
-
},
|
|
2136
|
-
event_id: () => event_id_final,
|
|
2137
|
-
wait_for_id: async () => {
|
|
2138
|
-
await job;
|
|
2139
|
-
return event_id;
|
|
2140
|
-
}
|
|
2141
|
-
};
|
|
2142
|
-
return iterator;
|
|
2143
|
-
} catch (error) {
|
|
2144
|
-
console.error("Submit function encountered an error:", error);
|
|
2145
|
-
throw error;
|
|
2146
|
-
}
|
|
1703
|
+
try {
|
|
1704
|
+
const { token } = this.options;
|
|
1705
|
+
const { fetch, app_reference, config, session_hash, api_info, api_map, stream_status, pending_stream_messages, pending_diff_streams, event_callbacks, unclosed_events, post_data, options, api_prefix } = this;
|
|
1706
|
+
const addt_headers = additional_headers || { "x-gradio-user": "api" };
|
|
1707
|
+
const that = this;
|
|
1708
|
+
if (!api_info) throw new Error(NO_API_INFO_MSG);
|
|
1709
|
+
if (!config) throw new Error("Could not resolve app config");
|
|
1710
|
+
let { fn_index, endpoint_info, dependency } = get_endpoint_info(api_info, endpoint, api_map, config);
|
|
1711
|
+
let resolved_data = map_data_to_params(data, endpoint_info);
|
|
1712
|
+
let protocol = config.protocol ?? "ws";
|
|
1713
|
+
if (protocol === "ws") throw new Error(WS_PROTOCOL_MSG);
|
|
1714
|
+
const history_endpoint = typeof dependency.api_name === "string" ? `/${dependency.api_name}` : endpoint;
|
|
1715
|
+
const history_api_name = typeof dependency.api_name === "string" ? `/${dependency.api_name}` : `Function ${fn_index}`;
|
|
1716
|
+
const component_metadata = (id) => {
|
|
1717
|
+
const component = config.components.find((item) => item.id === id);
|
|
1718
|
+
if (!component) return null;
|
|
1719
|
+
return {
|
|
1720
|
+
type: component.type,
|
|
1721
|
+
component_class_id: component.component_class_id,
|
|
1722
|
+
props: component.props
|
|
1723
|
+
};
|
|
1724
|
+
};
|
|
1725
|
+
const is_documented_endpoint = dependency.api_visibility === "public";
|
|
1726
|
+
const history_enabled = config.run_history !== false && this.options.record_history !== false;
|
|
1727
|
+
const history_scope = {
|
|
1728
|
+
app_id: config.app_id,
|
|
1729
|
+
username: config.username
|
|
1730
|
+
};
|
|
1731
|
+
const history_run_id = !history_enabled || !is_documented_endpoint ? null : start_run_history({
|
|
1732
|
+
...history_scope,
|
|
1733
|
+
endpoint: history_endpoint,
|
|
1734
|
+
api_name: history_api_name,
|
|
1735
|
+
fn_index,
|
|
1736
|
+
inputs: handle_payload(resolved_data, dependency, config.components, "input", true),
|
|
1737
|
+
input_components: dependency.inputs.map(component_metadata),
|
|
1738
|
+
output_components: dependency.outputs.map(component_metadata)
|
|
1739
|
+
});
|
|
1740
|
+
let stream;
|
|
1741
|
+
let event_id_final = "";
|
|
1742
|
+
const _endpoint = typeof endpoint === "number" ? "/predict" : endpoint;
|
|
1743
|
+
let payload;
|
|
1744
|
+
let event_id = null;
|
|
1745
|
+
let complete = false;
|
|
1746
|
+
let last_status = {};
|
|
1747
|
+
let url_params = typeof window !== "undefined" && typeof document !== "undefined" ? new URLSearchParams(window.location.search).toString() : "";
|
|
1748
|
+
const events_to_publish = options?.events?.reduce((acc, event) => {
|
|
1749
|
+
acc[event] = true;
|
|
1750
|
+
return acc;
|
|
1751
|
+
}, {}) || {};
|
|
1752
|
+
function fire_event(event) {
|
|
1753
|
+
update_run_history(history_scope, history_run_id, event);
|
|
1754
|
+
if (all_events || events_to_publish[event.type]) push_event(event);
|
|
1755
|
+
}
|
|
1756
|
+
async function cancel() {
|
|
1757
|
+
let reset_request = {};
|
|
1758
|
+
let cancel_request = {};
|
|
1759
|
+
reset_request = { event_id };
|
|
1760
|
+
cancel_request = {
|
|
1761
|
+
event_id,
|
|
1762
|
+
session_hash,
|
|
1763
|
+
fn_index
|
|
1764
|
+
};
|
|
1765
|
+
try {
|
|
1766
|
+
if (!config) throw new Error("Could not resolve app config");
|
|
1767
|
+
if ("event_id" in cancel_request) await fetch(`${config.root}${api_prefix}/${CANCEL_URL}`, {
|
|
1768
|
+
headers: { "Content-Type": "application/json" },
|
|
1769
|
+
method: "POST",
|
|
1770
|
+
body: JSON.stringify(cancel_request)
|
|
1771
|
+
});
|
|
1772
|
+
await fetch(`${config.root}${api_prefix}/${RESET_URL}`, {
|
|
1773
|
+
headers: { "Content-Type": "application/json" },
|
|
1774
|
+
method: "POST",
|
|
1775
|
+
body: JSON.stringify(reset_request)
|
|
1776
|
+
});
|
|
1777
|
+
} catch (e) {
|
|
1778
|
+
console.warn("The `/reset` endpoint could not be called. Subsequent endpoint results may be unreliable.");
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
const resolve_heartbeat = async (config) => {
|
|
1782
|
+
await this._resolve_heartbeat(config);
|
|
1783
|
+
};
|
|
1784
|
+
async function handle_render_config(render_config) {
|
|
1785
|
+
if (!config) return;
|
|
1786
|
+
let render_id = render_config.render_id;
|
|
1787
|
+
config.components = [...config.components.filter((c) => c.props.rendered_in !== render_id), ...render_config.components];
|
|
1788
|
+
config.dependencies = [...config.dependencies.filter((d) => d.rendered_in !== render_id), ...render_config.dependencies];
|
|
1789
|
+
const any_state = config.components.some((c) => c.type === "state");
|
|
1790
|
+
const any_unload = config.dependencies.some((d) => d.targets.some((t) => t[1] === "unload"));
|
|
1791
|
+
config.connect_heartbeat = any_state || any_unload;
|
|
1792
|
+
await resolve_heartbeat(config);
|
|
1793
|
+
fire_event({
|
|
1794
|
+
type: "render",
|
|
1795
|
+
data: render_config,
|
|
1796
|
+
endpoint: _endpoint,
|
|
1797
|
+
fn_index
|
|
1798
|
+
});
|
|
1799
|
+
}
|
|
1800
|
+
const job = this.handle_blob(config.root, resolved_data, endpoint_info).then(async (_payload) => {
|
|
1801
|
+
let input_data = handle_payload(_payload, dependency, config.components, "input", true);
|
|
1802
|
+
update_run_inputs(history_scope, history_run_id, input_data || []);
|
|
1803
|
+
payload = {
|
|
1804
|
+
data: input_data || [],
|
|
1805
|
+
event_data,
|
|
1806
|
+
fn_index,
|
|
1807
|
+
trigger_id,
|
|
1808
|
+
...options.oauth_token && endpoint_info?.oauth_token ? { oauth_token: options.oauth_token } : {}
|
|
1809
|
+
};
|
|
1810
|
+
if (skip_queue(fn_index, config)) {
|
|
1811
|
+
fire_event({
|
|
1812
|
+
type: "status",
|
|
1813
|
+
endpoint: _endpoint,
|
|
1814
|
+
stage: "pending",
|
|
1815
|
+
queue: false,
|
|
1816
|
+
fn_index,
|
|
1817
|
+
time: /* @__PURE__ */ new Date()
|
|
1818
|
+
});
|
|
1819
|
+
post_data(`${config.root}${api_prefix}/run${_endpoint.startsWith("/") ? _endpoint : `/${_endpoint}`}${url_params ? "?" + url_params : ""}`, {
|
|
1820
|
+
...payload,
|
|
1821
|
+
session_hash
|
|
1822
|
+
}, addt_headers).then(async ([output, status_code]) => {
|
|
1823
|
+
const data = output.data;
|
|
1824
|
+
if (status_code == 200) {
|
|
1825
|
+
fire_event({
|
|
1826
|
+
type: "data",
|
|
1827
|
+
endpoint: _endpoint,
|
|
1828
|
+
fn_index,
|
|
1829
|
+
data: handle_payload(data, dependency, config.components, "output", options.with_null_state),
|
|
1830
|
+
time: /* @__PURE__ */ new Date(),
|
|
1831
|
+
event_data,
|
|
1832
|
+
trigger_id
|
|
1833
|
+
});
|
|
1834
|
+
if (output.render_config) await handle_render_config(output.render_config);
|
|
1835
|
+
fire_event({
|
|
1836
|
+
type: "status",
|
|
1837
|
+
endpoint: _endpoint,
|
|
1838
|
+
fn_index,
|
|
1839
|
+
stage: "complete",
|
|
1840
|
+
eta: output.average_duration,
|
|
1841
|
+
queue: false,
|
|
1842
|
+
time: /* @__PURE__ */ new Date()
|
|
1843
|
+
});
|
|
1844
|
+
} else {
|
|
1845
|
+
const is_connection_error = output?.error === BROKEN_CONNECTION_MSG;
|
|
1846
|
+
fire_event({
|
|
1847
|
+
type: "status",
|
|
1848
|
+
stage: "error",
|
|
1849
|
+
endpoint: _endpoint,
|
|
1850
|
+
fn_index,
|
|
1851
|
+
message: output.error,
|
|
1852
|
+
broken: is_connection_error,
|
|
1853
|
+
queue: false,
|
|
1854
|
+
time: /* @__PURE__ */ new Date()
|
|
1855
|
+
});
|
|
1856
|
+
}
|
|
1857
|
+
}).catch((e) => {
|
|
1858
|
+
fire_event({
|
|
1859
|
+
type: "status",
|
|
1860
|
+
stage: "error",
|
|
1861
|
+
message: e.message,
|
|
1862
|
+
endpoint: _endpoint,
|
|
1863
|
+
fn_index,
|
|
1864
|
+
queue: false,
|
|
1865
|
+
time: /* @__PURE__ */ new Date()
|
|
1866
|
+
});
|
|
1867
|
+
});
|
|
1868
|
+
} else if (protocol == "sse") {
|
|
1869
|
+
fire_event({
|
|
1870
|
+
type: "status",
|
|
1871
|
+
stage: "pending",
|
|
1872
|
+
queue: true,
|
|
1873
|
+
endpoint: _endpoint,
|
|
1874
|
+
fn_index,
|
|
1875
|
+
time: /* @__PURE__ */ new Date()
|
|
1876
|
+
});
|
|
1877
|
+
var params = new URLSearchParams({
|
|
1878
|
+
fn_index: fn_index.toString(),
|
|
1879
|
+
session_hash
|
|
1880
|
+
}).toString();
|
|
1881
|
+
let url = new URL(`${config.root}${api_prefix}/${SSE_URL}?${url_params ? url_params + "&" : ""}${params}`);
|
|
1882
|
+
if (this.jwt) url.searchParams.set("__sign", this.jwt);
|
|
1883
|
+
stream = this.stream(url);
|
|
1884
|
+
if (!stream) return Promise.reject(/* @__PURE__ */ new Error("Cannot connect to SSE endpoint: " + url.toString()));
|
|
1885
|
+
stream.onmessage = async function(event) {
|
|
1886
|
+
const { type, status, data } = handle_message(JSON.parse(event.data), last_status[fn_index]);
|
|
1887
|
+
if (type === "update" && status && !complete) {
|
|
1888
|
+
fire_event({
|
|
1889
|
+
type: "status",
|
|
1890
|
+
endpoint: _endpoint,
|
|
1891
|
+
fn_index,
|
|
1892
|
+
time: /* @__PURE__ */ new Date(),
|
|
1893
|
+
...status
|
|
1894
|
+
});
|
|
1895
|
+
if (status.stage === "error") {
|
|
1896
|
+
stream?.close();
|
|
1897
|
+
close();
|
|
1898
|
+
}
|
|
1899
|
+
} else if (type === "data") {
|
|
1900
|
+
let [_, status] = await post_data(`${config.root}${api_prefix}/queue/data`, {
|
|
1901
|
+
...payload,
|
|
1902
|
+
session_hash,
|
|
1903
|
+
event_id
|
|
1904
|
+
});
|
|
1905
|
+
if (status !== 200) {
|
|
1906
|
+
fire_event({
|
|
1907
|
+
type: "status",
|
|
1908
|
+
stage: "error",
|
|
1909
|
+
message: BROKEN_CONNECTION_MSG,
|
|
1910
|
+
queue: true,
|
|
1911
|
+
endpoint: _endpoint,
|
|
1912
|
+
fn_index,
|
|
1913
|
+
time: /* @__PURE__ */ new Date()
|
|
1914
|
+
});
|
|
1915
|
+
stream?.close();
|
|
1916
|
+
close();
|
|
1917
|
+
}
|
|
1918
|
+
} else if (type === "complete") complete = status;
|
|
1919
|
+
else if (type === "log") fire_event({
|
|
1920
|
+
type: "log",
|
|
1921
|
+
title: data.title,
|
|
1922
|
+
log: data.log,
|
|
1923
|
+
level: data.level,
|
|
1924
|
+
endpoint: _endpoint,
|
|
1925
|
+
duration: data.duration,
|
|
1926
|
+
visible: data.visible,
|
|
1927
|
+
fn_index
|
|
1928
|
+
});
|
|
1929
|
+
else if (type === "generating" || type === "streaming") fire_event({
|
|
1930
|
+
type: "status",
|
|
1931
|
+
time: /* @__PURE__ */ new Date(),
|
|
1932
|
+
...status,
|
|
1933
|
+
stage: status?.stage,
|
|
1934
|
+
queue: true,
|
|
1935
|
+
endpoint: _endpoint,
|
|
1936
|
+
fn_index
|
|
1937
|
+
});
|
|
1938
|
+
if (data) {
|
|
1939
|
+
fire_event({
|
|
1940
|
+
type: "data",
|
|
1941
|
+
time: /* @__PURE__ */ new Date(),
|
|
1942
|
+
data: handle_payload(data.data, dependency, config.components, "output", options.with_null_state),
|
|
1943
|
+
endpoint: _endpoint,
|
|
1944
|
+
fn_index,
|
|
1945
|
+
event_data,
|
|
1946
|
+
trigger_id
|
|
1947
|
+
});
|
|
1948
|
+
if (complete) {
|
|
1949
|
+
fire_event({
|
|
1950
|
+
type: "status",
|
|
1951
|
+
time: /* @__PURE__ */ new Date(),
|
|
1952
|
+
...complete,
|
|
1953
|
+
stage: status?.stage,
|
|
1954
|
+
queue: true,
|
|
1955
|
+
endpoint: _endpoint,
|
|
1956
|
+
fn_index
|
|
1957
|
+
});
|
|
1958
|
+
stream?.close();
|
|
1959
|
+
close();
|
|
1960
|
+
}
|
|
1961
|
+
}
|
|
1962
|
+
};
|
|
1963
|
+
} else if (protocol == "sse_v1" || protocol == "sse_v2" || protocol == "sse_v2.1" || protocol == "sse_v3") {
|
|
1964
|
+
fire_event({
|
|
1965
|
+
type: "status",
|
|
1966
|
+
stage: "pending",
|
|
1967
|
+
queue: true,
|
|
1968
|
+
endpoint: _endpoint,
|
|
1969
|
+
fn_index,
|
|
1970
|
+
time: /* @__PURE__ */ new Date()
|
|
1971
|
+
});
|
|
1972
|
+
let hostname = "";
|
|
1973
|
+
if (typeof window !== "undefined" && typeof document !== "undefined") hostname = window?.location?.hostname;
|
|
1974
|
+
const origin = get_zerogpu_origin(hostname);
|
|
1975
|
+
return (typeof window !== "undefined" && typeof document !== "undefined" && window.parent != window && !!origin && window.supports_zerogpu_headers ? post_message("zerogpu-headers", origin) : Promise.resolve(null)).then((headers) => {
|
|
1976
|
+
const combined_headers = {
|
|
1977
|
+
...addt_headers,
|
|
1978
|
+
...headers || {}
|
|
1979
|
+
};
|
|
1980
|
+
return post_data(`${config.root}${api_prefix}/${SSE_DATA_URL}?${url_params}`, {
|
|
1981
|
+
...payload,
|
|
1982
|
+
session_hash
|
|
1983
|
+
}, combined_headers);
|
|
1984
|
+
}).then(async ([response, status]) => {
|
|
1985
|
+
if (response.event_id) event_id_final = response.event_id;
|
|
1986
|
+
if (status === 503) {
|
|
1987
|
+
fire_event({
|
|
1988
|
+
type: "status",
|
|
1989
|
+
stage: "error",
|
|
1990
|
+
message: QUEUE_FULL_MSG,
|
|
1991
|
+
queue: true,
|
|
1992
|
+
endpoint: _endpoint,
|
|
1993
|
+
fn_index,
|
|
1994
|
+
time: /* @__PURE__ */ new Date(),
|
|
1995
|
+
visible: true
|
|
1996
|
+
});
|
|
1997
|
+
close();
|
|
1998
|
+
} else if (status === 422) {
|
|
1999
|
+
fire_event({
|
|
2000
|
+
type: "status",
|
|
2001
|
+
stage: "error",
|
|
2002
|
+
message: response.detail,
|
|
2003
|
+
queue: true,
|
|
2004
|
+
endpoint: _endpoint,
|
|
2005
|
+
fn_index,
|
|
2006
|
+
code: "validation_error",
|
|
2007
|
+
time: /* @__PURE__ */ new Date(),
|
|
2008
|
+
visible: true
|
|
2009
|
+
});
|
|
2010
|
+
close();
|
|
2011
|
+
} else if (status !== 200) {
|
|
2012
|
+
const is_connection_error = response?.error === BROKEN_CONNECTION_MSG;
|
|
2013
|
+
fire_event({
|
|
2014
|
+
type: "status",
|
|
2015
|
+
stage: "error",
|
|
2016
|
+
broken: is_connection_error,
|
|
2017
|
+
message: is_connection_error ? BROKEN_CONNECTION_MSG : response.detail || response.error,
|
|
2018
|
+
queue: true,
|
|
2019
|
+
endpoint: _endpoint,
|
|
2020
|
+
fn_index,
|
|
2021
|
+
time: /* @__PURE__ */ new Date(),
|
|
2022
|
+
visible: true
|
|
2023
|
+
});
|
|
2024
|
+
close();
|
|
2025
|
+
} else {
|
|
2026
|
+
event_id = response.event_id;
|
|
2027
|
+
event_id_final = event_id;
|
|
2028
|
+
let callback = async function(_data) {
|
|
2029
|
+
try {
|
|
2030
|
+
const { type, status, data, original_msg } = handle_message(_data, last_status[fn_index]);
|
|
2031
|
+
if (type == "heartbeat") return;
|
|
2032
|
+
if (type === "update" && status && !complete) fire_event({
|
|
2033
|
+
type: "status",
|
|
2034
|
+
endpoint: _endpoint,
|
|
2035
|
+
fn_index,
|
|
2036
|
+
time: /* @__PURE__ */ new Date(),
|
|
2037
|
+
original_msg,
|
|
2038
|
+
...status
|
|
2039
|
+
});
|
|
2040
|
+
else if (type === "complete") complete = status;
|
|
2041
|
+
else if (type == "unexpected_error" || type == "broken_connection") {
|
|
2042
|
+
console.error("Unexpected error", status?.message);
|
|
2043
|
+
const broken = type === "broken_connection";
|
|
2044
|
+
fire_event({
|
|
2045
|
+
type: "status",
|
|
2046
|
+
stage: "error",
|
|
2047
|
+
message: status?.message || "An Unexpected Error Occurred!",
|
|
2048
|
+
queue: true,
|
|
2049
|
+
endpoint: _endpoint,
|
|
2050
|
+
broken,
|
|
2051
|
+
session_not_found: status?.session_not_found,
|
|
2052
|
+
fn_index,
|
|
2053
|
+
time: /* @__PURE__ */ new Date()
|
|
2054
|
+
});
|
|
2055
|
+
} else if (type === "log") {
|
|
2056
|
+
fire_event({
|
|
2057
|
+
type: "log",
|
|
2058
|
+
title: data.title,
|
|
2059
|
+
log: data.log,
|
|
2060
|
+
level: data.level,
|
|
2061
|
+
endpoint: _endpoint,
|
|
2062
|
+
duration: data.duration,
|
|
2063
|
+
visible: data.visible,
|
|
2064
|
+
fn_index
|
|
2065
|
+
});
|
|
2066
|
+
return;
|
|
2067
|
+
} else if (type === "generating" || type === "streaming") {
|
|
2068
|
+
fire_event({
|
|
2069
|
+
type: "status",
|
|
2070
|
+
time: /* @__PURE__ */ new Date(),
|
|
2071
|
+
...status,
|
|
2072
|
+
stage: status?.stage,
|
|
2073
|
+
queue: true,
|
|
2074
|
+
endpoint: _endpoint,
|
|
2075
|
+
fn_index
|
|
2076
|
+
});
|
|
2077
|
+
if (data && dependency.connection !== "stream" && [
|
|
2078
|
+
"sse_v2",
|
|
2079
|
+
"sse_v2.1",
|
|
2080
|
+
"sse_v3"
|
|
2081
|
+
].includes(protocol)) apply_diff_stream(pending_diff_streams, event_id, data);
|
|
2082
|
+
}
|
|
2083
|
+
if (data) {
|
|
2084
|
+
fire_event({
|
|
2085
|
+
type: "data",
|
|
2086
|
+
time: /* @__PURE__ */ new Date(),
|
|
2087
|
+
data: handle_payload(data.data, dependency, config.components, "output", options.with_null_state),
|
|
2088
|
+
endpoint: _endpoint,
|
|
2089
|
+
fn_index
|
|
2090
|
+
});
|
|
2091
|
+
if (data.render_config) await handle_render_config(data.render_config);
|
|
2092
|
+
if (complete) {
|
|
2093
|
+
fire_event({
|
|
2094
|
+
type: "status",
|
|
2095
|
+
time: /* @__PURE__ */ new Date(),
|
|
2096
|
+
...complete,
|
|
2097
|
+
stage: status?.stage,
|
|
2098
|
+
queue: true,
|
|
2099
|
+
endpoint: _endpoint,
|
|
2100
|
+
fn_index
|
|
2101
|
+
});
|
|
2102
|
+
close();
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
if (status?.stage === "complete" || status?.stage === "error") {
|
|
2106
|
+
if (event_callbacks[event_id]) delete event_callbacks[event_id];
|
|
2107
|
+
if (event_id in pending_diff_streams) delete pending_diff_streams[event_id];
|
|
2108
|
+
close();
|
|
2109
|
+
}
|
|
2110
|
+
} catch (e) {
|
|
2111
|
+
console.error("Unexpected client exception", e);
|
|
2112
|
+
fire_event({
|
|
2113
|
+
type: "status",
|
|
2114
|
+
stage: "error",
|
|
2115
|
+
message: "An Unexpected Error Occurred!",
|
|
2116
|
+
queue: true,
|
|
2117
|
+
endpoint: _endpoint,
|
|
2118
|
+
fn_index,
|
|
2119
|
+
time: /* @__PURE__ */ new Date()
|
|
2120
|
+
});
|
|
2121
|
+
if ([
|
|
2122
|
+
"sse_v2",
|
|
2123
|
+
"sse_v2.1",
|
|
2124
|
+
"sse_v3"
|
|
2125
|
+
].includes(protocol)) {
|
|
2126
|
+
close_stream(stream_status, that.abort_controller);
|
|
2127
|
+
stream_status.open = false;
|
|
2128
|
+
close();
|
|
2129
|
+
}
|
|
2130
|
+
}
|
|
2131
|
+
};
|
|
2132
|
+
if (event_id in pending_stream_messages) {
|
|
2133
|
+
pending_stream_messages[event_id].forEach((msg) => callback(msg));
|
|
2134
|
+
delete pending_stream_messages[event_id];
|
|
2135
|
+
}
|
|
2136
|
+
event_callbacks[event_id] = callback;
|
|
2137
|
+
unclosed_events.add(event_id);
|
|
2138
|
+
if (!stream_status.open) await this.open_stream();
|
|
2139
|
+
}
|
|
2140
|
+
});
|
|
2141
|
+
}
|
|
2142
|
+
});
|
|
2143
|
+
job.catch((e) => {
|
|
2144
|
+
fire_event({
|
|
2145
|
+
type: "status",
|
|
2146
|
+
stage: "error",
|
|
2147
|
+
message: e instanceof Error ? e.message : String(e),
|
|
2148
|
+
queue: !skip_queue(fn_index, config),
|
|
2149
|
+
endpoint: _endpoint,
|
|
2150
|
+
fn_index,
|
|
2151
|
+
time: /* @__PURE__ */ new Date()
|
|
2152
|
+
});
|
|
2153
|
+
close();
|
|
2154
|
+
});
|
|
2155
|
+
let done = false;
|
|
2156
|
+
const values = [];
|
|
2157
|
+
const resolvers = [];
|
|
2158
|
+
function close() {
|
|
2159
|
+
done = true;
|
|
2160
|
+
while (resolvers.length > 0) resolvers.shift()({
|
|
2161
|
+
value: void 0,
|
|
2162
|
+
done: true
|
|
2163
|
+
});
|
|
2164
|
+
}
|
|
2165
|
+
function push(data) {
|
|
2166
|
+
if (resolvers.length > 0) resolvers.shift()(data);
|
|
2167
|
+
else values.push(data);
|
|
2168
|
+
}
|
|
2169
|
+
function push_error(error) {
|
|
2170
|
+
push(thenable_reject(error));
|
|
2171
|
+
close();
|
|
2172
|
+
}
|
|
2173
|
+
function push_event(event) {
|
|
2174
|
+
push({
|
|
2175
|
+
value: event,
|
|
2176
|
+
done: false
|
|
2177
|
+
});
|
|
2178
|
+
}
|
|
2179
|
+
function next() {
|
|
2180
|
+
if (values.length > 0) return Promise.resolve(values.shift());
|
|
2181
|
+
if (done) return Promise.resolve({
|
|
2182
|
+
value: void 0,
|
|
2183
|
+
done: true
|
|
2184
|
+
});
|
|
2185
|
+
return new Promise((resolve) => resolvers.push(resolve));
|
|
2186
|
+
}
|
|
2187
|
+
const iterator = {
|
|
2188
|
+
[Symbol.asyncIterator]: () => iterator,
|
|
2189
|
+
next,
|
|
2190
|
+
throw: async (value) => {
|
|
2191
|
+
push_error(value);
|
|
2192
|
+
return next();
|
|
2193
|
+
},
|
|
2194
|
+
return: async () => {
|
|
2195
|
+
close();
|
|
2196
|
+
return {
|
|
2197
|
+
value: void 0,
|
|
2198
|
+
done: true
|
|
2199
|
+
};
|
|
2200
|
+
},
|
|
2201
|
+
cancel,
|
|
2202
|
+
send_chunk: (payload) => {
|
|
2203
|
+
this.post_data(`${config.root}${api_prefix}/stream/${event_id_final}`, {
|
|
2204
|
+
...payload,
|
|
2205
|
+
session_hash: this.session_hash
|
|
2206
|
+
});
|
|
2207
|
+
},
|
|
2208
|
+
close_stream: () => {
|
|
2209
|
+
this.post_data(`${config.root}${api_prefix}/stream/${event_id_final}/close`, {});
|
|
2210
|
+
close();
|
|
2211
|
+
},
|
|
2212
|
+
event_id: () => event_id_final,
|
|
2213
|
+
wait_for_id: async () => {
|
|
2214
|
+
await job;
|
|
2215
|
+
return event_id;
|
|
2216
|
+
}
|
|
2217
|
+
};
|
|
2218
|
+
return iterator;
|
|
2219
|
+
} catch (error) {
|
|
2220
|
+
console.error("Submit function encountered an error:", error);
|
|
2221
|
+
throw error;
|
|
2222
|
+
}
|
|
2147
2223
|
}
|
|
2148
2224
|
function thenable_reject(error) {
|
|
2149
|
-
|
|
2150
|
-
then: (resolve, reject) => reject(error)
|
|
2151
|
-
};
|
|
2225
|
+
return { then: (resolve, reject) => reject(error) };
|
|
2152
2226
|
}
|
|
2153
2227
|
function get_endpoint_info(api_info, endpoint, api_map, config) {
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
}
|
|
2176
|
-
class Client {
|
|
2177
|
-
app_reference;
|
|
2178
|
-
options;
|
|
2179
|
-
deep_link = null;
|
|
2180
|
-
config;
|
|
2181
|
-
api_prefix = "";
|
|
2182
|
-
api_info;
|
|
2183
|
-
api_map = {};
|
|
2184
|
-
session_hash = Math.random().toString(36).substring(2);
|
|
2185
|
-
jwt = false;
|
|
2186
|
-
last_status = {};
|
|
2187
|
-
cookies = null;
|
|
2188
|
-
// streaming
|
|
2189
|
-
stream_status = { open: false };
|
|
2190
|
-
closed = false;
|
|
2191
|
-
pending_stream_messages = {};
|
|
2192
|
-
pending_diff_streams = {};
|
|
2193
|
-
event_callbacks = {};
|
|
2194
|
-
unclosed_events = /* @__PURE__ */ new Set();
|
|
2195
|
-
heartbeat_event = null;
|
|
2196
|
-
abort_controller = null;
|
|
2197
|
-
stream_instance = null;
|
|
2198
|
-
current_payload;
|
|
2199
|
-
get_url_config(url = null) {
|
|
2200
|
-
if (!this.config) {
|
|
2201
|
-
throw new Error(CONFIG_ERROR_MSG);
|
|
2202
|
-
}
|
|
2203
|
-
if (url === null) {
|
|
2204
|
-
url = window.location.href;
|
|
2205
|
-
}
|
|
2206
|
-
const stripSlashes = (str) => str.replace(/^\/+|\/+$/g, "");
|
|
2207
|
-
let root_path = stripSlashes(new URL(this.config.root).pathname);
|
|
2208
|
-
let url_path = stripSlashes(new URL(url).pathname);
|
|
2209
|
-
let page;
|
|
2210
|
-
if (!url_path.startsWith(root_path)) {
|
|
2211
|
-
page = "";
|
|
2212
|
-
} else {
|
|
2213
|
-
page = stripSlashes(url_path.substring(root_path.length));
|
|
2214
|
-
}
|
|
2215
|
-
return this.get_page_config(page);
|
|
2216
|
-
}
|
|
2217
|
-
get_page_config(page) {
|
|
2218
|
-
if (!this.config) {
|
|
2219
|
-
throw new Error(CONFIG_ERROR_MSG);
|
|
2220
|
-
}
|
|
2221
|
-
let config = this.config;
|
|
2222
|
-
if (!(page in config.page)) {
|
|
2223
|
-
page = "";
|
|
2224
|
-
}
|
|
2225
|
-
return {
|
|
2226
|
-
...config,
|
|
2227
|
-
current_page: page,
|
|
2228
|
-
layout: config.page[page].layout,
|
|
2229
|
-
components: config.components.filter(
|
|
2230
|
-
(c) => config.page[page].components.includes(c.id)
|
|
2231
|
-
),
|
|
2232
|
-
dependencies: this.config.dependencies.filter(
|
|
2233
|
-
(d) => config.page[page].dependencies.includes(d.id)
|
|
2234
|
-
)
|
|
2235
|
-
};
|
|
2236
|
-
}
|
|
2237
|
-
fetch(input, init) {
|
|
2238
|
-
const headers = new Headers(init?.headers || {});
|
|
2239
|
-
if (this && this.cookies) {
|
|
2240
|
-
headers.append("Cookie", this.cookies);
|
|
2241
|
-
}
|
|
2242
|
-
if (this && this.options.headers) {
|
|
2243
|
-
let additional_headers = new Headers(this.options.headers);
|
|
2244
|
-
additional_headers.forEach((value, name) => {
|
|
2245
|
-
headers.append(name, value);
|
|
2246
|
-
});
|
|
2247
|
-
}
|
|
2248
|
-
return fetch(input, { ...init, headers });
|
|
2249
|
-
}
|
|
2250
|
-
stream(url) {
|
|
2251
|
-
const headers = new Headers();
|
|
2252
|
-
if (this && this.cookies) {
|
|
2253
|
-
headers.append("Cookie", this.cookies);
|
|
2254
|
-
}
|
|
2255
|
-
if (this && this.options.headers) {
|
|
2256
|
-
let additional_headers = new Headers(this.options.headers);
|
|
2257
|
-
additional_headers.forEach((value, name) => {
|
|
2258
|
-
headers.append(name, value);
|
|
2259
|
-
});
|
|
2260
|
-
}
|
|
2261
|
-
if (this && this.options.token) {
|
|
2262
|
-
headers.append("Authorization", `Bearer ${this.options.token}`);
|
|
2263
|
-
}
|
|
2264
|
-
this.abort_controller = new AbortController();
|
|
2265
|
-
this.stream_instance = readable_stream(url.toString(), {
|
|
2266
|
-
credentials: this.options.credentials ?? "same-origin",
|
|
2267
|
-
headers,
|
|
2268
|
-
signal: this.abort_controller.signal
|
|
2269
|
-
});
|
|
2270
|
-
return this.stream_instance;
|
|
2271
|
-
}
|
|
2272
|
-
view_api;
|
|
2273
|
-
upload_files;
|
|
2274
|
-
upload;
|
|
2275
|
-
handle_blob;
|
|
2276
|
-
post_data;
|
|
2277
|
-
submit;
|
|
2278
|
-
predict;
|
|
2279
|
-
open_stream;
|
|
2280
|
-
resolve_config;
|
|
2281
|
-
resolve_cookies;
|
|
2282
|
-
constructor(app_reference, options = { events: ["data"] }) {
|
|
2283
|
-
this.app_reference = app_reference;
|
|
2284
|
-
this.deep_link = options.query_params?.deep_link || null;
|
|
2285
|
-
if (!options.events) {
|
|
2286
|
-
options.events = ["data"];
|
|
2287
|
-
}
|
|
2288
|
-
this.options = options;
|
|
2289
|
-
this.current_payload = {};
|
|
2290
|
-
if (options.cookies) {
|
|
2291
|
-
this.cookies = options.cookies;
|
|
2292
|
-
}
|
|
2293
|
-
this.view_api = view_api.bind(this);
|
|
2294
|
-
this.upload_files = upload_files.bind(this);
|
|
2295
|
-
this.handle_blob = handle_blob.bind(this);
|
|
2296
|
-
this.post_data = post_data.bind(this);
|
|
2297
|
-
this.submit = submit.bind(this);
|
|
2298
|
-
this.predict = predict.bind(this);
|
|
2299
|
-
this.open_stream = open_stream.bind(this);
|
|
2300
|
-
this.resolve_config = resolve_config.bind(this);
|
|
2301
|
-
this.resolve_cookies = resolve_cookies.bind(this);
|
|
2302
|
-
this.upload = upload.bind(this);
|
|
2303
|
-
this.fetch = this.fetch.bind(this);
|
|
2304
|
-
this.handle_space_success = this.handle_space_success.bind(this);
|
|
2305
|
-
this.stream = this.stream.bind(this);
|
|
2306
|
-
}
|
|
2307
|
-
async init() {
|
|
2308
|
-
initialize_zerogpu_handshake();
|
|
2309
|
-
if (this.options.auth) {
|
|
2310
|
-
await this.resolve_cookies();
|
|
2311
|
-
}
|
|
2312
|
-
await this._resolve_config().then(
|
|
2313
|
-
({ config }) => this._resolve_heartbeat(config)
|
|
2314
|
-
);
|
|
2315
|
-
this.api_info = await this.view_api();
|
|
2316
|
-
this.api_map = map_names_to_ids(this.config?.dependencies || []);
|
|
2317
|
-
}
|
|
2318
|
-
async _resolve_heartbeat(_config) {
|
|
2319
|
-
if (_config) {
|
|
2320
|
-
this.config = _config;
|
|
2321
|
-
this.api_prefix = _config.api_prefix || "";
|
|
2322
|
-
if (this.config && this.config.connect_heartbeat) {
|
|
2323
|
-
if (this.config.space_id && this.options.token) {
|
|
2324
|
-
this.jwt = await get_jwt(
|
|
2325
|
-
this.config.space_id,
|
|
2326
|
-
this.options.token,
|
|
2327
|
-
this.cookies
|
|
2328
|
-
);
|
|
2329
|
-
}
|
|
2330
|
-
}
|
|
2331
|
-
}
|
|
2332
|
-
if (_config.space_id && this.options.token) {
|
|
2333
|
-
this.jwt = await get_jwt(_config.space_id, this.options.token);
|
|
2334
|
-
}
|
|
2335
|
-
if (this.config && this.config.connect_heartbeat) {
|
|
2336
|
-
const heartbeat_url = new URL(
|
|
2337
|
-
`${this.config.root}${this.api_prefix}/${HEARTBEAT_URL}/${this.session_hash}`
|
|
2338
|
-
);
|
|
2339
|
-
if (this.jwt) {
|
|
2340
|
-
heartbeat_url.searchParams.set("__sign", this.jwt);
|
|
2341
|
-
}
|
|
2342
|
-
if (!this.heartbeat_event) {
|
|
2343
|
-
this.heartbeat_event = this.stream(heartbeat_url);
|
|
2344
|
-
}
|
|
2345
|
-
}
|
|
2346
|
-
}
|
|
2347
|
-
static async connect(app_reference, options = {
|
|
2348
|
-
events: ["data"]
|
|
2349
|
-
}) {
|
|
2350
|
-
const client2 = new this(app_reference, options);
|
|
2351
|
-
if (options.session_hash) {
|
|
2352
|
-
client2.session_hash = options.session_hash;
|
|
2353
|
-
}
|
|
2354
|
-
await client2.init();
|
|
2355
|
-
return client2;
|
|
2356
|
-
}
|
|
2357
|
-
async reconnect() {
|
|
2358
|
-
const app_id_url = new URL(
|
|
2359
|
-
`${this.config.root}${this.api_prefix}/${APP_ID_URL}`
|
|
2360
|
-
);
|
|
2361
|
-
let app_id;
|
|
2362
|
-
try {
|
|
2363
|
-
const response = await this.fetch(app_id_url);
|
|
2364
|
-
if (!response.ok) {
|
|
2365
|
-
throw new Error();
|
|
2366
|
-
}
|
|
2367
|
-
app_id = (await response.json()).app_id;
|
|
2368
|
-
} catch (e) {
|
|
2369
|
-
return "broken";
|
|
2370
|
-
}
|
|
2371
|
-
if (app_id !== this.config.app_id) {
|
|
2372
|
-
return "changed";
|
|
2373
|
-
}
|
|
2374
|
-
return "connected";
|
|
2375
|
-
}
|
|
2376
|
-
close() {
|
|
2377
|
-
this.closed = true;
|
|
2378
|
-
close_stream(this.stream_status, this.abort_controller);
|
|
2379
|
-
}
|
|
2380
|
-
set_current_payload(payload) {
|
|
2381
|
-
this.current_payload = payload;
|
|
2382
|
-
}
|
|
2383
|
-
static async duplicate(app_reference, options = {
|
|
2384
|
-
events: ["data"]
|
|
2385
|
-
}) {
|
|
2386
|
-
return duplicate(app_reference, options);
|
|
2387
|
-
}
|
|
2388
|
-
async _resolve_config() {
|
|
2389
|
-
const { http_protocol, host, space_id } = await process_endpoint(
|
|
2390
|
-
this.app_reference,
|
|
2391
|
-
this.options.token
|
|
2392
|
-
);
|
|
2393
|
-
const { status_callback } = this.options;
|
|
2394
|
-
if (space_id && status_callback) {
|
|
2395
|
-
await check_and_wake_space(space_id, status_callback);
|
|
2396
|
-
}
|
|
2397
|
-
let config;
|
|
2398
|
-
try {
|
|
2399
|
-
let configUrl = `${http_protocol}//${host}`;
|
|
2400
|
-
config = await this.resolve_config(configUrl);
|
|
2401
|
-
if (!config) {
|
|
2402
|
-
throw new Error(CONFIG_ERROR_MSG);
|
|
2403
|
-
}
|
|
2404
|
-
return this.config_success(config);
|
|
2405
|
-
} catch (e) {
|
|
2406
|
-
if (space_id && status_callback) {
|
|
2407
|
-
check_space_status(
|
|
2408
|
-
space_id,
|
|
2409
|
-
RE_SPACE_NAME.test(space_id) ? "space_name" : "subdomain",
|
|
2410
|
-
this.handle_space_success
|
|
2411
|
-
);
|
|
2412
|
-
} else {
|
|
2413
|
-
if (status_callback)
|
|
2414
|
-
status_callback({
|
|
2415
|
-
status: "error",
|
|
2416
|
-
message: "Could not load this space.",
|
|
2417
|
-
load_status: "error",
|
|
2418
|
-
detail: "NOT_FOUND"
|
|
2419
|
-
});
|
|
2420
|
-
throw Error(e);
|
|
2421
|
-
}
|
|
2422
|
-
}
|
|
2423
|
-
}
|
|
2424
|
-
async config_success(_config) {
|
|
2425
|
-
this.config = _config;
|
|
2426
|
-
this.api_prefix = _config.api_prefix || "";
|
|
2427
|
-
if (this.config.auth_required) {
|
|
2428
|
-
return this.prepare_return_obj();
|
|
2429
|
-
}
|
|
2430
|
-
try {
|
|
2431
|
-
this.api_info = await this.view_api();
|
|
2432
|
-
} catch (e) {
|
|
2433
|
-
console.error(API_INFO_ERROR_MSG + e.message);
|
|
2434
|
-
}
|
|
2435
|
-
return this.prepare_return_obj();
|
|
2436
|
-
}
|
|
2437
|
-
async handle_space_success(status) {
|
|
2438
|
-
if (!this) {
|
|
2439
|
-
throw new Error(CONFIG_ERROR_MSG);
|
|
2440
|
-
}
|
|
2441
|
-
const { status_callback } = this.options;
|
|
2442
|
-
if (status_callback) status_callback(status);
|
|
2443
|
-
if (status.status === "running") {
|
|
2444
|
-
try {
|
|
2445
|
-
this.config = await this._resolve_config();
|
|
2446
|
-
this.api_prefix = this?.config?.api_prefix || "";
|
|
2447
|
-
if (!this.config) {
|
|
2448
|
-
throw new Error(CONFIG_ERROR_MSG);
|
|
2449
|
-
}
|
|
2450
|
-
const _config = await this.config_success(this.config);
|
|
2451
|
-
return _config;
|
|
2452
|
-
} catch (e) {
|
|
2453
|
-
if (status_callback) {
|
|
2454
|
-
status_callback({
|
|
2455
|
-
status: "error",
|
|
2456
|
-
message: "Could not load this space.",
|
|
2457
|
-
load_status: "error",
|
|
2458
|
-
detail: "NOT_FOUND"
|
|
2459
|
-
});
|
|
2460
|
-
}
|
|
2461
|
-
throw e;
|
|
2462
|
-
}
|
|
2463
|
-
}
|
|
2464
|
-
}
|
|
2465
|
-
async component_server(component_id, fn_name, data) {
|
|
2466
|
-
if (!this.config) {
|
|
2467
|
-
throw new Error(CONFIG_ERROR_MSG);
|
|
2468
|
-
}
|
|
2469
|
-
const headers = {};
|
|
2470
|
-
const { token } = this.options;
|
|
2471
|
-
const { session_hash } = this;
|
|
2472
|
-
if (token) {
|
|
2473
|
-
headers.Authorization = `Bearer ${this.options.token}`;
|
|
2474
|
-
}
|
|
2475
|
-
let root_url;
|
|
2476
|
-
let component = this.config.components.find(
|
|
2477
|
-
(comp) => comp.id === component_id
|
|
2478
|
-
);
|
|
2479
|
-
if (component?.props?.root_url) {
|
|
2480
|
-
root_url = component.props.root_url;
|
|
2481
|
-
} else {
|
|
2482
|
-
root_url = this.config.root;
|
|
2483
|
-
}
|
|
2484
|
-
let body;
|
|
2485
|
-
if (typeof data === "object" && data !== null && "binary" in data) {
|
|
2486
|
-
const _data = data;
|
|
2487
|
-
body = new FormData();
|
|
2488
|
-
for (const key in _data.data) {
|
|
2489
|
-
if (key === "binary") continue;
|
|
2490
|
-
body.append(key, _data.data[key]);
|
|
2491
|
-
}
|
|
2492
|
-
body.set("component_id", component_id.toString());
|
|
2493
|
-
body.set("fn_name", fn_name);
|
|
2494
|
-
body.set("session_hash", session_hash);
|
|
2495
|
-
} else {
|
|
2496
|
-
body = JSON.stringify({
|
|
2497
|
-
data,
|
|
2498
|
-
component_id,
|
|
2499
|
-
fn_name,
|
|
2500
|
-
session_hash
|
|
2501
|
-
});
|
|
2502
|
-
headers["Content-Type"] = "application/json";
|
|
2503
|
-
}
|
|
2504
|
-
if (token) {
|
|
2505
|
-
headers.Authorization = `Bearer ${token}`;
|
|
2506
|
-
}
|
|
2507
|
-
try {
|
|
2508
|
-
const response = await this.fetch(
|
|
2509
|
-
`${root_url}${this.api_prefix}/${COMPONENT_SERVER_URL}/`,
|
|
2510
|
-
{
|
|
2511
|
-
method: "POST",
|
|
2512
|
-
body,
|
|
2513
|
-
headers,
|
|
2514
|
-
credentials: this.options.credentials ?? "same-origin"
|
|
2515
|
-
}
|
|
2516
|
-
);
|
|
2517
|
-
if (!response.ok) {
|
|
2518
|
-
throw new Error(
|
|
2519
|
-
"Could not connect to component server: " + response.statusText
|
|
2520
|
-
);
|
|
2521
|
-
}
|
|
2522
|
-
const output = await response.json();
|
|
2523
|
-
return output;
|
|
2524
|
-
} catch (e) {
|
|
2525
|
-
console.warn(e);
|
|
2526
|
-
}
|
|
2527
|
-
}
|
|
2528
|
-
set_cookies(raw_cookies) {
|
|
2529
|
-
this.cookies = parse_and_set_cookies(raw_cookies).join("; ");
|
|
2530
|
-
}
|
|
2531
|
-
prepare_return_obj() {
|
|
2532
|
-
return {
|
|
2533
|
-
config: this.config,
|
|
2534
|
-
predict: this.predict,
|
|
2535
|
-
submit: this.submit,
|
|
2536
|
-
view_api: this.view_api,
|
|
2537
|
-
component_server: this.component_server
|
|
2538
|
-
};
|
|
2539
|
-
}
|
|
2540
|
-
}
|
|
2541
|
-
async function client(app_reference, options = {
|
|
2542
|
-
events: ["data"]
|
|
2543
|
-
}) {
|
|
2544
|
-
return await Client.connect(app_reference, options);
|
|
2228
|
+
let fn_index;
|
|
2229
|
+
let endpoint_info;
|
|
2230
|
+
let dependency;
|
|
2231
|
+
if (typeof endpoint === "number") {
|
|
2232
|
+
fn_index = endpoint;
|
|
2233
|
+
endpoint_info = api_info.unnamed_endpoints[fn_index];
|
|
2234
|
+
dependency = config.dependencies.find((dep) => dep.id == endpoint);
|
|
2235
|
+
} else {
|
|
2236
|
+
const trimmed_endpoint = endpoint.replace(/^\//, "");
|
|
2237
|
+
fn_index = api_map[trimmed_endpoint];
|
|
2238
|
+
endpoint_info = api_info.named_endpoints[endpoint.trim()] ?? api_info.named_endpoints[`/${trimmed_endpoint}`];
|
|
2239
|
+
dependency = config.dependencies.find((dep) => dep.id == api_map[trimmed_endpoint]);
|
|
2240
|
+
}
|
|
2241
|
+
if (typeof fn_index !== "number" || !dependency) {
|
|
2242
|
+
const valid_endpoints = config.dependencies.filter((dep) => dep.api_name).map((dep) => `"/${dep.api_name}"`).join(", ");
|
|
2243
|
+
throw new Error(`No endpoint matching ${JSON.stringify(endpoint)} was found. ` + (valid_endpoints ? `Valid named endpoints are: ${valid_endpoints}. ` : "This app exposes no named endpoints. ") + "An fn_index (number) of an existing dependency can also be used.");
|
|
2244
|
+
}
|
|
2245
|
+
return {
|
|
2246
|
+
fn_index,
|
|
2247
|
+
endpoint_info,
|
|
2248
|
+
dependency
|
|
2249
|
+
};
|
|
2545
2250
|
}
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2251
|
+
//#endregion
|
|
2252
|
+
//#region src/client.ts
|
|
2253
|
+
var Client = class {
|
|
2254
|
+
app_reference;
|
|
2255
|
+
options;
|
|
2256
|
+
deep_link = null;
|
|
2257
|
+
config;
|
|
2258
|
+
api_prefix = "";
|
|
2259
|
+
api_info;
|
|
2260
|
+
api_map = {};
|
|
2261
|
+
session_hash = Math.random().toString(36).substring(2);
|
|
2262
|
+
jwt = false;
|
|
2263
|
+
last_status = {};
|
|
2264
|
+
cookies = null;
|
|
2265
|
+
stream_status = { open: false };
|
|
2266
|
+
closed = false;
|
|
2267
|
+
pending_stream_messages = {};
|
|
2268
|
+
pending_diff_streams = {};
|
|
2269
|
+
event_callbacks = {};
|
|
2270
|
+
unclosed_events = /* @__PURE__ */ new Set();
|
|
2271
|
+
heartbeat_event = null;
|
|
2272
|
+
abort_controller = null;
|
|
2273
|
+
stream_instance = null;
|
|
2274
|
+
current_payload;
|
|
2275
|
+
get_url_config(url = null) {
|
|
2276
|
+
if (!this.config) throw new Error(CONFIG_ERROR_MSG);
|
|
2277
|
+
if (url === null) url = window.location.href;
|
|
2278
|
+
const stripSlashes = (str) => str.replace(/^\/+|\/+$/g, "");
|
|
2279
|
+
let root_path = stripSlashes(new URL(this.config.root).pathname);
|
|
2280
|
+
let url_path = stripSlashes(new URL(url).pathname);
|
|
2281
|
+
let page;
|
|
2282
|
+
if (!url_path.startsWith(root_path)) page = "";
|
|
2283
|
+
else page = stripSlashes(url_path.substring(root_path.length));
|
|
2284
|
+
return this.get_page_config(page);
|
|
2285
|
+
}
|
|
2286
|
+
get_page_config(page) {
|
|
2287
|
+
if (!this.config) throw new Error(CONFIG_ERROR_MSG);
|
|
2288
|
+
let config = this.config;
|
|
2289
|
+
if (!(page in config.page)) page = "";
|
|
2290
|
+
return {
|
|
2291
|
+
...config,
|
|
2292
|
+
current_page: page,
|
|
2293
|
+
layout: config.page[page].layout,
|
|
2294
|
+
components: config.components.filter((c) => config.page[page].components.includes(c.id)),
|
|
2295
|
+
dependencies: this.config.dependencies.filter((d) => config.page[page].dependencies.includes(d.id))
|
|
2296
|
+
};
|
|
2297
|
+
}
|
|
2298
|
+
fetch(input, init) {
|
|
2299
|
+
const headers = new Headers(init?.headers || {});
|
|
2300
|
+
if (this && this.cookies) headers.append("Cookie", this.cookies);
|
|
2301
|
+
if (this && this.options.headers) new Headers(this.options.headers).forEach((value, name) => {
|
|
2302
|
+
headers.append(name, value);
|
|
2303
|
+
});
|
|
2304
|
+
return fetch(input, {
|
|
2305
|
+
...init,
|
|
2306
|
+
headers
|
|
2307
|
+
});
|
|
2308
|
+
}
|
|
2309
|
+
stream(url) {
|
|
2310
|
+
const headers = new Headers();
|
|
2311
|
+
if (this && this.cookies) headers.append("Cookie", this.cookies);
|
|
2312
|
+
if (this && this.options.headers) new Headers(this.options.headers).forEach((value, name) => {
|
|
2313
|
+
headers.append(name, value);
|
|
2314
|
+
});
|
|
2315
|
+
if (this && this.options.token) headers.append("Authorization", `Bearer ${this.options.token}`);
|
|
2316
|
+
this.abort_controller = new AbortController();
|
|
2317
|
+
this.stream_instance = readable_stream(url.toString(), {
|
|
2318
|
+
credentials: this.options.credentials ?? "same-origin",
|
|
2319
|
+
headers,
|
|
2320
|
+
signal: this.abort_controller.signal
|
|
2321
|
+
});
|
|
2322
|
+
return this.stream_instance;
|
|
2323
|
+
}
|
|
2324
|
+
view_api;
|
|
2325
|
+
upload_files;
|
|
2326
|
+
upload;
|
|
2327
|
+
handle_blob;
|
|
2328
|
+
post_data;
|
|
2329
|
+
submit;
|
|
2330
|
+
predict;
|
|
2331
|
+
open_stream;
|
|
2332
|
+
resolve_config;
|
|
2333
|
+
resolve_cookies;
|
|
2334
|
+
constructor(app_reference, options = { events: ["data"] }) {
|
|
2335
|
+
this.app_reference = app_reference;
|
|
2336
|
+
this.deep_link = options.query_params?.deep_link || null;
|
|
2337
|
+
if (!options.events) options.events = ["data"];
|
|
2338
|
+
normalise_token_option(options);
|
|
2339
|
+
this.options = options;
|
|
2340
|
+
this.current_payload = {};
|
|
2341
|
+
if (options.cookies) this.cookies = options.cookies;
|
|
2342
|
+
this.view_api = view_api.bind(this);
|
|
2343
|
+
this.upload_files = upload_files.bind(this);
|
|
2344
|
+
this.handle_blob = handle_blob.bind(this);
|
|
2345
|
+
this.post_data = post_data.bind(this);
|
|
2346
|
+
this.submit = submit.bind(this);
|
|
2347
|
+
this.predict = predict.bind(this);
|
|
2348
|
+
this.open_stream = open_stream.bind(this);
|
|
2349
|
+
this.resolve_config = resolve_config.bind(this);
|
|
2350
|
+
this.resolve_cookies = resolve_cookies.bind(this);
|
|
2351
|
+
this.upload = upload.bind(this);
|
|
2352
|
+
this.fetch = this.fetch.bind(this);
|
|
2353
|
+
this.handle_space_success = this.handle_space_success.bind(this);
|
|
2354
|
+
this.stream = this.stream.bind(this);
|
|
2355
|
+
}
|
|
2356
|
+
async init() {
|
|
2357
|
+
initialize_zerogpu_handshake();
|
|
2358
|
+
if (this.options.auth) await this.resolve_cookies();
|
|
2359
|
+
await this._resolve_config().then((res) => res?.config && this._resolve_heartbeat(res.config));
|
|
2360
|
+
try {
|
|
2361
|
+
this.api_info = await this.view_api();
|
|
2362
|
+
} catch (e) {
|
|
2363
|
+
console.error(e.message);
|
|
2364
|
+
}
|
|
2365
|
+
this.api_map = map_names_to_ids(this.config?.dependencies || []);
|
|
2366
|
+
}
|
|
2367
|
+
async _resolve_heartbeat(_config) {
|
|
2368
|
+
if (_config) {
|
|
2369
|
+
this.config = _config;
|
|
2370
|
+
this.api_prefix = _config.api_prefix || "";
|
|
2371
|
+
if (this.config && this.config.connect_heartbeat) {
|
|
2372
|
+
if (this.config.space_id && this.options.token) this.jwt = await get_jwt(this.config.space_id, this.options.token, this.cookies);
|
|
2373
|
+
}
|
|
2374
|
+
}
|
|
2375
|
+
if (_config.space_id && this.options.token) this.jwt = await get_jwt(_config.space_id, this.options.token);
|
|
2376
|
+
if (this.config && this.config.connect_heartbeat) {
|
|
2377
|
+
const heartbeat_url = new URL(`${this.config.root}${this.api_prefix}/${HEARTBEAT_URL}/${this.session_hash}`);
|
|
2378
|
+
if (this.jwt) heartbeat_url.searchParams.set("__sign", this.jwt);
|
|
2379
|
+
if (!this.heartbeat_event) this.heartbeat_event = this.stream(heartbeat_url);
|
|
2380
|
+
}
|
|
2381
|
+
}
|
|
2382
|
+
static async connect(app_reference, options = { events: ["data"] }) {
|
|
2383
|
+
const client = new this(app_reference, options);
|
|
2384
|
+
if (options.session_hash) client.session_hash = options.session_hash;
|
|
2385
|
+
await client.init();
|
|
2386
|
+
return client;
|
|
2387
|
+
}
|
|
2388
|
+
async reconnect() {
|
|
2389
|
+
const app_id_url = new URL(`${this.config.root}${this.api_prefix}/${APP_ID_URL}`);
|
|
2390
|
+
let app_id;
|
|
2391
|
+
try {
|
|
2392
|
+
const response = await this.fetch(app_id_url);
|
|
2393
|
+
if (!response.ok) throw new Error();
|
|
2394
|
+
app_id = (await response.json()).app_id;
|
|
2395
|
+
} catch (e) {
|
|
2396
|
+
return "broken";
|
|
2397
|
+
}
|
|
2398
|
+
if (app_id !== this.config.app_id) return "changed";
|
|
2399
|
+
return "connected";
|
|
2400
|
+
}
|
|
2401
|
+
close() {
|
|
2402
|
+
this.closed = true;
|
|
2403
|
+
close_stream(this.stream_status, this.abort_controller);
|
|
2404
|
+
}
|
|
2405
|
+
/**
|
|
2406
|
+
* Re-fetch the app config without closing the SSE stream.
|
|
2407
|
+
* Used by hot-reload so in-flight generators keep delivering updates.
|
|
2408
|
+
*/
|
|
2409
|
+
async refresh() {
|
|
2410
|
+
if (!this.config) throw new Error(CONFIG_ERROR_MSG);
|
|
2411
|
+
const config = await this.resolve_config(this.config.root, false);
|
|
2412
|
+
if (!config) throw new Error(CONFIG_ERROR_MSG);
|
|
2413
|
+
this.config = config;
|
|
2414
|
+
this.api_prefix = config.api_prefix || "";
|
|
2415
|
+
this.api_map = map_names_to_ids(config.dependencies || []);
|
|
2416
|
+
try {
|
|
2417
|
+
this.api_info = await this.view_api();
|
|
2418
|
+
} catch (e) {
|
|
2419
|
+
console.error(API_INFO_ERROR_MSG + e.message);
|
|
2420
|
+
}
|
|
2421
|
+
return this.get_url_config();
|
|
2422
|
+
}
|
|
2423
|
+
set_current_payload(payload) {
|
|
2424
|
+
this.current_payload = payload;
|
|
2425
|
+
}
|
|
2426
|
+
static async duplicate(app_reference, options = { events: ["data"] }) {
|
|
2427
|
+
return duplicate(app_reference, options);
|
|
2428
|
+
}
|
|
2429
|
+
async _resolve_config() {
|
|
2430
|
+
const { http_protocol, host, space_id } = await process_endpoint(this.app_reference, this.options.token);
|
|
2431
|
+
const { status_callback } = this.options;
|
|
2432
|
+
if (space_id && status_callback) await check_and_wake_space(space_id, status_callback);
|
|
2433
|
+
let config;
|
|
2434
|
+
try {
|
|
2435
|
+
let configUrl = `${http_protocol}//${host}`;
|
|
2436
|
+
config = await this.resolve_config(configUrl);
|
|
2437
|
+
if (!config) throw new Error(CONFIG_ERROR_MSG);
|
|
2438
|
+
return this.config_success(config);
|
|
2439
|
+
} catch (e) {
|
|
2440
|
+
if (space_id && status_callback) check_space_status(space_id, RE_SPACE_NAME.test(space_id) ? "space_name" : "subdomain", this.handle_space_success);
|
|
2441
|
+
else {
|
|
2442
|
+
if (status_callback) status_callback({
|
|
2443
|
+
status: "error",
|
|
2444
|
+
message: "Could not load this space.",
|
|
2445
|
+
load_status: "error",
|
|
2446
|
+
detail: "NOT_FOUND"
|
|
2447
|
+
});
|
|
2448
|
+
throw e instanceof Error ? e : new Error(String(e));
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
}
|
|
2452
|
+
async config_success(_config) {
|
|
2453
|
+
this.config = _config;
|
|
2454
|
+
this.api_prefix = _config.api_prefix || "";
|
|
2455
|
+
if (_config.run_history === false) clear_run_history({
|
|
2456
|
+
app_id: _config.app_id,
|
|
2457
|
+
username: _config.username
|
|
2458
|
+
});
|
|
2459
|
+
if (this.config.auth_required) return this.prepare_return_obj();
|
|
2460
|
+
try {
|
|
2461
|
+
this.api_info = await this.view_api();
|
|
2462
|
+
} catch (e) {
|
|
2463
|
+
console.error(API_INFO_ERROR_MSG + e.message);
|
|
2464
|
+
}
|
|
2465
|
+
return this.prepare_return_obj();
|
|
2466
|
+
}
|
|
2467
|
+
async handle_space_success(status) {
|
|
2468
|
+
if (!this) throw new Error(CONFIG_ERROR_MSG);
|
|
2469
|
+
const { status_callback } = this.options;
|
|
2470
|
+
if (status_callback) status_callback(status);
|
|
2471
|
+
if (status.status === "running") try {
|
|
2472
|
+
this.config = await this._resolve_config();
|
|
2473
|
+
this.api_prefix = this?.config?.api_prefix || "";
|
|
2474
|
+
if (!this.config) throw new Error(CONFIG_ERROR_MSG);
|
|
2475
|
+
return await this.config_success(this.config);
|
|
2476
|
+
} catch (e) {
|
|
2477
|
+
if (status_callback) status_callback({
|
|
2478
|
+
status: "error",
|
|
2479
|
+
message: "Could not load this space.",
|
|
2480
|
+
load_status: "error",
|
|
2481
|
+
detail: "NOT_FOUND"
|
|
2482
|
+
});
|
|
2483
|
+
throw e;
|
|
2484
|
+
}
|
|
2485
|
+
}
|
|
2486
|
+
async component_server(component_id, fn_name, data) {
|
|
2487
|
+
if (!this.config) throw new Error(CONFIG_ERROR_MSG);
|
|
2488
|
+
const headers = {};
|
|
2489
|
+
const { token } = this.options;
|
|
2490
|
+
const { session_hash } = this;
|
|
2491
|
+
if (token) headers.Authorization = `Bearer ${this.options.token}`;
|
|
2492
|
+
let root_url;
|
|
2493
|
+
let component = this.config.components.find((comp) => comp.id === component_id);
|
|
2494
|
+
if (component?.props?.root_url) root_url = component.props.root_url;
|
|
2495
|
+
else root_url = this.config.root;
|
|
2496
|
+
let body;
|
|
2497
|
+
if (typeof data === "object" && data !== null && "binary" in data) {
|
|
2498
|
+
const _data = data;
|
|
2499
|
+
body = new FormData();
|
|
2500
|
+
for (const key in _data.data) {
|
|
2501
|
+
if (key === "binary") continue;
|
|
2502
|
+
body.append(key, _data.data[key]);
|
|
2503
|
+
}
|
|
2504
|
+
body.set("component_id", component_id.toString());
|
|
2505
|
+
body.set("fn_name", fn_name);
|
|
2506
|
+
body.set("session_hash", session_hash);
|
|
2507
|
+
} else {
|
|
2508
|
+
body = JSON.stringify({
|
|
2509
|
+
data,
|
|
2510
|
+
component_id,
|
|
2511
|
+
fn_name,
|
|
2512
|
+
session_hash
|
|
2513
|
+
});
|
|
2514
|
+
headers["Content-Type"] = "application/json";
|
|
2515
|
+
}
|
|
2516
|
+
if (token) headers.Authorization = `Bearer ${token}`;
|
|
2517
|
+
try {
|
|
2518
|
+
const response = await this.fetch(`${root_url}${this.api_prefix}/${COMPONENT_SERVER_URL}/`, {
|
|
2519
|
+
method: "POST",
|
|
2520
|
+
body,
|
|
2521
|
+
headers,
|
|
2522
|
+
credentials: this.options.credentials ?? "same-origin"
|
|
2523
|
+
});
|
|
2524
|
+
if (!response.ok) throw new Error("Could not connect to component server: " + response.statusText);
|
|
2525
|
+
return await response.json();
|
|
2526
|
+
} catch (e) {
|
|
2527
|
+
console.warn(e);
|
|
2528
|
+
}
|
|
2529
|
+
}
|
|
2530
|
+
set_cookies(raw_cookies) {
|
|
2531
|
+
this.cookies = parse_and_set_cookies(raw_cookies).join("; ");
|
|
2532
|
+
}
|
|
2533
|
+
prepare_return_obj() {
|
|
2534
|
+
return {
|
|
2535
|
+
config: this.config,
|
|
2536
|
+
predict: this.predict,
|
|
2537
|
+
submit: this.submit,
|
|
2538
|
+
view_api: this.view_api,
|
|
2539
|
+
component_server: this.component_server
|
|
2540
|
+
};
|
|
2541
|
+
}
|
|
2561
2542
|
};
|
|
2543
|
+
/**
|
|
2544
|
+
* @deprecated This method will be removed in v1.0. Use `Client.connect()` instead.
|
|
2545
|
+
* Creates a client instance for interacting with Gradio apps.
|
|
2546
|
+
*
|
|
2547
|
+
* @param {string} app_reference - The reference or URL to a Gradio space or app.
|
|
2548
|
+
* @param {ClientOptions} options - Configuration options for the client.
|
|
2549
|
+
* @returns {Promise<Client>} A promise that resolves to a `Client` instance.
|
|
2550
|
+
*/
|
|
2551
|
+
async function client(app_reference, options = { events: ["data"] }) {
|
|
2552
|
+
return await Client.connect(app_reference, options);
|
|
2553
|
+
}
|
|
2554
|
+
/**
|
|
2555
|
+
* @deprecated This method will be removed in v1.0. Use `Client.duplicate()` instead.
|
|
2556
|
+
* Creates a duplicate of a space and returns a client instance for the duplicated space.
|
|
2557
|
+
*
|
|
2558
|
+
* @param {string} app_reference - The reference or URL to a Gradio space or app to duplicate.
|
|
2559
|
+
* @param {DuplicateOptions} options - Configuration options for the client.
|
|
2560
|
+
* @returns {Promise<Client>} A promise that resolves to a `Client` instance.
|
|
2561
|
+
*/
|
|
2562
|
+
async function duplicate_space(app_reference, options) {
|
|
2563
|
+
return await Client.duplicate(app_reference, options);
|
|
2564
|
+
}
|
|
2565
|
+
//#endregion
|
|
2566
|
+
export { Client, FileData, MISSING_CREDENTIALS_MSG, clear_run_history, client, consume_run_history_replay, delete_run_history, duplicate_space as duplicate, handle_file, on_run_history_change, predict, prepare_files, read_run_history, run_history_url, stage_run_history_replay, submit, upload, upload_files };
|