这是我们构建自定义多模态聊天机器人组件两部分系列的第一部分。在第一部分中,我们将修改 Gradio 聊天机器人组件,使其能够在同一消息中显示文本和媒体文件(视频、音频、图片)。在第二部分中,我们将构建一个自定义的文本框组件,该组件能够向聊天机器人发送多模态消息(文本和媒体文件)。
您可以跟随这篇文章的作者,通过以下 YouTube 视频实现聊天机器人组件!
这里是我们的多模态聊天机器人组件将会是什么样子的预览:
第 1 部分 - 创建我们的项目
对于这个演示,我们将调整现有的 Gradio Chatbot
组件,以便在同一消息中显示文本和媒体文件。让我们通过模板化 Chatbot
组件源代码来创建一个新的自定义组件目录。
gradio cc create MultimodalChatbot --template Chatbot
我们准备好出发了!
✍️ 提示:确保在 pyproject.toml
文件中修改 Author
键。
第 2a 部分 - 后端数据模型
在您最喜欢的代码编辑器中打开 multimodalchatbot.py
文件,让我们开始修改组件的后端。
我们将要做的第一件事是创建我们组件的 data_model
。 data_model
是您的 Python 组件将接收并发送给运行 UI 的 JavaScript 客户端的数据格式。您可以在后端指南中了解更多关于 data_model
的信息。
对于我们的组件,每个聊天机器人消息将包含两个键:一个 text
键用于显示文本消息,以及一个可选的媒体文件列表,可以显示在文本下方。
从 gradio.data_classes
导入 FileData
和 GradioModel
类,并修改现有的 ChatbotData
类,使其看起来如下:
# 定义文件消息类,继承自 GradioModel
class FileMessage(GradioModel):
# 文件数据,类型为 FileData
file: FileData
# 可选的替代文本,类型为可选的字符串
alt_text: Optional[str] = None
# 定义多模态消息类,继承自 GradioModel
class MultimodalMessage(GradioModel):
# 文本消息,类型为可选的字符串
text: Optional[str] = None
# 文件消息,类型为 FileMessage 类的列表,是可选的
files: Optional[List[FileMessage]] = None
# 定义聊天机器人数据类,继承自 GradioRootModel
class ChatbotData(GradioRootModel):
# 聊天数据,类型为包含多模态消息类的元组的列表
root: List[Tuple[Optional[MultimodalMessage], Optional[MultimodalMessage]]]
# 定义多模态聊天机器人组件,继承自 Component
class MultimodalChatbot(Component):
...
# 多模态聊天机器人组件的数据模型为聊天机器人数据类
data_model = ChatbotData
✍️ 提示:`data_model`是使用`Pydantic V2`实现的。请阅读此处的文档。
我们已经完成了最困难的部分!
第 2b 部分 - 预处理和后处理方法
对于 preprocess
方法,我们将保持简单,将一个 MultimodalMessage
列表传递给使用此组件作为输入的 python 函数。这将允许我们组件的用户使用 .text
和 .files
属性访问聊天机器人数据。这是您可以在实现中修改的设计选择!我们可以像这样返回带有 root
属性的 ChatbotData
的消息列表:
# 定义预处理方法,输入参数为聊天数据,类型为 ChatbotData 或 None
def preprocess(
self,
payload: ChatbotData | None,
) -> List[MultimodalMessage] | None:
# 如果输入参数为空,则直接返回
if payload is None:
return payload
# 如果存在聊天数据,则返回其中的 root 属性,即所有的聊天消息
return payload.root
✍️ 提示:了解`preprocess`和`postprocess`方法背后的原理,请参阅关键概念指南
在 postprocess
方法中,我们将强制 python 函数返回的每条消息都是一个 MultimodalMessage
类。我们还将清理 text
字段中的任何缩进,以便它可以在前端正确显示为 markdown。
我们可以保留 postprocess
方法并修改 _postprocess_chat_messages
# 定义后处理聊天消息的方法,输入参数为多模态消息,类型为 MultimodalMessage 或 字典 或 None
def _postprocess_chat_messages(
self, chat_message: MultimodalMessage | dict | None
) -> MultimodalMessage | None:
# 如果聊天消息为空,则直接返回 None
if chat_message is None:
return None
# 如果聊天消息是一个字典,则将其转化为 MultimodalMessage 类型
if isinstance(chat_message, dict):
chat_message = MultimodalMessage(**chat_message)
# 清理聊天消息的文本,使用 cleandoc 方法对文本进行清理,如果文本不存在,则返回一个空字符串
chat_message.text = inspect.cleandoc(chat_message.text or "")
# 遍历消息中的所有文件
for file_ in chat_message.files:
# 使用 get_mimetype 方法获取文件的 MIME 类型,并设置给文件的 mime_type 属性
file_.file.mime_type = client_utils.get_mimetype(file_.file.path)
# 返回处理过后的聊天消息
return chat_message
在我们结束后端代码之前,让我们修改 example_value
和 example_payload
方法,以返回 ChatbotData
的有效字典表示形式:
# 定义example_value方法,返回一个任意类型的值
def example_value(self) -> Any:
# 返回一个示例聊天信息(仅包含文本“Hello!”)的列表
return [[{"text": "Hello!", "files": []}, None]]
# 定义example_payload方法,返回一个任意类型的值
def example_payload(self) -> Any:
# 返回一个示例聊天信息(仅包含文本