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
33.34k stars 2.51k forks source link

chatbot buttons support #4763

Open taoari opened 1 year ago

taoari commented 1 year ago

Chatbot buttons are pretty much standard. It can restrict the user inputs and control the conversation flow. It would be great if gr.Chatbot() can have chatbot buttons support.

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]

Describe the solution you'd like
A clear and concise description of what you want to happen.

It would be great that gr.Chatbot() can natively support Buttons. Currently, I developed a workaround for chatbot buttons with the following script:

import gradio as gr

def bot(history, msg):
    bot_msg = """
Hello, how can I help you today? <br /><button type="button" class="btn btn-primary btn-chatbot">Primary</button> \
<button type="button" class="btn btn-primary btn-chatbot">Secondary</button>
"""
    return history + [[msg, bot_msg]], ""

with gr.Blocks() as demo:
    chatbot = gr.Chatbot()
    msg = gr.Textbox(show_label=False,
        placeholder="Enter text and press ENTER", container=False, elem_id="inputTextBox")
    msg.submit(bot, [chatbot, msg], [chatbot, msg])

def reload_javascript():
    js = """
// for bootstrap
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script>

// for message buttons to work
<script>
function registerMessageButtons() {
    const collection = document.querySelectorAll(".btn-chatbot");
    for (let i = 0; i < collection.length; i++) {
      // NOTE: gradio use .value instead of .innerHTML for gr.Textbox
      collection[i].onclick=function() {document.getElementById("inputTextBox").getElementsByTagName('textarea')[0].value = collection[i].innerHTML};
    }
}
// need to make sure registerMessageButtons() is executed all the time as new message can come out;
var intervalId = window.setInterval(function(){
  registerMessageButtons();
}, 1000);
</script>
"""
    def template_response(*args, **kwargs):
        res = GradioTemplateResponseOriginal(*args, **kwargs)
        res.body = res.body.replace(b'</html>', f'{js}</html>'.encode("utf8"))
        res.init_headers()
        return res

    gr.routes.templates.TemplateResponse = template_response

GradioTemplateResponseOriginal = gr.routes.templates.TemplateResponse

reload_javascript()
demo.launch()

image

It is almost done (click the button and the textbox got updated), but encountered a bug described in https://github.com/gradio-app/gradio/issues/4762 (the Textbox display text and sent text mismatch). Hope to find a solution.

Additional context
Add any other context or screenshots about the feature request here.

abidlabs commented 1 year ago

I agree this would be nice to support -- we just need to figure out the right API for this. cc @dawoodkhan82

RobinIR commented 11 months ago

Would you please let me know when the issue will be fixed? I am also stuck on implementing the chatbot response button.

freddyaboulton commented 11 months ago

Can you try building a custom chatbot component @RobinIR ?

Getting started building custom components: https://www.gradio.app/guides/five-minute-guide Building a custom chatbot: https://www.gradio.app/guides/multimodal-chatbot-part1

s-wel commented 10 months ago

Hi, it is not so clear for me what the modification of the Chatbot component should do different. As far as I understand, the "in chat" buttons must have the same behavior as a "submit". Where to start?

codenprogressive commented 7 months ago

I see a huge value in implementing a button or a selector radio functionalities in chatbot component.

latinostats commented 3 months ago

I found this ticket after I opened mine a few minutes ago.... I am basically requesting the same feature. It would be really a great component addition! this is my issue in case you want to merge it... https://github.com/gradio-app/gradio/issues/8698

ajayarora1235 commented 3 months ago

This would also be amazing for me as I can offer buttons for the user to press after the assistant sends back a response.

Watched the yt vid on building a custom component -- in this case would we just have to define a new type of message where we allow for button text + their connected function to be a part of the message that's returned? And then go into svelte and then create a button for each message?

if @freddyaboulton could just confirm if this is right or give a few pointers on what changes need to made to the chatbot component, would be super helpful

ajayarora1235 commented 3 months ago

I guess as a follow up, curious as to why gr.Image, gr.Plot, gr.Audio, and gr.HTML are all possible to be included in the chatbot but not gr.Button. Thanks!

learnasteve commented 3 months ago

Also keen for this! Trying to get feedback from user on bot responses and require more granularity than like / dislike.

ajayarora1235 commented 3 months ago

hi, any updates on this? tried making a custom component but ran into same issues everyone else is having with gradio cc dev!

dawoodkhan82 commented 2 months ago

@ajayarora1235 Will work on this soon.

taoari commented 2 months ago

Surprised to see the issue is still open after more than one year. If someone is urgent for this feature. Here is a workaround by tweaking HTML and Javascript:

import gradio as gr

def bot(history, msg):
    bot_msg = """
Hello, how can I help you today? <br />
<a class="btn btn-primary btn-chatbot text-white" value="Primary">Primary</a> \
<a class="btn btn-primary btn-chatbot text-white" value="Secondary">Secondary</a>
"""
    return history + [[msg, bot_msg]], ""

with gr.Blocks() as demo:
    chatbot = gr.Chatbot()
    msg = gr.Textbox(show_label=False,
        placeholder="Enter text and press ENTER", container=False, elem_id="inputTextBox")
    msg.submit(bot, [chatbot, msg], [chatbot, msg])

def reload_javascript():
    js = """
// for bootstrap
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js" integrity="sha384-geWF76RCwLtnZ8qwWowPQNguL3RmwHVBC9FhGdlKrxdiJJigb/j/68SIy3Te4Bkz" crossorigin="anonymous"></script>

// for message buttons to work
<script>
function registerMessageButtons() {
    const collection = document.querySelectorAll(".btn-chatbot");
    for (let i = 0; i < collection.length; i++) {
      // NOTE: gradio use .value instead of .innerHTML for gr.Textbox
      collection[i].onclick=function() {
        elem = document.getElementById("inputTextBox").getElementsByTagName('textarea')[0];
        elem.value = collection[i].getAttribute("value"); // use value instead of innerHTML
        elem.dispatchEvent(new Event('input', {
            view: window,
            bubbles: true,
            cancelable: true
            }))
        };  
    }
}
// need to make sure registerMessageButtons() is executed all the time as new message can come out;
var intervalId = window.setInterval(function(){
  registerMessageButtons();
}, 1000);
</script>
"""
    def template_response(*args, **kwargs):
        res = GradioTemplateResponseOriginal(*args, **kwargs)
        res.body = res.body.replace(b'</html>', f'{js}</html>'.encode("utf8"))
        res.init_headers()
        return res

    gr.routes.templates.TemplateResponse = template_response

GradioTemplateResponseOriginal = gr.routes.templates.TemplateResponse

reload_javascript()
demo.launch()
david-thrower commented 6 days ago

One comment I have on this one is that it would be ideal if the implementation of this feature supports conditional logic where some messages will display one list of options, and other messages will display others.

I am working on a clinical assistant, which asks around 25 questions, many of which are close ended with the same 2 sets of repetitive valid options. For the symptom related questions, most the valid options are ["no", "yes - mild", "Yes- moderate", "Yes- severe", "not sure"] ... and most of the lab result questions would have the options ["test not done yet", "result was normal", "result was, elevated and abnormal: ENTER NUMBER", "result was low and abnormal ENTER NUMBER", "I'm not sure"]. We want the user to not have to write the same answers repeatedly, and we also want to standardize how users enter answers to the questions and how the LLM sees them worded, so it can be practical to validate the bot objectively and fine tune a model to get it right consistently.

If the messages can be easily individually instantiated with a list of options to select based on a business logic or based on a sequential order in a list of initial questions, that may make this feature more robust and practical for advanced use cases like this.