@gradio/multimodaltextbox 0.11.0-dev.2 → 0.11.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 +23 -0
- package/Index.svelte +3 -3
- package/MultimodalTextbox.test.ts +20 -21
- package/README.md +1 -1
- package/dist/Index.svelte +3 -3
- package/dist/shared/MultimodalTextbox.svelte +219 -56
- package/package.json +11 -11
- package/shared/MultimodalTextbox.svelte +219 -56
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,27 @@
|
|
|
1
1
|
# @gradio/multimodaltextbox
|
|
2
|
+
## 0.11.0
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
- [#11908](https://github.com/gradio-app/gradio/pull/11908) [`029034f`](https://github.com/gradio-app/gradio/commit/029034f7853ea018d110efe9b7e2ef7d1407091c) - remove_placeholder_type_here
|
|
7
|
+
- [#11908](https://github.com/gradio-app/gradio/pull/11908) [`029034f`](https://github.com/gradio-app/gradio/commit/029034f7853ea018d110efe9b7e2ef7d1407091c) - Clear Error statuses
|
|
8
|
+
- [#11908](https://github.com/gradio-app/gradio/pull/11908) [`029034f`](https://github.com/gradio-app/gradio/commit/029034f7853ea018d110efe9b7e2ef7d1407091c) - Improve gr.MultimodalTextbox in mobile
|
|
9
|
+
- [#11908](https://github.com/gradio-app/gradio/pull/11908) [`029034f`](https://github.com/gradio-app/gradio/commit/029034f7853ea018d110efe9b7e2ef7d1407091c) - Add minimal recording UI to gr.MultimodalTextbox
|
|
10
|
+
- [#11908](https://github.com/gradio-app/gradio/pull/11908) [`029034f`](https://github.com/gradio-app/gradio/commit/029034f7853ea018d110efe9b7e2ef7d1407091c) - Add back default values for labels
|
|
11
|
+
- [#11908](https://github.com/gradio-app/gradio/pull/11908) [`029034f`](https://github.com/gradio-app/gradio/commit/029034f7853ea018d110efe9b7e2ef7d1407091c) - Unit test fixes
|
|
12
|
+
- [#12438](https://github.com/gradio-app/gradio/pull/12438) [`25ffc03`](https://github.com/gradio-app/gradio/commit/25ffc0398f8feb43d817c02b2ab970c16de6d797) - Svelte5 migration and bugfix
|
|
13
|
+
|
|
14
|
+
### Dependencies
|
|
15
|
+
|
|
16
|
+
- @gradio/atoms@0.19.0
|
|
17
|
+
- @gradio/icons@0.15.0
|
|
18
|
+
- @gradio/statustracker@0.12.0
|
|
19
|
+
- @gradio/utils@0.10.3
|
|
20
|
+
- @gradio/upload@0.17.2
|
|
21
|
+
- @gradio/image@0.24.0
|
|
22
|
+
- @gradio/video@0.17.0
|
|
23
|
+
- @gradio/client@2.0.0
|
|
24
|
+
- @gradio/audio@0.20.0
|
|
2
25
|
|
|
3
26
|
## 0.11.0-dev.2
|
|
4
27
|
|
package/Index.svelte
CHANGED
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
|
|
40
40
|
const value = $derived(gradio.props.value || { text: "", files: [] });
|
|
41
41
|
|
|
42
|
-
let dragging
|
|
43
|
-
let active_source
|
|
42
|
+
let dragging = $state<boolean>(false);
|
|
43
|
+
let active_source = $state<"microphone" | null>(null);
|
|
44
44
|
|
|
45
45
|
let color_accent = "darkorange";
|
|
46
46
|
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
autoscroll={gradio.shared.autoscroll}
|
|
128
128
|
i18n={gradio.i18n}
|
|
129
129
|
{...gradio.shared.loading_status}
|
|
130
|
-
|
|
130
|
+
on_clear_status={() =>
|
|
131
131
|
gradio.dispatch("clear_status", gradio.shared.loading_status)}
|
|
132
132
|
/>
|
|
133
133
|
{/if}
|
|
@@ -28,7 +28,8 @@ describe("MultimodalTextbox", () => {
|
|
|
28
28
|
value: { text: "hello world", files: [] },
|
|
29
29
|
label: "Textbox",
|
|
30
30
|
interactive: false,
|
|
31
|
-
root: ""
|
|
31
|
+
root: "",
|
|
32
|
+
sources: []
|
|
32
33
|
});
|
|
33
34
|
|
|
34
35
|
const item: HTMLInputElement = getByDisplayValue(
|
|
@@ -38,19 +39,17 @@ describe("MultimodalTextbox", () => {
|
|
|
38
39
|
});
|
|
39
40
|
|
|
40
41
|
test("changing the text should update the value", async () => {
|
|
41
|
-
const {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
);
|
|
42
|
+
const { getByDisplayValue, listen } = await render(MultimodalTextbox, {
|
|
43
|
+
show_label: true,
|
|
44
|
+
max_lines: 10,
|
|
45
|
+
loading_status,
|
|
46
|
+
lines: 1,
|
|
47
|
+
value: { text: "hi ", files: [] },
|
|
48
|
+
label: "MultimodalTextbox",
|
|
49
|
+
interactive: true,
|
|
50
|
+
root: "",
|
|
51
|
+
sources: []
|
|
52
|
+
});
|
|
54
53
|
|
|
55
54
|
const item: HTMLInputElement = getByDisplayValue("hi") as HTMLInputElement;
|
|
56
55
|
|
|
@@ -60,14 +59,13 @@ describe("MultimodalTextbox", () => {
|
|
|
60
59
|
await event.keyboard("some text");
|
|
61
60
|
|
|
62
61
|
assert.equal(item.value, "hi some text");
|
|
63
|
-
assert.equal(component.value.text, "hi some text");
|
|
64
62
|
assert.equal(mock.callCount, 9);
|
|
65
63
|
assert.equal(mock.calls[8][0].detail.data.text, "hi some text");
|
|
66
64
|
assert.equal(mock.calls[8][0].detail.data.files.length, 0);
|
|
67
65
|
});
|
|
68
66
|
|
|
69
67
|
test("submitting should clear mic_audio", async () => {
|
|
70
|
-
const {
|
|
68
|
+
const { getByTestId, listen } = await render(MultimodalTextbox, {
|
|
71
69
|
show_label: true,
|
|
72
70
|
max_lines: 10,
|
|
73
71
|
loading_status,
|
|
@@ -76,12 +74,13 @@ describe("MultimodalTextbox", () => {
|
|
|
76
74
|
label: "MultimodalTextbox",
|
|
77
75
|
interactive: true,
|
|
78
76
|
root: "",
|
|
79
|
-
sources: ["microphone"]
|
|
77
|
+
sources: ["microphone"],
|
|
78
|
+
submit_btn: true
|
|
80
79
|
});
|
|
81
80
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
await
|
|
85
|
-
assert.equal(
|
|
81
|
+
const mock = listen("submit");
|
|
82
|
+
const submitButton = getByTestId("submit-button");
|
|
83
|
+
await event.click(submitButton);
|
|
84
|
+
assert.equal(mock.callCount, 1);
|
|
86
85
|
});
|
|
87
86
|
});
|
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ BaseMultimodalTextbox
|
|
|
11
11
|
export let value = "";
|
|
12
12
|
export let value_is_output = false;
|
|
13
13
|
export let lines = 1;
|
|
14
|
-
export let placeholder = "
|
|
14
|
+
export let placeholder = "";
|
|
15
15
|
export let label: string;
|
|
16
16
|
export let info: string | undefined = undefined;
|
|
17
17
|
export let disabled = false;
|
package/dist/Index.svelte
CHANGED
|
@@ -39,8 +39,8 @@
|
|
|
39
39
|
|
|
40
40
|
const value = $derived(gradio.props.value || { text: "", files: [] });
|
|
41
41
|
|
|
42
|
-
let dragging
|
|
43
|
-
let active_source
|
|
42
|
+
let dragging = $state<boolean>(false);
|
|
43
|
+
let active_source = $state<"microphone" | null>(null);
|
|
44
44
|
|
|
45
45
|
let color_accent = "darkorange";
|
|
46
46
|
|
|
@@ -127,7 +127,7 @@
|
|
|
127
127
|
autoscroll={gradio.shared.autoscroll}
|
|
128
128
|
i18n={gradio.i18n}
|
|
129
129
|
{...gradio.shared.loading_status}
|
|
130
|
-
|
|
130
|
+
on_clear_status={() =>
|
|
131
131
|
gradio.dispatch("clear_status", gradio.shared.loading_status)}
|
|
132
132
|
/>
|
|
133
133
|
{/if}
|
|
@@ -21,10 +21,15 @@
|
|
|
21
21
|
Video,
|
|
22
22
|
ArrowUp,
|
|
23
23
|
Square,
|
|
24
|
-
Microphone
|
|
24
|
+
Microphone,
|
|
25
|
+
Check
|
|
25
26
|
} from "@gradio/icons";
|
|
26
27
|
import type { SelectData } from "@gradio/utils";
|
|
27
28
|
import { BaseInteractiveAudio as InteractiveAudio } from "@gradio/audio";
|
|
29
|
+
import {
|
|
30
|
+
MinimalAudioPlayer,
|
|
31
|
+
MinimalAudioRecorder
|
|
32
|
+
} from "@gradio/audio/shared";
|
|
28
33
|
import type { InputHTMLAttributes } from "./types";
|
|
29
34
|
|
|
30
35
|
export let value: { text: string; files: FileData[] } = {
|
|
@@ -35,7 +40,7 @@
|
|
|
35
40
|
export let value_is_output = false;
|
|
36
41
|
export let lines = 1;
|
|
37
42
|
export let i18n: I18nFormatter;
|
|
38
|
-
export let placeholder = "
|
|
43
|
+
export let placeholder = "";
|
|
39
44
|
export let disabled = false;
|
|
40
45
|
export let label: string;
|
|
41
46
|
export let info: string | undefined = undefined;
|
|
@@ -181,10 +186,10 @@
|
|
|
181
186
|
max_lines >= 1
|
|
182
187
|
) {
|
|
183
188
|
e.preventDefault();
|
|
189
|
+
add_mic_audio_to_files();
|
|
190
|
+
active_source = null;
|
|
184
191
|
await tick();
|
|
185
192
|
dispatch("submit");
|
|
186
|
-
active_source = null;
|
|
187
|
-
add_mic_audio_to_files();
|
|
188
193
|
}
|
|
189
194
|
}
|
|
190
195
|
|
|
@@ -241,13 +246,14 @@
|
|
|
241
246
|
value.files.push(mic_audio);
|
|
242
247
|
value = value;
|
|
243
248
|
mic_audio = null;
|
|
249
|
+
dispatch("change", value);
|
|
244
250
|
}
|
|
245
251
|
}
|
|
246
252
|
|
|
247
253
|
function handle_submit(): void {
|
|
248
|
-
dispatch("submit");
|
|
249
|
-
active_source = null;
|
|
250
254
|
add_mic_audio_to_files();
|
|
255
|
+
active_source = null;
|
|
256
|
+
dispatch("submit");
|
|
251
257
|
}
|
|
252
258
|
|
|
253
259
|
async function handle_paste(event: ClipboardEvent): Promise<void> {
|
|
@@ -343,36 +349,71 @@
|
|
|
343
349
|
<BlockTitle {show_label} {info} {rtl}>{label}</BlockTitle>
|
|
344
350
|
<div class="input-container">
|
|
345
351
|
{#if sources && sources.includes("microphone") && active_source === "microphone"}
|
|
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
|
-
|
|
352
|
+
<div class="recording-overlay" class:has-audio={mic_audio !== null}>
|
|
353
|
+
{#if !mic_audio}
|
|
354
|
+
<div class="recording-content">
|
|
355
|
+
<MinimalAudioRecorder
|
|
356
|
+
label={label || "Audio"}
|
|
357
|
+
{waveform_settings}
|
|
358
|
+
{recording}
|
|
359
|
+
{upload}
|
|
360
|
+
{root}
|
|
361
|
+
{max_file_size}
|
|
362
|
+
bind:upload_promise
|
|
363
|
+
on:change={({ detail }) => {
|
|
364
|
+
mic_audio = detail;
|
|
365
|
+
}}
|
|
366
|
+
on:stop_recording={() => {
|
|
367
|
+
recording = false;
|
|
368
|
+
dispatch("stop_recording");
|
|
369
|
+
}}
|
|
370
|
+
on:clear={() => {
|
|
371
|
+
active_source = null;
|
|
372
|
+
recording = false;
|
|
373
|
+
mic_audio = null;
|
|
374
|
+
}}
|
|
375
|
+
on:error={({ detail }) => {
|
|
376
|
+
console.log("Failed to record:", detail);
|
|
377
|
+
active_source = null;
|
|
378
|
+
recording = false;
|
|
379
|
+
mic_audio = null;
|
|
380
|
+
}}
|
|
381
|
+
/>
|
|
382
|
+
</div>
|
|
383
|
+
{:else}
|
|
384
|
+
<div class="recording-content">
|
|
385
|
+
<MinimalAudioPlayer
|
|
386
|
+
value={mic_audio}
|
|
387
|
+
label={label || "Audio"}
|
|
388
|
+
loop={false}
|
|
389
|
+
/>
|
|
390
|
+
<div class="action-buttons">
|
|
391
|
+
<button
|
|
392
|
+
class="confirm-button"
|
|
393
|
+
on:click={() => {
|
|
394
|
+
add_mic_audio_to_files();
|
|
395
|
+
active_source = null;
|
|
396
|
+
recording = false;
|
|
397
|
+
}}
|
|
398
|
+
aria-label="Attach audio"
|
|
399
|
+
>
|
|
400
|
+
<Check />
|
|
401
|
+
</button>
|
|
402
|
+
<button
|
|
403
|
+
class="cancel-button"
|
|
404
|
+
on:click={() => {
|
|
405
|
+
active_source = null;
|
|
406
|
+
recording = false;
|
|
407
|
+
mic_audio = null;
|
|
408
|
+
}}
|
|
409
|
+
aria-label="Clear audio"
|
|
410
|
+
>
|
|
411
|
+
<Clear />
|
|
412
|
+
</button>
|
|
413
|
+
</div>
|
|
414
|
+
</div>
|
|
415
|
+
{/if}
|
|
416
|
+
</div>
|
|
376
417
|
{/if}
|
|
377
418
|
{#if show_upload}
|
|
378
419
|
<Upload
|
|
@@ -407,7 +448,7 @@
|
|
|
407
448
|
{#if show_upload}
|
|
408
449
|
<button
|
|
409
450
|
data-testid="upload-button"
|
|
410
|
-
class="upload-button
|
|
451
|
+
class="upload-button thumbnail-add"
|
|
411
452
|
{disabled}
|
|
412
453
|
on:click={handle_upload_click}
|
|
413
454
|
aria-label="Upload a file"
|
|
@@ -492,9 +533,15 @@
|
|
|
492
533
|
class="microphone-button"
|
|
493
534
|
class:recording
|
|
494
535
|
{disabled}
|
|
495
|
-
on:click={() => {
|
|
496
|
-
active_source
|
|
497
|
-
active_source
|
|
536
|
+
on:click={async () => {
|
|
537
|
+
if (active_source !== "microphone") {
|
|
538
|
+
active_source = "microphone";
|
|
539
|
+
await tick();
|
|
540
|
+
recording = true;
|
|
541
|
+
} else {
|
|
542
|
+
active_source = null;
|
|
543
|
+
recording = false;
|
|
544
|
+
}
|
|
498
545
|
}}
|
|
499
546
|
aria-label="Record audio"
|
|
500
547
|
>
|
|
@@ -505,6 +552,7 @@
|
|
|
505
552
|
{#if submit_btn}
|
|
506
553
|
<button
|
|
507
554
|
class="submit-button"
|
|
555
|
+
data-testid="submit-button"
|
|
508
556
|
class:padded-button={submit_btn !== true}
|
|
509
557
|
{disabled}
|
|
510
558
|
on:click={handle_submit}
|
|
@@ -626,7 +674,6 @@
|
|
|
626
674
|
display: flex;
|
|
627
675
|
justify-content: center;
|
|
628
676
|
align-items: center;
|
|
629
|
-
border: var(--size-px) solid var(--border-color-primary);
|
|
630
677
|
border-radius: var(--radius-md);
|
|
631
678
|
background: var(--background-fill-secondary);
|
|
632
679
|
width: var(--size-full);
|
|
@@ -712,7 +759,6 @@
|
|
|
712
759
|
transform: scaleX(-1);
|
|
713
760
|
}
|
|
714
761
|
|
|
715
|
-
.mobile-thumbnail-add,
|
|
716
762
|
.microphone-button {
|
|
717
763
|
color: var(--body-text-color);
|
|
718
764
|
cursor: pointer;
|
|
@@ -722,14 +768,33 @@
|
|
|
722
768
|
align-items: center;
|
|
723
769
|
flex-shrink: 0;
|
|
724
770
|
border-radius: var(--radius-md);
|
|
725
|
-
transition:
|
|
726
|
-
background 0.2s var(--easing-standard),
|
|
727
|
-
border-color 0.2s var(--easing-standard);
|
|
728
771
|
}
|
|
729
772
|
|
|
730
|
-
.
|
|
773
|
+
.thumbnail-add {
|
|
774
|
+
background: var(--button-secondary-background-fill);
|
|
775
|
+
cursor: pointer;
|
|
776
|
+
display: flex;
|
|
777
|
+
justify-content: center;
|
|
778
|
+
align-items: center;
|
|
779
|
+
flex-shrink: 0;
|
|
731
780
|
width: var(--size-10);
|
|
732
781
|
height: var(--size-10);
|
|
782
|
+
border-radius: var(--radius-md);
|
|
783
|
+
z-index: var(--layer-1);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
.thumbnail-add:hover:not(:disabled) {
|
|
787
|
+
background: var(--button-secondary-background-fill-hover);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
.thumbnail-add:disabled {
|
|
791
|
+
opacity: 0.5;
|
|
792
|
+
cursor: not-allowed;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
.thumbnail-add :global(svg) {
|
|
796
|
+
width: var(--size-5);
|
|
797
|
+
height: var(--size-5);
|
|
733
798
|
}
|
|
734
799
|
|
|
735
800
|
.microphone-button {
|
|
@@ -737,19 +802,15 @@
|
|
|
737
802
|
height: var(--size-9);
|
|
738
803
|
}
|
|
739
804
|
|
|
740
|
-
.mobile-thumbnail-add:hover:not(:disabled),
|
|
741
805
|
.microphone-button:hover:not(:disabled) {
|
|
742
|
-
background: var(--button-secondary-background-fill
|
|
743
|
-
border-color: var(--border-color-primary);
|
|
806
|
+
background: var(--button-secondary-background-fill);
|
|
744
807
|
}
|
|
745
808
|
|
|
746
|
-
.mobile-thumbnail-add:disabled,
|
|
747
809
|
.microphone-button:disabled {
|
|
748
810
|
opacity: 0.5;
|
|
749
811
|
cursor: not-allowed;
|
|
750
812
|
}
|
|
751
813
|
|
|
752
|
-
.mobile-thumbnail-add :global(svg),
|
|
753
814
|
.microphone-button :global(svg) {
|
|
754
815
|
width: var(--size-5);
|
|
755
816
|
height: var(--size-5);
|
|
@@ -757,7 +818,6 @@
|
|
|
757
818
|
|
|
758
819
|
.submit-button,
|
|
759
820
|
.stop-button {
|
|
760
|
-
border: var(--size-px) solid var(--border-color-primary);
|
|
761
821
|
background: var(--button-secondary-background-fill);
|
|
762
822
|
cursor: pointer;
|
|
763
823
|
display: flex;
|
|
@@ -768,9 +828,6 @@
|
|
|
768
828
|
height: var(--size-9);
|
|
769
829
|
border-radius: var(--radius-md);
|
|
770
830
|
z-index: var(--layer-1);
|
|
771
|
-
transition:
|
|
772
|
-
background 0.2s var(--easing-standard),
|
|
773
|
-
border-color 0.2s var(--easing-standard);
|
|
774
831
|
}
|
|
775
832
|
|
|
776
833
|
.submit-button:hover:not(:disabled),
|
|
@@ -820,6 +877,112 @@
|
|
|
820
877
|
}
|
|
821
878
|
}
|
|
822
879
|
|
|
880
|
+
.recording-overlay {
|
|
881
|
+
position: absolute;
|
|
882
|
+
top: 0;
|
|
883
|
+
left: 0;
|
|
884
|
+
right: 0;
|
|
885
|
+
bottom: 0;
|
|
886
|
+
background: var(--block-background-fill);
|
|
887
|
+
border-radius: var(--radius-xl);
|
|
888
|
+
display: flex;
|
|
889
|
+
align-items: center;
|
|
890
|
+
justify-content: center;
|
|
891
|
+
z-index: var(--layer-5);
|
|
892
|
+
padding: var(--spacing-lg);
|
|
893
|
+
backdrop-filter: blur(8px);
|
|
894
|
+
animation: fadeIn 0.2s var(--easing-standard);
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
@keyframes fadeIn {
|
|
898
|
+
from {
|
|
899
|
+
opacity: 0;
|
|
900
|
+
}
|
|
901
|
+
to {
|
|
902
|
+
opacity: 1;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
.recording-content {
|
|
907
|
+
display: flex;
|
|
908
|
+
align-items: center;
|
|
909
|
+
gap: var(--spacing-lg);
|
|
910
|
+
width: 100%;
|
|
911
|
+
max-width: 700px;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
.recording-content :global(.minimal-audio-recorder),
|
|
915
|
+
.recording-content :global(.minimal-audio-player) {
|
|
916
|
+
flex: 1;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
.action-buttons {
|
|
920
|
+
display: flex;
|
|
921
|
+
align-items: center;
|
|
922
|
+
gap: var(--spacing-sm);
|
|
923
|
+
flex-shrink: 0;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
.stop-button,
|
|
927
|
+
.confirm-button,
|
|
928
|
+
.cancel-button {
|
|
929
|
+
display: flex;
|
|
930
|
+
align-items: center;
|
|
931
|
+
justify-content: center;
|
|
932
|
+
width: var(--size-9);
|
|
933
|
+
height: var(--size-9);
|
|
934
|
+
padding: 0;
|
|
935
|
+
border-radius: var(--radius-md);
|
|
936
|
+
cursor: pointer;
|
|
937
|
+
flex-shrink: 0;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
.stop-button {
|
|
941
|
+
background: var(--button-secondary-background-fill);
|
|
942
|
+
border-color: var(--border-color-primary);
|
|
943
|
+
color: var(--error-500);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
.stop-button:hover {
|
|
947
|
+
background: var(--button-secondary-background-fill-hover);
|
|
948
|
+
color: var(--error-600);
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
.stop-button:active {
|
|
952
|
+
transform: scale(0.95);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
.confirm-button {
|
|
956
|
+
background: var(--button-primary-background-fill);
|
|
957
|
+
border-color: var(--button-primary-border-color);
|
|
958
|
+
color: white;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
.confirm-button:hover {
|
|
962
|
+
background: var(--button-primary-background-fill-hover);
|
|
963
|
+
color: var(--button-primary-text-color-hover);
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
.confirm-button:active {
|
|
967
|
+
transform: scale(0.95);
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
.cancel-button {
|
|
971
|
+
background: var(--button-secondary-background-fill);
|
|
972
|
+
color: var(--body-text-color);
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
.cancel-button:hover {
|
|
976
|
+
background: var(--button-secondary-background-fill-hover);
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
.stop-button :global(svg),
|
|
980
|
+
.confirm-button :global(svg),
|
|
981
|
+
.cancel-button :global(svg) {
|
|
982
|
+
width: var(--size-5);
|
|
983
|
+
height: var(--size-5);
|
|
984
|
+
}
|
|
985
|
+
|
|
823
986
|
@media (max-width: 768px) {
|
|
824
987
|
.input-wrapper {
|
|
825
988
|
padding: var(--spacing-xs);
|
|
@@ -831,7 +994,7 @@
|
|
|
831
994
|
}
|
|
832
995
|
|
|
833
996
|
.thumbnail-small,
|
|
834
|
-
.
|
|
997
|
+
.thumbnail-add {
|
|
835
998
|
width: var(--size-9);
|
|
836
999
|
height: var(--size-9);
|
|
837
1000
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradio/multimodaltextbox",
|
|
3
|
-
"version": "0.11.0
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Gradio UI packages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "",
|
|
@@ -22,18 +22,18 @@
|
|
|
22
22
|
"./package.json": "./package.json"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@gradio/
|
|
26
|
-
"@gradio/
|
|
27
|
-
"@gradio/utils": "^0.10.3
|
|
28
|
-
"@gradio/upload": "^0.17.2
|
|
29
|
-
"@gradio/statustracker": "^0.12.0
|
|
30
|
-
"@gradio/
|
|
31
|
-
"@gradio/
|
|
32
|
-
"@gradio/client": "^2.0.0
|
|
33
|
-
"@gradio/audio": "^0.20.0
|
|
25
|
+
"@gradio/icons": "^0.15.0",
|
|
26
|
+
"@gradio/atoms": "^0.19.0",
|
|
27
|
+
"@gradio/utils": "^0.10.3",
|
|
28
|
+
"@gradio/upload": "^0.17.2",
|
|
29
|
+
"@gradio/statustracker": "^0.12.0",
|
|
30
|
+
"@gradio/video": "^0.17.0",
|
|
31
|
+
"@gradio/image": "^0.24.0",
|
|
32
|
+
"@gradio/client": "^2.0.0",
|
|
33
|
+
"@gradio/audio": "^0.20.0"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
|
-
"@gradio/preview": "^0.15.0
|
|
36
|
+
"@gradio/preview": "^0.15.0"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
39
|
"svelte": "^5.43.4"
|
|
@@ -21,10 +21,15 @@
|
|
|
21
21
|
Video,
|
|
22
22
|
ArrowUp,
|
|
23
23
|
Square,
|
|
24
|
-
Microphone
|
|
24
|
+
Microphone,
|
|
25
|
+
Check
|
|
25
26
|
} from "@gradio/icons";
|
|
26
27
|
import type { SelectData } from "@gradio/utils";
|
|
27
28
|
import { BaseInteractiveAudio as InteractiveAudio } from "@gradio/audio";
|
|
29
|
+
import {
|
|
30
|
+
MinimalAudioPlayer,
|
|
31
|
+
MinimalAudioRecorder
|
|
32
|
+
} from "@gradio/audio/shared";
|
|
28
33
|
import type { InputHTMLAttributes } from "./types";
|
|
29
34
|
|
|
30
35
|
export let value: { text: string; files: FileData[] } = {
|
|
@@ -35,7 +40,7 @@
|
|
|
35
40
|
export let value_is_output = false;
|
|
36
41
|
export let lines = 1;
|
|
37
42
|
export let i18n: I18nFormatter;
|
|
38
|
-
export let placeholder = "
|
|
43
|
+
export let placeholder = "";
|
|
39
44
|
export let disabled = false;
|
|
40
45
|
export let label: string;
|
|
41
46
|
export let info: string | undefined = undefined;
|
|
@@ -181,10 +186,10 @@
|
|
|
181
186
|
max_lines >= 1
|
|
182
187
|
) {
|
|
183
188
|
e.preventDefault();
|
|
189
|
+
add_mic_audio_to_files();
|
|
190
|
+
active_source = null;
|
|
184
191
|
await tick();
|
|
185
192
|
dispatch("submit");
|
|
186
|
-
active_source = null;
|
|
187
|
-
add_mic_audio_to_files();
|
|
188
193
|
}
|
|
189
194
|
}
|
|
190
195
|
|
|
@@ -241,13 +246,14 @@
|
|
|
241
246
|
value.files.push(mic_audio);
|
|
242
247
|
value = value;
|
|
243
248
|
mic_audio = null;
|
|
249
|
+
dispatch("change", value);
|
|
244
250
|
}
|
|
245
251
|
}
|
|
246
252
|
|
|
247
253
|
function handle_submit(): void {
|
|
248
|
-
dispatch("submit");
|
|
249
|
-
active_source = null;
|
|
250
254
|
add_mic_audio_to_files();
|
|
255
|
+
active_source = null;
|
|
256
|
+
dispatch("submit");
|
|
251
257
|
}
|
|
252
258
|
|
|
253
259
|
async function handle_paste(event: ClipboardEvent): Promise<void> {
|
|
@@ -343,36 +349,71 @@
|
|
|
343
349
|
<BlockTitle {show_label} {info} {rtl}>{label}</BlockTitle>
|
|
344
350
|
<div class="input-container">
|
|
345
351
|
{#if sources && sources.includes("microphone") && active_source === "microphone"}
|
|
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
|
-
|
|
352
|
+
<div class="recording-overlay" class:has-audio={mic_audio !== null}>
|
|
353
|
+
{#if !mic_audio}
|
|
354
|
+
<div class="recording-content">
|
|
355
|
+
<MinimalAudioRecorder
|
|
356
|
+
label={label || "Audio"}
|
|
357
|
+
{waveform_settings}
|
|
358
|
+
{recording}
|
|
359
|
+
{upload}
|
|
360
|
+
{root}
|
|
361
|
+
{max_file_size}
|
|
362
|
+
bind:upload_promise
|
|
363
|
+
on:change={({ detail }) => {
|
|
364
|
+
mic_audio = detail;
|
|
365
|
+
}}
|
|
366
|
+
on:stop_recording={() => {
|
|
367
|
+
recording = false;
|
|
368
|
+
dispatch("stop_recording");
|
|
369
|
+
}}
|
|
370
|
+
on:clear={() => {
|
|
371
|
+
active_source = null;
|
|
372
|
+
recording = false;
|
|
373
|
+
mic_audio = null;
|
|
374
|
+
}}
|
|
375
|
+
on:error={({ detail }) => {
|
|
376
|
+
console.log("Failed to record:", detail);
|
|
377
|
+
active_source = null;
|
|
378
|
+
recording = false;
|
|
379
|
+
mic_audio = null;
|
|
380
|
+
}}
|
|
381
|
+
/>
|
|
382
|
+
</div>
|
|
383
|
+
{:else}
|
|
384
|
+
<div class="recording-content">
|
|
385
|
+
<MinimalAudioPlayer
|
|
386
|
+
value={mic_audio}
|
|
387
|
+
label={label || "Audio"}
|
|
388
|
+
loop={false}
|
|
389
|
+
/>
|
|
390
|
+
<div class="action-buttons">
|
|
391
|
+
<button
|
|
392
|
+
class="confirm-button"
|
|
393
|
+
on:click={() => {
|
|
394
|
+
add_mic_audio_to_files();
|
|
395
|
+
active_source = null;
|
|
396
|
+
recording = false;
|
|
397
|
+
}}
|
|
398
|
+
aria-label="Attach audio"
|
|
399
|
+
>
|
|
400
|
+
<Check />
|
|
401
|
+
</button>
|
|
402
|
+
<button
|
|
403
|
+
class="cancel-button"
|
|
404
|
+
on:click={() => {
|
|
405
|
+
active_source = null;
|
|
406
|
+
recording = false;
|
|
407
|
+
mic_audio = null;
|
|
408
|
+
}}
|
|
409
|
+
aria-label="Clear audio"
|
|
410
|
+
>
|
|
411
|
+
<Clear />
|
|
412
|
+
</button>
|
|
413
|
+
</div>
|
|
414
|
+
</div>
|
|
415
|
+
{/if}
|
|
416
|
+
</div>
|
|
376
417
|
{/if}
|
|
377
418
|
{#if show_upload}
|
|
378
419
|
<Upload
|
|
@@ -407,7 +448,7 @@
|
|
|
407
448
|
{#if show_upload}
|
|
408
449
|
<button
|
|
409
450
|
data-testid="upload-button"
|
|
410
|
-
class="upload-button
|
|
451
|
+
class="upload-button thumbnail-add"
|
|
411
452
|
{disabled}
|
|
412
453
|
on:click={handle_upload_click}
|
|
413
454
|
aria-label="Upload a file"
|
|
@@ -492,9 +533,15 @@
|
|
|
492
533
|
class="microphone-button"
|
|
493
534
|
class:recording
|
|
494
535
|
{disabled}
|
|
495
|
-
on:click={() => {
|
|
496
|
-
active_source
|
|
497
|
-
active_source
|
|
536
|
+
on:click={async () => {
|
|
537
|
+
if (active_source !== "microphone") {
|
|
538
|
+
active_source = "microphone";
|
|
539
|
+
await tick();
|
|
540
|
+
recording = true;
|
|
541
|
+
} else {
|
|
542
|
+
active_source = null;
|
|
543
|
+
recording = false;
|
|
544
|
+
}
|
|
498
545
|
}}
|
|
499
546
|
aria-label="Record audio"
|
|
500
547
|
>
|
|
@@ -505,6 +552,7 @@
|
|
|
505
552
|
{#if submit_btn}
|
|
506
553
|
<button
|
|
507
554
|
class="submit-button"
|
|
555
|
+
data-testid="submit-button"
|
|
508
556
|
class:padded-button={submit_btn !== true}
|
|
509
557
|
{disabled}
|
|
510
558
|
on:click={handle_submit}
|
|
@@ -626,7 +674,6 @@
|
|
|
626
674
|
display: flex;
|
|
627
675
|
justify-content: center;
|
|
628
676
|
align-items: center;
|
|
629
|
-
border: var(--size-px) solid var(--border-color-primary);
|
|
630
677
|
border-radius: var(--radius-md);
|
|
631
678
|
background: var(--background-fill-secondary);
|
|
632
679
|
width: var(--size-full);
|
|
@@ -712,7 +759,6 @@
|
|
|
712
759
|
transform: scaleX(-1);
|
|
713
760
|
}
|
|
714
761
|
|
|
715
|
-
.mobile-thumbnail-add,
|
|
716
762
|
.microphone-button {
|
|
717
763
|
color: var(--body-text-color);
|
|
718
764
|
cursor: pointer;
|
|
@@ -722,14 +768,33 @@
|
|
|
722
768
|
align-items: center;
|
|
723
769
|
flex-shrink: 0;
|
|
724
770
|
border-radius: var(--radius-md);
|
|
725
|
-
transition:
|
|
726
|
-
background 0.2s var(--easing-standard),
|
|
727
|
-
border-color 0.2s var(--easing-standard);
|
|
728
771
|
}
|
|
729
772
|
|
|
730
|
-
.
|
|
773
|
+
.thumbnail-add {
|
|
774
|
+
background: var(--button-secondary-background-fill);
|
|
775
|
+
cursor: pointer;
|
|
776
|
+
display: flex;
|
|
777
|
+
justify-content: center;
|
|
778
|
+
align-items: center;
|
|
779
|
+
flex-shrink: 0;
|
|
731
780
|
width: var(--size-10);
|
|
732
781
|
height: var(--size-10);
|
|
782
|
+
border-radius: var(--radius-md);
|
|
783
|
+
z-index: var(--layer-1);
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
.thumbnail-add:hover:not(:disabled) {
|
|
787
|
+
background: var(--button-secondary-background-fill-hover);
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
.thumbnail-add:disabled {
|
|
791
|
+
opacity: 0.5;
|
|
792
|
+
cursor: not-allowed;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
.thumbnail-add :global(svg) {
|
|
796
|
+
width: var(--size-5);
|
|
797
|
+
height: var(--size-5);
|
|
733
798
|
}
|
|
734
799
|
|
|
735
800
|
.microphone-button {
|
|
@@ -737,19 +802,15 @@
|
|
|
737
802
|
height: var(--size-9);
|
|
738
803
|
}
|
|
739
804
|
|
|
740
|
-
.mobile-thumbnail-add:hover:not(:disabled),
|
|
741
805
|
.microphone-button:hover:not(:disabled) {
|
|
742
|
-
background: var(--button-secondary-background-fill
|
|
743
|
-
border-color: var(--border-color-primary);
|
|
806
|
+
background: var(--button-secondary-background-fill);
|
|
744
807
|
}
|
|
745
808
|
|
|
746
|
-
.mobile-thumbnail-add:disabled,
|
|
747
809
|
.microphone-button:disabled {
|
|
748
810
|
opacity: 0.5;
|
|
749
811
|
cursor: not-allowed;
|
|
750
812
|
}
|
|
751
813
|
|
|
752
|
-
.mobile-thumbnail-add :global(svg),
|
|
753
814
|
.microphone-button :global(svg) {
|
|
754
815
|
width: var(--size-5);
|
|
755
816
|
height: var(--size-5);
|
|
@@ -757,7 +818,6 @@
|
|
|
757
818
|
|
|
758
819
|
.submit-button,
|
|
759
820
|
.stop-button {
|
|
760
|
-
border: var(--size-px) solid var(--border-color-primary);
|
|
761
821
|
background: var(--button-secondary-background-fill);
|
|
762
822
|
cursor: pointer;
|
|
763
823
|
display: flex;
|
|
@@ -768,9 +828,6 @@
|
|
|
768
828
|
height: var(--size-9);
|
|
769
829
|
border-radius: var(--radius-md);
|
|
770
830
|
z-index: var(--layer-1);
|
|
771
|
-
transition:
|
|
772
|
-
background 0.2s var(--easing-standard),
|
|
773
|
-
border-color 0.2s var(--easing-standard);
|
|
774
831
|
}
|
|
775
832
|
|
|
776
833
|
.submit-button:hover:not(:disabled),
|
|
@@ -820,6 +877,112 @@
|
|
|
820
877
|
}
|
|
821
878
|
}
|
|
822
879
|
|
|
880
|
+
.recording-overlay {
|
|
881
|
+
position: absolute;
|
|
882
|
+
top: 0;
|
|
883
|
+
left: 0;
|
|
884
|
+
right: 0;
|
|
885
|
+
bottom: 0;
|
|
886
|
+
background: var(--block-background-fill);
|
|
887
|
+
border-radius: var(--radius-xl);
|
|
888
|
+
display: flex;
|
|
889
|
+
align-items: center;
|
|
890
|
+
justify-content: center;
|
|
891
|
+
z-index: var(--layer-5);
|
|
892
|
+
padding: var(--spacing-lg);
|
|
893
|
+
backdrop-filter: blur(8px);
|
|
894
|
+
animation: fadeIn 0.2s var(--easing-standard);
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
@keyframes fadeIn {
|
|
898
|
+
from {
|
|
899
|
+
opacity: 0;
|
|
900
|
+
}
|
|
901
|
+
to {
|
|
902
|
+
opacity: 1;
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
|
|
906
|
+
.recording-content {
|
|
907
|
+
display: flex;
|
|
908
|
+
align-items: center;
|
|
909
|
+
gap: var(--spacing-lg);
|
|
910
|
+
width: 100%;
|
|
911
|
+
max-width: 700px;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
.recording-content :global(.minimal-audio-recorder),
|
|
915
|
+
.recording-content :global(.minimal-audio-player) {
|
|
916
|
+
flex: 1;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
.action-buttons {
|
|
920
|
+
display: flex;
|
|
921
|
+
align-items: center;
|
|
922
|
+
gap: var(--spacing-sm);
|
|
923
|
+
flex-shrink: 0;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
.stop-button,
|
|
927
|
+
.confirm-button,
|
|
928
|
+
.cancel-button {
|
|
929
|
+
display: flex;
|
|
930
|
+
align-items: center;
|
|
931
|
+
justify-content: center;
|
|
932
|
+
width: var(--size-9);
|
|
933
|
+
height: var(--size-9);
|
|
934
|
+
padding: 0;
|
|
935
|
+
border-radius: var(--radius-md);
|
|
936
|
+
cursor: pointer;
|
|
937
|
+
flex-shrink: 0;
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
.stop-button {
|
|
941
|
+
background: var(--button-secondary-background-fill);
|
|
942
|
+
border-color: var(--border-color-primary);
|
|
943
|
+
color: var(--error-500);
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
.stop-button:hover {
|
|
947
|
+
background: var(--button-secondary-background-fill-hover);
|
|
948
|
+
color: var(--error-600);
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
.stop-button:active {
|
|
952
|
+
transform: scale(0.95);
|
|
953
|
+
}
|
|
954
|
+
|
|
955
|
+
.confirm-button {
|
|
956
|
+
background: var(--button-primary-background-fill);
|
|
957
|
+
border-color: var(--button-primary-border-color);
|
|
958
|
+
color: white;
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
.confirm-button:hover {
|
|
962
|
+
background: var(--button-primary-background-fill-hover);
|
|
963
|
+
color: var(--button-primary-text-color-hover);
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
.confirm-button:active {
|
|
967
|
+
transform: scale(0.95);
|
|
968
|
+
}
|
|
969
|
+
|
|
970
|
+
.cancel-button {
|
|
971
|
+
background: var(--button-secondary-background-fill);
|
|
972
|
+
color: var(--body-text-color);
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
.cancel-button:hover {
|
|
976
|
+
background: var(--button-secondary-background-fill-hover);
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
.stop-button :global(svg),
|
|
980
|
+
.confirm-button :global(svg),
|
|
981
|
+
.cancel-button :global(svg) {
|
|
982
|
+
width: var(--size-5);
|
|
983
|
+
height: var(--size-5);
|
|
984
|
+
}
|
|
985
|
+
|
|
823
986
|
@media (max-width: 768px) {
|
|
824
987
|
.input-wrapper {
|
|
825
988
|
padding: var(--spacing-xs);
|
|
@@ -831,7 +994,7 @@
|
|
|
831
994
|
}
|
|
832
995
|
|
|
833
996
|
.thumbnail-small,
|
|
834
|
-
.
|
|
997
|
+
.thumbnail-add {
|
|
835
998
|
width: var(--size-9);
|
|
836
999
|
height: var(--size-9);
|
|
837
1000
|
}
|