Allow download button for interactive Audio and Video components (#7104)

* allow download button for interactive audio and video components

* add changeset

* document show_download_button in video.py

* ensure show_download_button is by default true for output and false for input components

* fix component test

* tweak default val

* val tweak

* fix test and add story

* pass editable param where needed

* fix another test

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
Co-authored-by: Dawood Khan <dawoodkhan82@gmail.com>
This commit is contained in:
Hannah 2024-01-23 11:33:59 +01:00 committed by GitHub
parent c35fac049a
commit bc2cdc1df9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 102 additions and 11 deletions

View File

@ -0,0 +1,8 @@
---
"@gradio/audio": minor
"@gradio/upload": minor
"@gradio/video": minor
"gradio": minor
---
feat:Allow download button for interactive Audio and Video components

View File

@ -92,7 +92,7 @@ class Audio(
render: bool = True,
format: Literal["wav", "mp3"] = "wav",
autoplay: bool = False,
show_download_button=True,
show_download_button: bool | None = None,
show_share_button: bool | None = None,
editable: bool = True,
min_length: int | None = None,
@ -118,9 +118,9 @@ class Audio(
render: If False, component will not render be rendered in the Blocks context. Should be used if the intention is to assign event listeners now but render the component later.
format: The file format to save audio files. Either 'wav' or 'mp3'. wav files are lossless but will tend to be larger files. mp3 files tend to be smaller. Default is wav. Applies both when this component is used as an input (when `type` is "format") and when this component is used as an output.
autoplay: Whether to automatically play the audio when the component is used as an output. Note: browsers will not autoplay audio files if the user has not interacted with the page yet.
show_download_button: If True, will show a download button in the corner of the component for saving audio. If False, icon does not appear.
show_download_button: If True, will show a download button in the corner of the component for saving audio. If False, icon does not appear. By default, it will be True for output components and False for input components.
show_share_button: If True, will show a share icon in the corner of the component that allows user to share outputs to Hugging Face Spaces Discussions. If False, icon does not appear. If set to None (default behavior), then the icon appears if this Gradio app is launched on Spaces, but not otherwise.
editable: If True, allows users to manipulate the audio file (if the component is interactive).
editable: If True, allows users to manipulate the audio file if the component is interactive. Defaults to True.
min_length: The minimum length of audio (in seconds) that the user can pass into the prediction function. If None, there is no minimum length.
max_length: The maximum length of audio (in seconds) that the user can pass into the prediction function. If None, there is no maximum length.
waveform_options: A dictionary of options for the waveform display. Options include: waveform_color (str), waveform_progress_color (str), show_controls (bool), skip_length (int). Default is None, which uses the default values for these options.

View File

@ -83,6 +83,7 @@ class Video(Component):
include_audio: bool | None = None,
autoplay: bool = False,
show_share_button: bool | None = None,
show_download_button: bool | None = None,
min_length: int | None = None,
max_length: int | None = None,
):
@ -108,6 +109,7 @@ class Video(Component):
include_audio: Whether the component should record/retain the audio track for a video. By default, audio is excluded for webcam videos and included for uploaded videos.
autoplay: Whether to automatically play the video when the component is used as an output. Note: browsers will not autoplay video files if the user has not interacted with the page yet.
show_share_button: If True, will show a share icon in the corner of the component that allows user to share outputs to Hugging Face Spaces Discussions. If False, icon does not appear. If set to None (default behavior), then the icon appears if this Gradio app is launched on Spaces, but not otherwise.
show_download_button: If True, will show a download icon in the corner of the component that allows user to download the output. If False, icon does not appear. By default, it will be True for output components and False for input components.
min_length: The minimum length of video (in seconds) that the user can pass into the prediction function. If None, there is no minimum length.
max_length: The maximum length of video (in seconds) that the user can pass into the prediction function. If None, there is no maximum length.
"""
@ -140,6 +142,7 @@ class Video(Component):
if show_share_button is None
else show_share_button
)
self.show_download_button = show_download_button
self.min_length = min_length
self.max_length = max_length
super().__init__(

View File

@ -31,6 +31,35 @@
}}
/>
<Story
name="Audio Recorder with download button"
args={{
value: {
path: "https://audio-samples.github.io/samples/mp3/blizzard_unconditional/sample-0.mp3",
url: "https://audio-samples.github.io/samples/mp3/blizzard_unconditional/sample-0.mp3",
orig_name: "sample-0.mp3"
},
interactive: true,
show_download_button: true,
sources: ["microphone"],
label: "Audio Recorder"
}}
/>
<Story
name="output with hidden download button"
args={{
value: {
path: "https://audio-samples.github.io/samples/mp3/blizzard_unconditional/sample-0.mp3",
url: "https://audio-samples.github.io/samples/mp3/blizzard_unconditional/sample-0.mp3",
orig_name: "sample-0.mp3"
},
interactive: false,
show_download_button: false,
label: "Audio Recorder"
}}
/>
<Story
name="Upload Audio"
args={{
@ -57,7 +86,7 @@
/>
<Story
name="with disabled editing"
name="upload with disabled editing"
args={{
value: {
path: "https://audio-samples.github.io/samples/mp3/blizzard_unconditional/sample-0.mp3",

View File

@ -32,7 +32,7 @@
export let min_width: number | undefined = undefined;
export let loading_status: LoadingStatus;
export let autoplay = false;
export let show_download_button = true;
export let show_download_button: boolean;
export let show_share_button = false;
export let editable = true;
export let waveform_options: WaveformOptions = {};
@ -152,6 +152,7 @@
{label}
{waveform_settings}
{waveform_options}
{editable}
on:share={(e) => gradio.dispatch("share", e.detail)}
on:error={(e) => gradio.dispatch("error", e.detail)}
on:play={() => gradio.dispatch("play")}
@ -179,6 +180,7 @@
<InteractiveAudio
{label}
{show_label}
{show_download_button}
value={_value}
on:change={({ detail }) => (value = detail)}
on:stream={({ detail }) => {

View File

@ -22,6 +22,7 @@
export let label: string;
export let root: string;
export let show_label = true;
export let show_download_button = false;
export let sources:
| ["microphone"]
| ["upload"]
@ -235,6 +236,7 @@
<AudioRecorder
bind:mode
{i18n}
{editable}
{dispatch_blob}
{waveform_settings}
{waveform_options}
@ -258,6 +260,7 @@
{i18n}
on:clear={clear}
on:edit={() => (mode = "edit")}
download={show_download_button ? value.url : null}
absolute={true}
/>

View File

@ -21,6 +21,7 @@
show_recording_waveform: true
};
export let handle_reset_value: () => void;
export let editable = true;
let micWaveform: WaveSurfer;
let recordingWaveform: WaveSurfer;
@ -238,6 +239,7 @@
{playing}
{audio_duration}
{i18n}
{editable}
interactive={true}
{handle_trim_audio}
bind:trimDuration

View File

@ -18,6 +18,7 @@
export let i18n: I18nFormatter;
export let waveform_settings: Record<string, any>;
export let waveform_options: WaveformOptions;
export let editable = true;
const dispatch = createEventDispatcher<{
change: FileData;
@ -65,6 +66,7 @@
{i18n}
{waveform_settings}
{waveform_options}
{editable}
on:pause
on:play
on:stop

View File

@ -11,7 +11,8 @@
"@gradio/icons": "workspace:^",
"@gradio/client": "workspace:^",
"@gradio/upload": "workspace:^",
"@gradio/utils": "workspace:^"
"@gradio/utils": "workspace:^",
"@gradio/wasm": "workspace:^"
},
"main_changeset": true,
"exports": {

View File

@ -1,12 +1,14 @@
<script lang="ts">
import { IconButton } from "@gradio/atoms";
import type { I18nFormatter } from "@gradio/utils";
import { Edit, Clear, Undo } from "@gradio/icons";
import { Edit, Clear, Undo, Download } from "@gradio/icons";
import { DownloadLink } from "@gradio/wasm/svelte";
import { createEventDispatcher } from "svelte";
export let editable = false;
export let undoable = false;
export let download: string | null = null;
export let absolute = true;
export let i18n: I18nFormatter;
@ -37,6 +39,12 @@
/>
{/if}
{#if download}
<DownloadLink href={download} download>
<IconButton Icon={Download} label={i18n("common.download")} />
</DownloadLink>
{/if}
<IconButton
Icon={Clear}
label={i18n("common.clear")}

View File

@ -35,6 +35,7 @@
export let min_width: number | undefined = undefined;
export let autoplay = false;
export let show_share_button = true;
export let show_download_button: boolean;
export let gradio: Gradio<{
change: never;
clear: never;
@ -146,7 +147,7 @@
{show_label}
{autoplay}
{show_share_button}
show_download_button={true}
{show_download_button}
on:play={() => gradio.dispatch("play")}
on:pause={() => gradio.dispatch("pause")}
on:stop={() => gradio.dispatch("stop")}
@ -185,6 +186,7 @@
on:error={handle_error}
{label}
{show_label}
{show_download_button}
{sources}
{active_source}
{mirror_webcam}

View File

@ -38,6 +38,7 @@
},
label: "world video",
show_label: true,
show_download_button: true,
interactive: false,
height: 200,
width: 400
@ -55,6 +56,7 @@
},
label: "world video",
show_label: true,
show_download_button: false,
interactive: false,
height: 200,
width: 400
@ -74,6 +76,26 @@
}}
/>
<Story
name="Upload video with download button"
args={{
label: "world video",
show_label: true,
interactive: true,
sources: ["upload", "webcam"],
show_download_button: true,
width: 400,
height: 400,
value: {
video: {
path: "https://gradio-static-files.s3.us-west-2.amazonaws.com/world.mp4",
url: "https://gradio-static-files.s3.us-west-2.amazonaws.com/world.mp4",
orig_name: "world.mp4"
}
}
}}
/>
<Story
name="Trim video"
args={{

View File

@ -19,6 +19,7 @@
| ["webcam", "upload"]
| ["upload", "webcam"] = ["webcam", "upload"];
export let label: string | undefined = undefined;
export let show_download_button = false;
export let show_label = true;
export let mirror_webcam = false;
export let include_audio: boolean;
@ -96,7 +97,11 @@
{/if}
</div>
{:else}
<ModifyUpload {i18n} on:clear={handle_clear} />
<ModifyUpload
{i18n}
on:clear={handle_clear}
download={show_download_button ? value.url : null}
/>
{#if playable()}
{#key value?.url}
<Player

3
pnpm-lock.yaml generated
View File

@ -1461,6 +1461,9 @@ importers:
'@gradio/utils':
specifier: workspace:^
version: link:../utils
'@gradio/wasm':
specifier: workspace:^
version: link:../wasm
js/uploadbutton:
dependencies:

View File

@ -816,7 +816,7 @@ class TestAudio:
"autoplay": False,
"sources": ["upload", "microphone"],
"name": "audio",
"show_download_button": True,
"show_download_button": None,
"show_share_button": False,
"streaming": False,
"show_label": True,
@ -867,7 +867,7 @@ class TestAudio:
assert audio_output.get_config() == {
"autoplay": False,
"name": "audio",
"show_download_button": True,
"show_download_button": None,
"show_share_button": False,
"streaming": False,
"show_label": True,
@ -1483,6 +1483,7 @@ class TestVideo:
"container": True,
"min_width": 160,
"scale": None,
"show_download_button": None,
"height": None,
"width": None,
"elem_id": None,