mirror of
https://github.com/gradio-app/gradio.git
synced 2025-04-12 12:40:29 +08:00
Reset flagged values when switching conversations in chat history (#10292)
* chat history * add changeset * changes * add changeset * changes * changes * more changes * changes * changes * format * notebook * fix test * changes * add changeset * changes * changes * changes * add changeset --------- Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com> Co-authored-by: Ali Abid <aliabid94@gmail.com>
This commit is contained in:
parent
890eaa3a9e
commit
f2bd72f9ef
7
.changeset/short-rice-clean.md
Normal file
7
.changeset/short-rice-clean.md
Normal file
@ -0,0 +1,7 @@
|
||||
---
|
||||
"@gradio/atoms": minor
|
||||
"@gradio/chatbot": minor
|
||||
"gradio": minor
|
||||
---
|
||||
|
||||
feat:Reset flagged values when switching conversations in chat history
|
@ -1 +1 @@
|
||||
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: chatinterface_streaming_echo"]}, {"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 time\n", "import gradio as gr\n", "\n", "def slow_echo(message, history):\n", " for i in range(len(message)):\n", " time.sleep(0.05)\n", " yield \"You typed: \" + message[: i + 1]\n", "\n", "demo = gr.ChatInterface(\n", " slow_echo,\n", " type=\"messages\",\n", " flagging_mode=\"manual\",\n", " flagging_options=[\"Like\", \"Spam\", \"Inappropriate\", \"Other\"], \n", " save_history=True,\n", ")\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
|
||||
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: chatinterface_streaming_echo"]}, {"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 time\n", "import gradio as gr\n", "\n", "def slow_echo(message, history):\n", " for i in range(len(message)):\n", " time.sleep(0.05)\n", " yield \"You typed: \" + message[: i + 1]\n", "\n", "demo = gr.ChatInterface(\n", " slow_echo,\n", " type=\"messages\",\n", " flagging_mode=\"manual\",\n", " flagging_options=[\"Like\", \"Spam\", \"Inappropriate\", \"Other\"],\n", " save_history=True,\n", ")\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
|
@ -10,7 +10,7 @@ demo = gr.ChatInterface(
|
||||
slow_echo,
|
||||
type="messages",
|
||||
flagging_mode="manual",
|
||||
flagging_options=["Like", "Spam", "Inappropriate", "Other"],
|
||||
flagging_options=["Like", "Spam", "Inappropriate", "Other"],
|
||||
save_history=True,
|
||||
)
|
||||
|
||||
|
@ -249,7 +249,7 @@ class ChatInterface(Blocks):
|
||||
|
||||
with self:
|
||||
self.saved_conversations = BrowserState(
|
||||
[], storage_key="_saved_conversations"
|
||||
[], storage_key=f"_saved_conversations_{self._id}"
|
||||
)
|
||||
self.conversation_id = State(None)
|
||||
self.saved_input = State() # Stores the most recent user message
|
||||
@ -279,7 +279,7 @@ class ChatInterface(Blocks):
|
||||
with Column(scale=1, min_width=100):
|
||||
self.new_chat_button = Button(
|
||||
"New chat",
|
||||
variant="secondary",
|
||||
variant="primary",
|
||||
size="md",
|
||||
icon=utils.get_icon_path("plus.svg"),
|
||||
)
|
||||
@ -467,6 +467,28 @@ class ChatInterface(Blocks):
|
||||
saved_conversations.pop(index)
|
||||
return None, saved_conversations
|
||||
|
||||
def _load_chat_history(self, conversations):
|
||||
return Dataset(
|
||||
samples=[
|
||||
[self._generate_chat_title(conv)]
|
||||
for conv in conversations or []
|
||||
if conv
|
||||
]
|
||||
)
|
||||
|
||||
def _load_conversation(
|
||||
self,
|
||||
index: int,
|
||||
conversations: list[list[MessageDict]],
|
||||
):
|
||||
return (
|
||||
index,
|
||||
Chatbot(
|
||||
value=conversations[index], # type: ignore
|
||||
feedback_value=[],
|
||||
),
|
||||
)
|
||||
|
||||
def _setup_events(self) -> None:
|
||||
from gradio import on
|
||||
|
||||
@ -645,28 +667,29 @@ class ChatInterface(Blocks):
|
||||
queue=False,
|
||||
)
|
||||
|
||||
@on(
|
||||
[self.load, self.saved_conversations.change],
|
||||
on(
|
||||
triggers=[self.load, self.saved_conversations.change],
|
||||
fn=self._load_chat_history,
|
||||
inputs=[self.saved_conversations],
|
||||
outputs=[self.chat_history_dataset],
|
||||
show_api=False,
|
||||
queue=False,
|
||||
)
|
||||
def load_chat_history(conversations):
|
||||
return Dataset(
|
||||
samples=[
|
||||
[self._generate_chat_title(conv)]
|
||||
for conv in conversations or []
|
||||
if conv
|
||||
]
|
||||
)
|
||||
|
||||
self.chat_history_dataset.click(
|
||||
lambda index, conversations: (index, conversations[index]),
|
||||
lambda: [],
|
||||
None,
|
||||
[self.chatbot],
|
||||
show_api=False,
|
||||
queue=False,
|
||||
show_progress="hidden",
|
||||
).then(
|
||||
self._load_conversation,
|
||||
[self.chat_history_dataset, self.saved_conversations],
|
||||
[self.conversation_id, self.chatbot],
|
||||
show_api=False,
|
||||
queue=False,
|
||||
show_progress="hidden",
|
||||
).then(**synchronize_chat_state_kwargs)
|
||||
|
||||
if self.flagging_mode != "never":
|
||||
|
@ -195,6 +195,7 @@ class Chatbot(Component):
|
||||
sanitize_html: bool = True,
|
||||
render_markdown: bool = True,
|
||||
feedback_options: list[str] | tuple[str, ...] | None = ("Like", "Dislike"),
|
||||
feedback_value: Sequence[str | None] | None = None,
|
||||
bubble_full_width=None,
|
||||
line_breaks: bool = True,
|
||||
layout: Literal["panel", "bubble"] | None = None,
|
||||
@ -234,6 +235,7 @@ class Chatbot(Component):
|
||||
sanitize_html: If False, will disable HTML sanitization for chatbot messages. This is not recommended, as it can lead to security vulnerabilities.
|
||||
render_markdown: If False, will disable Markdown rendering for chatbot messages.
|
||||
feedback_options: A list of strings representing the feedback options that will be displayed to the user. The exact case-sensitive strings "Like" and "Dislike" will render as thumb icons, but any other choices will appear under a separate flag icon.
|
||||
feedback_value: A list of strings representing the feedback state for entire chat. Only works when type="messages". Each entry in the list corresponds to that assistant message, in order, and the value is the feedback given (e.g. "Like", "Dislike", or any custom feedback option) or None if no feedback was given for that message.
|
||||
bubble_full_width: Deprecated.
|
||||
line_breaks: If True (default), will enable Github-flavored Markdown line breaks in chatbot messages. If False, single new lines will be ignored. Only applies if `render_markdown` is True.
|
||||
layout: If "panel", will display the chatbot in a llm style layout. If "bubble", will display the chatbot with message bubbles, with the user and bot messages on alterating sides. Will default to "bubble".
|
||||
@ -290,6 +292,7 @@ class Chatbot(Component):
|
||||
self.show_copy_all_button = show_copy_all_button
|
||||
self.allow_file_downloads = allow_file_downloads
|
||||
self.feedback_options = feedback_options
|
||||
self.feedback_value = feedback_value
|
||||
super().__init__(
|
||||
label=label,
|
||||
every=every,
|
||||
|
@ -280,7 +280,7 @@ class LikeData(EventData):
|
||||
"chatbot_value": value,
|
||||
"liked_message": like_data.value,
|
||||
"liked_index": like_data.index,
|
||||
"liked_or_disliked_as_bool": like_data.liked
|
||||
"liked_or_disliked": like_data.liked
|
||||
}
|
||||
with gr.Blocks() as demo:
|
||||
c = gr.Chatbot([("abc", "def")])
|
||||
|
@ -1,8 +1,8 @@
|
||||
<svg
|
||||
fill="#FF7020"
|
||||
fill="white"
|
||||
width="100%"
|
||||
height="100%"
|
||||
viewBox="0 0 24 24"
|
||||
viewBox="-4.8 0 28.8 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
|
Before Width: | Height: | Size: 477 B After Width: | Height: | Size: 480 B |
@ -59,11 +59,9 @@
|
||||
}
|
||||
|
||||
.icon-button-wrapper
|
||||
:global(
|
||||
a.download-link:not(:last-child):not(.extra-feedback-option)::after
|
||||
),
|
||||
:global(a.download-link:not(:last-child):not(.no-border *)::after),
|
||||
.icon-button-wrapper
|
||||
:global(button:not(:last-child):not(.extra-feedback-option)::after) {
|
||||
:global(button:not(:last-child):not(.no-border *)::after) {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: -4.5px;
|
||||
|
@ -33,6 +33,7 @@
|
||||
export let _selectable = false;
|
||||
export let likeable = false;
|
||||
export let feedback_options: string[] = ["Like", "Dislike"];
|
||||
export let feedback_value: (string | null)[] | null = null;
|
||||
export let show_share_button = false;
|
||||
export let rtl = false;
|
||||
export let show_copy_button = true;
|
||||
@ -128,6 +129,7 @@
|
||||
selectable={_selectable}
|
||||
{likeable}
|
||||
{feedback_options}
|
||||
{feedback_value}
|
||||
{show_share_button}
|
||||
{show_copy_all_button}
|
||||
value={_value}
|
||||
|
@ -16,6 +16,7 @@
|
||||
export let position: "right" | "left";
|
||||
export let avatar: FileData | null;
|
||||
export let generating: boolean;
|
||||
export let current_feedback: string | null;
|
||||
|
||||
export let handle_action: (selected: string | null) => void;
|
||||
export let layout: "bubble" | "panel";
|
||||
@ -94,7 +95,11 @@
|
||||
/>
|
||||
{/if}
|
||||
{#if likeable}
|
||||
<LikeDislike {handle_action} {feedback_options} />
|
||||
<LikeDislike
|
||||
{handle_action}
|
||||
{feedback_options}
|
||||
selected={current_feedback}
|
||||
/>
|
||||
{/if}
|
||||
{/if}
|
||||
</IconButtonWrapper>
|
||||
|
@ -68,6 +68,7 @@
|
||||
export let selectable = false;
|
||||
export let likeable = false;
|
||||
export let feedback_options: string[];
|
||||
export let feedback_value: (string | null)[] | null = null;
|
||||
export let editable: "user" | "all" | null = null;
|
||||
export let show_share_button = false;
|
||||
export let show_copy_all_button = false;
|
||||
@ -204,11 +205,11 @@
|
||||
});
|
||||
} else {
|
||||
let feedback =
|
||||
selected === "like"
|
||||
selected === "Like"
|
||||
? true
|
||||
: selected === "dislike"
|
||||
: selected === "Dislike"
|
||||
? false
|
||||
: selected?.substring(9); // remove "feedback:" prefix
|
||||
: selected || "";
|
||||
if (msg_format === "tuples") {
|
||||
dispatch("like", {
|
||||
index: message.index,
|
||||
@ -283,6 +284,13 @@
|
||||
{@const role = messages[0].role === "user" ? "user" : "bot"}
|
||||
{@const avatar_img = avatar_images[role === "user" ? 0 : 1]}
|
||||
{@const opposite_avatar_img = avatar_images[role === "user" ? 0 : 1]}
|
||||
{@const feedback_index = groupedMessages
|
||||
.slice(0, i)
|
||||
.filter((m) => m[0].role === "assistant").length}
|
||||
{@const current_feedback =
|
||||
role === "bot" && feedback_value && feedback_value[feedback_index]
|
||||
? feedback_value[feedback_index]
|
||||
: null}
|
||||
<Message
|
||||
{messages}
|
||||
{display_consecutive_in_same_bubble}
|
||||
@ -309,6 +317,7 @@
|
||||
{generating}
|
||||
{msg_format}
|
||||
{feedback_options}
|
||||
{current_feedback}
|
||||
show_like={role === "user" ? likeable && like_user_message : likeable}
|
||||
show_retry={_retryable && is_last_bot_message(messages, value)}
|
||||
show_undo={_undoable && is_last_bot_message(messages, value)}
|
||||
|
@ -9,44 +9,42 @@
|
||||
|
||||
export let handle_action: (selected: string | null) => void;
|
||||
export let feedback_options: string[];
|
||||
export let selected: string | null = null;
|
||||
$: extra_feedback = feedback_options.filter(
|
||||
(option) => option !== "Like" && option !== "Dislike"
|
||||
);
|
||||
|
||||
let selected: string | null = null;
|
||||
function toggleSelection(newSelection: string): void {
|
||||
selected = selected === newSelection ? null : newSelection;
|
||||
handle_action(selected);
|
||||
}
|
||||
</script>
|
||||
|
||||
{#if feedback_options.includes("Like") || feedback_options.includes("Dislike")}
|
||||
{#if feedback_options.includes("Dislike")}
|
||||
<IconButton
|
||||
Icon={selected === "dislike" ? ThumbDownActive : ThumbDownDefault}
|
||||
label={selected === "dislike" ? "clicked dislike" : "dislike"}
|
||||
color={selected === "dislike"
|
||||
Icon={selected === "Dislike" ? ThumbDownActive : ThumbDownDefault}
|
||||
label={selected === "Dislike" ? "clicked dislike" : "dislike"}
|
||||
color={selected === "Dislike"
|
||||
? "var(--color-accent)"
|
||||
: "var(--block-label-text-color)"}
|
||||
on:click={() => {
|
||||
selected = "dislike";
|
||||
handle_action(selected);
|
||||
}}
|
||||
on:click={() => toggleSelection("Dislike")}
|
||||
/>
|
||||
{/if}
|
||||
{#if feedback_options.includes("Like")}
|
||||
<IconButton
|
||||
Icon={selected === "like" ? ThumbUpActive : ThumbUpDefault}
|
||||
label={selected === "like" ? "clicked like" : "like"}
|
||||
color={selected === "like"
|
||||
Icon={selected === "Like" ? ThumbUpActive : ThumbUpDefault}
|
||||
label={selected === "Like" ? "clicked like" : "like"}
|
||||
color={selected === "Like"
|
||||
? "var(--color-accent)"
|
||||
: "var(--block-label-text-color)"}
|
||||
on:click={() => {
|
||||
selected = "like";
|
||||
handle_action(selected);
|
||||
}}
|
||||
on:click={() => toggleSelection("Like")}
|
||||
/>
|
||||
{/if}
|
||||
{/if}
|
||||
|
||||
{#if extra_feedback.length > 0}
|
||||
<div class="extra-feedback">
|
||||
<div class="extra-feedback no-border">
|
||||
<IconButton
|
||||
Icon={selected && extra_feedback.includes(selected) ? FlagActive : Flag}
|
||||
label="Feedback"
|
||||
@ -60,8 +58,8 @@
|
||||
class="extra-feedback-option"
|
||||
style:font-weight={selected === option ? "bold" : "normal"}
|
||||
on:click={() => {
|
||||
selected = option;
|
||||
handle_action("feedback:" + selected);
|
||||
toggleSelection(option);
|
||||
handle_action(selected ? selected : null);
|
||||
}}>{option}</button
|
||||
>
|
||||
{/each}
|
||||
|
@ -50,6 +50,7 @@
|
||||
export let in_edit_mode: boolean;
|
||||
export let edit_message: string;
|
||||
export let display_consecutive_in_same_bubble: boolean;
|
||||
export let current_feedback: string | null = null;
|
||||
let messageElements: HTMLDivElement[] = [];
|
||||
let previous_edit_mode = false;
|
||||
let last_message_width = 0;
|
||||
@ -102,6 +103,7 @@
|
||||
layout: "bubble" | "panel";
|
||||
avatar: FileData | null;
|
||||
dispatch: any;
|
||||
current_feedback: string | null;
|
||||
};
|
||||
|
||||
let button_panel_props: ButtonPanelProps;
|
||||
@ -119,7 +121,8 @@
|
||||
position: role === "user" ? "right" : "left",
|
||||
avatar: avatar_img,
|
||||
layout,
|
||||
dispatch
|
||||
dispatch,
|
||||
current_feedback
|
||||
};
|
||||
</script>
|
||||
|
||||
@ -235,6 +238,7 @@
|
||||
{#if layout === "panel"}
|
||||
<ButtonPanel
|
||||
{...button_panel_props}
|
||||
{current_feedback}
|
||||
on:copy={(e) => dispatch("copy", e.detail)}
|
||||
/>
|
||||
{/if}
|
||||
|
@ -47,6 +47,7 @@ class TestChatbot:
|
||||
"placeholder": None,
|
||||
"height": 400,
|
||||
"feedback_options": ("Like", "Dislike"),
|
||||
"feedback_value": None,
|
||||
"resizeable": False,
|
||||
"max_height": None,
|
||||
"min_height": None,
|
||||
|
Loading…
x
Reference in New Issue
Block a user