@gradio/upload 0.17.2-dev.0 → 0.17.2-dev.2
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/dist/src/ModifyUpload.svelte +18 -9
- package/dist/src/ModifyUpload.svelte.d.ts +34 -25
- package/dist/src/Upload.svelte +276 -206
- package/dist/src/Upload.svelte.d.ts +59 -48
- package/dist/src/UploadProgress.svelte +85 -64
- package/dist/src/UploadProgress.svelte.d.ts +23 -21
- package/package.json +6 -6
- package/src/Upload.svelte +37 -24
- package/src/UploadProgress.svelte +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,26 @@
|
|
|
1
1
|
# @gradio/upload
|
|
2
2
|
|
|
3
|
+
## 0.17.2-dev.2
|
|
4
|
+
|
|
5
|
+
### Dependency updates
|
|
6
|
+
|
|
7
|
+
- @gradio/atoms@0.19.0-dev.1
|
|
8
|
+
- @gradio/client@2.0.0-dev.2
|
|
9
|
+
|
|
10
|
+
## 0.17.2-dev.1
|
|
11
|
+
|
|
12
|
+
### Dependency updates
|
|
13
|
+
|
|
14
|
+
- @gradio/atoms@0.18.2-dev.0
|
|
15
|
+
- @gradio/utils@0.10.3-dev.0
|
|
16
|
+
- @gradio/icons@0.15.0-dev.0
|
|
17
|
+
|
|
18
|
+
## 0.17.2-dev.0
|
|
19
|
+
|
|
20
|
+
### Dependency updates
|
|
21
|
+
|
|
22
|
+
- @gradio/client@2.0.0-dev.1
|
|
23
|
+
|
|
3
24
|
## 0.17.2-dev.0
|
|
4
25
|
|
|
5
26
|
### Dependency updates
|
|
@@ -1,12 +1,21 @@
|
|
|
1
|
-
<script
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { IconButton, IconButtonWrapper } from "@gradio/atoms";
|
|
3
|
+
import type { I18nFormatter } from "@gradio/utils";
|
|
4
|
+
import { Edit, Clear, Undo, Download } from "@gradio/icons";
|
|
5
|
+
import { DownloadLink } from "@gradio/atoms";
|
|
6
|
+
|
|
7
|
+
import { createEventDispatcher } from "svelte";
|
|
8
|
+
|
|
9
|
+
export let editable = false;
|
|
10
|
+
export let undoable = false;
|
|
11
|
+
export let download: string | null = null;
|
|
12
|
+
export let i18n: I18nFormatter;
|
|
13
|
+
|
|
14
|
+
const dispatch = createEventDispatcher<{
|
|
15
|
+
edit?: never;
|
|
16
|
+
clear?: never;
|
|
17
|
+
undo?: never;
|
|
18
|
+
}>();
|
|
10
19
|
</script>
|
|
11
20
|
|
|
12
21
|
<IconButtonWrapper>
|
|
@@ -1,28 +1,37 @@
|
|
|
1
|
-
import { SvelteComponent } from "svelte";
|
|
2
1
|
import type { I18nFormatter } from "@gradio/utils";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
+
$$bindings?: Bindings;
|
|
5
|
+
} & Exports;
|
|
6
|
+
(internal: unknown, props: Props & {
|
|
7
|
+
$$events?: Events;
|
|
8
|
+
$$slots?: Slots;
|
|
9
|
+
}): Exports & {
|
|
10
|
+
$set?: any;
|
|
11
|
+
$on?: any;
|
|
9
12
|
};
|
|
10
|
-
|
|
11
|
-
edit?: CustomEvent<undefined> | undefined;
|
|
12
|
-
clear?: CustomEvent<undefined> | undefined;
|
|
13
|
-
undo?: CustomEvent<undefined> | undefined;
|
|
14
|
-
} & {
|
|
15
|
-
[evt: string]: CustomEvent<any>;
|
|
16
|
-
};
|
|
17
|
-
slots: {
|
|
18
|
-
default: {};
|
|
19
|
-
};
|
|
20
|
-
exports?: {} | undefined;
|
|
21
|
-
bindings?: string | undefined;
|
|
22
|
-
};
|
|
23
|
-
export type ModifyUploadProps = typeof __propDef.props;
|
|
24
|
-
export type ModifyUploadEvents = typeof __propDef.events;
|
|
25
|
-
export type ModifyUploadSlots = typeof __propDef.slots;
|
|
26
|
-
export default class ModifyUpload extends SvelteComponent<ModifyUploadProps, ModifyUploadEvents, ModifyUploadSlots> {
|
|
13
|
+
z_$$bindings?: Bindings;
|
|
27
14
|
}
|
|
28
|
-
|
|
15
|
+
type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
|
|
16
|
+
default: any;
|
|
17
|
+
} ? Props extends Record<string, never> ? any : {
|
|
18
|
+
children?: any;
|
|
19
|
+
} : {});
|
|
20
|
+
declare const ModifyUpload: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
|
|
21
|
+
editable?: boolean;
|
|
22
|
+
undoable?: boolean;
|
|
23
|
+
download?: string | null;
|
|
24
|
+
i18n: I18nFormatter;
|
|
25
|
+
}, {
|
|
26
|
+
default: {};
|
|
27
|
+
}>, {
|
|
28
|
+
edit?: CustomEvent<undefined> | undefined;
|
|
29
|
+
clear?: CustomEvent<undefined> | undefined;
|
|
30
|
+
undo?: CustomEvent<undefined> | undefined;
|
|
31
|
+
} & {
|
|
32
|
+
[evt: string]: CustomEvent<any>;
|
|
33
|
+
}, {
|
|
34
|
+
default: {};
|
|
35
|
+
}, {}, string>;
|
|
36
|
+
type ModifyUpload = InstanceType<typeof ModifyUpload>;
|
|
37
|
+
export default ModifyUpload;
|
package/dist/src/Upload.svelte
CHANGED
|
@@ -1,209 +1,279 @@
|
|
|
1
|
-
<script
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
export let
|
|
11
|
-
export let
|
|
12
|
-
export let
|
|
13
|
-
export let
|
|
14
|
-
export let
|
|
15
|
-
export let
|
|
16
|
-
export let
|
|
17
|
-
export let
|
|
18
|
-
export let
|
|
19
|
-
export let
|
|
20
|
-
export let
|
|
21
|
-
export let
|
|
22
|
-
export let
|
|
23
|
-
export let
|
|
24
|
-
export
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
let
|
|
28
|
-
let
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
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
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { createEventDispatcher, tick, getContext } from "svelte";
|
|
3
|
+
import type { FileData } from "@gradio/client";
|
|
4
|
+
import { prepare_files, type Client } from "@gradio/client";
|
|
5
|
+
import UploadProgress from "./UploadProgress.svelte";
|
|
6
|
+
import { create_drag } from "./utils";
|
|
7
|
+
|
|
8
|
+
const { drag, open_file_upload: _open_file_upload } = create_drag();
|
|
9
|
+
|
|
10
|
+
export let filetype: string | string[] | null = null;
|
|
11
|
+
export let dragging = false;
|
|
12
|
+
export let boundedheight = true;
|
|
13
|
+
export let center = true;
|
|
14
|
+
export let flex = true;
|
|
15
|
+
export let file_count: "single" | "multiple" | "directory" = "single";
|
|
16
|
+
export let disable_click = false;
|
|
17
|
+
export let root: string;
|
|
18
|
+
export let hidden = false;
|
|
19
|
+
export let format: "blob" | "file" = "file";
|
|
20
|
+
export let uploading = false;
|
|
21
|
+
export let show_progress = true;
|
|
22
|
+
export let max_file_size: number | null = null;
|
|
23
|
+
export let upload: Client["upload"];
|
|
24
|
+
export let stream_handler: Client["stream"];
|
|
25
|
+
export let icon_upload = false;
|
|
26
|
+
export let height: number | string | undefined = undefined;
|
|
27
|
+
export let aria_label: string | undefined = undefined;
|
|
28
|
+
export let upload_promise: Promise<(FileData | null)[]> | null = null;
|
|
29
|
+
|
|
30
|
+
export function open_upload(): void {
|
|
31
|
+
_open_file_upload();
|
|
32
|
+
}
|
|
33
|
+
let upload_id: string = "";
|
|
34
|
+
let file_data: FileData[];
|
|
35
|
+
let accept_file_types: string | null;
|
|
36
|
+
let use_post_upload_validation: boolean | null = null;
|
|
37
|
+
|
|
38
|
+
const get_ios = (): boolean => {
|
|
39
|
+
if (typeof navigator !== "undefined") {
|
|
40
|
+
const userAgent = navigator.userAgent.toLowerCase();
|
|
41
|
+
return userAgent.indexOf("iphone") > -1 || userAgent.indexOf("ipad") > -1;
|
|
42
|
+
}
|
|
43
|
+
return false;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
$: ios = get_ios();
|
|
47
|
+
|
|
48
|
+
const dispatch = createEventDispatcher();
|
|
49
|
+
const validFileTypes = ["image", "video", "audio", "text", "file"];
|
|
50
|
+
const process_file_type = (type: string): string => {
|
|
51
|
+
if (ios && type.startsWith(".")) {
|
|
52
|
+
use_post_upload_validation = true;
|
|
53
|
+
return type;
|
|
54
|
+
}
|
|
55
|
+
if (ios && type.includes("file/*")) {
|
|
56
|
+
return "*";
|
|
57
|
+
}
|
|
58
|
+
if (type.startsWith(".") || type.endsWith("/*")) {
|
|
59
|
+
return type;
|
|
60
|
+
}
|
|
61
|
+
if (validFileTypes.includes(type)) {
|
|
62
|
+
return type + "/*";
|
|
63
|
+
}
|
|
64
|
+
return "." + type;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
$: if (filetype == null) {
|
|
68
|
+
accept_file_types = null;
|
|
69
|
+
} else if (typeof filetype === "string") {
|
|
70
|
+
accept_file_types = process_file_type(filetype);
|
|
71
|
+
} else if (ios && filetype.includes("file/*")) {
|
|
72
|
+
accept_file_types = "*";
|
|
73
|
+
} else {
|
|
74
|
+
filetype = filetype.map(process_file_type);
|
|
75
|
+
accept_file_types = filetype.join(", ");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function paste_clipboard(): void {
|
|
79
|
+
navigator.clipboard.read().then(async (items) => {
|
|
80
|
+
for (let i = 0; i < items.length; i++) {
|
|
81
|
+
const type = items[i].types.find((t) => t.startsWith("image/"));
|
|
82
|
+
if (type) {
|
|
83
|
+
items[i].getType(type).then(async (blob) => {
|
|
84
|
+
const file = new File(
|
|
85
|
+
[blob],
|
|
86
|
+
`clipboard.${type.replace("image/", "")}`
|
|
87
|
+
);
|
|
88
|
+
await load_files([file]);
|
|
89
|
+
});
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export function open_file_upload(): void {
|
|
97
|
+
_open_file_upload();
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function handle_upload(
|
|
101
|
+
file_data: FileData[],
|
|
102
|
+
_upload_id?: string
|
|
103
|
+
): Promise<(FileData | null)[]> {
|
|
104
|
+
upload_promise = new Promise(async (resolve, rej) => {
|
|
105
|
+
await tick();
|
|
106
|
+
if (!_upload_id) {
|
|
107
|
+
upload_id = Math.random().toString(36).substring(2, 15);
|
|
108
|
+
} else {
|
|
109
|
+
upload_id = _upload_id;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
uploading = true;
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const _file_data = await upload(
|
|
116
|
+
file_data,
|
|
117
|
+
root,
|
|
118
|
+
upload_id,
|
|
119
|
+
max_file_size ?? Infinity
|
|
120
|
+
);
|
|
121
|
+
dispatch(
|
|
122
|
+
"load",
|
|
123
|
+
file_count === "single" ? _file_data?.[0] : _file_data
|
|
124
|
+
);
|
|
125
|
+
resolve(_file_data || []);
|
|
126
|
+
uploading = false;
|
|
127
|
+
return _file_data || [];
|
|
128
|
+
} catch (e) {
|
|
129
|
+
dispatch("error", (e as Error).message);
|
|
130
|
+
uploading = false;
|
|
131
|
+
resolve([]);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
return upload_promise;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function is_valid_mimetype(
|
|
139
|
+
file_accept: string | string[] | null,
|
|
140
|
+
uploaded_file_extension: string,
|
|
141
|
+
uploaded_file_type: string
|
|
142
|
+
): boolean {
|
|
143
|
+
if (
|
|
144
|
+
!file_accept ||
|
|
145
|
+
file_accept === "*" ||
|
|
146
|
+
file_accept === "file/*" ||
|
|
147
|
+
(Array.isArray(file_accept) &&
|
|
148
|
+
file_accept.some((accept) => accept === "*" || accept === "file/*"))
|
|
149
|
+
) {
|
|
150
|
+
return true;
|
|
151
|
+
}
|
|
152
|
+
let acceptArray: string[];
|
|
153
|
+
if (typeof file_accept === "string") {
|
|
154
|
+
acceptArray = file_accept.split(",").map((s) => s.trim());
|
|
155
|
+
} else if (Array.isArray(file_accept)) {
|
|
156
|
+
acceptArray = file_accept;
|
|
157
|
+
} else {
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return (
|
|
162
|
+
acceptArray.includes(uploaded_file_extension) ||
|
|
163
|
+
acceptArray.some((type) => {
|
|
164
|
+
const [category] = type.split("/").map((s) => s.trim());
|
|
165
|
+
return (
|
|
166
|
+
type.endsWith("/*") && uploaded_file_type.startsWith(category + "/")
|
|
167
|
+
);
|
|
168
|
+
})
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export async function load_files(
|
|
173
|
+
files: File[] | Blob[],
|
|
174
|
+
upload_id?: string
|
|
175
|
+
): Promise<(FileData | null)[] | void> {
|
|
176
|
+
if (!files.length) {
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
let _files: File[] = files.map(
|
|
180
|
+
(f) =>
|
|
181
|
+
new File([f], f instanceof File ? f.name : "file", { type: f.type })
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
if (ios && use_post_upload_validation) {
|
|
185
|
+
_files = _files.filter((file) => {
|
|
186
|
+
if (is_valid_file(file)) {
|
|
187
|
+
return true;
|
|
188
|
+
}
|
|
189
|
+
dispatch(
|
|
190
|
+
"error",
|
|
191
|
+
`Invalid file type: ${file.name}. Only ${filetype} allowed.`
|
|
192
|
+
);
|
|
193
|
+
return false;
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
if (_files.length === 0) {
|
|
197
|
+
return [];
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
file_data = await prepare_files(_files);
|
|
202
|
+
return await handle_upload(file_data, upload_id);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function is_valid_file(file: File): boolean {
|
|
206
|
+
if (!filetype) return true;
|
|
207
|
+
|
|
208
|
+
const allowed_types = Array.isArray(filetype) ? filetype : [filetype];
|
|
209
|
+
|
|
210
|
+
return allowed_types.some((type) => {
|
|
211
|
+
const processed_type = process_file_type(type);
|
|
212
|
+
|
|
213
|
+
if (processed_type.startsWith(".")) {
|
|
214
|
+
return file.name.toLowerCase().endsWith(processed_type.toLowerCase());
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (processed_type === "*") {
|
|
218
|
+
return true;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
if (processed_type.endsWith("/*")) {
|
|
222
|
+
const [category] = processed_type.split("/");
|
|
223
|
+
return file.type.startsWith(category + "/");
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return file.type === processed_type;
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
async function load_files_from_upload(files: File[]): Promise<void> {
|
|
231
|
+
const files_to_load = files.filter((file) => {
|
|
232
|
+
const file_extension = "." + file.name.toLowerCase().split(".").pop();
|
|
233
|
+
if (
|
|
234
|
+
file_extension &&
|
|
235
|
+
is_valid_mimetype(accept_file_types, file_extension, file.type)
|
|
236
|
+
) {
|
|
237
|
+
return true;
|
|
238
|
+
}
|
|
239
|
+
if (
|
|
240
|
+
file_extension && Array.isArray(filetype)
|
|
241
|
+
? filetype.includes(file_extension)
|
|
242
|
+
: file_extension === filetype
|
|
243
|
+
) {
|
|
244
|
+
return true;
|
|
245
|
+
}
|
|
246
|
+
dispatch("error", `Invalid file type only ${filetype} allowed.`);
|
|
247
|
+
return false;
|
|
248
|
+
});
|
|
249
|
+
if (format != "blob") {
|
|
250
|
+
await load_files(files_to_load);
|
|
251
|
+
} else {
|
|
252
|
+
if (file_count === "single") {
|
|
253
|
+
dispatch("load", files_to_load[0]);
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
dispatch("load", files_to_load);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export async function load_files_from_drop(e: DragEvent): Promise<void> {
|
|
261
|
+
dragging = false;
|
|
262
|
+
if (!e.dataTransfer?.files) return;
|
|
263
|
+
const files_to_load = Array.from(e.dataTransfer.files).filter(
|
|
264
|
+
is_valid_file
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
if (format != "blob") {
|
|
268
|
+
await load_files(files_to_load);
|
|
269
|
+
} else {
|
|
270
|
+
if (file_count === "single") {
|
|
271
|
+
dispatch("load", files_to_load[0]);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
dispatch("load", files_to_load);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
207
277
|
</script>
|
|
208
278
|
|
|
209
279
|
{#if filetype === "clipboard"}
|
|
@@ -1,52 +1,63 @@
|
|
|
1
|
-
import { SvelteComponent } from "svelte";
|
|
2
1
|
import type { FileData } from "@gradio/client";
|
|
3
2
|
import { type Client } from "@gradio/client";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
hidden?: boolean;
|
|
15
|
-
format?: "blob" | "file";
|
|
16
|
-
uploading?: boolean;
|
|
17
|
-
show_progress?: boolean;
|
|
18
|
-
max_file_size?: number | null;
|
|
19
|
-
upload: Client["upload"];
|
|
20
|
-
stream_handler: Client["stream"];
|
|
21
|
-
icon_upload?: boolean;
|
|
22
|
-
height?: number | string | undefined;
|
|
23
|
-
aria_label?: string | undefined;
|
|
24
|
-
open_upload?: () => void;
|
|
25
|
-
paste_clipboard?: () => void;
|
|
26
|
-
open_file_upload?: () => void;
|
|
27
|
-
load_files?: (files: File[] | Blob[], upload_id?: string) => Promise<(FileData | null)[] | void>;
|
|
28
|
-
load_files_from_drop?: (e: DragEvent) => Promise<void>;
|
|
3
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
4
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
5
|
+
$$bindings?: Bindings;
|
|
6
|
+
} & Exports;
|
|
7
|
+
(internal: unknown, props: Props & {
|
|
8
|
+
$$events?: Events;
|
|
9
|
+
$$slots?: Slots;
|
|
10
|
+
}): Exports & {
|
|
11
|
+
$set?: any;
|
|
12
|
+
$on?: any;
|
|
29
13
|
};
|
|
30
|
-
|
|
31
|
-
load: CustomEvent<any>;
|
|
32
|
-
error: CustomEvent<any>;
|
|
33
|
-
} & {
|
|
34
|
-
[evt: string]: CustomEvent<any>;
|
|
35
|
-
};
|
|
36
|
-
slots: {
|
|
37
|
-
default: {};
|
|
38
|
-
};
|
|
39
|
-
exports?: {} | undefined;
|
|
40
|
-
bindings?: string | undefined;
|
|
41
|
-
};
|
|
42
|
-
export type UploadProps = typeof __propDef.props;
|
|
43
|
-
export type UploadEvents = typeof __propDef.events;
|
|
44
|
-
export type UploadSlots = typeof __propDef.slots;
|
|
45
|
-
export default class Upload extends SvelteComponent<UploadProps, UploadEvents, UploadSlots> {
|
|
46
|
-
get open_upload(): () => void;
|
|
47
|
-
get paste_clipboard(): () => void;
|
|
48
|
-
get open_file_upload(): () => void;
|
|
49
|
-
get load_files(): (files: File[] | Blob[], upload_id?: string) => Promise<(FileData | null)[] | void>;
|
|
50
|
-
get load_files_from_drop(): (e: DragEvent) => Promise<void>;
|
|
14
|
+
z_$$bindings?: Bindings;
|
|
51
15
|
}
|
|
52
|
-
|
|
16
|
+
type $$__sveltets_2_PropsWithChildren<Props, Slots> = Props & (Slots extends {
|
|
17
|
+
default: any;
|
|
18
|
+
} ? Props extends Record<string, never> ? any : {
|
|
19
|
+
children?: any;
|
|
20
|
+
} : {});
|
|
21
|
+
declare const Upload: $$__sveltets_2_IsomorphicComponent<$$__sveltets_2_PropsWithChildren<{
|
|
22
|
+
filetype?: string | string[] | null;
|
|
23
|
+
dragging?: boolean;
|
|
24
|
+
boundedheight?: boolean;
|
|
25
|
+
center?: boolean;
|
|
26
|
+
flex?: boolean;
|
|
27
|
+
file_count?: "single" | "multiple" | "directory";
|
|
28
|
+
disable_click?: boolean;
|
|
29
|
+
root: string;
|
|
30
|
+
hidden?: boolean;
|
|
31
|
+
format?: "blob" | "file";
|
|
32
|
+
uploading?: boolean;
|
|
33
|
+
show_progress?: boolean;
|
|
34
|
+
max_file_size?: number | null;
|
|
35
|
+
upload: Client["upload"];
|
|
36
|
+
stream_handler: Client["stream"];
|
|
37
|
+
icon_upload?: boolean;
|
|
38
|
+
height?: number | string | undefined;
|
|
39
|
+
aria_label?: string | undefined;
|
|
40
|
+
upload_promise?: Promise<(FileData | null)[]> | null;
|
|
41
|
+
open_upload?: () => void;
|
|
42
|
+
paste_clipboard?: () => void;
|
|
43
|
+
open_file_upload?: () => void;
|
|
44
|
+
load_files?: (files: File[] | Blob[], upload_id?: string) => Promise<(FileData | null)[] | void>;
|
|
45
|
+
load_files_from_drop?: (e: DragEvent) => Promise<void>;
|
|
46
|
+
}, {
|
|
47
|
+
default: {};
|
|
48
|
+
}>, {
|
|
49
|
+
load: CustomEvent<any>;
|
|
50
|
+
error: CustomEvent<any>;
|
|
51
|
+
} & {
|
|
52
|
+
[evt: string]: CustomEvent<any>;
|
|
53
|
+
}, {
|
|
54
|
+
default: {};
|
|
55
|
+
}, {
|
|
56
|
+
open_upload: () => void;
|
|
57
|
+
paste_clipboard: () => void;
|
|
58
|
+
open_file_upload: () => void;
|
|
59
|
+
load_files: (files: File[] | Blob[], upload_id?: string) => Promise<(FileData | null)[] | void>;
|
|
60
|
+
load_files_from_drop: (e: DragEvent) => Promise<void>;
|
|
61
|
+
}, string>;
|
|
62
|
+
type Upload = InstanceType<typeof Upload>;
|
|
63
|
+
export default Upload;
|
|
@@ -1,66 +1,86 @@
|
|
|
1
|
-
<script
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
let
|
|
8
|
-
let
|
|
9
|
-
let
|
|
10
|
-
let
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
function
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { FileData, type Client } from "@gradio/client";
|
|
3
|
+
import { onMount, createEventDispatcher, onDestroy } from "svelte";
|
|
4
|
+
|
|
5
|
+
type FileDataWithProgress = FileData & { progress: number };
|
|
6
|
+
|
|
7
|
+
export let upload_id: string;
|
|
8
|
+
export let root: string;
|
|
9
|
+
export let files: FileData[];
|
|
10
|
+
export let stream_handler: Client["stream"];
|
|
11
|
+
|
|
12
|
+
let stream: Awaited<ReturnType<Client["stream"]>>;
|
|
13
|
+
let progress = false;
|
|
14
|
+
let current_file_upload: FileDataWithProgress;
|
|
15
|
+
let file_to_display: FileDataWithProgress;
|
|
16
|
+
|
|
17
|
+
let files_with_progress: FileDataWithProgress[] = files.map((file) => {
|
|
18
|
+
return {
|
|
19
|
+
...file,
|
|
20
|
+
progress: 0
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const dispatch = createEventDispatcher();
|
|
25
|
+
|
|
26
|
+
function handleProgress(filename: string, chunk_size: number): void {
|
|
27
|
+
// Find the corresponding file in the array and update its progress
|
|
28
|
+
files_with_progress = files_with_progress.map((file) => {
|
|
29
|
+
if (file.orig_name === filename) {
|
|
30
|
+
file.progress += chunk_size;
|
|
31
|
+
}
|
|
32
|
+
return file;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function getProgress(file: FileDataWithProgress): number {
|
|
37
|
+
return (file.progress * 100) / (file.size || 0) || 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
onMount(async () => {
|
|
41
|
+
stream = await stream_handler(
|
|
42
|
+
new URL(`${root}/gradio_api/upload_progress?upload_id=${upload_id}`)
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
if (stream == null) {
|
|
46
|
+
throw new Error("Event source is not defined");
|
|
47
|
+
}
|
|
48
|
+
// Event listener for progress updates
|
|
49
|
+
stream.onmessage = async function (event) {
|
|
50
|
+
const _data = JSON.parse(event.data);
|
|
51
|
+
if (!progress) progress = true;
|
|
52
|
+
if (_data.msg === "done") {
|
|
53
|
+
// the stream will close itself but is here for clarity; remove .close() in 5.0
|
|
54
|
+
stream?.close();
|
|
55
|
+
dispatch("done");
|
|
56
|
+
} else {
|
|
57
|
+
current_file_upload = _data;
|
|
58
|
+
handleProgress(_data.orig_name, _data.chunk_size);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
});
|
|
62
|
+
onDestroy(() => {
|
|
63
|
+
// the stream will close itself but is here for clarity; remove .close() in 5.0
|
|
64
|
+
if (stream != null || stream != undefined) stream.close();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
function calculateTotalProgress(files: FileData[]): number {
|
|
68
|
+
let totalProgress = 0;
|
|
69
|
+
files.forEach((file) => {
|
|
70
|
+
totalProgress += getProgress(file as FileDataWithProgress);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
document.documentElement.style.setProperty(
|
|
74
|
+
"--upload-progress-width",
|
|
75
|
+
(totalProgress / files.length).toFixed(2) + "%"
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
return totalProgress / files.length;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
$: calculateTotalProgress(files_with_progress);
|
|
82
|
+
|
|
83
|
+
$: file_to_display = current_file_upload || files_with_progress[0];
|
|
64
84
|
</script>
|
|
65
85
|
|
|
66
86
|
<div class="wrap" class:progress>
|
|
@@ -154,7 +174,8 @@ $: file_to_display = current_file_upload || files_with_progress[0];
|
|
|
154
174
|
width: 14px;
|
|
155
175
|
height: 14px;
|
|
156
176
|
border-radius: 50%;
|
|
157
|
-
background:
|
|
177
|
+
background:
|
|
178
|
+
radial-gradient(
|
|
158
179
|
closest-side,
|
|
159
180
|
var(--block-background-fill) 64%,
|
|
160
181
|
transparent 53% 100%
|
|
@@ -1,24 +1,26 @@
|
|
|
1
|
-
import { SvelteComponent } from "svelte";
|
|
2
1
|
import { FileData, type Client } from "@gradio/client";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
2
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
3
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
4
|
+
$$bindings?: Bindings;
|
|
5
|
+
} & Exports;
|
|
6
|
+
(internal: unknown, props: Props & {
|
|
7
|
+
$$events?: Events;
|
|
8
|
+
$$slots?: Slots;
|
|
9
|
+
}): Exports & {
|
|
10
|
+
$set?: any;
|
|
11
|
+
$on?: any;
|
|
9
12
|
};
|
|
10
|
-
|
|
11
|
-
done: CustomEvent<any>;
|
|
12
|
-
} & {
|
|
13
|
-
[evt: string]: CustomEvent<any>;
|
|
14
|
-
};
|
|
15
|
-
slots: {};
|
|
16
|
-
exports?: {} | undefined;
|
|
17
|
-
bindings?: string | undefined;
|
|
18
|
-
};
|
|
19
|
-
export type UploadProgressProps = typeof __propDef.props;
|
|
20
|
-
export type UploadProgressEvents = typeof __propDef.events;
|
|
21
|
-
export type UploadProgressSlots = typeof __propDef.slots;
|
|
22
|
-
export default class UploadProgress extends SvelteComponent<UploadProgressProps, UploadProgressEvents, UploadProgressSlots> {
|
|
13
|
+
z_$$bindings?: Bindings;
|
|
23
14
|
}
|
|
24
|
-
|
|
15
|
+
declare const UploadProgress: $$__sveltets_2_IsomorphicComponent<{
|
|
16
|
+
upload_id: string;
|
|
17
|
+
root: string;
|
|
18
|
+
files: FileData[];
|
|
19
|
+
stream_handler: Client["stream"];
|
|
20
|
+
}, {
|
|
21
|
+
done: CustomEvent<any>;
|
|
22
|
+
} & {
|
|
23
|
+
[evt: string]: CustomEvent<any>;
|
|
24
|
+
}, {}, {}, string>;
|
|
25
|
+
type UploadProgress = InstanceType<typeof UploadProgress>;
|
|
26
|
+
export default UploadProgress;
|
package/package.json
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradio/upload",
|
|
3
|
-
"version": "0.17.2-dev.
|
|
3
|
+
"version": "0.17.2-dev.2",
|
|
4
4
|
"description": "Gradio UI packages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
7
7
|
"author": "",
|
|
8
8
|
"license": "ISC",
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@gradio/atoms": "^0.
|
|
11
|
-
"@gradio/
|
|
12
|
-
"@gradio/
|
|
13
|
-
"@gradio/utils": "^0.10.
|
|
10
|
+
"@gradio/atoms": "^0.19.0-dev.1",
|
|
11
|
+
"@gradio/client": "^2.0.0-dev.2",
|
|
12
|
+
"@gradio/icons": "^0.15.0-dev.0",
|
|
13
|
+
"@gradio/utils": "^0.10.3-dev.0"
|
|
14
14
|
},
|
|
15
15
|
"main_changeset": true,
|
|
16
16
|
"exports": {
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
}
|
|
22
22
|
},
|
|
23
23
|
"peerDependencies": {
|
|
24
|
-
"svelte": "^
|
|
24
|
+
"svelte": "^5.43.4"
|
|
25
25
|
},
|
|
26
26
|
"repository": {
|
|
27
27
|
"type": "git",
|
package/src/Upload.svelte
CHANGED
|
@@ -25,10 +25,12 @@
|
|
|
25
25
|
export let icon_upload = false;
|
|
26
26
|
export let height: number | string | undefined = undefined;
|
|
27
27
|
export let aria_label: string | undefined = undefined;
|
|
28
|
+
export let upload_promise: Promise<(FileData | null)[]> | null = null;
|
|
29
|
+
|
|
28
30
|
export function open_upload(): void {
|
|
29
31
|
_open_file_upload();
|
|
30
32
|
}
|
|
31
|
-
let upload_id: string;
|
|
33
|
+
let upload_id: string = "";
|
|
32
34
|
let file_data: FileData[];
|
|
33
35
|
let accept_file_types: string | null;
|
|
34
36
|
let use_post_upload_validation: boolean | null = null;
|
|
@@ -95,30 +97,42 @@
|
|
|
95
97
|
_open_file_upload();
|
|
96
98
|
}
|
|
97
99
|
|
|
98
|
-
|
|
100
|
+
function handle_upload(
|
|
99
101
|
file_data: FileData[],
|
|
100
|
-
|
|
102
|
+
_upload_id?: string
|
|
101
103
|
): Promise<(FileData | null)[]> {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
104
|
+
upload_promise = new Promise(async (resolve, rej) => {
|
|
105
|
+
await tick();
|
|
106
|
+
if (!_upload_id) {
|
|
107
|
+
upload_id = Math.random().toString(36).substring(2, 15);
|
|
108
|
+
} else {
|
|
109
|
+
upload_id = _upload_id;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
uploading = true;
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
const _file_data = await upload(
|
|
116
|
+
file_data,
|
|
117
|
+
root,
|
|
118
|
+
upload_id,
|
|
119
|
+
max_file_size ?? Infinity
|
|
120
|
+
);
|
|
121
|
+
dispatch(
|
|
122
|
+
"load",
|
|
123
|
+
file_count === "single" ? _file_data?.[0] : _file_data
|
|
124
|
+
);
|
|
125
|
+
resolve(_file_data || []);
|
|
126
|
+
uploading = false;
|
|
127
|
+
return _file_data || [];
|
|
128
|
+
} catch (e) {
|
|
129
|
+
dispatch("error", (e as Error).message);
|
|
130
|
+
uploading = false;
|
|
131
|
+
resolve([]);
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
return upload_promise;
|
|
122
136
|
}
|
|
123
137
|
|
|
124
138
|
function is_valid_mimetype(
|
|
@@ -232,7 +246,6 @@
|
|
|
232
246
|
dispatch("error", `Invalid file type only ${filetype} allowed.`);
|
|
233
247
|
return false;
|
|
234
248
|
});
|
|
235
|
-
|
|
236
249
|
if (format != "blob") {
|
|
237
250
|
await load_files(files_to_load);
|
|
238
251
|
} else {
|