@gradio/upload 0.3.3 → 0.4.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 CHANGED
@@ -1,5 +1,12 @@
1
1
  # @gradio/upload
2
2
 
3
+ ## 0.4.0
4
+
5
+ ### Features
6
+
7
+ - [#6356](https://github.com/gradio-app/gradio/pull/6356) [`854b482f5`](https://github.com/gradio-app/gradio/commit/854b482f598e0dc47673846631643c079576da9c) - Redesign file upload. Thanks [@hannahblair](https://github.com/hannahblair)!
8
+ - [#6307](https://github.com/gradio-app/gradio/pull/6307) [`f1409f95e`](https://github.com/gradio-app/gradio/commit/f1409f95ed39c5565bed6a601e41f94e30196a57) - Provide status updates on file uploads. Thanks [@freddyaboulton](https://github.com/freddyaboulton)!
9
+
3
10
  ## 0.3.3
4
11
 
5
12
  ### Fixes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gradio/upload",
3
- "version": "0.3.3",
3
+ "version": "0.4.0",
4
4
  "description": "Gradio UI packages",
5
5
  "type": "module",
6
6
  "main": "src/index.ts",
@@ -9,8 +9,8 @@
9
9
  "dependencies": {
10
10
  "@gradio/atoms": "^0.2.1",
11
11
  "@gradio/icons": "^0.2.0",
12
- "@gradio/client": "^0.7.2",
13
- "@gradio/upload": "^0.3.3",
12
+ "@gradio/client": "^0.8.0",
13
+ "@gradio/upload": "^0.4.0",
14
14
  "@gradio/utils": "^0.2.0"
15
15
  },
16
16
  "main_changeset": true,
package/src/Upload.svelte CHANGED
@@ -3,6 +3,7 @@
3
3
  import type { FileData } from "@gradio/client";
4
4
  import { upload_files, upload, prepare_files } from "@gradio/client";
5
5
  import { _ } from "svelte-i18n";
6
+ import UploadProgress from "./UploadProgress.svelte";
6
7
 
7
8
  export let filetype: string | null = null;
8
9
  export let dragging = false;
@@ -15,6 +16,10 @@
15
16
  export let hidden = false;
16
17
  export let include_sources = false;
17
18
 
19
+ let uploading = false;
20
+ let upload_id: string;
21
+ let file_data: FileData[];
22
+
18
23
  // Needed for wasm support
19
24
  const upload_fn = getContext<typeof upload_files>("upload_files");
20
25
 
@@ -36,8 +41,11 @@
36
41
  file_data: FileData[]
37
42
  ): Promise<(FileData | null)[]> {
38
43
  await tick();
39
- const _file_data = await upload(file_data, root, upload_fn);
44
+ upload_id = Math.random().toString(36).substring(2, 15);
45
+ uploading = true;
46
+ const _file_data = await upload(file_data, root, upload_id, upload_fn);
40
47
  dispatch("load", file_count === "single" ? _file_data?.[0] : _file_data);
48
+ uploading = false;
41
49
  return _file_data || [];
42
50
  }
43
51
 
@@ -48,7 +56,7 @@
48
56
  return;
49
57
  }
50
58
  let _files: File[] = files.map((f) => new File([f], f.name));
51
- let file_data = await prepare_files(_files);
59
+ file_data = await prepare_files(_files);
52
60
  return await handle_upload(file_data);
53
61
  }
54
62
 
@@ -90,35 +98,39 @@
90
98
  }
91
99
  </script>
92
100
 
