|
# Liking, Retrying and Undoing Messages |
|
|
|
Tags: LLM, CHAT |
|
|
|
Users expect modern chatbot UIs to let them easily interact with individual chat messages: for example, users might want to retry message generations, undo messages, or click on a like/dislike button to upvote or downvote a generated message. |
|
|
|
Thankfully, the Gradio Chatbot exposes three events, `.retry`, `.undo`, and `like`, to let you build this functionality into your application. As an application developer, you can attach functions to any of these event, allowing you to run arbitrary Python functions e.g. when a user interacts with a message. |
|
|
|
In this demo, we'll build a UI that implements these events. You can see our finished demo deployed on Hugging Face spaces here: |
|
|
|
$demo_chatbot_retry_undo_like |
|
|
|
Tip: `gr.ChatInterface` automatically uses the `retry` and `.undo` events so it's best to start there in order get a fully working application quickly. |
|
|
|
|
|
## The UI |
|
|
|
First, we'll build the UI without handling these events and build from there. |
|
We'll use the Hugging Face InferenceClient in order to get started without setting up |
|
any API keys. |
|
|
|
This is what the first draft of our application looks like: |
|
|
|
```python |
|
from huggingface_hub import InferenceClient |
|
import gradio as gr |
|
|
|
client = InferenceClient() |
|
|
|
def respond( |
|
prompt: str, |
|
history, |
|
): |
|
if not history: |
|
history = [{"role": "system", "content": "You are a friendly chatbot"}] |
|
history.append({"role": "user", "content": prompt}) |
|
|
|
yield history |
|
|
|
response = {"role": "assistant", "content": ""} |
|
for message in client.chat_completion( |
|
history, |
|
temperature=0.95, |
|
top_p=0.9, |
|
max_tokens=512, |
|
stream=True, |
|
model="HuggingFaceH4/zephyr-7b-beta" |
|
): |
|
response["content"] += message.choices[0].delta.content or "" |
|
|
|
yield history + [response] |
|
|
|
|
|
with gr.Blocks() as demo: |
|
gr.Markdown("# Chat with Hugging Face Zephyr 7b 🤗") |
|
chatbot = gr.Chatbot( |
|
label="Agent", |
|
type="messages", |
|
avatar_images=( |
|
None, |
|
"https://em-content.zobj.net/source/twitter/376/hugging-face_1f917.png", |
|
), |
|
) |
|
prompt = gr.Textbox(max_lines=1, label="Chat Message") |
|
prompt.submit(respond, [prompt, chatbot], [chatbot]) |
|
prompt.submit(lambda: "", None, [prompt]) |
|
|
|
|
|
if __name__ == "__main__": |
|
demo.launch() |
|
``` |
|
|
|
## The Undo Event |
|
|
|
Our undo event will populate the textbox with the previous user message and also remove all subsequent assistant responses. |
|
|
|
In order to know the index of the last user message, we can pass `gr.UndoData` to our event handler function like so: |
|
|
|
``python |
|
def handle_undo(history, undo_data: gr.UndoData): |
|
return history[:undo_data.index], history[undo_data.index]['content'] |
|
``` |
|
|
|
We then pass this function to the `undo` event! |
|
|
|
```python |
|
chatbot.undo(handle_undo, chatbot, [chatbot, prompt]) |
|
``` |
|
|
|
You'll notice that every bot response will now have an "undo icon" you can use to undo the response - |
|
|
|
 |
|
|
|
Tip: You can also access the content of the user message with `undo_data.value` |
|
|
|
## The Retry Event |
|
|
|
The retry event will work similarly. We'll use `gr.RetryData` to get the index of the previous user message and remove all the subsequent messages from the history. Then we'll use the `respond` function to generate a new response. We could also get the previous prompt via the `value` property of `gr.RetryData`. |
|
|
|
```python |
|
def handle_retry(history, retry_data: gr.RetryData): |
|
new_history = history[:retry_data.index] |
|
previous_prompt = history[retry_data.index]['content'] |
|
yield from respond(previous_prompt, new_history) |
|
|
|
... |
|
|
|
chatbot.retry(handle_retry, chatbot, [chatbot]) |
|
``` |
|
|
|
You'll see that the bot messages have a "retry" icon now - |
|
|
|
 |
|
|
|
Tip: The Hugging Face inference API caches responses, so in this demo, the retry button will not generate a new response. |
|
|
|
## The Like Event |
|
|
|
By now you should hopefully be seeing the pattern! |
|
To let users like a message, we'll add a `.like` event to our chatbot. |
|
We'll pass it a function that accepts a `gr.LikeData` object. |
|
In this case, we'll just print the message that was either liked or disliked. |
|
|
|
```python |
|
def handle_like(data: gr.LikeData): |
|
if data.liked: |
|
print("You upvoted this response: ", data.value) |
|
else: |
|
print("You downvoted this response: ", data.value) |
|
|
|
... |
|
|
|
chatbot.like(vote, None, None) |
|
``` |
|
|
|
|
|
## Conclusion |
|
|
|
That's it! You now know how you can implement the retry, undo, and like events for the Chatbot. |
|
|
|
|
|
|
|
|