如何创建聊天机器人

标签:NLP, TEXT, CHAT 相关空间: https://huggingface.co/spaces/gradio/chatbot_streaming , https://huggingface.co/spaces/project-baize/Baize-7B ,

介绍

聊天机器人广泛应用于自然语言处理 (NLP) 研究和行业。 由于聊天机器人旨在供客户和最终用户直接使用,因此验证聊天机器人在遇到各种输入提示时是否按预期运行非常重要。

Chatbots are widely used in natural language processing (NLP) research and industry. Because chatbots are designed to be used directly by customers and end users, it is important to validate that chatbots are behaving as expected when confronted with a wide variety of input prompts.

使用 gradio ,你可以轻松构建聊天机器人模型的演示并与你的用户分享,或者使用直观的聊天机器人 GUI 自己尝试。

Using gradio, you can easily build a demo of your chatbot model and share that with your users, or try it yourself using an intuitive chatbot GUI.

本教程将展示如何使用 Gradio 制作多种聊天机器人 UI:第一种是简单的显示文本,第二种是流式传输文本响应,最后一种是可以处理媒体文件的聊天机器人。 我们创建的聊天机器人界面将如下所示:

This tutorial will show how to make several kinds of chatbot UIs with Gradio: first a simple one to display text, second one to stream text responses, and finally a chatbot that can handle media files as well. The chatbot interface that we create will look something like this:

先决条件:我们将使用 gradio.Blocks 类来构建我们的聊天机器人演示。 如果你还不熟悉,可以先阅读构造块指南

Prerequisite: We'll be using the gradio.Blocks class to build our Chatbot demo. You can read the Guide to Blocks first if you are not already familiar with it.

一个简单的聊天机器人演示

让我们从重新创建上面的简单演示开始。 你可能已经注意到,我们的机器人只是随机地对任何输入做出“你好吗?”、“我爱你”或“我很饿”的回应。 下面是使用 Gradio 创建它的代码:

Let's start with recreating the simple demo above. As you may have noticed, our bot simply randomly responds "How are you?", "I love you", or "I'm very hungry" to any input. Here's the code to create this with Gradio:

import gradio as gr
import random
import time

md = """This is some code:

hello

```py def fn(x, y, z): print(x, y, z) """ with gr.Blocks() as demo: chatbot = gr.Chatbot() msg = gr.Textbox() clear = gr.Button("Clear") def respond(message, chat_history): bot_message = random.choice(["How are you?", "I love you", "I'm very hungry"]) chat_history.append((message, md)) time.sleep(1) return "", chat_history msg.submit(respond, [msg, chatbot], [msg, chatbot]) clear.click(lambda: None, None, chatbot, queue=False) demo.launch()

这里包含三个 Gradio 组件:

There are three Gradio components here:

  • 一个 Chatbot ,其值存储对话的整个历史记录,作为用户和机器人之间的响应对列表。

    A Chatbot, whose value stores the entire history of the conversation, as a list of response pairs between the user and bot.

  • 一个 Textbox ,用户可以在其中键入他们的消息,然后点击回车/提交以触发聊天机器人响应

    A Textbox where the user can type their message, and then hit enter/submit to trigger the chatbot response

  • 清除整个聊天机器人历史记录的 Clear 按钮

    A Clear button to clear the entire Chatbot history

我们只有一个函数 respond() ,它接收聊天机器人的整个历史记录,附加一条随机消息,等待 1 秒,然后返回更新后的聊天记录。 respond() 函数在返回时还会清除文本框。

We have a single function, respond(), which takes in the entire history of the chatbot, appends a random message, waits 1 second, and then returns the updated chat history. The respond() function also clears the textbox when it returns.

当然,在实践中,你可以将 respond() 替换为你自己的更复杂的函数,该函数可能会调用预训练模型或 API 来生成响应。

Of course, in practice, you would replace respond() with your own more complex function, which might call a pretrained model or an API, to generate a response.

最后,当单击 Clear 按钮时,我们将 None 分配给 Chatbot 的值以清除其整个历史记录。 在这里试用这个聊天机器人:

Finally, when the Clear button is clicked, we assign None to the value of the Chatbot to clear its entire history. Try out this chatbot here:

将流媒体添加到你的聊天机器人

我们可以通过多种方式改善上述聊天机器人的用户体验。 首先,我们可以流式传输响应,这样用户就不必等待很长时间才能生成消息。 其次,我们可以让用户消息立即出现在聊天记录中,同时生成聊天机器人的响应。 这是实现该目标的代码:

There are several ways we can improve the user experience of the chatbot above. First, we can stream responses so the user doesn't have to wait as long for a message to be generated. Second, we can have the user message appear immediately in the chat history, while the chatbot's response is being generated. Here's the code to achieve that:

import gradio as gr
import random
import time

with gr.Blocks() as demo:
    chatbot = gr.Chatbot()
    msg = gr.Textbox()
    clear = gr.Button("Clear")

    def user(user_message, history):
        return gr.update(value="", interactive=False), history + [[user_message, None]]

    def bot(history):
        bot_message = random.choice(["How are you?", "I love you", "I'm very hungry"])
        history[-1][1] = ""
        for character in bot_message:
            history[-1][1] += character
            time.sleep(0.05)
            yield history

    response = msg.submit(user, [msg, chatbot], [msg, chatbot], queue=False).then(
        bot, chatbot, chatbot
    )
    response.then(lambda: gr.update(interactive=True), None, [msg], queue=False)
    clear.click(lambda: None, None, chatbot, queue=False)

demo.queue()
demo.launch()

