|
36 | 36 | )
|
37 | 37 | from gradio.components.multimodal_textbox import MultimodalPostprocess, MultimodalValue
|
38 | 38 | from gradio.context import get_blocks_context
|
39 |
| -from gradio.events import Dependency, SelectData |
| 39 | +from gradio.events import Dependency, EditData, SelectData |
40 | 40 | from gradio.helpers import create_examples as Examples # noqa: N812
|
41 | 41 | from gradio.helpers import special_args, update
|
42 | 42 | from gradio.layouts import Accordion, Column, Group, Row
|
@@ -75,6 +75,7 @@ def __init__(
|
75 | 75 | additional_inputs: str | Component | list[str | Component] | None = None,
|
76 | 76 | additional_inputs_accordion: str | Accordion | None = None,
|
77 | 77 | additional_outputs: Component | list[Component] | None = None,
|
| 78 | + editable: bool = False, |
78 | 79 | examples: list[str] | list[MultimodalValue] | list[list] | None = None,
|
79 | 80 | example_labels: list[str] | None = None,
|
80 | 81 | example_icons: list[str] | None = None,
|
@@ -108,6 +109,7 @@ def __init__(
|
108 | 109 | type: The format of the messages passed into the chat history parameter of `fn`. If "messages", passes the history as a list of dictionaries with openai-style "role" and "content" keys. The "content" key's value should be one of the following - (1) strings in valid Markdown (2) a dictionary with a "path" key and value corresponding to the file to display or (3) an instance of a Gradio component: at the moment gr.Image, gr.Plot, gr.Video, gr.Gallery, gr.Audio, and gr.HTML are supported. The "role" key should be one of 'user' or 'assistant'. Any other roles will not be displayed in the output. If this parameter is 'tuples' (deprecated), passes the chat history as a `list[list[str | None | tuple]]`, i.e. a list of lists. The inner list should have 2 elements: the user message and the response message.
|
109 | 110 | chatbot: an instance of the gr.Chatbot component to use for the chat interface, if you would like to customize the chatbot properties. If not provided, a default gr.Chatbot component will be created.
|
110 | 111 | textbox: an instance of the gr.Textbox or gr.MultimodalTextbox component to use for the chat interface, if you would like to customize the textbox properties. If not provided, a default gr.Textbox or gr.MultimodalTextbox component will be created.
|
| 112 | + editable: if True, users can edit past messages to regenerate responses. |
111 | 113 | additional_inputs: an instance or list of instances of gradio components (or their string shortcuts) to use as additional inputs to the chatbot. If the components are not already rendered in a surrounding Blocks, then the components will be displayed under the chatbot, in an accordion. The values of these components will be passed into `fn` as arguments in order after the chat history.
|
112 | 114 | additional_inputs_accordion: if a string is provided, this is the label of the `gr.Accordion` to use to contain additional inputs. A `gr.Accordion` object can be provided as well to configure other properties of the container holding the additional inputs. Defaults to a `gr.Accordion(label="Additional Inputs", open=False)`. This parameter is only used if `additional_inputs` is provided.
|
113 | 115 | additional_outputs: an instance or list of instances of gradio components to use as additional outputs from the chat function. These must be components that are already defined in the same Blocks scope. If provided, the chat function should return additional values for these components. See $demo/chatinterface_artifacts.
|
@@ -173,6 +175,7 @@ def __init__(
|
173 | 175 | self.run_examples_on_click = run_examples_on_click
|
174 | 176 | self.cache_examples = cache_examples
|
175 | 177 | self.cache_mode = cache_mode
|
| 178 | + self.editable = editable |
176 | 179 | self.additional_inputs = [
|
177 | 180 | get_component_instance(i)
|
178 | 181 | for i in utils.none_or_singleton_to_list(additional_inputs)
|
@@ -490,6 +493,14 @@ def _setup_events(self) -> None:
|
490 | 493 |
|
491 | 494 | self.chatbot.clear(**synchronize_chat_state_kwargs)
|
492 | 495 |
|
| 496 | + if self.editable: |
| 497 | + self.chatbot.edit( |
| 498 | + self._edit_message, |
| 499 | + [self.chatbot], |
| 500 | + [self.chatbot, self.chatbot_state, self.saved_input], |
| 501 | + show_api=False, |
| 502 | + ).success(**submit_fn_kwargs).success(**synchronize_chat_state_kwargs) |
| 503 | + |
493 | 504 | def _setup_stop_events(
|
494 | 505 | self, event_triggers: list[Callable], events_to_cancel: list[Dependency]
|
495 | 506 | ) -> None:
|
@@ -712,6 +723,19 @@ def example_populated(self, example: SelectData):
|
712 | 723 | else:
|
713 | 724 | return example.value["text"]
|
714 | 725 |
|
| 726 | + def _edit_message( |
| 727 | + self, history: list[MessageDict] | TupleFormat, edit_data: EditData |
| 728 | + ) -> tuple[ |
| 729 | + list[MessageDict] | TupleFormat, |
| 730 | + list[MessageDict] | TupleFormat, |
| 731 | + str | MultimodalPostprocess, |
| 732 | + ]: |
| 733 | + if isinstance(edit_data.index, (list, tuple)): |
| 734 | + history = history[: edit_data.index[0]] |
| 735 | + else: |
| 736 | + history = history[: edit_data.index] |
| 737 | + return history, history, edit_data.value |
| 738 | + |
715 | 739 | def example_clicked(
|
716 | 740 | self, example: SelectData
|
717 | 741 | ) -> Generator[
|
|
0 commit comments