Add .input() events to gr.Audio and gr.Image (#8836)

* add input

* format

* add changeset

* add changeset

* add audio browser tests

* add browser tests

* notebooks

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
This commit is contained in:
Abubakar Abid 2024-07-18 23:17:13 -07:00 committed by GitHub
parent 3a81fb2578
commit 7e8c829aad
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 57 additions and 17 deletions

View File

@ -0,0 +1,7 @@
---
"@gradio/audio": patch
"@gradio/image": patch
"gradio": patch
---
fix:Add `.input()` events to `gr.Audio` and `gr.Image`

View File

@ -1 +1 @@
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: audio_component_events"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "with gr.Blocks() as demo:\n", " with gr.Row():\n", " with gr.Column():\n", " input_video = gr.Audio(type=\"filepath\", label=\"Input Audio\", sources=[\"upload\", \"microphone\"])\n", " with gr.Column():\n", " output_video = gr.Audio(label=\"Output Audio\", sources=[\"upload\", \"microphone\"])\n", "\n", " with gr.Row():\n", " with gr.Column():\n", " input_num_change = gr.Number(label=\"# Input Change Events\", value=0)\n", " input_num_load = gr.Number(label=\"# Input Upload Events\", value=0)\n", " input_num_play = gr.Number(label=\"# Input Play Events\", value=0)\n", " input_num_pause = gr.Number(label=\"# Input Pause Events\", value=0)\n", "\n", " with gr.Column():\n", " input_record = gr.Number(label=\"# Input Start Recording Events\", value=0)\n", " input_pause = gr.Number(label=\"# Input Pause Recording Events\", value=0)\n", " input_stop = gr.Number(label=\"# Input Stop Recording Events\", value=0)\n", "\n", "\n", " with gr.Column():\n", " output_num_play = gr.Number(label=\"# Output Play Events\", value=0)\n", " output_num_pause = gr.Number(label=\"# Output Pause Events\", value=0)\n", " output_num_stop = gr.Number(label=\"# Output Stop Events\", value=0)\n", "\n", " input_video.upload(lambda s, n: (s, n + 1), [input_video, input_num_load], [output_video, input_num_load])\n", " input_video.change(lambda n: n + 1, input_num_change, input_num_change)\n", " input_video.play(lambda n: n + 1, input_num_play, input_num_play)\n", " input_video.pause(lambda n: n + 1, input_num_pause, input_num_pause)\n", " input_video.change(lambda n: n + 1, input_num_change, input_num_change)\n", "\n", " input_video.start_recording(lambda n: n + 1, input_record, input_record)\n", " input_video.pause_recording(lambda n: n + 1, input_pause, input_pause)\n", " input_video.stop_recording(lambda n: n + 1, input_stop, input_stop)\n", "\n", " output_video.play(lambda n: n + 1, output_num_play, output_num_play)\n", " output_video.pause(lambda n: n + 1, output_num_pause, output_num_pause)\n", " output_video.stop(lambda n: n + 1, output_num_stop, output_num_stop)\n", "\n", "\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: audio_component_events"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "with gr.Blocks() as demo:\n", " with gr.Row():\n", " with gr.Column():\n", " input_audio = gr.Audio(type=\"filepath\", label=\"Input Audio\", sources=[\"upload\", \"microphone\"])\n", " with gr.Column():\n", " output_audio = gr.Audio(label=\"Output Audio\", sources=[\"upload\", \"microphone\"])\n", "\n", " with gr.Row():\n", " with gr.Column():\n", " input_num_change = gr.Number(label=\"# Input Change Events\", value=0)\n", " input_num_input = gr.Number(label=\"# Input Input Events\", value=0)\n", " input_num_load = gr.Number(label=\"# Input Upload Events\", value=0)\n", " input_num_play = gr.Number(label=\"# Input Play Events\", value=0)\n", " input_num_pause = gr.Number(label=\"# Input Pause Events\", value=0)\n", "\n", " with gr.Column():\n", " input_record = gr.Number(label=\"# Input Start Recording Events\", value=0)\n", " input_pause = gr.Number(label=\"# Input Pause Recording Events\", value=0)\n", " input_stop = gr.Number(label=\"# Input Stop Recording Events\", value=0)\n", "\n", "\n", " with gr.Column():\n", " output_num_play = gr.Number(label=\"# Output Play Events\", value=0)\n", " output_num_pause = gr.Number(label=\"# Output Pause Events\", value=0)\n", " output_num_stop = gr.Number(label=\"# Output Stop Events\", value=0)\n", "\n", " input_audio.upload(lambda s, n: (s, n + 1), [input_audio, input_num_load], [output_audio, input_num_load])\n", " input_audio.change(lambda n: n + 1, input_num_change, input_num_change)\n", " input_audio.play(lambda n: n + 1, input_num_play, input_num_play)\n", " input_audio.pause(lambda n: n + 1, input_num_pause, input_num_pause)\n", " input_audio.change(lambda n: n + 1, input_num_change, input_num_change)\n", " input_audio.input(lambda n: n + 1, input_num_input, input_num_input)\n", "\n", " input_audio.start_recording(lambda n: n + 1, input_record, input_record)\n", " input_audio.pause_recording(lambda n: n + 1, input_pause, input_pause)\n", " input_audio.stop_recording(lambda n: n + 1, input_stop, input_stop)\n", "\n", " output_audio.play(lambda n: n + 1, output_num_play, output_num_play)\n", " output_audio.pause(lambda n: n + 1, output_num_pause, output_num_pause)\n", " output_audio.stop(lambda n: n + 1, output_num_stop, output_num_stop)\n", "\n", "\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}

View File

@ -3,13 +3,14 @@ import gradio as gr
with gr.Blocks() as demo:
with gr.Row():
with gr.Column():
input_video = gr.Audio(type="filepath", label="Input Audio", sources=["upload", "microphone"])
input_audio = gr.Audio(type="filepath", label="Input Audio", sources=["upload", "microphone"])
with gr.Column():
output_video = gr.Audio(label="Output Audio", sources=["upload", "microphone"])
output_audio = gr.Audio(label="Output Audio", sources=["upload", "microphone"])
with gr.Row():
with gr.Column():
input_num_change = gr.Number(label="# Input Change Events", value=0)
input_num_input = gr.Number(label="# Input Input Events", value=0)
input_num_load = gr.Number(label="# Input Upload Events", value=0)
input_num_play = gr.Number(label="# Input Play Events", value=0)
input_num_pause = gr.Number(label="# Input Pause Events", value=0)
@ -25,19 +26,20 @@ with gr.Blocks() as demo:
output_num_pause = gr.Number(label="# Output Pause Events", value=0)
output_num_stop = gr.Number(label="# Output Stop Events", value=0)
input_video.upload(lambda s, n: (s, n + 1), [input_video, input_num_load], [output_video, input_num_load])
input_video.change(lambda n: n + 1, input_num_change, input_num_change)
input_video.play(lambda n: n + 1, input_num_play, input_num_play)
input_video.pause(lambda n: n + 1, input_num_pause, input_num_pause)
input_video.change(lambda n: n + 1, input_num_change, input_num_change)
input_audio.upload(lambda s, n: (s, n + 1), [input_audio, input_num_load], [output_audio, input_num_load])
input_audio.change(lambda n: n + 1, input_num_change, input_num_change)
input_audio.play(lambda n: n + 1, input_num_play, input_num_play)
input_audio.pause(lambda n: n + 1, input_num_pause, input_num_pause)
input_audio.change(lambda n: n + 1, input_num_change, input_num_change)
input_audio.input(lambda n: n + 1, input_num_input, input_num_input)
input_video.start_recording(lambda n: n + 1, input_record, input_record)
input_video.pause_recording(lambda n: n + 1, input_pause, input_pause)
input_video.stop_recording(lambda n: n + 1, input_stop, input_stop)
input_audio.start_recording(lambda n: n + 1, input_record, input_record)
input_audio.pause_recording(lambda n: n + 1, input_pause, input_pause)
input_audio.stop_recording(lambda n: n + 1, input_stop, input_stop)
output_video.play(lambda n: n + 1, output_num_play, output_num_play)
output_video.pause(lambda n: n + 1, output_num_pause, output_num_pause)
output_video.stop(lambda n: n + 1, output_num_stop, output_num_stop)
output_audio.play(lambda n: n + 1, output_num_play, output_num_play)
output_audio.pause(lambda n: n + 1, output_num_pause, output_num_pause)
output_audio.stop(lambda n: n + 1, output_num_stop, output_num_stop)

View File

@ -1 +1 @@
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: image_component_events"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "def test_select_is_defined(n, evt: gr.SelectData):\n", " assert isinstance(evt.index, list)\n", " assert isinstance(evt.index[0], int)\n", " return n + 1\n", "\n", "\n", "with gr.Blocks() as demo:\n", " with gr.Row():\n", " with gr.Column():\n", " input_img = gr.Image(type=\"filepath\", label=\"Input Image\", sources=[\"upload\", \"clipboard\"])\n", " with gr.Column():\n", " output_img = gr.Image(type=\"filepath\", label=\"Output Image\", sources=[\"upload\", \"clipboard\"])\n", " with gr.Column():\n", " num_change = gr.Number(label=\"# Change Events\", value=0)\n", " num_load = gr.Number(label=\"# Upload Events\", value=0)\n", " num_change_o = gr.Number(label=\"# Change Events Output\", value=0)\n", " num_clear = gr.Number(label=\"# Clear Events\", value=0)\n", " num_select = gr.Number(label=\"# Select Events\", value=0)\n", " input_img.upload(lambda s, n: (s, n + 1), [input_img, num_load], [output_img, num_load])\n", " input_img.change(lambda n: n + 1, num_change, num_change)\n", " input_img.clear(lambda n: n + 1, num_clear, num_clear)\n", " output_img.change(lambda n: n + 1, num_change_o, num_change_o)\n", " output_img.select(test_select_is_defined, num_select, num_select)\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: image_component_events"]}, {"cell_type": "code", "execution_count": null, "id": "272996653310673477252411125948039410165", "metadata": {}, "outputs": [], "source": ["!pip install -q gradio "]}, {"cell_type": "code", "execution_count": null, "id": "288918539441861185822528903084949547379", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "def test_select_is_defined(n, evt: gr.SelectData):\n", " assert isinstance(evt.index, list)\n", " assert isinstance(evt.index[0], int)\n", " return n + 1\n", "\n", "\n", "with gr.Blocks() as demo:\n", " with gr.Row():\n", " with gr.Column():\n", " input_img = gr.Image(type=\"filepath\", label=\"Input Image\", sources=[\"upload\", \"clipboard\"])\n", " with gr.Column():\n", " output_img = gr.Image(type=\"filepath\", label=\"Output Image\", sources=[\"upload\", \"clipboard\"])\n", " with gr.Column():\n", " num_change = gr.Number(label=\"# Change Events\", value=0)\n", " num_input = gr.Number(label=\"# Input Events\", value=0)\n", " num_load = gr.Number(label=\"# Upload Events\", value=0)\n", " num_change_o = gr.Number(label=\"# Change Events Output\", value=0)\n", " num_clear = gr.Number(label=\"# Clear Events\", value=0)\n", " num_select = gr.Number(label=\"# Select Events\", value=0)\n", "\n", " input_img.upload(lambda s, n: (s, n + 1), [input_img, num_load], [output_img, num_load])\n", " input_img.input(lambda n: n + 1, num_input, num_input)\n", " input_img.change(lambda n: n + 1, num_change, num_change)\n", " input_img.clear(lambda n: n + 1, num_clear, num_clear)\n", " output_img.change(lambda n: n + 1, num_change_o, num_change_o)\n", " output_img.select(test_select_is_defined, num_select, num_select)\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}

View File

@ -14,11 +14,14 @@ with gr.Blocks() as demo:
output_img = gr.Image(type="filepath", label="Output Image", sources=["upload", "clipboard"])
with gr.Column():
num_change = gr.Number(label="# Change Events", value=0)
num_input = gr.Number(label="# Input Events", value=0)
num_load = gr.Number(label="# Upload Events", value=0)
num_change_o = gr.Number(label="# Change Events Output", value=0)
num_clear = gr.Number(label="# Clear Events", value=0)
num_select = gr.Number(label="# Select Events", value=0)
input_img.upload(lambda s, n: (s, n + 1), [input_img, num_load], [output_img, num_load])
input_img.input(lambda n: n + 1, num_input, num_input)
input_img.change(lambda n: n + 1, num_change, num_change)
input_img.clear(lambda n: n + 1, num_clear, num_clear)
output_img.change(lambda n: n + 1, num_change_o, num_change_o)

View File

@ -70,6 +70,7 @@ class Audio(
Events.pause_recording,
Events.stop_recording,
Events.upload,
Events.input,
]
data_model = FileData

View File

@ -38,6 +38,7 @@ class Image(StreamingInput, Component):
Events.stream,
Events.select,
Events.upload,
Events.input,
]
data_model = FileData

View File

@ -1,7 +1,7 @@
import { test, expect, drag_and_drop_file } from "@gradio/tootils";
import { chromium } from "playwright";
test("Audio click-to-upload uploads audio successfuly. File downloading works and file has correct name.", async ({
test("Audio events are dispatched correctly. File downloading works and file has correct name.", async ({
page
}) => {
await page
@ -11,10 +11,12 @@ test("Audio click-to-upload uploads audio successfuly. File downloading works an
await uploader.setInputFiles(["../../test/test_files/audio_sample.wav"]);
await expect(page.getByLabel("# Input Change Events")).toHaveValue("1");
await expect(page.getByLabel("# Input Input Events")).toHaveValue("1");
await expect(page.getByLabel("# Input Upload Events")).toHaveValue("1");
await page.getByLabel("Clear").click();
await expect(page.getByLabel("# Input Change Events")).toHaveValue("2");
await expect(page.getByLabel("# Input Input Events")).toHaveValue("2");
await page
.getByRole("button", { name: "Drop Audio Here - or - Click to Upload" })
.click();
@ -22,6 +24,7 @@ test("Audio click-to-upload uploads audio successfuly. File downloading works an
await uploader.setInputFiles(["../../test/test_files/audio_sample.wav"]);
await expect(page.getByLabel("# Input Change Events")).toHaveValue("3");
await expect(page.getByLabel("# Input Input Events")).toHaveValue("3");
await expect(page.getByLabel("# Input Upload Events")).toHaveValue("2");
const downloadPromise = page.waitForEvent("download");

View File

@ -1,7 +1,7 @@
import { test, expect, drag_and_drop_file } from "@gradio/tootils";
import fs from "fs";
test("Image click-to-upload uploads image successfuly. Clear button dispatches event correctly. Downloading the file works and has the correct name.", async ({
test("Image events are dispatched correctly. Downloading the file works and has the correct name.", async ({
page
}) => {
await page.getByRole("button", { name: "Drop Image Here" }).click();
@ -9,6 +9,7 @@ test("Image click-to-upload uploads image successfuly. Clear button dispatches e
const change_counter = await page.getByLabel("# Change Events", {
exact: true
});
const input_counter = await page.getByLabel("# Input Events");
const clear_counter = await page.getByLabel("# Clear Events");
const upload_counter = await page.getByLabel("# Upload Events");
const change_output_counter = await page.getByLabel("# Change Events Output");
@ -16,6 +17,7 @@ test("Image click-to-upload uploads image successfuly. Clear button dispatches e
await uploader.setInputFiles("./test/files/cheetah1.jpg");
await expect(change_counter).toHaveValue("1");
await expect(input_counter).toHaveValue("1");
await expect(upload_counter).toHaveValue("1");
await expect(change_output_counter).toHaveValue("1");
@ -28,10 +30,12 @@ test("Image click-to-upload uploads image successfuly. Clear button dispatches e
await page.getByLabel("Remove Image").click();
await expect(clear_counter).toHaveValue("1");
await expect(change_counter).toHaveValue("2");
await expect(input_counter).toHaveValue("2");
await expect(upload_counter).toHaveValue("1");
await uploader.setInputFiles("./test/files/gradio-logo.svg");
await expect(change_counter).toHaveValue("3");
await expect(input_counter).toHaveValue("3");
await expect(upload_counter).toHaveValue("2");
await expect(change_output_counter).toHaveValue("2");

View File

@ -5,6 +5,7 @@
import type { FileData } from "@gradio/client";
import type { LoadingStatus } from "@gradio/statustracker";
import { afterUpdate } from "svelte";
import StaticAudio from "./static/StaticAudio.svelte";
import InteractiveAudio from "./interactive/InteractiveAudio.svelte";
@ -12,6 +13,7 @@
import { Block, UploadText } from "@gradio/atoms";
import type { WaveformOptions } from "./shared/types";
export let value_is_output = false;
export let elem_id = "";
export let elem_classes: string[] = [];
export let visible = true;
@ -38,6 +40,7 @@
export let pending: boolean;
export let streaming: boolean;
export let gradio: Gradio<{
input: never;
change: typeof value;
stream: typeof value;
error: string;
@ -78,6 +81,9 @@
if (JSON.stringify(value) !== JSON.stringify(old_value)) {
old_value = value;
gradio.dispatch("change");
if (!value_is_output) {
gradio.dispatch("input");
}
}
}
@ -134,6 +140,10 @@
loading_status.message = detail;
gradio.dispatch(level as "error" | "warning", detail);
}
afterUpdate(() => {
value_is_output = false;
});
</script>
{#if !interactive}

View File

@ -12,6 +12,7 @@
import type { Gradio, SelectData } from "@gradio/utils";
import StaticImage from "./shared/ImagePreview.svelte";
import ImageUploader from "./shared/ImageUploader.svelte";
import { afterUpdate } from "svelte";
import { Block, Empty, UploadText } from "@gradio/atoms";
import { Image } from "@gradio/icons";
@ -21,6 +22,7 @@
type sources = "upload" | "webcam" | "clipboard" | null;
export let value_is_output = false;
export let elem_id = "";
export let elem_classes: string[] = [];
export let visible = true;
@ -51,6 +53,7 @@
export let mirror_webcam: boolean;
export let gradio: Gradio<{
input: never;
change: never;
error: string;
edit: never;
@ -67,8 +70,14 @@
if (JSON.stringify(value) !== JSON.stringify(old_value)) {
old_value = value;
gradio.dispatch("change");
if (!value_is_output) {
gradio.dispatch("input");
}
}
}
afterUpdate(() => {
value_is_output = false;
});
let dragging: boolean;
let active_source: sources = null;