mirror of
https://github.com/gradio-app/gradio.git
synced 2025-03-31 12:20:26 +08:00
Fixes .change()
in Video
, Audio
, Image
(#4793)
This commit is contained in:
parent
a82eee5733
commit
abd0ced3db
@ -5,7 +5,8 @@
|
||||
|
||||
## Bug Fixes:
|
||||
|
||||
No changes to highlight.
|
||||
* The `.change()` event is fixed in `Video` and `Image` so that it only fires once by [@abidlabs](https://github.com/abidlabs) in [PR 4793](https://github.com/gradio-app/gradio/pull/4793)
|
||||
* The `.change()` event is fixed in `Audio` so that fires when the component value is programmatically updated by [@abidlabs](https://github.com/abidlabs) in [PR 4793](https://github.com/gradio-app/gradio/pull/4793)
|
||||
|
||||
## Other Changes:
|
||||
|
||||
|
BIN
demo/change_vs_input/files/cantina.wav
Normal file
BIN
demo/change_vs_input/files/cantina.wav
Normal file
Binary file not shown.
BIN
demo/change_vs_input/files/lion.jpg
Normal file
BIN
demo/change_vs_input/files/lion.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
BIN
demo/change_vs_input/files/world.mp4
Normal file
BIN
demo/change_vs_input/files/world.mp4
Normal file
Binary file not shown.
File diff suppressed because one or more lines are too long
@ -1,9 +1,10 @@
|
||||
import os
|
||||
import gradio as gr
|
||||
|
||||
with gr.Blocks() as demo:
|
||||
set_button = gr.Button("Set Values")
|
||||
with gr.Row():
|
||||
with gr.Column():
|
||||
with gr.Column(min_width=200):
|
||||
gr.Markdown("# Enter Here")
|
||||
text = gr.Textbox()
|
||||
num = gr.Number()
|
||||
@ -15,9 +16,12 @@ with gr.Blocks() as demo:
|
||||
colorpicker = gr.ColorPicker()
|
||||
code = gr.Code()
|
||||
dataframe = gr.Dataframe()
|
||||
image = gr.Image(elem_id="image-original")
|
||||
audio = gr.Audio(elem_id="audio-original")
|
||||
video = gr.Video(elem_id="video-original")
|
||||
|
||||
with gr.Column():
|
||||
gr.Markdown("# ON:INPUT")
|
||||
with gr.Column(min_width=200):
|
||||
gr.Markdown("# ON:INPUT/UPLOAD")
|
||||
text_in = gr.Textbox()
|
||||
num_in = gr.Number()
|
||||
slider_in = gr.Slider()
|
||||
@ -28,8 +32,11 @@ with gr.Blocks() as demo:
|
||||
colorpicker_in = gr.ColorPicker()
|
||||
code_in = gr.Code()
|
||||
dataframe_in = gr.Dataframe()
|
||||
image_up = gr.Image(elem_id="image-upload")
|
||||
audio_up = gr.Audio(elem_id="audio-upload")
|
||||
video_up = gr.Video(elem_id="video-upload")
|
||||
|
||||
with gr.Column():
|
||||
with gr.Column(min_width=200):
|
||||
gr.Markdown("# ON:CHANGE")
|
||||
text_ch = gr.Textbox()
|
||||
num_ch = gr.Number()
|
||||
@ -41,33 +48,79 @@ with gr.Blocks() as demo:
|
||||
colorpicker_ch = gr.ColorPicker()
|
||||
code_ch = gr.Code()
|
||||
dataframe_ch = gr.Dataframe()
|
||||
image_ch = gr.Image(elem_id="image-change")
|
||||
audio_ch = gr.Audio(elem_id="audio-change")
|
||||
video_ch = gr.Video(elem_id="video-change")
|
||||
|
||||
set_button.click(
|
||||
lambda: ["asdf", 555, 12, True, ["a", "c"], "b", "b", "#FF0000", "import gradio as gr", [["a", "b", "c", "d"], ["1", "2", "3", "4"]]],
|
||||
None,
|
||||
[text, num, slider, checkbox, checkbox_group, radio, dropdown, colorpicker, code, dataframe])
|
||||
with gr.Column(min_width=200):
|
||||
gr.Markdown("# ON:CHANGE x2")
|
||||
text_ch2 = gr.Textbox()
|
||||
num_ch2 = gr.Number()
|
||||
slider_ch2 = gr.Slider()
|
||||
checkbox_ch2 = gr.Checkbox()
|
||||
checkbox_group_ch2 = gr.CheckboxGroup(["a", "b", "c"])
|
||||
radio_ch2 = gr.Radio(["a", "b", "c"])
|
||||
dropdown_ch2 = gr.Dropdown(["a", "b", "c"])
|
||||
colorpicker_ch2 = gr.ColorPicker()
|
||||
code_ch2 = gr.Code()
|
||||
dataframe_ch2 = gr.Dataframe()
|
||||
image_ch2 = gr.Image(elem_id="image-change-2")
|
||||
audio_ch2 = gr.Audio(elem_id="audio-change-2")
|
||||
video_ch2 = gr.Video(elem_id="video-change-2")
|
||||
|
||||
text.input(lambda x:x, text, text_in)
|
||||
num.input(lambda x:x, num, num_in)
|
||||
slider.input(lambda x:x, slider, slider_in)
|
||||
checkbox.input(lambda x:x, checkbox, checkbox_in)
|
||||
checkbox_group.input(lambda x:x, checkbox_group, checkbox_group_in)
|
||||
radio.input(lambda x:x, radio, radio_in)
|
||||
dropdown.input(lambda x:x, dropdown, dropdown_in)
|
||||
colorpicker.input(lambda x:x, colorpicker, colorpicker_in)
|
||||
code.input(lambda x:x, code, code_in)
|
||||
dataframe.input(lambda x:x, dataframe, dataframe_in)
|
||||
counter = gr.Number(label="Change counter")
|
||||
|
||||
text.change(lambda x:x, text, text_ch)
|
||||
num.change(lambda x:x, num, num_ch)
|
||||
slider.change(lambda x:x, slider, slider_ch)
|
||||
checkbox.change(lambda x:x, checkbox, checkbox_ch)
|
||||
checkbox_group.change(lambda x:x, checkbox_group, checkbox_group_ch)
|
||||
radio.change(lambda x:x, radio, radio_ch)
|
||||
dropdown.change(lambda x:x, dropdown, dropdown_ch)
|
||||
colorpicker.change(lambda x:x, colorpicker, colorpicker_ch)
|
||||
code.change(lambda x:x, code, code_ch)
|
||||
dataframe.change(lambda x:x, dataframe, dataframe_ch)
|
||||
lion = os.path.join(os.path.dirname(__file__), "files/lion.jpg")
|
||||
cantina = os.path.join(os.path.dirname(__file__), "files/cantina.wav")
|
||||
world = os.path.join(os.path.dirname(__file__), "files/world.mp4")
|
||||
|
||||
set_button.click(
|
||||
lambda: ["asdf", 555, 12, True, ["a", "c"], "b", "b", "#FF0000", "import gradio as gr", [["a", "b", "c", "d"], ["1", "2", "3", "4"]], lion, cantina, world],
|
||||
None,
|
||||
[text, num, slider, checkbox, checkbox_group, radio, dropdown, colorpicker, code, dataframe, image, audio, video])
|
||||
|
||||
text.input(lambda x:x, text, text_in)
|
||||
num.input(lambda x:x, num, num_in)
|
||||
slider.input(lambda x:x, slider, slider_in)
|
||||
checkbox.input(lambda x:x, checkbox, checkbox_in)
|
||||
checkbox_group.input(lambda x:x, checkbox_group, checkbox_group_in)
|
||||
radio.input(lambda x:x, radio, radio_in)
|
||||
dropdown.input(lambda x:x, dropdown, dropdown_in)
|
||||
colorpicker.input(lambda x:x, colorpicker, colorpicker_in)
|
||||
code.input(lambda x:x, code, code_in)
|
||||
dataframe.input(lambda x:x, dataframe, dataframe_in)
|
||||
image.upload(lambda x:x, image, image_up)
|
||||
audio.upload(lambda x:x, audio, audio_up)
|
||||
video.upload(lambda x:x, video, video_up)
|
||||
|
||||
text.change(lambda x,y:(x,y+1), [text, counter], [text_ch, counter])
|
||||
num.change(lambda x,y:(x, y+1), [num, counter], [num_ch, counter])
|
||||
slider.change(lambda x,y:(x, y+1), [slider, counter], [slider_ch, counter])
|
||||
checkbox.change(lambda x,y:(x, y+1), [checkbox, counter], [checkbox_ch, counter])
|
||||
checkbox_group.change(lambda x,y:(x, y+1), [checkbox_group, counter], [checkbox_group_ch, counter])
|
||||
radio.change(lambda x,y:(x, y+1), [radio, counter], [radio_ch, counter])
|
||||
dropdown.change(lambda x,y:(x, y+1), [dropdown, counter], [dropdown_ch, counter])
|
||||
colorpicker.change(lambda x,y:(x, y+1), [colorpicker, counter], [colorpicker_ch, counter])
|
||||
code.change(lambda x,y:(x, y+1), [code, counter], [code_ch, counter])
|
||||
dataframe.change(lambda x,y:(x, y+1), [dataframe, counter], [dataframe_ch, counter])
|
||||
image.change(lambda x,y:(x, y+1), [image, counter], [image_ch, counter])
|
||||
audio.change(lambda x,y:(x, y+1), [audio, counter], [audio_ch, counter])
|
||||
video.change(lambda x,y:(x, y+1), [video, counter], [video_ch, counter])
|
||||
|
||||
text_ch.change(lambda x:x, text_ch, text_ch2)
|
||||
num_ch.change(lambda x:x, num_ch, num_ch2)
|
||||
slider_ch.change(lambda x:x, slider_ch, slider_ch2)
|
||||
checkbox_ch.change(lambda x:x, checkbox_ch, checkbox_ch2)
|
||||
checkbox_group_ch.change(lambda x:x, checkbox_group_ch, checkbox_group_ch2)
|
||||
radio_ch.change(lambda x:x, radio_ch, radio_ch2)
|
||||
dropdown_ch.change(lambda x:x, dropdown_ch, dropdown_ch2)
|
||||
colorpicker_ch.change(lambda x:x, colorpicker_ch, colorpicker_ch2)
|
||||
code_ch.change(lambda x:x, code_ch, code_ch2)
|
||||
dataframe_ch.change(lambda x:x, dataframe_ch, dataframe_ch2)
|
||||
image_ch.change(lambda x:x, image_ch, image_ch2)
|
||||
audio_ch.change(lambda x:x, audio_ch, audio_ch2)
|
||||
video_ch.change(lambda x:x, video_ch, video_ch2)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
demo.launch()
|
@ -1,3 +1,5 @@
|
||||
<svelte:options accessors={true} />
|
||||
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { _ } from "svelte-i18n";
|
||||
@ -23,6 +25,7 @@
|
||||
export let visible = true;
|
||||
export let mode: "static" | "dynamic";
|
||||
export let value: null | FileData | string = null;
|
||||
let old_value: null | FileData | string = null;
|
||||
export let name: string;
|
||||
export let source: "microphone" | "upload";
|
||||
export let label: string;
|
||||
@ -41,6 +44,13 @@
|
||||
let _value: null | FileData;
|
||||
$: _value = normalise_file(value, root, root_url);
|
||||
|
||||
$: {
|
||||
if (JSON.stringify(value) !== JSON.stringify(old_value)) {
|
||||
old_value = value;
|
||||
dispatch("change");
|
||||
}
|
||||
}
|
||||
|
||||
let dragging: boolean;
|
||||
</script>
|
||||
|
||||
@ -64,10 +74,7 @@
|
||||
{label}
|
||||
{show_label}
|
||||
value={_value}
|
||||
on:change={({ detail }) => {
|
||||
value = detail;
|
||||
dispatch("change", value);
|
||||
}}
|
||||
on:change={({ detail }) => (value = detail)}
|
||||
on:stream={({ detail }) => {
|
||||
value = detail;
|
||||
dispatch("stream", value);
|
||||
|
@ -317,4 +317,36 @@ describe("Audio", () => {
|
||||
|
||||
assert.equal(fn.callCount, 2);
|
||||
});
|
||||
|
||||
test("audio change event trigger fires when value is changed and only fires once", async () => {
|
||||
const { component } = await render(Audio, {
|
||||
show_label: true,
|
||||
loading_status,
|
||||
mode: "static",
|
||||
value: {
|
||||
name: "https://gradio-builds.s3.amazonaws.com/demo-files/audio_sample.wav",
|
||||
data: null,
|
||||
is_file: true
|
||||
},
|
||||
label: "static",
|
||||
root: "foo",
|
||||
root_url: null,
|
||||
streaming: false,
|
||||
pending: false,
|
||||
source: "microphone",
|
||||
autoplay: true
|
||||
});
|
||||
|
||||
const mock = spy();
|
||||
component.$on("change", mock);
|
||||
|
||||
(component.value = [
|
||||
{
|
||||
name: "https://gradio-builds.s3.amazonaws.com/demo-files/audio_sample2.wav",
|
||||
data: null,
|
||||
is_file: true
|
||||
}
|
||||
]),
|
||||
assert.equal(mock.callCount, 1);
|
||||
});
|
||||
});
|
||||
|
@ -1,3 +1,5 @@
|
||||
<svelte:options accessors={true} />
|
||||
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import { Image, StaticImage } from "@gradio/image";
|
||||
@ -81,7 +83,6 @@
|
||||
{selectable}
|
||||
on:edit
|
||||
on:clear
|
||||
on:change
|
||||
on:stream
|
||||
on:drag={({ detail }) => (dragging = detail)}
|
||||
on:upload
|
||||
|
57
js/app/src/components/Image/Image.test.ts
Normal file
57
js/app/src/components/Image/Image.test.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import {
|
||||
test,
|
||||
describe,
|
||||
assert,
|
||||
afterEach,
|
||||
vi,
|
||||
beforeAll,
|
||||
beforeEach
|
||||
} from "vitest";
|
||||
import { spy } from "tinyspy";
|
||||
import { cleanup, render } from "@gradio/tootils";
|
||||
import { setupi18n } from "../../i18n";
|
||||
|
||||
import Image from "./Image.svelte";
|
||||
import type { LoadingStatus } from "../StatusTracker/types";
|
||||
|
||||
const loading_status = {
|
||||
eta: 0,
|
||||
queue_position: 1,
|
||||
queue_size: 1,
|
||||
status: "complete" as LoadingStatus["status"],
|
||||
scroll_to_output: false,
|
||||
visible: true,
|
||||
fn_index: 0,
|
||||
show_progress: "full" as LoadingStatus["show_progress"]
|
||||
};
|
||||
|
||||
describe("Image", () => {
|
||||
beforeAll(() => {
|
||||
window.HTMLMediaElement.prototype.play = vi.fn();
|
||||
window.HTMLMediaElement.prototype.pause = vi.fn();
|
||||
});
|
||||
beforeEach(setupi18n);
|
||||
afterEach(() => cleanup());
|
||||
|
||||
test("image change event trigger fires when value is changed and only fires once", async () => {
|
||||
const { component } = await render(Image, {
|
||||
show_label: true,
|
||||
loading_status,
|
||||
mode: "dynamic",
|
||||
value:
|
||||
"https://raw.githubusercontent.com/gradio-app/gradio/main/test/test_files/bus.png",
|
||||
root: "foo",
|
||||
root_url: null,
|
||||
streaming: false,
|
||||
pending: false,
|
||||
source: "upload"
|
||||
});
|
||||
|
||||
const mock = spy();
|
||||
component.$on("change", mock);
|
||||
|
||||
component.value =
|
||||
"https://github.com/gradio-app/gradio/blob/main/test/test_files/cheetah1.jpg";
|
||||
assert.equal(mock.callCount, 1);
|
||||
});
|
||||
});
|
@ -1,3 +1,5 @@
|
||||
<svelte:options accessors={true} />
|
||||
|
||||
<script lang="ts">
|
||||
import { createEventDispatcher } from "svelte";
|
||||
import type { FileData } from "@gradio/upload";
|
||||
@ -17,7 +19,7 @@
|
||||
let old_value: [FileData, FileData | null] | null = null;
|
||||
|
||||
export let label: string;
|
||||
export let source: string;
|
||||
export let source: "upload" | "webcam";
|
||||
export let root: string;
|
||||
export let root_url: null | string;
|
||||
export let show_label: boolean;
|
||||
@ -31,7 +33,7 @@
|
||||
export let min_width: number | undefined = undefined;
|
||||
export let mode: "static" | "dynamic";
|
||||
export let autoplay = false;
|
||||
export let show_share_button: boolean = true;
|
||||
export let show_share_button = true;
|
||||
|
||||
let _video: FileData | null = null;
|
||||
let _subtitle: FileData | null = null;
|
||||
@ -58,8 +60,6 @@
|
||||
} else {
|
||||
value = null;
|
||||
}
|
||||
|
||||
dispatch("change");
|
||||
}
|
||||
|
||||
$: {
|
||||
|
@ -8,7 +8,7 @@ import {
|
||||
beforeEach,
|
||||
expect
|
||||
} from "vitest";
|
||||
import { spyOn } from "tinyspy";
|
||||
import { spy, spyOn } from "tinyspy";
|
||||
import { cleanup, render } from "@gradio/tootils";
|
||||
import { setupi18n } from "../../i18n";
|
||||
|
||||
@ -125,7 +125,7 @@ describe("Video", () => {
|
||||
root_url: null,
|
||||
streaming: false,
|
||||
pending: false,
|
||||
source: "microphone",
|
||||
source: "upload",
|
||||
autoplay: true
|
||||
});
|
||||
const startButton = getByTestId<HTMLAudioElement>("test-player");
|
||||
@ -150,7 +150,7 @@ describe("Video", () => {
|
||||
root_url: null,
|
||||
streaming: false,
|
||||
pending: false,
|
||||
source: "microphone",
|
||||
source: "upload",
|
||||
autoplay: true
|
||||
});
|
||||
const startButton = getByTestId<HTMLAudioElement>("test-player");
|
||||
@ -175,7 +175,7 @@ describe("Video", () => {
|
||||
root_url: null,
|
||||
streaming: false,
|
||||
pending: false,
|
||||
source: "microphone",
|
||||
source: "upload",
|
||||
autoplay: true
|
||||
});
|
||||
const startButton = getByTestId<HTMLAudioElement>("test-player");
|
||||
@ -208,7 +208,7 @@ describe("Video", () => {
|
||||
root_url: null,
|
||||
streaming: false,
|
||||
pending: false,
|
||||
source: "microphone",
|
||||
source: "upload",
|
||||
autoplay: true
|
||||
});
|
||||
const startButton = getByTestId<HTMLAudioElement>("test-player");
|
||||
@ -248,4 +248,37 @@ describe("Video", () => {
|
||||
downloadButton.getElementsByTagName("button").length
|
||||
).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
test("video change event trigger fires when value is changed and only fires once", async () => {
|
||||
const { component } = await render(Video, {
|
||||
show_label: true,
|
||||
loading_status,
|
||||
mode: "dynamic",
|
||||
value: [
|
||||
{
|
||||
name: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/a.mp4",
|
||||
data: null,
|
||||
is_file: true
|
||||
}
|
||||
],
|
||||
root: "foo",
|
||||
root_url: null,
|
||||
streaming: false,
|
||||
pending: false,
|
||||
source: "upload",
|
||||
autoplay: true
|
||||
});
|
||||
|
||||
const mock = spy();
|
||||
component.$on("change", mock);
|
||||
|
||||
(component.value = [
|
||||
{
|
||||
name: "https://raw.githubusercontent.com/gradio-app/gradio/main/gradio/demo/video_component/files/b.mp4",
|
||||
data: null,
|
||||
is_file: true
|
||||
}
|
||||
]),
|
||||
assert.equal(mock.callCount, 1);
|
||||
});
|
||||
});
|
||||
|
@ -96,8 +96,6 @@
|
||||
select: SelectData;
|
||||
}>();
|
||||
|
||||
$: dispatch("change", value as string);
|
||||
|
||||
let dragging = false;
|
||||
|
||||
$: dispatch("drag", dragging);
|
||||
|
4
pnpm-lock.yaml
generated
4
pnpm-lock.yaml
generated
@ -1,4 +1,4 @@
|
||||
lockfileVersion: '6.0'
|
||||
lockfileVersion: '6.1'
|
||||
|
||||
settings:
|
||||
autoInstallPeers: true
|
||||
@ -5766,7 +5766,7 @@ packages:
|
||||
peerDependencies:
|
||||
'@sveltejs/kit': ^1.0.0
|
||||
dependencies:
|
||||
'@sveltejs/kit': 1.16.3(svelte@3.57.0)(vite@4.3.5)
|
||||
'@sveltejs/kit': 1.16.3(svelte@3.59.2)(vite@4.3.9)
|
||||
import-meta-resolve: 3.0.0
|
||||
dev: true
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
# Reference: https://github.com/sweepai/sweep/blob/main/sweep.yaml
|
||||
branch: dev
|
||||
branch: dev
|
||||
|
Loading…
x
Reference in New Issue
Block a user