93
- <button
94
- class:hidden
95
- class:center
96
- class:boundedheight
97
- class:flex
98
- style:height={include_sources ? "calc(100% - 40px" : "100%"}
99
- on:drag|preventDefault|stopPropagation
100
- on:dragstart|preventDefault|stopPropagation
101
- on:dragend|preventDefault|stopPropagation
102
- on:dragover|preventDefault|stopPropagation
103
- on:dragenter|preventDefault|stopPropagation
104
- on:dragleave|preventDefault|stopPropagation
105
- on:drop|preventDefault|stopPropagation
106
- on:click={open_file_upload}
107
- on:drop={loadFilesFromDrop}
108
- on:dragenter={updateDragging}
109
- on:dragleave={updateDragging}
110
- >
111
- <slot />
112
- <input
113
- type="file"
114
- bind:this={hidden_upload}
115
- on:change={load_files_from_upload}
116
- accept={filetype}
117
- multiple={file_count === "multiple" || undefined}
118
- webkitdirectory={file_count === "directory" || undefined}
119
- mozdirectory={file_count === "directory" || undefined}
120
- />
121
- </button>
101
+ {#if uploading}
102
+ <UploadProgress {root} {upload_id} files={file_data} />
103
+ {:else}
104
+ <button
105
+ class:hidden
106
+ class:center
107
+ class:boundedheight
108
+ class:flex
109
+ style:height={include_sources ? "calc(100% - 40px" : "100%"}
110
+ on:drag|preventDefault|stopPropagation
111
+ on:dragstart|preventDefault|stopPropagation
112
+ on:dragend|preventDefault|stopPropagation
113
+ on:dragover|preventDefault|stopPropagation
114
+ on:dragenter|preventDefault|stopPropagation
115
+ on:dragleave|preventDefault|stopPropagation
116
+ on:drop|preventDefault|stopPropagation
117
+ on:click={open_file_upload}
118
+ on:drop={loadFilesFromDrop}
119
+ on:dragenter={updateDragging}
120
+ on:dragleave={updateDragging}
121
+ >
122
+ <slot />
123
+ <input
124
+ type="file"
125
+ bind:this={hidden_upload}
126
+ on:change={load_files_from_upload}
127
+ accept={filetype}
128
+ multiple={file_count === "multiple" || undefined}
129
+ webkitdirectory={file_count === "directory" || undefined}
130
+ mozdirectory={file_count === "directory" || undefined}
131
+ />
132
+ </button>
133
+ {/if}
122
134
 
123
135
  <style>
124
136
  button {
@@ -0,0 +1,174 @@
1
+ <script lang="ts">
2
+ import { FileData } from "@gradio/client";
3
+ import { onMount, createEventDispatcher } 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
+
11
+ let event_source: EventSource;
12
+ let progress = false;
13
+ let current_file_upload: FileDataWithProgress;
14
+
15
+ let files_with_progress: FileDataWithProgress[] = files.map((file) => {
16
+ return {
17
+ ...file,
18
+ progress: 0
19
+ };
20
+ });
21
+
22
+ const dispatch = createEventDispatcher();
23
+
24
+ function handleProgress(filename: string, chunk_size: number): void {
25
+ // Find the corresponding file in the array and update its progress
26
+ files_with_progress = files_with_progress.map((file) => {
27
+ if (file.orig_name === filename) {
28
+ file.progress += chunk_size;
29
+ }
30
+ return file;
31
+ });
32
+ }
33
+
34
+ function getProgress(file: FileDataWithProgress): number {
35
+ return (file.progress * 100) / (file.size || 0) || 0;
36
+ }
37
+
38
+ onMount(() => {
39
+ event_source = new EventSource(
40
+ `${root}/upload_progress?upload_id=${upload_id}`
41
+ );
42
+ // Event listener for progress updates
43
+ event_source.onmessage = async function (event) {
44
+ const _data = JSON.parse(event.data);
45
+ if (!progress) progress = true;
46
+ if (_data.msg === "done") {
47
+ event_source.close();
48
+ dispatch("done");
49
+ } else {
50
+ current_file_upload = _data;
51
+ handleProgress(_data.orig_name, _data.chunk_size);
52
+ }
53
+ };
54
+ });
55
+
56
+ function calculateTotalProgress(files: FileData[]): number {
57
+ let totalProgress = 0;
58
+ files.forEach((file) => {
59
+ totalProgress += getProgress(file as FileDataWithProgress);
60
+ });
61
+
62
+ document.documentElement.style.setProperty(
63
+ "--upload-progress-width",
64
+ (totalProgress / files.length).toFixed(2) + "%"
65
+ );
66
+
67
+ return totalProgress / files.length;
68
+ }
69
+
70
+ $: calculateTotalProgress(files_with_progress);
71
+ </script>
72
+
73
+ <div class="wrap" class:progress>
74
+ <span class="uploading"
75
+ >Uploading {files_with_progress.length}
76
+ {files_with_progress.length > 1 ? "files" : "file"}...</span
77
+ >
78
+
79
+ {#if current_file_upload}
80
+ <div class="file">
81
+ <span>
82
+ <div class="progress-bar">
83
+ <progress
84
+ style="visibility:hidden;height:0;width:0;"
85
+ value={getProgress(current_file_upload)}
86
+ max="100">{getProgress(current_file_upload)}</progress
87
+ >
88
+ </div>
89
+ </span>
90
+ <span class="file-name">
91
+ {current_file_upload.orig_name}
92
+ </span>
93
+ </div>
94
+ {/if}
95
+ </div>
96
+
97
+ <style>
98
+ .wrap {
99
+ overflow-y: auto;
100
+ transition: opacity 0.5s ease-in-out;
101
+ background: var(--block-background-fill);
102
+ position: relative;
103
+ display: flex;
104
+ flex-direction: column;
105
+ align-items: center;
106
+ justify-content: center;
107
+ min-height: var(--size-40);
108
+ }
109
+
110
+ .wrap::after {
111
+ content: "";
112
+ position: absolute;
113
+ top: 0;
114
+ left: 0;
115
+ width: var(--upload-progress-width);
116
+ height: 100%;
117
+ transition: all 0.5s ease-in-out;
118
+ z-index: 1;
119
+ }
120
+
121
+ .uploading {
122
+ font-size: var(--text-lg);
123
+ font-family: var(--font);
124
+ z-index: 2;
125
+ }
126
+
127
+ .file-name {
128
+ margin: var(--spacing-md);
129
+ font-size: var(--text-lg);
130
+ color: var(--body-text-color-subdued);
131
+ }
132
+
133
+ .file {
134
+ font-size: var(--text-md);
135
+ z-index: 2;
136
+ display: flex;
137
+ align-items: center;
138
+ }
139
+
140
+ .file progress {
141
+ display: inline;
142
+ height: var(--size-1);
143
+ width: 100%;
144
+ transition: all 0.5s ease-in-out;
145
+ color: var(--color-accent);
146
+ border: none;
147
+ }
148
+
149
+ .file progress[value]::-webkit-progress-value {
150
+ background-color: var(--color-accent);
151
+ border-radius: 20px;
152
+ }
153
+
154
+ .file progress[value]::-webkit-progress-bar {
155
+ background-color: var(--border-color-accent);
156
+ border-radius: 20px;
157
+ }
158
+
159
+ .progress-bar {
160
+ width: 14px;
161
+ height: 14px;
162
+ border-radius: 50%;
163
+ background: radial-gradient(
164
+ closest-side,
165
+ var(--block-background-fill) 64%,
166
+ transparent 53% 100%
167
+ ),
168
+ conic-gradient(
169
+ var(--color-accent) var(--upload-progress-width),
170
+ var(--border-color-accent) 0
171
+ );
172
+ transition: all 0.5s ease-in-out;
173
+ }
174
+ </style>