Skip to content

Commit b42e461

Browse files
Adds a watermark parameter to gr.Chatbot that is added to copied text (#10814)
* changes * add changeset * format' * test * copy * changes * doc * format --------- Co-authored-by: gradio-pr-bot <[email protected]>
1 parent 4fa8e00 commit b42e461

9 files changed

Lines changed: 33 additions & 5 deletions

File tree

.changeset/fifty-yaks-trade.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@gradio/chatbot": minor
3+
"gradio": minor
4+
---
5+
6+
feat:Adds a watermark parameter to `gr.Chatbot` that is added to copied text

gradio/components/chatbot.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ def __init__(
225225
rtl: bool = False,
226226
show_share_button: bool | None = None,
227227
show_copy_button: bool = False,
228+
watermark: str | None = None,
228229
avatar_images: tuple[str | Path | None, str | Path | None] | None = None,
229230
sanitize_html: bool = True,
230231
render_markdown: bool = True,
@@ -266,6 +267,7 @@ def __init__(
266267
rtl: If True, sets the direction of the rendered text to right-to-left. Default is False, which renders text left-to-right.
267268
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.
268269
show_copy_button: If True, will show a copy button for each chatbot message.
270+
watermark: If provided, this text will be appended to the end of messages copied from the chatbot, after a blank line. Useful for indicating that the message is generated by an AI model.
269271
avatar_images: Tuple of two avatar image paths or URLs for user and bot (in that order). Pass None for either the user or bot image to skip. Must be within the working directory of the Gradio app or an external URL.
270272
sanitize_html: If False, will disable HTML sanitization for chatbot messages. This is not recommended, as it can lead to security vulnerabilities.
271273
render_markdown: If False, will disable Markdown rendering for chatbot messages.
@@ -325,6 +327,7 @@ def __init__(
325327
)
326328
self.render_markdown = render_markdown
327329
self.show_copy_button = show_copy_button
330+
self.watermark = watermark
328331
self.sanitize_html = sanitize_html
329332
if bubble_full_width is not None:
330333
warnings.warn(

js/chatbot/Index.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@
8888
export let examples: ExampleMessage[] | null = null;
8989
export let theme_mode: "system" | "light" | "dark";
9090
export let allow_file_downloads = true;
91+
export let watermark: string | null = null;
9192
</script>
9293

9394
<Block
@@ -186,6 +187,7 @@
186187
root={gradio.root}
187188
{allow_file_downloads}
188189
{allow_tags}
190+
{watermark}
189191
/>
190192
</div>
191193
</Block>

js/chatbot/shared/ButtonPanel.svelte

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
export let show_edit: boolean;
1515
export let in_edit_mode: boolean;
1616
export let show_copy_button: boolean;
17+
export let watermark: string | null = null;
1718
export let message: NormalisedMessage | NormalisedMessage[];
1819
export let position: "right" | "left";
1920
export let avatar: FileData | null;
@@ -52,6 +53,7 @@
5253
<Copy
5354
value={message_text}
5455
on:copy={(e) => dispatch("copy", e.detail)}
56+
{watermark}
5557
/>
5658
{/if}
5759
{#if show_retry}

js/chatbot/shared/ChatBot.svelte

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@
9191
export let like_user_message = false;
9292
export let root: string;
9393
export let allow_tags: string[] | boolean = false;
94+
export let watermark: string | null = null;
9495
9596
let target: HTMLElement | null = null;
9697
let edit_index: number | null = null;
@@ -268,7 +269,7 @@
268269
<IconButton Icon={Trash} on:click={() => dispatch("clear")} label={"Clear"}
269270
></IconButton>
270271
{#if show_copy_all_button}
271-
<CopyAll {value} />
272+
<CopyAll {value} {watermark} />
272273
{/if}
273274
</IconButtonWrapper>
274275
{/if}
@@ -321,6 +322,7 @@
321322
{feedback_options}
322323
{current_feedback}
323324
{allow_tags}
325+
{watermark}
324326
show_like={role === "user" ? likeable && like_user_message : likeable}
325327
show_retry={_retryable && is_last_bot_message(messages, value)}
326328
show_undo={_undoable && is_last_bot_message(messages, value)}

js/chatbot/shared/Copy.svelte

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
1212
let copied = false;
1313
export let value: string;
14+
export let watermark: string | null = null;
1415
let timer: NodeJS.Timeout;
1516
1617
function copy_feedback(): void {
@@ -24,11 +25,13 @@
2425
async function handle_copy(): Promise<void> {
2526
if ("clipboard" in navigator) {
2627
dispatch("copy", { value: value });
27-
await navigator.clipboard.writeText(value);
28+
const text_to_copy = watermark ? `${value}\n\n${watermark}` : value;
29+
await navigator.clipboard.writeText(text_to_copy);
2830
copy_feedback();
2931
} else {
3032
const textArea = document.createElement("textarea");
31-
textArea.value = value;
33+
const text_to_copy = watermark ? `${value}\n\n${watermark}` : value;
34+
textArea.value = text_to_copy;
3235
3336
textArea.style.position = "absolute";
3437
textArea.style.left = "-999999px";

js/chatbot/shared/CopyAll.svelte

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
77
let copied = false;
88
export let value: NormalisedMessage[] | null;
9+
export let watermark: string | null = null;
910
1011
let timer: NodeJS.Timeout;
1112
@@ -28,7 +29,11 @@
2829
})
2930
.join("\n\n");
3031
31-
navigator.clipboard.writeText(conversation_value).catch((err) => {
32+
const text_to_copy = watermark
33+
? `${conversation_value}\n\n${watermark}`
34+
: conversation_value;
35+
36+
navigator.clipboard.writeText(text_to_copy).catch((err) => {
3237
console.error("Failed to copy conversation: ", err);
3338
});
3439
}

js/chatbot/shared/Message.svelte

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
export let display_consecutive_in_same_bubble: boolean;
5252
export let current_feedback: string | null = null;
5353
export let allow_tags: string[] | boolean = false;
54+
export let watermark: string | null = null;
5455
let messageElements: HTMLDivElement[] = [];
5556
let previous_edit_mode = false;
5657
let last_message_width = 0;
@@ -104,6 +105,7 @@
104105
avatar: FileData | null;
105106
dispatch: any;
106107
current_feedback: string | null;
108+
watermark: string | null;
107109
};
108110
109111
let button_panel_props: ButtonPanelProps;
@@ -122,7 +124,8 @@
122124
avatar: avatar_img,
123125
layout,
124126
dispatch,
125-
current_feedback
127+
current_feedback,
128+
watermark
126129
};
127130
</script>
128131

@@ -236,6 +239,7 @@
236239
<ButtonPanel
237240
{...button_panel_props}
238241
{current_feedback}
242+
{watermark}
239243
on:copy={(e) => dispatch("copy", e.detail)}
240244
/>
241245
{/if}

test/components/test_chatbot.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ def test_component_functions(self):
7272
"allow_tags": False,
7373
"show_copy_all_button": False,
7474
"examples": None,
75+
"watermark": None,
7576
}
7677

7778
def test_avatar_images_are_moved_to_cache(self):

0 commit comments

Comments
 (0)