Improve like/dislike functionality (#6572)

* amend like/dislike logic

* add like/dislike to chatbot demo and add e2e test

* add changeset

* e2e test changes

* revert chatbot_component changes

* tweak

* generate notebooks

* tweak

---------

Co-authored-by: gradio-pr-bot <gradio-pr-bot@users.noreply.github.com>
This commit is contained in:
Hannah 2023-11-24 19:03:18 +01:00 committed by GitHub
parent 2b625ad940
commit 206af31d7c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 50 additions and 32 deletions

View File

@ -0,0 +1,7 @@
---
"@gradio/chatbot": patch
"@gradio/icons": patch
"gradio": patch
---
fix:Improve like/dislike functionality

View File

@ -1 +1 @@
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: chatbot_multimodal"]}, {"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": ["# Downloading files from the demo repo\n", "import os\n", "!wget -q https://github.com/gradio-app/gradio/raw/main/demo/chatbot_multimodal/avatar.png"]}, {"cell_type": "code", "execution_count": null, "id": "44380577570523278879349135829904343037", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "import os\n", "import time\n", "\n", "# Chatbot demo with multimodal input (text, markdown, LaTeX, code blocks, image, audio, & video). Plus shows support for streaming text.\n", "\n", "\n", "def add_text(history, text):\n", " history = history + [(text, None)]\n", " return history, gr.Textbox(value=\"\", interactive=False)\n", "\n", "\n", "def add_file(history, file):\n", " history = history + [((file.name,), None)]\n", " return history\n", "\n", "\n", "def bot(history):\n", " response = \"**That's cool!**\"\n", " history[-1][1] = \"\"\n", " for character in response:\n", " history[-1][1] += character\n", " time.sleep(0.05)\n", " yield history\n", "\n", "\n", "with gr.Blocks() as demo:\n", " chatbot = gr.Chatbot(\n", " [],\n", " elem_id=\"chatbot\",\n", " bubble_full_width=False,\n", " avatar_images=(None, (os.path.join(os.path.abspath(''), \"avatar.png\"))),\n", " )\n", "\n", " with gr.Row():\n", " txt = gr.Textbox(\n", " scale=4,\n", " show_label=False,\n", " placeholder=\"Enter text and press enter, or upload an image\",\n", " container=False,\n", " )\n", " btn = gr.UploadButton(\"\ud83d\udcc1\", file_types=[\"image\", \"video\", \"audio\"])\n", "\n", " txt_msg = txt.submit(add_text, [chatbot, txt], [chatbot, txt], queue=False).then(\n", " bot, chatbot, chatbot, api_name=\"bot_response\"\n", " )\n", " txt_msg.then(lambda: gr.Textbox(interactive=True), None, [txt], queue=False)\n", " file_msg = btn.upload(add_file, [chatbot, btn], [chatbot], queue=False).then(\n", " bot, chatbot, chatbot\n", " )\n", "\n", "demo.queue()\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}
{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: chatbot_multimodal"]}, {"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": ["# Downloading files from the demo repo\n", "import os\n", "!wget -q https://github.com/gradio-app/gradio/raw/main/demo/chatbot_multimodal/avatar.png"]}, {"cell_type": "code", "execution_count": null, "id": "44380577570523278879349135829904343037", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "import os\n", "import time\n", "\n", "# Chatbot demo with multimodal input (text, markdown, LaTeX, code blocks, image, audio, & video). Plus shows support for streaming text.\n", "\n", "\n", "def print_like_dislike(x: gr.LikeData):\n", " print(x.index, x.value, x.liked)\n", "\n", "\n", "def add_text(history, text):\n", " history = history + [(text, None)]\n", " return history, gr.Textbox(value=\"\", interactive=False)\n", "\n", "\n", "def add_file(history, file):\n", " history = history + [((file.name,), None)]\n", " return history\n", "\n", "\n", "def bot(history):\n", " response = \"**That's cool!**\"\n", " history[-1][1] = \"\"\n", " for character in response:\n", " history[-1][1] += character\n", " time.sleep(0.05)\n", " yield history\n", "\n", "\n", "with gr.Blocks() as demo:\n", " chatbot = gr.Chatbot(\n", " [],\n", " elem_id=\"chatbot\",\n", " bubble_full_width=False,\n", " avatar_images=(None, (os.path.join(os.path.abspath(''), \"avatar.png\"))),\n", " )\n", "\n", " with gr.Row():\n", " txt = gr.Textbox(\n", " scale=4,\n", " show_label=False,\n", " placeholder=\"Enter text and press enter, or upload an image\",\n", " container=False,\n", " )\n", " btn = gr.UploadButton(\"\ud83d\udcc1\", file_types=[\"image\", \"video\", \"audio\"])\n", "\n", " txt_msg = txt.submit(add_text, [chatbot, txt], [chatbot, txt], queue=False).then(\n", " bot, chatbot, chatbot, api_name=\"bot_response\"\n", " )\n", " txt_msg.then(lambda: gr.Textbox(interactive=True), None, [txt], queue=False)\n", " file_msg = btn.upload(add_file, [chatbot, btn], [chatbot], queue=False).then(\n", " bot, chatbot, chatbot\n", " )\n", "\n", " chatbot.like(print_like_dislike, None, None)\n", "\n", "\n", "demo.queue()\n", "if __name__ == \"__main__\":\n", " demo.launch()\n"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5}

View File

@ -5,6 +5,10 @@ import time
# Chatbot demo with multimodal input (text, markdown, LaTeX, code blocks, image, audio, & video). Plus shows support for streaming text.
def print_like_dislike(x: gr.LikeData):
print(x.index, x.value, x.liked)
def add_text(history, text):
history = history + [(text, None)]
return history, gr.Textbox(value="", interactive=False)
@ -49,6 +53,9 @@ with gr.Blocks() as demo:
bot, chatbot, chatbot
)
chatbot.like(print_like_dislike, None, None)
demo.queue()
if __name__ == "__main__":
demo.launch()

View File

@ -177,3 +177,14 @@ test("when a new message is sent the chatbot should scroll to the latest message
const bot_message_text = bot_message.textContent();
await expect(bot_message_text).toBeTruthy();
});
test("chatbot like and dislike functionality", async ({ page }) => {
await page.getByTestId("textbox").click();
await page.getByTestId("textbox").fill("hello");
await page.keyboard.press("Enter");
await page.getByLabel("like", { exact: true }).click();
await page.getByLabel("dislike").click();
expect(await page.getByLabel("clicked dislike").count()).toEqual(1);
expect(await page.getByLabel("clicked like").count()).toEqual(0);
});

