mirror of
https://github.com/gradio-app/gradio.git
synced 2024-11-27 01:40:20 +08:00
Add allow_file_downloads
param to allow downloading image/video/audio media in chatbot (#9905)
* add allow_file_downloads param * add download btn for markdown images * add changeset * tweak * fix test * remove param * revert param removal * fix show logic * rename show_download_button to allow_file_downloads * change default to True --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Abubakar Abid <abubakar@huggingface.co>
This commit is contained in:
parent
da6f191554
commit
08f4b8b000
6
.changeset/huge-windows-mate.md
Normal file
6
.changeset/huge-windows-mate.md
Normal file
@ -0,0 +1,6 @@
|
||||
---
|
||||
"@gradio/chatbot": patch
|
||||
"gradio": patch
|
||||
---
|
||||
|
||||
fix:Add `allow_file_downloads` param to allow downloading image/video/audio media in chatbot
|
@ -184,6 +184,7 @@ class Chatbot(Component):
|
||||
placeholder: str | None = None,
|
||||
examples: list[ExampleMessage] | None = None,
|
||||
show_copy_all_button=False,
|
||||
allow_file_downloads=True,
|
||||
):
|
||||
"""
|
||||
Parameters:
|
||||
@ -218,6 +219,7 @@ class Chatbot(Component):
|
||||
placeholder: a placeholder message to display in the chatbot when it is empty. Centered vertically and horizontally in the Chatbot. Supports Markdown and HTML. If None, no placeholder is displayed.
|
||||
examples: A list of example messages to display in the chatbot before any user/assistant messages are shown. Each example should be a dictionary with an optional "text" key representing the message that should be populated in the Chatbot when clicked, an optional "files" key, whose value should be a list of files to populate in the Chatbot, an optional "icon" key, whose value should be a filepath or URL to an image to display in the example box, and an optional "display_text" key, whose value should be the text to display in the example box. If "display_text" is not provided, the value of "text" will be displayed.
|
||||
show_copy_all_button: If True, will show a copy all button that copies all chatbot messages to the clipboard.
|
||||
allow_file_downloads: If True, will show a download button for chatbot messages that contain media. Defaults to True.
|
||||
"""
|
||||
if type is None:
|
||||
warnings.warn(
|
||||
@ -259,6 +261,7 @@ class Chatbot(Component):
|
||||
self.line_breaks = line_breaks
|
||||
self.layout = layout
|
||||
self.show_copy_all_button = show_copy_all_button
|
||||
self.allow_file_downloads = allow_file_downloads
|
||||
super().__init__(
|
||||
label=label,
|
||||
every=every,
|
||||
|
@ -58,7 +58,7 @@
|
||||
|
||||
<Story
|
||||
name="Chatbot with math disabled, small height"
|
||||
args={{ latex_delimiters: [], height: 200 }}
|
||||
args={{ latex_delimiters: [], height: 200, show_copy_button: false }}
|
||||
/>
|
||||
|
||||
<Story
|
||||
@ -85,24 +85,10 @@
|
||||
/>
|
||||
|
||||
<Story
|
||||
name="Chatbot with copy button"
|
||||
args={{
|
||||
show_copy_button: true
|
||||
}}
|
||||
/>
|
||||
|
||||
<Story
|
||||
name="Chatbot with chat bubble full width disabled"
|
||||
args={{
|
||||
bubble_full_width: false
|
||||
}}
|
||||
/>
|
||||
|
||||
<Story
|
||||
name="Chatbot with panel layout enabled"
|
||||
name="Chatbot with chat bubble full width disabled and copy button"
|
||||
args={{
|
||||
bubble_full_width: false,
|
||||
layout: "panel"
|
||||
show_copy_button: true
|
||||
}}
|
||||
/>
|
||||
|
||||
|
@ -79,6 +79,7 @@
|
||||
export let placeholder: string | null = null;
|
||||
export let examples: ExampleMessage[] | null = null;
|
||||
export let theme_mode: "system" | "light" | "dark";
|
||||
export let allow_file_downloads = true;
|
||||
</script>
|
||||
|
||||
<Block
|
||||
@ -157,6 +158,7 @@
|
||||
load_component={gradio.load_component}
|
||||
msg_format={type}
|
||||
root={gradio.root}
|
||||
{allow_file_downloads}
|
||||
/>
|
||||
</div>
|
||||
</Block>
|
||||
|
@ -13,7 +13,6 @@
|
||||
export let show_retry: boolean;
|
||||
export let show_undo: boolean;
|
||||
export let show_copy_button: boolean;
|
||||
export let show: boolean;
|
||||
export let message: NormalisedMessage | NormalisedMessage[];
|
||||
export let position: "right" | "left";
|
||||
export let avatar: FileData | null;
|
||||
@ -48,7 +47,7 @@
|
||||
message.content.value?.url;
|
||||
</script>
|
||||
|
||||
{#if show}
|
||||
{#if show_copy || show_retry || show_undo || likeable}
|
||||
<div
|
||||
class="message-buttons-{position} {layout} message-buttons {avatar !==
|
||||
null && 'with-avatar'}"
|
||||
@ -57,14 +56,6 @@
|
||||
{#if show_copy}
|
||||
<Copy value={message_text} />
|
||||
{/if}
|
||||
{#if show_download && !Array.isArray(message) && is_component_message(message)}
|
||||
<DownloadLink
|
||||
href={message?.content?.value.url}
|
||||
download={message.content.value.orig_name || "image"}
|
||||
>
|
||||
<IconButton Icon={DownloadIcon} />
|
||||
</DownloadLink>
|
||||
{/if}
|
||||
{#if show_retry}
|
||||
<IconButton
|
||||
Icon={Retry}
|
||||
|
@ -10,6 +10,7 @@
|
||||
import type { NormalisedMessage } from "../types";
|
||||
import { copy } from "@gradio/utils";
|
||||
import Message from "./Message.svelte";
|
||||
import { DownloadLink } from "@gradio/wasm/svelte";
|
||||
|
||||
import { dequal } from "dequal/lite";
|
||||
import {
|
||||
@ -22,7 +23,13 @@
|
||||
} from "svelte";
|
||||
import { Image } from "@gradio/image/shared";
|
||||
|
||||
import { Clear, Trash, Community, ScrollDownArrow } from "@gradio/icons";
|
||||
import {
|
||||
Clear,
|
||||
Trash,
|
||||
Community,
|
||||
ScrollDownArrow,
|
||||
Download
|
||||
} from "@gradio/icons";
|
||||
import { IconButtonWrapper, IconButton } from "@gradio/atoms";
|
||||
import type { SelectData, LikeData } from "@gradio/utils";
|
||||
import type { ExampleMessage } from "../types";
|
||||
@ -40,6 +47,7 @@
|
||||
|
||||
export let _fetch: typeof fetch;
|
||||
export let load_component: Gradio["load_component"];
|
||||
export let allow_file_downloads: boolean;
|
||||
|
||||
let _components: Record<string, ComponentType<SvelteComponent>> = {};
|
||||
|
||||
@ -292,6 +300,14 @@
|
||||
on:click={() => (is_image_preview_open = false)}
|
||||
label={"Clear"}
|
||||
/>
|
||||
{#if allow_file_downloads}
|
||||
<DownloadLink
|
||||
href={image_preview_source}
|
||||
download={image_preview_source_alt || "image"}
|
||||
>
|
||||
<IconButton Icon={Download} label={"Download"} />
|
||||
</DownloadLink>
|
||||
{/if}
|
||||
</IconButtonWrapper>
|
||||
</div>
|
||||
{/if}
|
||||
@ -326,6 +342,7 @@
|
||||
{show_copy_button}
|
||||
handle_action={(selected) => handle_like(i, messages[0], selected)}
|
||||
scroll={is_browser ? scroll : () => {}}
|
||||
{allow_file_downloads}
|
||||
/>
|
||||
{/each}
|
||||
{#if pending_message}
|
||||
|
@ -8,6 +8,7 @@
|
||||
export let i18n;
|
||||
export let upload;
|
||||
export let _fetch;
|
||||
export let allow_file_downloads: boolean;
|
||||
</script>
|
||||
|
||||
{#if type === "gallery"}
|
||||
@ -45,7 +46,7 @@
|
||||
label=""
|
||||
waveform_settings={{}}
|
||||
waveform_options={{}}
|
||||
show_download_button={false}
|
||||
show_download_button={allow_file_downloads}
|
||||
on:load
|
||||
/>
|
||||
{:else if type === "video"}
|
||||
@ -57,7 +58,7 @@
|
||||
show_share_button={true}
|
||||
{i18n}
|
||||
{upload}
|
||||
show_download_button={false}
|
||||
show_download_button={allow_file_downloads}
|
||||
on:load
|
||||
>
|
||||
<track kind="captions" />
|
||||
@ -68,7 +69,7 @@
|
||||
{value}
|
||||
show_label={false}
|
||||
label="chatbot-image"
|
||||
show_download_button={false}
|
||||
show_download_button={allow_file_downloads}
|
||||
on:load
|
||||
{i18n}
|
||||
/>
|
||||
|
@ -44,6 +44,7 @@
|
||||
export let msg_format: "tuples" | "messages";
|
||||
export let handle_action: (selected: string | null) => void;
|
||||
export let scroll: () => void;
|
||||
export let allow_file_downloads: boolean;
|
||||
|
||||
function handle_select(i: number, message: NormalisedMessage): void {
|
||||
dispatch("select", {
|
||||
@ -71,7 +72,6 @@
|
||||
}
|
||||
|
||||
type ButtonPanelProps = {
|
||||
show: boolean;
|
||||
handle_action: (selected: string | null) => void;
|
||||
likeable: boolean;
|
||||
show_retry: boolean;
|
||||
@ -86,7 +86,6 @@
|
||||
|
||||
let button_panel_props: ButtonPanelProps;
|
||||
$: button_panel_props = {
|
||||
show: show_like || show_retry || show_undo || show_copy_button,
|
||||
handle_action,
|
||||
likeable: show_like,
|
||||
show_retry,
|
||||
@ -147,11 +146,23 @@
|
||||
aria-label={role + "'s message: " + get_message_label_data(message)}
|
||||
>
|
||||
{#if message.type === "text"}
|
||||
{#if message.metadata.title}
|
||||
<MessageBox
|
||||
title={message.metadata.title}
|
||||
expanded={is_last_bot_message([message], value)}
|
||||
>
|
||||
<div class="message-content">
|
||||
{#if message.metadata.title}
|
||||
<MessageBox
|
||||
title={message.metadata.title}
|
||||
expanded={is_last_bot_message([message], value)}
|
||||
>
|
||||
<Markdown
|
||||
message={message.content}
|
||||
{latex_delimiters}
|
||||
{sanitize_html}
|
||||
{render_markdown}
|
||||
{line_breaks}
|
||||
on:load={scroll}
|
||||
{root}
|
||||
/>
|
||||
</MessageBox>
|
||||
{:else}
|
||||
<Markdown
|
||||
message={message.content}
|
||||
{latex_delimiters}
|
||||
@ -161,18 +172,8 @@
|
||||
on:load={scroll}
|
||||
{root}
|
||||
/>
|
||||
</MessageBox>
|
||||
{:else}
|
||||
<Markdown
|
||||
message={message.content}
|
||||
{latex_delimiters}
|
||||
{sanitize_html}
|
||||
{render_markdown}
|
||||
{line_breaks}
|
||||
on:load={scroll}
|
||||
{root}
|
||||
/>
|
||||
{/if}
|
||||
{/if}
|
||||
</div>
|
||||
{:else if message.type === "component" && message.content.component in _components}
|
||||
<Component
|
||||
{target}
|
||||
@ -185,6 +186,7 @@
|
||||
{upload}
|
||||
{_fetch}
|
||||
on:load={() => scroll()}
|
||||
{allow_file_downloads}
|
||||
/>
|
||||
{:else if message.type === "component" && message.content.component === "file"}
|
||||
<a
|
||||
@ -316,7 +318,6 @@
|
||||
box-shadow: var(--shadow-drop);
|
||||
align-self: flex-start;
|
||||
text-align: right;
|
||||
padding: var(--spacing-sm) var(--spacing-xl);
|
||||
border-color: var(--border-color-accent-subdued);
|
||||
background-color: var(--color-accent-soft);
|
||||
}
|
||||
@ -330,7 +331,6 @@
|
||||
box-shadow: var(--shadow-drop);
|
||||
align-self: flex-start;
|
||||
text-align: right;
|
||||
padding: var(--spacing-sm) var(--spacing-xl);
|
||||
}
|
||||
|
||||
.panel .user :global(*) {
|
||||
@ -417,17 +417,6 @@
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
|
||||
.user {
|
||||
border-width: 1px;
|
||||
border-radius: var(--radius-md);
|
||||
align-self: flex-start;
|
||||
border-bottom-right-radius: 0;
|
||||
box-shadow: var(--shadow-drop);
|
||||
text-align: right;
|
||||
padding: var(--spacing-sm) var(--spacing-xl);
|
||||
border-color: var(--border-color-accent-subdued);
|
||||
background-color: var(--color-accent-soft);
|
||||
}
|
||||
@media (max-width: 480px) {
|
||||
.user-row.bubble {
|
||||
align-self: flex-end;
|
||||
@ -441,6 +430,10 @@
|
||||
}
|
||||
}
|
||||
|
||||
.message-content {
|
||||
padding: var(--spacing-sm) var(--spacing-xl);
|
||||
}
|
||||
|
||||
.avatar-container {
|
||||
align-self: flex-start;
|
||||
position: relative;
|
||||
|
@ -51,6 +51,7 @@ class TestChatbot:
|
||||
"_selectable": False,
|
||||
"_retryable": False,
|
||||
"_undoable": False,
|
||||
"allow_file_downloads": True,
|
||||
"key": None,
|
||||
"type": "tuples",
|
||||
"latex_delimiters": [{"display": True, "left": "$$", "right": "$$"}],
|
||||
|
Loading…
Reference in New Issue
Block a user