@gradio/client 0.20.1 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +201 -0
- package/README.md +21 -36
- package/dist/client.d.ts +6 -7
- package/dist/client.d.ts.map +1 -1
- package/dist/constants.d.ts +3 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/helpers/data.d.ts +15 -1
- package/dist/helpers/data.d.ts.map +1 -1
- package/dist/helpers/spaces.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +490 -114
- package/dist/test/handlers.d.ts +1 -0
- package/dist/test/handlers.d.ts.map +1 -1
- package/dist/test/test_data.d.ts.map +1 -1
- package/dist/types.d.ts +94 -24
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/handle_blob.d.ts +2 -1
- package/dist/utils/handle_blob.d.ts.map +1 -1
- package/dist/utils/predict.d.ts +2 -2
- package/dist/utils/predict.d.ts.map +1 -1
- package/dist/utils/stream.d.ts +2 -1
- package/dist/utils/stream.d.ts.map +1 -1
- package/dist/utils/submit.d.ts +2 -2
- package/dist/utils/submit.d.ts.map +1 -1
- package/index.html +39 -0
- package/package.json +5 -2
- package/src/client.ts +40 -35
- package/src/constants.ts +4 -0
- package/src/helpers/api_info.ts +1 -1
- package/src/helpers/data.ts +124 -10
- package/src/helpers/spaces.ts +2 -1
- package/src/index.ts +6 -1
- package/src/test/api_info.test.ts +0 -1
- package/src/test/data.test.ts +201 -26
- package/src/test/handlers.ts +9 -1
- package/src/test/stream.test.ts +12 -10
- package/src/test/test_data.ts +8 -5
- package/src/test/upload_files.test.ts +1 -1
- package/src/types.ts +111 -26
- package/src/utils/handle_blob.ts +91 -1
- package/src/utils/predict.ts +15 -16
- package/src/utils/stream.ts +66 -13
- package/src/utils/submit.ts +156 -63
- package/src/utils/upload_files.ts +1 -1
- package/vite.config.js +37 -24
package/src/helpers/data.ts
CHANGED
@@ -1,12 +1,18 @@
|
|
1
|
-
import {
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
import {
|
2
|
+
type ApiData,
|
3
|
+
type BlobRef,
|
4
|
+
type Config,
|
5
|
+
type EndpointInfo,
|
6
|
+
type JsApiData,
|
7
|
+
type DataType,
|
8
|
+
Command,
|
9
|
+
type Dependency,
|
10
|
+
type ComponentMeta
|
9
11
|
} from "../types";
|
12
|
+
import { FileData } from "../upload";
|
13
|
+
|
14
|
+
const is_node =
|
15
|
+
typeof process !== "undefined" && process.versions && process.versions.node;
|
10
16
|
|
11
17
|
export function update_object(
|
12
18
|
object: { [x: string]: any },
|
@@ -64,11 +70,10 @@ export async function walk_and_store_blobs(
|
|
64
70
|
(globalThis.Buffer && data instanceof globalThis.Buffer) ||
|
65
71
|
data instanceof Blob
|
66
72
|
) {
|
67
|
-
const is_image = type === "Image";
|
68
73
|
return [
|
69
74
|
{
|
70
75
|
path: path,
|
71
|
-
blob:
|
76
|
+
blob: new Blob([data]),
|
72
77
|
type
|
73
78
|
}
|
74
79
|
];
|
@@ -118,3 +123,112 @@ export function post_message<Res = any>(
|
|
118
123
|
window.parent.postMessage(message, origin, [channel.port2]);
|
119
124
|
});
|
120
125
|
}
|
126
|
+
|
127
|
+
export function handle_file(
|
128
|
+
file_or_url: File | string | Blob | Buffer
|
129
|
+
): FileData | Blob | Command {
|
130
|
+
if (typeof file_or_url === "string") {
|
131
|
+
if (
|
132
|
+
file_or_url.startsWith("http://") ||
|
133
|
+
file_or_url.startsWith("https://")
|
134
|
+
) {
|
135
|
+
return {
|
136
|
+
path: file_or_url,
|
137
|
+
url: file_or_url,
|
138
|
+
orig_name: file_or_url.split("/").pop() ?? "unknown",
|
139
|
+
meta: { _type: "gradio.FileData" }
|
140
|
+
};
|
141
|
+
}
|
142
|
+
|
143
|
+
if (is_node) {
|
144
|
+
// Handle local file paths
|
145
|
+
return new Command("upload_file", {
|
146
|
+
path: file_or_url,
|
147
|
+
name: file_or_url,
|
148
|
+
orig_path: file_or_url
|
149
|
+
});
|
150
|
+
}
|
151
|
+
} else if (typeof File !== "undefined" && file_or_url instanceof File) {
|
152
|
+
return {
|
153
|
+
path: file_or_url instanceof File ? file_or_url.name : "blob",
|
154
|
+
orig_name: file_or_url instanceof File ? file_or_url.name : "unknown",
|
155
|
+
// @ts-ignore
|
156
|
+
blob: file_or_url instanceof File ? file_or_url : new Blob([file_or_url]),
|
157
|
+
size:
|
158
|
+
file_or_url instanceof Blob
|
159
|
+
? file_or_url.size
|
160
|
+
: Buffer.byteLength(file_or_url as Buffer),
|
161
|
+
mime_type:
|
162
|
+
file_or_url instanceof File
|
163
|
+
? file_or_url.type
|
164
|
+
: "application/octet-stream", // Default MIME type for buffers
|
165
|
+
meta: { _type: "gradio.FileData" }
|
166
|
+
};
|
167
|
+
} else if (file_or_url instanceof Buffer) {
|
168
|
+
return new Blob([file_or_url]);
|
169
|
+
} else if (file_or_url instanceof Blob) {
|
170
|
+
return file_or_url;
|
171
|
+
}
|
172
|
+
throw new Error(
|
173
|
+
"Invalid input: must be a URL, File, Blob, or Buffer object."
|
174
|
+
);
|
175
|
+
}
|
176
|
+
|
177
|
+
/**
|
178
|
+
* Handles the payload by filtering out state inputs and returning an array of resolved payload values.
|
179
|
+
* We send null values for state inputs to the server, but we don't want to include them in the resolved payload.
|
180
|
+
*
|
181
|
+
* @param resolved_payload - The resolved payload values received from the client or the server
|
182
|
+
* @param dependency - The dependency object.
|
183
|
+
* @param components - The array of component metadata.
|
184
|
+
* @param with_null_state - Optional. Specifies whether to include null values for state inputs. Default is false.
|
185
|
+
* @returns An array of resolved payload values, filtered based on the dependency and component metadata.
|
186
|
+
*/
|
187
|
+
export function handle_payload(
|
188
|
+
resolved_payload: unknown[],
|
189
|
+
dependency: Dependency,
|
190
|
+
components: ComponentMeta[],
|
191
|
+
type: "input" | "output",
|
192
|
+
with_null_state = false
|
193
|
+
): unknown[] {
|
194
|
+
if (type === "input" && !with_null_state) {
|
195
|
+
throw new Error("Invalid code path. Cannot skip state inputs for input.");
|
196
|
+
}
|
197
|
+
// data comes from the server with null state values so we skip
|
198
|
+
if (type === "output" && with_null_state) {
|
199
|
+
return resolved_payload;
|
200
|
+
}
|
201
|
+
|
202
|
+
let updated_payload: unknown[] = [];
|
203
|
+
let payload_index = 0;
|
204
|
+
for (let i = 0; i < dependency.inputs.length; i++) {
|
205
|
+
const input_id = dependency.inputs[i];
|
206
|
+
const component = components.find((c) => c.id === input_id);
|
207
|
+
|
208
|
+
if (component?.type === "state") {
|
209
|
+
// input + with_null_state needs us to fill state with null values
|
210
|
+
if (with_null_state) {
|
211
|
+
if (resolved_payload.length === dependency.inputs.length) {
|
212
|
+
const value = resolved_payload[payload_index];
|
213
|
+
updated_payload.push(value);
|
214
|
+
payload_index++;
|
215
|
+
} else {
|
216
|
+
updated_payload.push(null);
|
217
|
+
}
|
218
|
+
} else {
|
219
|
+
// this is output & !with_null_state, we skip state inputs
|
220
|
+
// the server payload always comes with null state values so we move along the payload index
|
221
|
+
payload_index++;
|
222
|
+
continue;
|
223
|
+
}
|
224
|
+
// input & !with_null_state isn't a case we care about, server needs null
|
225
|
+
continue;
|
226
|
+
} else {
|
227
|
+
const value = resolved_payload[payload_index];
|
228
|
+
updated_payload.push(value);
|
229
|
+
payload_index++;
|
230
|
+
}
|
231
|
+
}
|
232
|
+
|
233
|
+
return updated_payload;
|
234
|
+
}
|
package/src/helpers/spaces.ts
CHANGED
@@ -106,9 +106,10 @@ export async function discussions_enabled(space_id: string): Promise<boolean> {
|
|
106
106
|
method: "HEAD"
|
107
107
|
}
|
108
108
|
);
|
109
|
+
|
109
110
|
const error = r.headers.get("x-error-message");
|
110
111
|
|
111
|
-
if (error && RE_DISABLED_DISCUSSION.test(error)) return false;
|
112
|
+
if (!r.ok || (error && RE_DISABLED_DISCUSSION.test(error))) return false;
|
112
113
|
return true;
|
113
114
|
} catch (e) {
|
114
115
|
return false;
|
package/src/index.ts
CHANGED
@@ -4,12 +4,17 @@ export { predict } from "./utils/predict";
|
|
4
4
|
export { submit } from "./utils/submit";
|
5
5
|
export { upload_files } from "./utils/upload_files";
|
6
6
|
export { FileData, upload, prepare_files } from "./upload";
|
7
|
+
export { handle_file } from "./helpers/data";
|
7
8
|
|
8
9
|
export type {
|
9
10
|
SpaceStatus,
|
11
|
+
StatusMessage,
|
10
12
|
Status,
|
11
13
|
client_return,
|
12
|
-
UploadResponse
|
14
|
+
UploadResponse,
|
15
|
+
RenderMessage,
|
16
|
+
LogMessage,
|
17
|
+
Payload
|
13
18
|
} from "./types";
|
14
19
|
|
15
20
|
// todo: remove in @gradio/client v1.0
|
@@ -16,7 +16,6 @@ import { initialise_server } from "./server";
|
|
16
16
|
import { transformed_api_info } from "./test_data";
|
17
17
|
|
18
18
|
const server = initialise_server();
|
19
|
-
const IS_NODE = process.env.TEST_MODE === "node";
|
20
19
|
|
21
20
|
beforeAll(() => server.listen());
|
22
21
|
afterEach(() => server.resetHandlers());
|
package/src/test/data.test.ts
CHANGED
@@ -3,11 +3,15 @@ import {
|
|
3
3
|
update_object,
|
4
4
|
walk_and_store_blobs,
|
5
5
|
skip_queue,
|
6
|
-
post_message
|
6
|
+
post_message,
|
7
|
+
handle_file,
|
8
|
+
handle_payload
|
7
9
|
} from "../helpers/data";
|
8
|
-
import { NodeBlob } from "../client";
|
9
10
|
import { config_response, endpoint_info } from "./test_data";
|
10
|
-
import { BlobRef } from "../types";
|
11
|
+
import { BlobRef, Command } from "../types";
|
12
|
+
import { FileData } from "../upload";
|
13
|
+
|
14
|
+
const IS_NODE = process.env.TEST_MODE === "node";
|
11
15
|
|
12
16
|
describe("walk_and_store_blobs", () => {
|
13
17
|
it("should convert a Buffer to a Blob", async () => {
|
@@ -15,7 +19,7 @@ describe("walk_and_store_blobs", () => {
|
|
15
19
|
const parts = await walk_and_store_blobs(buffer, "text");
|
16
20
|
|
17
21
|
expect(parts).toHaveLength(1);
|
18
|
-
expect(parts[0].blob).toBeInstanceOf(
|
22
|
+
expect(parts[0].blob).toBeInstanceOf(Blob);
|
19
23
|
});
|
20
24
|
|
21
25
|
it("should return a Blob when passed a Blob", async () => {
|
@@ -28,19 +32,7 @@ describe("walk_and_store_blobs", () => {
|
|
28
32
|
endpoint_info
|
29
33
|
);
|
30
34
|
|
31
|
-
expect(parts[0].blob).toBeInstanceOf(
|
32
|
-
});
|
33
|
-
|
34
|
-
it("should return blob: false when passed an image", async () => {
|
35
|
-
const blob = new Blob([]);
|
36
|
-
const parts = await walk_and_store_blobs(
|
37
|
-
blob,
|
38
|
-
"Image",
|
39
|
-
[],
|
40
|
-
true,
|
41
|
-
endpoint_info
|
42
|
-
);
|
43
|
-
expect(parts[0].blob).toBe(false);
|
35
|
+
expect(parts[0].blob).toBeInstanceOf(Blob);
|
44
36
|
});
|
45
37
|
|
46
38
|
it("should handle arrays", async () => {
|
@@ -48,7 +40,7 @@ describe("walk_and_store_blobs", () => {
|
|
48
40
|
const parts = await walk_and_store_blobs([image]);
|
49
41
|
|
50
42
|
expect(parts).toHaveLength(1);
|
51
|
-
expect(parts[0].blob).toBeInstanceOf(
|
43
|
+
expect(parts[0].blob).toBeInstanceOf(Blob);
|
52
44
|
expect(parts[0].path).toEqual(["0"]);
|
53
45
|
});
|
54
46
|
|
@@ -57,7 +49,7 @@ describe("walk_and_store_blobs", () => {
|
|
57
49
|
const parts = await walk_and_store_blobs({ a: { b: { data: { image } } } });
|
58
50
|
|
59
51
|
expect(parts).toHaveLength(1);
|
60
|
-
expect(parts[0].blob).toBeInstanceOf(
|
52
|
+
expect(parts[0].blob).toBeInstanceOf(Blob);
|
61
53
|
expect(parts[0].path).toEqual(["a", "b", "data", "image"]);
|
62
54
|
});
|
63
55
|
|
@@ -79,7 +71,7 @@ describe("walk_and_store_blobs", () => {
|
|
79
71
|
]
|
80
72
|
});
|
81
73
|
|
82
|
-
expect(parts[0].blob).toBeInstanceOf(
|
74
|
+
expect(parts[0].blob).toBeInstanceOf(Blob);
|
83
75
|
});
|
84
76
|
|
85
77
|
it("should handle deep structures with arrays (with equality check)", async () => {
|
@@ -103,8 +95,8 @@ describe("walk_and_store_blobs", () => {
|
|
103
95
|
let ref = obj;
|
104
96
|
path.forEach((p) => (ref = ref[p]));
|
105
97
|
|
106
|
-
// since ref is a Blob and blob is a
|
107
|
-
if (ref instanceof Blob && blob instanceof
|
98
|
+
// since ref is a Blob and blob is a Blob, we deep equal check the two buffers instead
|
99
|
+
if (ref instanceof Blob && blob instanceof Blob) {
|
108
100
|
const refBuffer = Buffer.from(await ref.arrayBuffer());
|
109
101
|
const blobBuffer = Buffer.from(await blob.arrayBuffer());
|
110
102
|
return refBuffer.equals(blobBuffer);
|
@@ -113,7 +105,7 @@ describe("walk_and_store_blobs", () => {
|
|
113
105
|
return ref === blob;
|
114
106
|
}
|
115
107
|
|
116
|
-
expect(parts[0].blob).toBeInstanceOf(
|
108
|
+
expect(parts[0].blob).toBeInstanceOf(Blob);
|
117
109
|
expect(map_path(obj, parts)).toBeTruthy();
|
118
110
|
});
|
119
111
|
|
@@ -122,7 +114,7 @@ describe("walk_and_store_blobs", () => {
|
|
122
114
|
const parts = await walk_and_store_blobs(buffer, undefined, ["blob"]);
|
123
115
|
|
124
116
|
expect(parts).toHaveLength(1);
|
125
|
-
expect(parts[0].blob).toBeInstanceOf(
|
117
|
+
expect(parts[0].blob).toBeInstanceOf(Blob);
|
126
118
|
expect(parts[0].path).toEqual(["blob"]);
|
127
119
|
});
|
128
120
|
|
@@ -132,7 +124,7 @@ describe("walk_and_store_blobs", () => {
|
|
132
124
|
|
133
125
|
expect(parts).toHaveLength(1);
|
134
126
|
expect(parts[0].path).toEqual([]);
|
135
|
-
expect(parts[0].blob).toBeInstanceOf(
|
127
|
+
expect(parts[0].blob).toBeInstanceOf(Blob);
|
136
128
|
});
|
137
129
|
|
138
130
|
it("should convert an object with deep structures to BlobRefs", async () => {
|
@@ -149,7 +141,7 @@ describe("walk_and_store_blobs", () => {
|
|
149
141
|
|
150
142
|
expect(parts).toHaveLength(1);
|
151
143
|
expect(parts[0].path).toEqual(["a", "b", "data", "image"]);
|
152
|
-
expect(parts[0].blob).toBeInstanceOf(
|
144
|
+
expect(parts[0].blob).toBeInstanceOf(Blob);
|
153
145
|
});
|
154
146
|
});
|
155
147
|
describe("update_object", () => {
|
@@ -276,3 +268,186 @@ describe("post_message", () => {
|
|
276
268
|
]);
|
277
269
|
});
|
278
270
|
});
|
271
|
+
|
272
|
+
describe("handle_file", () => {
|
273
|
+
it("should handle a Blob object and return the blob", () => {
|
274
|
+
const blob = new Blob(["test data"], { type: "image/png" });
|
275
|
+
const result = handle_file(blob) as FileData;
|
276
|
+
|
277
|
+
expect(result).toBe(blob);
|
278
|
+
});
|
279
|
+
|
280
|
+
it("should handle a Buffer object and return it as a blob", () => {
|
281
|
+
const buffer = Buffer.from("test data");
|
282
|
+
const result = handle_file(buffer) as FileData;
|
283
|
+
expect(result).toBeInstanceOf(Blob);
|
284
|
+
});
|
285
|
+
it("should handle a local file path and return a Command object", () => {
|
286
|
+
const file_path = "./owl.png";
|
287
|
+
const result = handle_file(file_path) as Command;
|
288
|
+
expect(result).toBeInstanceOf(Command);
|
289
|
+
expect(result).toEqual({
|
290
|
+
type: "command",
|
291
|
+
command: "upload_file",
|
292
|
+
meta: { path: "./owl.png", name: "./owl.png", orig_path: "./owl.png" },
|
293
|
+
fileData: undefined
|
294
|
+
});
|
295
|
+
});
|
296
|
+
|
297
|
+
it("should handle a File object and return it as FileData", () => {
|
298
|
+
if (IS_NODE) {
|
299
|
+
return;
|
300
|
+
}
|
301
|
+
const file = new File(["test image"], "test.png", { type: "image/png" });
|
302
|
+
const result = handle_file(file) as FileData;
|
303
|
+
expect(result.path).toBe("test.png");
|
304
|
+
expect(result.orig_name).toBe("test.png");
|
305
|
+
expect(result.blob).toBeInstanceOf(Blob);
|
306
|
+
expect(result.size).toBe(file.size);
|
307
|
+
expect(result.mime_type).toBe("image/png");
|
308
|
+
expect(result.meta).toEqual({ _type: "gradio.FileData" });
|
309
|
+
});
|
310
|
+
|
311
|
+
it("should throw an error for invalid input", () => {
|
312
|
+
const invalid_input = 123;
|
313
|
+
|
314
|
+
expect(() => {
|
315
|
+
// @ts-ignore
|
316
|
+
handle_file(invalid_input);
|
317
|
+
}).toThrowError(
|
318
|
+
"Invalid input: must be a URL, File, Blob, or Buffer object."
|
319
|
+
);
|
320
|
+
});
|
321
|
+
});
|
322
|
+
|
323
|
+
describe("handle_payload", () => {
|
324
|
+
it("should return an input payload with null in place of `state` when with_null_state is true", () => {
|
325
|
+
const resolved_payload = [2];
|
326
|
+
const dependency = {
|
327
|
+
inputs: [1, 2]
|
328
|
+
};
|
329
|
+
const components = [
|
330
|
+
{ id: 1, type: "number" },
|
331
|
+
{ id: 2, type: "state" }
|
332
|
+
];
|
333
|
+
const with_null_state = true;
|
334
|
+
const result = handle_payload(
|
335
|
+
resolved_payload,
|
336
|
+
// @ts-ignore
|
337
|
+
dependency,
|
338
|
+
components,
|
339
|
+
"input",
|
340
|
+
with_null_state
|
341
|
+
);
|
342
|
+
expect(result).toEqual([2, null]);
|
343
|
+
});
|
344
|
+
it("should return an input payload with null in place of two `state` components when with_null_state is true", () => {
|
345
|
+
const resolved_payload = ["hello", "goodbye"];
|
346
|
+
const dependency = {
|
347
|
+
inputs: [1, 2, 3, 4]
|
348
|
+
};
|
349
|
+
const components = [
|
350
|
+
{ id: 1, type: "textbox" },
|
351
|
+
{ id: 2, type: "state" },
|
352
|
+
{ id: 3, type: "textbox" },
|
353
|
+
{ id: 4, type: "state" }
|
354
|
+
];
|
355
|
+
const with_null_state = true;
|
356
|
+
const result = handle_payload(
|
357
|
+
resolved_payload,
|
358
|
+
// @ts-ignore
|
359
|
+
dependency,
|
360
|
+
components,
|
361
|
+
"input",
|
362
|
+
with_null_state
|
363
|
+
);
|
364
|
+
expect(result).toEqual(["hello", null, "goodbye", null]);
|
365
|
+
});
|
366
|
+
|
367
|
+
it("should return an output payload without the state component value when with_null_state is false", () => {
|
368
|
+
const resolved_payload = ["hello", null];
|
369
|
+
const dependency = {
|
370
|
+
inputs: [2, 3]
|
371
|
+
};
|
372
|
+
const components = [
|
373
|
+
{ id: 2, type: "textbox" },
|
374
|
+
{ id: 3, type: "state" }
|
375
|
+
];
|
376
|
+
const with_null_state = false;
|
377
|
+
const result = handle_payload(
|
378
|
+
resolved_payload,
|
379
|
+
// @ts-ignore
|
380
|
+
dependency,
|
381
|
+
components,
|
382
|
+
"output",
|
383
|
+
with_null_state
|
384
|
+
);
|
385
|
+
expect(result).toEqual(["hello"]);
|
386
|
+
});
|
387
|
+
|
388
|
+
it("should return an ouput payload without the two state component values when with_null_state is false", () => {
|
389
|
+
const resolved_payload = ["hello", null, "world", null];
|
390
|
+
const dependency = {
|
391
|
+
inputs: [2, 3, 4, 5]
|
392
|
+
};
|
393
|
+
const components = [
|
394
|
+
{ id: 2, type: "textbox" },
|
395
|
+
{ id: 3, type: "state" },
|
396
|
+
{ id: 4, type: "textbox" },
|
397
|
+
{ id: 5, type: "state" }
|
398
|
+
];
|
399
|
+
const with_null_state = false;
|
400
|
+
const result = handle_payload(
|
401
|
+
resolved_payload,
|
402
|
+
// @ts-ignore
|
403
|
+
dependency,
|
404
|
+
components,
|
405
|
+
"output",
|
406
|
+
with_null_state
|
407
|
+
);
|
408
|
+
expect(result).toEqual(["hello", "world"]);
|
409
|
+
});
|
410
|
+
|
411
|
+
it("should return an ouput payload with the two state component values when with_null_state is true", () => {
|
412
|
+
const resolved_payload = ["hello", null, "world", null];
|
413
|
+
const dependency = {
|
414
|
+
inputs: [2, 3, 4, 5]
|
415
|
+
};
|
416
|
+
const components = [
|
417
|
+
{ id: 2, type: "textbox" },
|
418
|
+
{ id: 3, type: "state" },
|
419
|
+
{ id: 4, type: "textbox" },
|
420
|
+
{ id: 5, type: "state" }
|
421
|
+
];
|
422
|
+
const with_null_state = true;
|
423
|
+
const result = handle_payload(
|
424
|
+
resolved_payload,
|
425
|
+
// @ts-ignore
|
426
|
+
dependency,
|
427
|
+
components,
|
428
|
+
"output",
|
429
|
+
with_null_state
|
430
|
+
);
|
431
|
+
expect(result).toEqual(["hello", null, "world", null]);
|
432
|
+
});
|
433
|
+
|
434
|
+
it("should return the same payload where no state components are defined", () => {
|
435
|
+
const resolved_payload = ["hello", "world"];
|
436
|
+
const dependency = {
|
437
|
+
inputs: [2, 3]
|
438
|
+
};
|
439
|
+
const components = [
|
440
|
+
{ id: 2, type: "textbox" },
|
441
|
+
{ id: 3, type: "textbox" }
|
442
|
+
];
|
443
|
+
const with_null_state = true;
|
444
|
+
const result = handle_payload(
|
445
|
+
resolved_payload,
|
446
|
+
// @ts-ignore
|
447
|
+
dependency,
|
448
|
+
components,
|
449
|
+
with_null_state
|
450
|
+
);
|
451
|
+
expect(result).toEqual(["hello", "world"]);
|
452
|
+
});
|
453
|
+
});
|
package/src/test/handlers.ts
CHANGED
@@ -21,7 +21,7 @@ import {
|
|
21
21
|
|
22
22
|
const root_url = "https://huggingface.co";
|
23
23
|
|
24
|
-
const direct_space_url = "https://hmb-hello-world.hf.space";
|
24
|
+
export const direct_space_url = "https://hmb-hello-world.hf.space";
|
25
25
|
const private_space_url = "https://hmb-secret-world.hf.space";
|
26
26
|
const private_auth_space_url = "https://hmb-private-auth-space.hf.space";
|
27
27
|
|
@@ -431,6 +431,14 @@ export const handlers: RequestHandler[] = [
|
|
431
431
|
});
|
432
432
|
}),
|
433
433
|
// queue requests
|
434
|
+
http.get(`${direct_space_url}/queue/data`, () => {
|
435
|
+
return new HttpResponse(JSON.stringify({ event_id: "123" }), {
|
436
|
+
status: 200,
|
437
|
+
headers: {
|
438
|
+
"Content-Type": "application/json"
|
439
|
+
}
|
440
|
+
});
|
441
|
+
}),
|
434
442
|
http.post(`${direct_space_url}/queue/join`, () => {
|
435
443
|
return new HttpResponse(JSON.stringify({ event_id: "123" }), {
|
436
444
|
status: 200,
|
package/src/test/stream.test.ts
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
import { vi, type Mock } from "vitest";
|
2
2
|
import { Client } from "../client";
|
3
|
+
import { readable_stream } from "../utils/stream";
|
3
4
|
import { initialise_server } from "./server";
|
5
|
+
import { direct_space_url } from "./handlers.ts";
|
4
6
|
|
5
7
|
import {
|
6
8
|
describe,
|
@@ -11,27 +13,23 @@ import {
|
|
11
13
|
afterAll,
|
12
14
|
beforeEach
|
13
15
|
} from "vitest";
|
14
|
-
import "./mock_eventsource.ts";
|
15
|
-
import NodeEventSource from "eventsource";
|
16
16
|
|
17
17
|
const server = initialise_server();
|
18
|
-
const IS_NODE = process.env.TEST_MODE === "node";
|
19
18
|
|
20
19
|
beforeAll(() => server.listen());
|
21
20
|
afterEach(() => server.resetHandlers());
|
22
21
|
afterAll(() => server.close());
|
23
22
|
|
24
23
|
describe("open_stream", () => {
|
25
|
-
let mock_eventsource: any;
|
26
24
|
let app: Client;
|
27
25
|
|
28
26
|
beforeEach(async () => {
|
29
27
|
app = await Client.connect("hmb/hello_world");
|
30
28
|
app.stream = vi.fn().mockImplementation(() => {
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
return
|
29
|
+
app.stream_instance = readable_stream(
|
30
|
+
new URL(`${direct_space_url}/queue/data`)
|
31
|
+
);
|
32
|
+
return app.stream_instance;
|
35
33
|
});
|
36
34
|
});
|
37
35
|
|
@@ -58,8 +56,12 @@ describe("open_stream", () => {
|
|
58
56
|
|
59
57
|
expect(app.stream).toHaveBeenCalledWith(eventsource_mock_call);
|
60
58
|
|
61
|
-
|
62
|
-
|
59
|
+
if (!app.stream_instance?.onmessage || !app.stream_instance?.onerror) {
|
60
|
+
throw new Error("stream instance is not defined");
|
61
|
+
}
|
62
|
+
|
63
|
+
const onMessageCallback = app.stream_instance.onmessage.bind(app);
|
64
|
+
const onErrorCallback = app.stream_instance.onerror.bind(app);
|
63
65
|
|
64
66
|
const message = { msg: "hello jerry" };
|
65
67
|
|
package/src/test/test_data.ts
CHANGED
@@ -46,7 +46,7 @@ export const transformed_api_info: ApiInfo<ApiData> = {
|
|
46
46
|
component: "Textbox"
|
47
47
|
}
|
48
48
|
],
|
49
|
-
type: { continuous: false, generator: false }
|
49
|
+
type: { continuous: false, generator: false, cancel: false }
|
50
50
|
}
|
51
51
|
},
|
52
52
|
unnamed_endpoints: {
|
@@ -68,7 +68,7 @@ export const transformed_api_info: ApiInfo<ApiData> = {
|
|
68
68
|
component: "Textbox"
|
69
69
|
}
|
70
70
|
],
|
71
|
-
type: { continuous: false, generator: false }
|
71
|
+
type: { continuous: false, generator: false, cancel: false }
|
72
72
|
}
|
73
73
|
}
|
74
74
|
};
|
@@ -395,7 +395,8 @@ export const config_response: Config = {
|
|
395
395
|
cancels: [],
|
396
396
|
types: {
|
397
397
|
continuous: false,
|
398
|
-
generator: false
|
398
|
+
generator: false,
|
399
|
+
cancel: false
|
399
400
|
},
|
400
401
|
collects_event_data: false,
|
401
402
|
trigger_after: null,
|
@@ -421,7 +422,8 @@ export const config_response: Config = {
|
|
421
422
|
cancels: [],
|
422
423
|
types: {
|
423
424
|
continuous: false,
|
424
|
-
generator: false
|
425
|
+
generator: false,
|
426
|
+
cancel: false
|
425
427
|
},
|
426
428
|
collects_event_data: false,
|
427
429
|
trigger_after: null,
|
@@ -447,7 +449,8 @@ export const config_response: Config = {
|
|
447
449
|
cancels: [],
|
448
450
|
types: {
|
449
451
|
continuous: false,
|
450
|
-
generator: false
|
452
|
+
generator: false,
|
453
|
+
cancel: false
|
451
454
|
},
|
452
455
|
collects_event_data: false,
|
453
456
|
trigger_after: null,
|
@@ -29,7 +29,7 @@ describe("upload_files", () => {
|
|
29
29
|
expect(response.files[0]).toBe("lion.jpg");
|
30
30
|
});
|
31
31
|
|
32
|
-
it("should handle a server error when connected to a running app and uploading files", async () => {
|
32
|
+
it.skip("should handle a server error when connected to a running app and uploading files", async () => {
|
33
33
|
const client = await Client.connect("hmb/server_test");
|
34
34
|
|
35
35
|
const root_url = "https://hmb-server-test.hf.space";
|