View File

@ -98,12 +98,12 @@
i: number,
j: number,
message: string | { file: FileData; alt_text: string | null } | null,
liked: boolean
selected: string | null
): void {
dispatch("like", {
index: [i, j],
value: message,
liked: liked
liked: selected === "like"
});
}
</script>
@ -238,12 +238,8 @@
>
{#if likeable && j == 1}
<LikeDislike
action="like"
handle_action={() => handle_like(i, j, message, true)}
/>
<LikeDislike
action="dislike"
handle_action={() => handle_like(i, j, message, false)}
handle_action={(selected) =>
handle_like(i, j, message, selected)}
/>
{/if}
{#if show_copy_button && message && typeof message === "string"}

View File

@ -2,32 +2,29 @@
import { Like } from "@gradio/icons";
import { Dislike } from "@gradio/icons";
export let action: "like" | "dislike";
export let handle_action: () => void;
export let handle_action: (selected: string | null) => void;
let actioned = false;
let Icon = action === "like" ? Like : Dislike;
function action_feedback(): void {
actioned = true;
}
let selected: "like" | "dislike" | null = null;
</script>
<button
on:click={() => {
action_feedback();
handle_action();
selected = "like";
handle_action(selected);
}}
on:keydown={(e) => {
if (e.key === "Enter") {
action_feedback();
handle_action();
}
}}
title={action + " message"}
aria-label={actioned ? `clicked ${action}` : action}
aria-label={selected === "like" ? "clicked like" : "like"}
>
<Icon {actioned} />
<Like selected={selected === "like"} />
</button>
<button
on:click={() => {
selected = "dislike";
handle_action(selected);
}}
aria-label={selected === "dislike" ? "clicked dislike" : "dislike"}
>
<Dislike selected={selected === "dislike"} />
</button>
<style>

View File

@ -1,5 +1,5 @@
<script lang="ts">
export let actioned: boolean;
export let selected: boolean;
</script>
<svg
@ -7,7 +7,7 @@
width="15px"
height="15px"
viewBox="0 0 24 24"
fill={actioned ? "currentColor" : "none"}
fill={selected ? "currentColor" : "none"}
stroke-width="1.5"
color="currentColor"
><path

View File

@ -1,5 +1,5 @@
<script lang="ts">
export let actioned: boolean;
export let selected: boolean;
</script>
<svg
@ -7,7 +7,7 @@
width="15px"
height="15px"
viewBox="0 0 24 24"
fill={actioned ? "currentColor" : "none"}
fill={selected ? "currentColor" : "none"}
stroke-width="1.5"
color="currentColor"
><path