diff --git a/.changeset/moody-squids-kiss.md b/.changeset/moody-squids-kiss.md new file mode 100644 index 0000000000000..60038c08536d8 --- /dev/null +++ b/.changeset/moody-squids-kiss.md @@ -0,0 +1,6 @@ +--- +"@gradio/chatbot": patch +"gradio": patch +--- + +feat:Fix Chatbot Examples Error diff --git a/demo/test_chatinterface_examples/multimodal_messages_examples_testcase.py b/demo/test_chatinterface_examples/multimodal_messages_examples_testcase.py new file mode 100644 index 0000000000000..707f350dd7992 --- /dev/null +++ b/demo/test_chatinterface_examples/multimodal_messages_examples_testcase.py @@ -0,0 +1,27 @@ +import gradio as gr + +def generate( + message: dict, + chat_history: list[dict], +): + + output = "" + for character in message['text']: + output += character + yield output + + +demo = gr.ChatInterface( + fn=generate, + examples=[ + [{"text": "Hey"}], + [{"text": "Can you explain briefly to me what is the Python programming language?"}], + ], + cache_examples=False, + type="messages", + multimodal=True, +) + + +if __name__ == "__main__": + demo.launch() \ No newline at end of file diff --git a/demo/test_chatinterface_examples/multimodal_tuples_examples_testcase.py b/demo/test_chatinterface_examples/multimodal_tuples_examples_testcase.py new file mode 100644 index 0000000000000..6fb7e3f3f8618 --- /dev/null +++ b/demo/test_chatinterface_examples/multimodal_tuples_examples_testcase.py @@ -0,0 +1,27 @@ +import gradio as gr + +def generate( + message: dict, + chat_history: list[dict], +): + + output = "" + for character in message['text']: + output += character + yield output + + +demo = gr.ChatInterface( + fn=generate, + examples=[ + [{"text": "Hey"}], + [{"text": "Can you explain briefly to me what is the Python programming language?"}], + ], + cache_examples=False, + type="tuples", + multimodal=True, +) + + +if __name__ == "__main__": + demo.launch() \ No newline at end of file diff --git a/demo/test_chatinterface_examples/run.ipynb b/demo/test_chatinterface_examples/run.ipynb new file mode 100644 index 0000000000000..008b27ef6e942 --- /dev/null +++ b/demo/test_chatinterface_examples/run.ipynb @@ -0,0 +1 @@ +{"cells": [{"cell_type": "markdown", "id": "302934307671667531413257853548643485645", "metadata": {}, "source": ["# Gradio Demo: test_chatinterface_examples"]}, {"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/test_chatinterface_examples/multimodal_messages_examples_testcase.py\n", "!wget -q https://github.com/gradio-app/gradio/raw/main/demo/test_chatinterface_examples/multimodal_tuples_examples_testcase.py\n", "!wget -q https://github.com/gradio-app/gradio/raw/main/demo/test_chatinterface_examples/tuples_examples_testcase.py"]}, {"cell_type": "code", "execution_count": null, "id": "44380577570523278879349135829904343037", "metadata": {}, "outputs": [], "source": ["import gradio as gr\n", "\n", "def generate(\n", " message: str,\n", " chat_history: list[dict],\n", "):\n", "\n", " output = \"\"\n", " for character in message:\n", " output += character\n", " yield output\n", "\n", "\n", "demo = gr.ChatInterface(\n", " fn=generate,\n", " examples=[\n", " [\"Hey\"],\n", " [\"Can you explain briefly to me what is the Python programming language?\"],\n", " ],\n", " cache_examples=False,\n", " type=\"messages\",\n", ")\n", "\n", "\n", "if __name__ == \"__main__\":\n", " demo.launch()"]}], "metadata": {}, "nbformat": 4, "nbformat_minor": 5} \ No newline at end of file diff --git a/demo/test_chatinterface_examples/run.py b/demo/test_chatinterface_examples/run.py new file mode 100644 index 0000000000000..66112d4b9bae3 --- /dev/null +++ b/demo/test_chatinterface_examples/run.py @@ -0,0 +1,26 @@ +import gradio as gr + +def generate( + message: str, + chat_history: list[dict], +): + + output = "" + for character in message: + output += character + yield output + + +demo = gr.ChatInterface( + fn=generate, + examples=[ + ["Hey"], + ["Can you explain briefly to me what is the Python programming language?"], + ], + cache_examples=False, + type="messages", +) + + +if __name__ == "__main__": + demo.launch() \ No newline at end of file diff --git a/demo/test_chatinterface_examples/tuples_examples_testcase.py b/demo/test_chatinterface_examples/tuples_examples_testcase.py new file mode 100644 index 0000000000000..be2497c30682d --- /dev/null +++ b/demo/test_chatinterface_examples/tuples_examples_testcase.py @@ -0,0 +1,27 @@ +import gradio as gr + +def generate( + message: str, + chat_history: list[dict], +): + + output = "" + for character in message: + output += character + yield output + + +demo = gr.ChatInterface( + fn=generate, + examples=[ + ["Hey"], + ["Can you explain briefly to me what is the Python programming language?"], + ], + cache_examples=False, + type="tuples", +) + + + +if __name__ == "__main__": + demo.launch() \ No newline at end of file diff --git a/gradio/chat_interface.py b/gradio/chat_interface.py index 53328a42646cc..cc92f31f86191 100644 --- a/gradio/chat_interface.py +++ b/gradio/chat_interface.py @@ -360,14 +360,14 @@ def _setup_events(self) -> None: self.chatbot.example_select( self.example_clicked, [self.chatbot], - [self.chatbot], + [self.chatbot, self.saved_input], show_api=False, ) else: self.chatbot.example_select( self.example_clicked, [self.chatbot], - [self.chatbot], + [self.chatbot, self.saved_input], show_api=False, ).then( submit_fn, @@ -680,9 +680,12 @@ def example_clicked(self, x: SelectData, history): self._append_multimodal_history(message, None, history) else: message = x.value["text"] - self._append_history(history, message) + if self.type == "tuples": + history.append([message, None]) + else: + history.append({"role": "user", "content": message}) self.saved_input.value = message - return history + return history, message def _process_example( self, message: ExampleMessage | str, response: MessageDict | str | None @@ -764,7 +767,7 @@ async def _undo_msg( previous_input: list[str | MultimodalPostprocess], history: list[MessageDict] | TupleFormat, ): - msg = previous_input.pop() + msg = previous_input.pop() if previous_input else None history, msg = await self._delete_prev_fn(msg, history) previous_msg = previous_input[-1] if len(previous_input) else msg diff --git a/js/chatbot/shared/ButtonPanel.svelte b/js/chatbot/shared/ButtonPanel.svelte index bbd9b8ee15e85..d6077ad83e7aa 100644 --- a/js/chatbot/shared/ButtonPanel.svelte +++ b/js/chatbot/shared/ButtonPanel.svelte @@ -68,12 +68,14 @@ {#if show_retry} handle_action("retry")} disabled={generating} /> {/if} {#if show_undo} handle_action("undo")} disabled={generating} diff --git a/js/chatbot/shared/ChatBot.svelte b/js/chatbot/shared/ChatBot.svelte index 9c0245e223a03..4e04d296929bf 100644 --- a/js/chatbot/shared/ChatBot.svelte +++ b/js/chatbot/shared/ChatBot.svelte @@ -260,7 +260,8 @@ {/if} - dispatch("clear")}> + dispatch("clear")} label={"Clear"} + > {#if show_copy_all_button} {/if} diff --git a/js/spa/test/test_chatinterface_examples.spec.ts b/js/spa/test/test_chatinterface_examples.spec.ts new file mode 100644 index 0000000000000..bea4d5192558e --- /dev/null +++ b/js/spa/test/test_chatinterface_examples.spec.ts @@ -0,0 +1,48 @@ +import { test, expect, go_to_testcase } from "@self/tootils"; + +const cases = [ + "messages", + "tuples_examples", + "multimodal_tuples_examples", + "multimodal_messages_examples" +]; + +for (const test_case of cases) { + test(`test case ${test_case} clicking example properly adds it to the history and passes the correct values to the prediction function`, async ({ + page + }) => { + if (cases.slice(1).includes(test_case)) { + await go_to_testcase(page, test_case); + } + + // Click on an example and the input/response are correct + await page.getByRole("button", { name: "Hey" }).click(); + await expect(page.locator(".user p")).toContainText("Hey"); + await expect(page.locator(".bot p")).toContainText("Hey"); + + // Clear the chat and click on a different example, the input/response are correct + await page.getByLabel("Clear").click(); + await page + .getByRole("button", { name: "Can you explain briefly to me" }) + .click(); + await expect(page.locator(".user p")).toContainText( + "Can you explain briefly to me what is the Python programming language?" + ); + await expect(page.locator(".bot p")).toContainText( + "Can you explain briefly to me what is the Python programming language?" + ); + + // Retry button works + await page.getByLabel("Retry").click(); + await expect(page.locator(".user p")).toContainText( + "Can you explain briefly to me what is the Python programming language?" + ); + await expect(page.locator(".bot p")).toContainText( + "Can you explain briefly to me what is the Python programming language?" + ); + + // Undo message resets to the examples view + await page.getByLabel("Undo", { exact: true }).click(); + await expect(page.getByRole("button", { name: "Hey" })).toBeVisible(); + }); +}