聊天机器人是大语言模型(LLMs)的一个流行应用。使用Gradio,你可以轻松构建你的LLM演示,并与用户分享,或者使用直观的聊天机器人界面自己尝试。
本教程使用gr.ChatInterface(),这是一个高级抽象,允许您快速创建聊天机器人用户界面,通常只需一行Python代码。它可以轻松适应支持多模态聊天机器人,或需要进一步定制的聊天机器人。
先决条件:请确保您使用的是最新版本的Gradio:
$ pip install --upgrade gradio如果你有一个提供与OpenAI API兼容的端点的聊天服务器(如果没有,请跳过),你可以在一行代码中启动一个ChatInterface。首先,还需要运行pip install openai。然后,使用你自己的URL、模型和可选的令牌:
import gradio as gr
gr.load_chat("http://localhost:11434/v1/", model="llama3.2", token=None).launch()在使用gr.ChatInterface()时,你应该做的第一件事是定义你的聊天函数。在最简单的情况下,你的聊天函数应该接受两个参数:message和history(参数可以任意命名,但必须按此顺序)。
message: 一个 str,表示用户最近的消息。history: 一个包含role和content键的openai风格字典列表,表示之前的对话历史。可能还包括表示消息元数据的其他键。例如,history 可能看起来像这样:
[
{"role": "user", "content": "What is the capital of France?"},
{"role": "assistant", "content": "Paris"}
]您的聊天功能只需返回:
str 值,这是聊天机器人基于聊天 history 和最近的 message 的响应。让我们来看几个示例聊天函数:
示例:一个随机回答是或否的聊天机器人
让我们编写一个随机响应Yes或No的聊天函数。
这是我们的聊天功能:
import random
def random_response(message, history):
return random.choice(["Yes", "No"])现在,我们可以将其插入gr.ChatInterface()并调用.launch()方法来创建网页界面:
import gradio as gr
gr.ChatInterface(
fn=random_response,
type="messages"
).launch()提示: 始终在 gr.ChatInterface 中设置 type="messages"。默认值 (type="tuples") 已被弃用,并将在未来的 Gradio 版本中移除。
就是这样!这是我们的运行演示,试试看:
示例:一个在同意和不同意之间交替的聊天机器人
当然,前面的例子非常简单,它没有考虑用户输入或之前的历史记录!这是另一个简单的例子,展示了如何结合用户的输入以及历史记录。
import gradio as gr
def alternatingly_agree(message, history):
if len([h for h in history if h['role'] == "assistant"]) % 2 == 0:
return f"Yes, I do think that: {message}"
else:
return "I don't think so"
gr.ChatInterface(
fn=alternatingly_agree,
type="messages"
).launch()我们将在下一个指南中查看更现实的聊天功能示例,该指南展示了使用gr.ChatInterface与流行LLMs的示例。
在你的聊天函数中,你可以使用yield来生成一系列部分响应,每个响应都会替换之前的响应。这样,你将得到一个流式聊天机器人。就是这么简单!
import time
import gradio as gr
def slow_echo(message, history):
for i in range(len(message)):
time.sleep(0.3)
yield "You typed: " + message[: i+1]
gr.ChatInterface(
fn=slow_echo,
type="messages"
).launch()当响应正在流式传输时,“提交”按钮会变成“停止”按钮,可用于停止生成器函数。
提示: 尽管你在每次迭代时都会生成最新的消息,但Gradio只会将每条消息的“差异”从服务器发送到前端,这减少了网络上的延迟和数据消耗。
如果你熟悉Gradio的gr.Interface类,gr.ChatInterface包含许多相同的参数,你可以使用这些参数来自定义你的聊天机器人的外观和感觉。例如,你可以:
title和description参数在您的聊天机器人上方添加标题和描述。theme和css参数分别添加主题或自定义CSS。examples 并启用 cache_examples,这使您的 Chatbot 更容易让用户试用。添加示例
你可以使用examples参数向你的gr.ChatInterface添加预设示例,该参数接受一个字符串示例列表。任何示例都会在发送任何消息之前以“按钮”的形式出现在聊天机器人中。如果你想在示例中包含图片或其他文件,你可以使用这种字典格式而不是字符串来表示每个示例:{"text": "这张图片里有什么?", "files": ["cheetah.jpg"]}。每个文件将作为一条单独的消息添加到你的聊天机器人历史中。
您可以使用example_labels参数更改每个示例的显示文本。您还可以使用example_icons参数为每个示例添加图标。这两个参数都接受一个字符串列表,该列表的长度应与examples列表相同。
如果您希望缓存示例以便它们预先计算并且结果立即显示,请设置cache_examples=True。
自定义聊天机器人或文本框组件
如果你想自定义组成ChatInterface的gr.Chatbot或gr.Textbox,那么你可以传入你自己的聊天机器人或文本框组件。以下是我们如何应用本节讨论的参数的示例:
import gradio as gr
def yes_man(message, history):
if message.endswith("?"):
return "Yes"
else:
return "Ask me anything!"
gr.ChatInterface(
yes_man,
type="messages",
chatbot=gr.Chatbot(height=300),
textbox=gr.Textbox(placeholder="Ask me a yes or no question", container=False, scale=7),
title="Yes Man",
description="Ask Yes Man any question",
theme="ocean",
examples=["Hello", "Am I cool?", "Are tomatoes vegetables?"],
cache_examples=True,
).launch()这是另一个示例,它为您的聊天界面添加了一个“占位符”,该占位符在用户开始聊天之前出现。gr.Chatbot的placeholder参数接受Markdown或HTML:
gr.ChatInterface(
yes_man,
type="messages",
chatbot=gr.Chatbot(placeholder="<strong>Your Personal Yes-Man</strong><br>Ask Me Anything"),
...占位符在聊天机器人中垂直和水平居中显示。
您可能希望为您的聊天界面添加多模态功能。例如,您可能希望用户能够上传图像或文件到您的聊天机器人,并向其提问。您可以通过向gr.ChatInterface类传递一个参数(multimodal=True)来使您的聊天机器人具备“多模态”功能。
当multimodal=True时,您的聊天函数的签名会略有变化:函数的第一个参数(我们上面提到的message)应该接受一个由提交的文本和上传的文件组成的字典,如下所示:
{
"text": "user input",
"files": [
"updated_file_1_path.ext",
"updated_file_2_path.ext",
...
]
}你的聊天函数的第二个参数,history,将采用与之前相同的openai风格的字典格式。然而,如果历史记录包含上传的文件,文件的content键将不是一个字符串,而是一个由文件路径组成的单元素元组。每个文件将是历史记录中的一条独立消息。因此,在上传两个文件并提问后,你的历史记录可能如下所示:
[
{"role": "user", "content": ("cat1.png")},
{"role": "user", "content": ("cat2.png")},
{"role": "user", "content": "What's the difference between these two images?"},
]当设置multimodal=True时,您的聊天函数的返回类型不会改变(即在最简单的情况下,您仍然应该返回一个字符串值)。我们讨论了更复杂的情况,例如返回文件如下。
如果您正在定制一个多模态聊天界面,您应该将一个gr.MultimodalTextbox的实例传递给textbox参数。您可以通过传递sources参数进一步定制MultimodalTextbox,该参数是一个要启用的源列表。以下是一个示例,展示了如何设置和定制多模态聊天界面:
import gradio as gr
def count_images(message, history):
num_images = len(message["files"])
total_images = 0
for message in history:
if isinstance(message["content"], tuple):
total_images += 1
return f"You just uploaded {num_images} images, total uploaded: {total_images+num_images}"
demo = gr.ChatInterface(
fn=count_images,
type="messages",
examples=[
{"text": "No files", "files": []}
],
multimodal=True,
textbox=gr.MultimodalTextbox(file_count="multiple", file_types=["image"], sources=["upload", "microphone"])
)
demo.launch()您可能希望向聊天函数添加额外的输入,并通过聊天UI向用户展示。例如,您可以添加一个用于系统提示的文本框,或者一个设置聊天机器人响应中令牌数量的滑块。gr.ChatInterface类支持一个additional_inputs参数,该参数可用于添加额外的输入组件。
additional_inputs 参数接受一个组件或组件列表。您可以直接传递组件实例,或使用它们的字符串快捷方式(例如,使用 "textbox" 而不是 gr.Textbox())。如果您传递组件实例,并且它们尚未被渲染,那么这些组件将出现在聊天机器人下方的 gr.Accordion() 中。
这是一个完整的示例:
import gradio as gr
import time
def echo(message, history, system_prompt, tokens):
response = f"System prompt: {system_prompt}\n Message: {message}."
for i in range(min(len(response), int(tokens))):
time.sleep(0.05)
yield response[: i + 1]
demo = gr.ChatInterface(
echo,
type="messages",
additional_inputs=[
gr.Textbox("You are helpful AI.", label="System Prompt"),
gr.Slider(10, 100),
],
)
demo.launch()
如果您传递到additional_inputs的组件已经在父级gr.Blocks()中渲染过,那么它们将不会在手风琴中重新渲染。这为决定输入组件的布局提供了灵活性。在下面的示例中,我们将gr.Textbox()放置在聊天机器人界面的顶部,同时将滑块保持在下方。
import gradio as gr
import time
def echo(message, history, system_prompt, tokens):
response = f"System prompt: {system_prompt}\n Message: {message}."
for i in range(min(len(response), int(tokens))):
time.sleep(0.05)
yield response[: i+1]
with gr.Blocks() as demo:
system_prompt = gr.Textbox("You are helpful AI.", label="System Prompt")
slider = gr.Slider(10, 100, render=False)
gr.ChatInterface(
echo, additional_inputs=[system_prompt, slider], type="messages"
)
demo.launch()带有额外输入的示例
您还可以为您的额外输入添加示例值。将列表的列表传递给examples参数,其中每个内部列表代表一个样本,每个内部列表的长度应为1 + len(additional_inputs)。内部列表中的第一个元素应为聊天消息的示例值,随后的每个元素应按顺序为其中一个额外输入的示例值。当提供额外输入时,示例将在聊天界面下方的表格中呈现。
如果您需要创建更定制化的内容,那么最好使用低级的gr.Blocks() API来构建聊天机器人UI。我们在这里有专门的指南。
就像你可以接受聊天函数中的额外输入一样,你也可以返回额外的输出。只需将组件列表传递给gr.ChatInterface中的additional_outputs参数,并从你的聊天函数中为每个组件返回额外的值。以下是一个提取代码并将其输出到单独的gr.Code组件中的示例:
import gradio as gr
python_code = """
def fib(n):
if n <= 0:
return 0
elif n == 1:
return 1
else:
return fib(n-1) + fib(n-2)
"""
js_code = """
function fib(n) {
if (n <= 0) return 0;
if (n === 1) return 1;
return fib(n - 1) + fib(n - 2);
}
"""
def chat(message, history):
if "python" in message.lower():
return "Type Python or JavaScript to see the code.", gr.Code(language="python", value=python_code)
elif "javascript" in message.lower():
return "Type Python or JavaScript to see the code.", gr.Code(language="javascript", value=js_code)
else:
return "Please ask about Python or JavaScript.", None
with gr.Blocks() as demo:
code = gr.Code(render=False)
with gr.Row():
with gr.Column():
gr.Markdown("<center><h1>Write Python or JavaScript</h1></center>")
gr.ChatInterface(
chat,
examples=["Python", "JavaScript"],
additional_outputs=[code],
type="messages"
)
with gr.Column():
gr.Markdown("<center><h1>Code Artifacts</h1></center>")
code.render()
demo.launch()
注意:与额外输入的情况不同,传递到additional_outputs中的组件必须在你的gr.Blocks上下文中已经定义——它们不会自动渲染。如果你需要在gr.ChatInterface之后渲染它们,你可以在首次定义时设置render=False,然后在gr.Blocks()的适当部分调用.render(),就像我们在上面的示例中所做的那样。
我们之前提到过,在最简单的情况下,您的聊天函数应该返回一个str响应,这将在聊天机器人中呈现为文本。然而,您也可以返回更复杂的响应,如下所述:
返回文件或Gradio组件
目前,以下Gradio组件可以在聊天界面中显示:
gr.Imagegr.Plotgr.Audiogr.HTMLgr.Videogr.Gallerygr.File只需从您的函数中返回这些组件之一即可与gr.ChatInterface一起使用。以下是一个返回音频文件的示例:
import gradio as gr
def music(message, history):
if message.strip():
return gr.Audio("https://github.com/gradio-app/gradio/raw/main/test/test_files/audio_sample.wav")
else:
return "Please provide the name of an artist"
gr.ChatInterface(
music,
type="messages",
textbox=gr.Textbox(placeholder="Which artist's music do you want to listen to?", scale=7),
).launch()同样地,你可以使用gr.Image返回图像文件,使用gr.Video返回视频文件,或者使用gr.File组件返回任意文件。
提供预设响应
您可能希望提供预设的响应,用户在与您的聊天机器人对话时可以选择这些响应。为此,从您的聊天函数中返回一个完整的openai风格的消息字典,并在从您的聊天函数返回的字典中添加options键来设置这些响应。
与options键对应的值应该是一个字典列表,每个字典包含一个value(一个字符串,当点击此响应时应发送到聊天函数的值)和一个可选的label(如果提供,则作为预设响应显示的文本,而不是value)。
这个例子展示了如何使用预设响应:
import gradio as gr
import random
example_code = """
Here's an example Python lambda function:
lambda x: x + {}
Is this correct?
"""
def chat(message, history):
if message == "Yes, that's correct.":
return "Great!"
else:
return {
"role": "assistant",
"content": example_code.format(random.randint(1, 100)),
"options": [
{"value": "Yes, that's correct.", "label": "Yes"},
{"value": "No"}
]
}
demo = gr.ChatInterface(
chat,
type="messages",
examples=["Write an example Python lambda function."]
)
demo.launch()
返回多条消息
你可以通过返回上述任何类型的消息的list来从你的聊天函数中返回多个助手消息(你甚至可以混合搭配)。这让你可以,例如,发送一条消息以及文件,如下例所示:
import gradio as gr
def echo_multimodal(message, history):
response = []
response.append("You wrote: '" + message["text"] + "' and uploaded:")
if message.get("files"):
for file in message["files"]:
response.append(gr.File(value=file))
return response
demo = gr.ChatInterface(
echo_multimodal,
type="messages",
multimodal=True,
textbox=gr.MultimodalTextbox(file_count="multiple"),
)
demo.launch()
一旦你构建了你的Gradio聊天界面并将其托管在Hugging Face Spaces或其他地方,你就可以通过/chat端点的简单API进行查询。该端点只需要用户的消息,并会返回响应,内部会跟踪消息历史。
要使用该端点,您应该使用Gradio Python Client或Gradio JS client。或者,您可以将您的聊天界面部署到其他平台,例如:
您可以为您的ChatInterface启用持久聊天历史记录,允许用户维护多个对话并轻松在它们之间切换。启用后,对话将使用本地存储在用户的浏览器中本地且私密地保存。因此,如果您在Hugging Face Spaces上部署ChatInterface,每个用户都将拥有自己独立的聊天历史记录,不会干扰其他用户的对话。这意味着多个用户可以同时与同一个ChatInterface交互,同时保持各自的私人对话历史记录。
要启用此功能,只需设置 gr.ChatInterface(save_history=True)(如下一节中的示例所示)。用户随后将在侧面板中看到他们之前的对话,并可以继续任何之前的聊天或开始新的聊天。
为了收集关于您的聊天模型的反馈,设置gr.ChatInterface(flagging_mode="manual"),用户将能够对助手的回答进行点赞或点踩。每个被标记的回答,连同整个聊天历史,将被保存在应用程序工作目录中的CSV文件中(这可以通过flagging_dir参数进行配置)。
您还可以通过flagging_options参数更改反馈选项。默认选项是“喜欢”和“不喜欢”,它们显示为竖起大拇指和倒大拇指的图标。任何其他选项都会显示在专用的标记图标下。此示例显示了一个启用了聊天历史记录(在上一节中提到)和用户反馈的ChatInterface:
import time
import gradio as gr
def slow_echo(message, history):
for i in range(len(message)):
time.sleep(0.05)
yield "You typed: " + message[: i + 1]
demo = gr.ChatInterface(
slow_echo,
type="messages",
flagging_mode="manual",
flagging_options=["Like", "Spam", "Inappropriate", "Other"],
save_history=True,
)
demo.launch()
请注意,在这个例子中,我们设置了几个标记选项:"Like"(喜欢)、"Spam"(垃圾)、"Inappropriate"(不适当)、"Other"(其他)。因为区分大小写的字符串"Like"是标记选项之一,用户将在每个助手消息旁边看到一个竖起大拇指的图标。其他三个标记选项将出现在标记图标下的下拉菜单中。
现在你已经了解了gr.ChatInterface类以及如何使用它快速创建聊天机器人用户界面,我们建议阅读以下内容之一:
gr.ChatInterface 与流行的LLM库的示例。