gradio-app / gradio

Build and share delightful machine learning apps, all in Python. 🌟 Star to support our work!
http://www.gradio.app
Apache License 2.0
29.84k stars 2.22k forks source link

Like/Dislike Button for Chatbot #5391

Closed dawoodkhan82 closed 9 months ago

dawoodkhan82 commented 9 months ago

Description

Adds like/dislike events trigger and buttons for chatbot messages

Screenshot 2023-09-01 at 4 38 45 PM

Here's an example of how to use the "Like" event trigger:

def on_like(evt: gr.LikeData):
    if evt.liked:
        print(f"The chat message {evt.value} was liked at {evt.index} from {evt.target}")
    if evt.liked:
        print(f"The chat message {evt.value} was disliked at {evt.index} from {evt.target}")

with gr.Blocks() as demo:
    chatbot = gr.Chatbot([])
    chatbot.like(on_like, <input>, <output>)

Closes: #5250

🎯 PRs Should Target Issues

Before your create a PR, please check to see if there is an existing issue for this change. If not, please create an issue before you create this PR, unless the fix is very small.

Not adhering to this guideline will result in the PR being closed.

Tests

  1. PRs will only be merged if tests pass on CI. To run the tests locally, please set up your Gradio environment locally and run the tests: bash scripts/run_all_tests.sh

  2. You may need to run the linters: bash scripts/format_backend.sh and bash scripts/format_frontend.sh

gradio-pr-bot commented 9 months ago

🪼 branch checks and previews

• Name Status URL
Spaces ready! Spaces preview
Website ready! Website preview
Storybook ready! Storybook preview
Visual tests all good! Build review
:unicorn: Changes detected! Details

Install Gradio from this PR

pip install https://gradio-builds.s3.amazonaws.com/af6314364b152c5594c83ef9f4ff9c4df358b460/gradio-3.41.2-py3-none-any.whl

Install Gradio Python Client from this PR

pip install "gradio-client @ git+https://github.com/gradio-app/gradio@af6314364b152c5594c83ef9f4ff9c4df358b460#subdirectory=client/python"
gradio-pr-bot commented 9 months ago

🦄 change detected

This Pull Request includes changes to the following packages.

Package Version
@gradio/chatbot minor
@gradio/icons minor
@gradio/utils minor
gradio minor

With the following changelog entry.

Like/Dislike Button for Chatbot

Maintainers or the PR author can modify the PR title to modify this entry.

#### Something isn't right? - Maintainers can change the version label to modify the version bump. - If the bot has failed to detect any changes, or if this pull request needs to update multiple packages to different versions or requires a more comprehensive changelog entry, maintainers can [update the changelog file directly](https://github.com/gradio-app/gradio/edit/like-chatbot/.changeset/gold-garlics-cut.md).
abidlabs commented 9 months ago

Works very nicely @dawoodkhan82!

In terms of the UI, are you thinking of putting the icons in the top right, similar to the copy button?

image
dawoodkhan82 commented 9 months ago

In terms of the UI, are you thinking of putting the icons in the top right, similar to the copy button?

Experimenting with a couple things to see what looks best. Probably just going to end up going with chatgpt UI Screenshot 2023-08-31 at 6 04 12 PM

Shelliemayinforest commented 9 months ago

hi, is this a bug or is it my problem? the like button is not on the top of the textbox.

image

when the answer is shorter, it is just ok. image

dawoodkhan82 commented 9 months ago

@Shelliemayinforest Currently fixing the UI.

dawoodkhan82 commented 9 months ago

@abidlabs ready for re-review

abidlabs commented 9 months ago

Did something happen to the height of the chatbot bubbles @dawoodkhan82? I'm seeing this for a regular Chatbot:

image

And this is how the likable chatbot looks:

image

Test code:

import gradio as gr

def test(x: gr.LikeData):
    print(x.index, x.value, x.liked)

with gr.Blocks() as demo:
    c = gr.Chatbot([("abc", "def"), ("egh", "ijk")])
    c.like(test, None, None)

demo.launch()
abidlabs commented 9 months ago