你会注意到,当用户提交他们的消息时,我们现在使用 .then()链接三个事件事件:

You'll notice that when a user submits their message, we now chain three event events with .then():

  1. 第一个方法 user() 使用用户消息更新聊天机器人并清除输入字段。 此方法还使输入字段成为非交互式,以便用户无法在聊天机器人响应时发送另一条消息。 因为我们希望这立即发生,所以我们设置了 queue=False ,如果启用它,它将跳过任何队列。 聊天机器人的历史附加了 (user_message, None)None 表示机器人没有响应。

    The first method user() updates the chatbot with the user message and clears the input field. This method also makes the input field non interactive so that the user can't send another message while the chatbot is responding. Because we want this to happen instantly, we set queue=False, which would skip any queue had it been enabled. The chatbot's history is appended with (user_message, None), the None signifying that the bot has not responded.

  2. 第二种方法 bot() 使用机器人的响应更新聊天机器人历史记录。 我们没有创建新消息,而是用机器人的响应替换了之前创建的 None 消息。 最后,我们逐个字符地构建消息,并在构建过程中 yield 中间输出。 Gradio 自动将任何带有 yield 关键字的函数变成流式输出界面

    The second method, bot() updates the chatbot history with the bot's response. Instead of creating a new message, we just replace the previously-created None message with the bot's response. Finally, we construct the message character by character and yield the intermediate outputs as they are being constructed. Gradio automatically turns any function with the yield keyword into a streaming output interface.

  3. 第三种方法使输入字段再次交互,以便用户可以向机器人发送另一条消息。

    The third method makes the input field interactive again so that users can send another message to the bot.

当然,在实践中,你可以将 bot() 替换为你自己的更复杂的函数,该函数可能会调用预训练模型或 API 来生成响应。

Of course, in practice, you would replace bot() with your own more complex function, which might call a pretrained model or an API, to generate a response.

最后,我们通过运行 demo.queue() 启用队列,这是流式传输中间输出所必需的。 你可以通过滚动到本页顶部的演示来试用改进后的聊天机器人。

Finally, we enable queuing by running demo.queue(), which is required for streaming intermediate outputs. You can try the improved chatbot by scrolling to the demo at the top of this page.

添加 Markdown、图像、音频或视频

gr.Chatbot 组件支持 markdown 的子集,包括粗体、斜体和代码。 例如,我们可以编写一个函数来响应用户的消息,使用粗体字太酷了! , 像这样:

The gr.Chatbot component supports a subset of markdown including bold, italics, and code. For example, we could write a function that responds to a user's message, with a bold That's cool!, like this:

def bot(history):
    response = "**That's cool!**"
    history[-1][1] = response
    return history

此外,它还可以处理图像、音频和视频等媒体文件。 要传入媒体文件,我们必须将文件作为两个字符串的元组传入,如下所示: (filepath, alt_text)alt_text 是可选的,因此你也可以只传入一个包含单个元素 (filepath,) 的元组,如下所示:

In addition, it can handle media files, such as images, audio, and video. To pass in a media file, we must pass in the file as a tuple of two strings, like this: (filepath, alt_text). The alt_text is optional, so you can also just pass in a tuple with a single element (filepath,), like this:

def add_file(history, file):
    history = history + [((file.name,), None)]
    return history

将这些放在一起,我们可以创建一个多模式聊天机器人,其中包含一个供用户提交文本的文本框和一个用于提交图像/音频/视频文件的文件上传按钮。 其余代码看起来与以前几乎相同:

Putting this together, we can create a multimodal chatbot with a textbox for a user to submit text and an file upload button to submit images / audio / video files. The rest of the code looks pretty much the same as before:

import gradio as gr


def add_text(history, text):
    history = history + [(text, None)]
    return history, gr.update(value="", interactive=False)


def add_file(history, file):
    history = history + [((file.name,), None)]
    return history


def bot(history):
    response = "**That's cool!**"
    history[-1][1] = response
    return history


with gr.Blocks() as demo:
    chatbot = gr.Chatbot([], elem_id="chatbot").style(height=750)

    with gr.Row():
        with gr.Column(scale=0.85):
            txt = gr.Textbox(
                show_label=False,
                placeholder="Enter text and press enter, or upload an image",
            ).style(container=False)
        with gr.Column(scale=0.15, min_width=0):
            btn = gr.UploadButton("📁", file_types=["image", "video", "audio"])

    txt_msg = txt.submit(add_text, [chatbot, txt], [chatbot, txt], queue=False).then(
        bot, chatbot, chatbot
    )
    txt_msg.then(lambda: gr.update(interactive=True), None, [txt], queue=False)
    file_msg = btn.upload(add_file, [chatbot, btn], [chatbot], queue=False).then(
        bot, chatbot, chatbot
    )

demo.launch()

你完成了! 这就是为聊天机器人模型构建界面所需的全部代码。 最后,我们将以一些指向在 Spaces 上运行的聊天机器人的链接结束我们的指南,以便你了解其他可能的内容:

And you're done! That's all the code you need to build an interface for your chatbot model. Finally, we'll end our Guide with some links to Chatbots that are running on Spaces so that you can get an idea of what else is possible:

  • project-baize/Baize-7B :一个程式化的聊天机器人,允许你停止生成以及重新生成响应。

    project-baize/Baize-7B: A stylized chatbot that allows you to stop generation as well as regenerate responses.

  • MAGAer13/mPLUG-Owl :一个多模态聊天机器人,允许你对响应进行赞成和反对。

    MAGAer13/mPLUG-Owl: A multimodal chatbot that allows you to upvote and downvote responses.