Super nit: could we put the thumbs icon before the copy button, and align all of the copy buttons to be at the same x-coordinate? i.e. so that the copy buttons for the user message and bot message are horizontally aligned

image
abidlabs commented 9 months ago

Finally, it would be great to add an example of how to use the like() method in the docs.

Maybe we could add a section right after streaming in this Guide? https://www.gradio.app/guides/creating-a-custom-chatbot-with-blocks

dawoodkhan82 commented 9 months ago

Ah yeah I did mess up the height. Was testing with the copy button enabled. Will address in a bit

dawoodkhan82 commented 9 months ago

@abidlabs Ok the UI should be good now

dawoodkhan82 commented 9 months ago

@abidlabs Will update the guide in a separate PR

abidlabs commented 9 months ago

LGTM @dawoodkhan82! I added a small section in our Chatbot guide for now -- though feel free to edit or expand it.

jeffchy commented 8 months ago

How about adding a labeling field which accept comments similar to the like and dislike button?

abidlabs commented 8 months ago

Hi @jeffchy you could add a gr.Textbox underneath the gr.Chatbot -- and use that as input in the chatbot.like event.

PrashantSaikia commented 7 months ago

How do I store the like value in a json or yaml file? As of now, I think the like/unlike can only be clicked and it doesn't do anything else, am I right? What if I want to record the user preferences somewhere?

abidlabs commented 7 months ago

Hi @PrashantSaikia, you can run arbitrary code (such as logging to a csv) within the function that is attached to the .like() event, e.g. test() in the example below:

import gradio as gr

def test(x: gr.LikeData):
    print(x.index, x.value, x.liked)

with gr.Blocks() as demo:
    c = gr.Chatbot([("abc", "def"), ("egh", "ijk")])
    c.like(test, None, None)

demo.launch()
PrashantSaikia commented 7 months ago

Hi @abidlabs,

The problem with the .like() method is that it can only see the liked response, it does not see the query for whom the response is being given. Also, and perhaps this is outside the scope of my question strictly speaking, but as you can see my implementation of dumping the chat and upvote histories is real time. Ideally, I'd prefer to have a button that says "Download chat history", and upon clicking it, it would download the chat history including the upvoting history. Any pointers on how to do that?

abidlabs commented 7 months ago

Ideally, I'd like to have the upvote history as a column in the chat history dump.

If I understand correctly, you should be able to achieve this by also passing the chatbot as an input to your vote function. The chatbot input will pass in the history of messages:

import gradio as gr

def test(x: gr.LikeData, history):
    print(x.index, x.value, x.liked)
    print(history)

with gr.Blocks() as demo:
    c = gr.Chatbot([("abc", "def"), ("egh", "ijk")])
    c.like(test, c, None)

demo.launch()
abidlabs commented 7 months ago

Ideally, I'd prefer to have a button that says "Download chat history", and upon clicking it, it would download the chat history including the upvoting history. Any pointers on how to do that?

You could save the chatbot history to a file every time the chatbot runs, and then create a gr.Button() whose link parameter points to downloading that file. Haven't tested but I think it should work

PrashantSaikia commented 7 months ago
import gradio as gr

def test(x: gr.LikeData, history):
    print(x.index, x.value, x.liked)
    print(history)

with gr.Blocks() as demo:
    c = gr.Chatbot([("abc", "def"), ("egh", "ijk")])
    c.like(test, c, None)

demo.launch()

With this, there is no way to know what was the query whose response was being upvoted or downvoted, right? That's what I want to be added, I guess some kind of handle would need to be there that shows which user query precedes the chatbot response. Am I correct or is it already there?

abidlabs commented 7 months ago

Hi @PrashantSaikia you can get the query by looking at the index -- x.index will be something like [3, 1], which means the bot response (1) to the 4th message (since 0-indexed). If you look at the history[3][0], that will be the user query

PrashantSaikia commented 7 months ago

Ah, ok, got it now. So its these then:

query = history[x.index[0]][x.index[1]-1]
response = x.value
upvote = x.liked # true or false
abidlabs commented 7 months ago

Yes that looks right