聊天接口与消息交互
聊天界面与消息交互
相关源文件
本章引用的主要源码文件:
web/app/components/app/configuration/debug/debug-with-multiple-model/chat-item.tsxweb/app/components/app/configuration/debug/debug-with-single-model/index.tsxweb/app/components/app/log/list.tsxweb/app/components/base/chat/__tests__/__snapshots__/utils.spec.ts.snapweb/app/components/base/chat/__tests__/branchedTestMessages.jsonweb/app/components/base/chat/__tests__/legacyTestMessages.jsonweb/app/components/base/chat/__tests__/mixedTestMessages.jsonweb/app/components/base/chat/__tests__/multiRootNodesMessages.jsonweb/app/components/base/chat/__tests__/multiRootNodesWithLegacyTestMessages.jsonweb/app/components/base/chat/__tests__/partialMessages.jsonweb/app/components/base/chat/__tests__/realWorldMessages.jsonweb/app/components/base/chat/__tests__/utils.spec.tsweb/app/components/base/chat/chat-with-history/chat-wrapper.tsxweb/app/components/base/chat/chat/__tests__/hooks.spec.tsxweb/app/components/base/chat/chat/__tests__/question.spec.tsxweb/app/components/base/chat/chat/answer/agent-content.tsxweb/app/components/base/chat/chat/answer/basic-content.tsxweb/app/components/base/chat/chat/answer/index.tsxweb/app/components/base/chat/chat/answer/more.tsxweb/app/components/base/chat/chat/answer/suggested-questions.tsxweb/app/components/base/chat/chat/chat-input-area/__tests__/index.spec.tsxweb/app/components/base/chat/chat/chat-input-area/index.tsxweb/app/components/base/chat/chat/chat-input-area/operation.tsxweb/app/components/base/chat/chat/hooks.tsweb/app/components/base/chat/chat/index.tsxweb/app/components/base/chat/chat/question.tsxweb/app/components/base/chat/chat/try-to-ask.tsxweb/app/components/base/chat/chat/type.tsweb/app/components/base/chat/embedded-chatbot/__tests__/hooks.spec.tsxweb/app/components/base/chat/embedded-chatbot/chat-wrapper.tsxweb/app/components/base/chat/types.tsweb/app/components/base/chat/utils.tsweb/app/components/base/file-uploader/constants.tsweb/app/components/base/file-uploader/file-input.tsxweb/app/components/base/file-uploader/file-list-in-log.tsxweb/app/components/base/file-uploader/file-uploader-in-attachment/file-item.tsxweb/app/components/base/file-uploader/hooks.tsweb/app/components/base/file-uploader/utils.tsweb/app/components/base/image-uploader/__tests__/chat-image-uploader.spec.tsxweb/app/components/base/image-uploader/__tests__/image-preview.spec.tsxweb/app/components/base/markdown-blocks/__tests__/think-block.spec.tsxweb/app/components/base/markdown-blocks/think-block.tsxweb/app/components/base/markdown/__tests__/markdown-utils.spec.tsweb/app/components/base/prompt-editor/plugins/shortcuts-popup-plugin/__tests__/index.spec.tsxweb/app/components/base/svg-gallery/index.tsxweb/app/components/workflow/nodes/_base/components/file-upload-setting.tsxweb/app/components/workflow/nodes/http/hooks/use-key-value-list.tsweb/app/components/workflow/nodes/llm/components/json-schema-config-modal/json-schema-generator/index.tsxweb/app/components/workflow/panel/chat-record/index.tsxweb/app/components/workflow/panel/debug-and-preview/__tests__/hooks.spec.tsweb/app/components/workflow/panel/debug-and-preview/chat-wrapper.tsxweb/app/components/workflow/panel/debug-and-preview/hooks.tsweb/app/components/workflow/run/output-panel.tsxweb/app/components/workflow/run/result-text.tsxweb/models/common.tsweb/models/log.tsweb/public/embed.jsweb/public/embed.min.jsweb/service/common.tsweb/service/use-common.tsweb/service/use-log.ts
本文档描述了 Dify Web 应用中负责消息交互的前端聊天界面组件。内容涵盖 Operation 组件、反馈系统、文本转语音(TTS)音频播放,以及复制、重新生成和标注控制等消息操作按钮。这些组件构成了交互层,使用户能够有效地与聊天响应进行交互。
关于支持这些交互的后端 API 详情,请参阅服务 API。关于工作流相关的 UI 组件,请参阅工作流节点 UI 组件。
操作栏组件架构
Operation 组件是消息交互的核心,它为每条聊天消息渲染一个操作栏。该组件根据配置和消息上下文,控制多个交互式 UI 元素的可见性、位置和内部状态。
属性与状态管理
Operation 组件接收以下属性来定义其渲染上下文:
| 属性 | 类型 | 描述 |
|---|---|---|
item | ChatItem | 聊天消息数据,包含反馈信息 |
question | string | 用于标注的用户问题文本 |
index | number | 消息在对话中的索引 |
showPromptLog | boolean | 控制提示日志按钮的可见性 |
maxSize | number | 操作栏的最大宽度约束 |
contentWidth | number | 用于定位的消息内容宽度 |
hasWorkflowProcess | boolean | 是否显示工作流处理 UI |
noChatInput | boolean | 禁用只读模式下的重新生成按钮 |
内部状态包括:
const [userLocalFeedback, setUserLocalFeedback] = useState(feedback)
const [adminLocalFeedback, setAdminLocalFeedback] = useState(adminFeedback)
const [feedbackTarget, setFeedbackTarget] = useState<'user' | 'admin'>('user')
const [isShowFeedbackModal, setIsShowFeedbackModal] = useState(false)
const [feedbackContent, setFeedbackContent] = useState('')
这些状态用于管理反馈 UI 和用于收集用户/管理员反馈的模态框。
来源: web/app/components/base/chat/chat/answer/operation.tsx:1-374
反馈系统架构
Dify 提供了两种独立的反馈机制,附加在聊天消息上:
- 用户反馈: 从与聊天交互的用户处收集。
- 管理员反馈: 由管理员收集,用于内部质量控制。
两种机制共存并影响 UI 渲染。
用户反馈流程
当标注功能禁用但反馈功能启用时,用户会看到一个简单的赞/踩反馈栏:
- 赞: 点击后立即发送正面反馈。
- 踩: 点击后会打开一个模态框,用于输入详细的负面反馈。
- 反馈后: 显示一个反映已提交评分的按钮;点击该按钮会清除反馈。
反馈栏使用 CSS 类在悬停时或存在反馈时显示/隐藏。
管理员反馈流程
当标注功能启用时,用户反馈和管理员反馈会并排显示:
- 用户反馈以只读方式显示,并带有工具提示显示任何评论。
- 管理员反馈显示交互式的赞/踩按钮,供管理员对消息质量进行评分。
- 两个反馈部分之间有一个分隔符进行视觉分隔。
工具提示文本使用 buildFeedbackTooltip 辅助函数构建,用于格式化评分和评论。
来源: web/app/components/base/chat/chat/answer/operation.tsx:87-286
文本转语音(TTS)音频播放
音频播放功能允许用户通过 TTS 收听生成的回答。它通过集成到操作栏中的 NewAudioButton 组件实现,在启用时显示。
音频按钮状态机
音频按钮维护五种状态,驱动 UI 和行为:
| 状态 | 视觉 | 用户操作 | 行为 |
|---|---|---|---|
| initial | 播放图标 | 点击播放 | 转换为 loading,开始获取 |
| loading | 旋转加载器 | 禁用 | 等待音频生成 |
| playing | 暂停图标 | 点击暂停 | 暂停音频播放 |
| paused | 播放图标 | 点击恢复 | 恢复音频播放 |
| ended | 播放图标 | 点击重播 | 播放完成或出错;重新开始音频 |
audio_finished_call 回调处理来自 AudioPlayerManager 的事件,以相应地更新状态。
音频 URL 端点选择
获取 TTS 音频的 URL 根据使用场景构建:
- 公开分享: 如果存在
params.token,则使用/text-to-audioAPI。 - 已安装应用: 使用
/installed-apps/${appId}/text-to-audio。 - 工作室应用: 使用
/apps/${appId}/text-to-audio。
播放/暂停切换通过音频管理器执行开始或暂停操作,并更新状态。
来源: web/app/components/base/chat/chat/answer/operation.tsx:294-300,web/app/components/base/audio-btn/index.tsx:1-112
消息操作按钮
操作栏的操作按钮分为三个核心功能:复制、重新生成和标注。
复制按钮
- 对要复制的内容进行记忆化处理,如果处于代理模式,则包含代理思考内容。
- 使用
copy-to-clipboard库执行复制操作。 - 复制成功时显示成功提示通知。
重新生成按钮
- 仅在聊天输入可用时渲染(
!noChatInput)。 - 调用
onRegenerate(item)回调以重试生成。 - 显示图标
"i-ri-reset-left-line"。
标注按钮
- 仅在标注支持和标注回复功能启用且不存在人工输入表单数据时渲染。
- 使用
AnnotationCtrlButton组件。 - 接受
onAdded、onEdit和onRemove回调,用于标注生命周期管理。 - 传递
appId、messageId、query(问题)和answer(内容)属性。
来源: web/app/components/base/chat/chat/answer/operation.tsx:292-343
操作栏定位逻辑
为了适应可变的消息宽度和工作流可视化,操作栏会动态定位,要么在消息内容上方右对齐,要么在下方。
宽度计算算法
操作栏的宽度是可见图标/元素的总和:
- 如果不是开场白,则 +26px(复制和重新生成)
- 如果提示日志按钮可见,则 +28px + 8px 间距
- 如果文本转语音启用,则 +26px
- 如果标注按钮启用,则 +26px
- 用户/管理员反馈按钮增加 +28px(存在反馈:单个图标)或 +60px(无反馈:赞 + 踩按钮)加上间距
如果此组合宽度小于可用的 maxSize,则操作栏定位在右上侧;否则,它会以固定偏移量显示在下方。如果存在工作流处理栏,则操作栏始终定位在下方以避免重叠。
来源: web/app/components/base/chat/chat/answer/operation.tsx:143-173
模态框交互
反馈模态框
当用户点击踩按钮时,会弹出一个反馈模态框以收集详细的文本反馈:
- 用户输入评论并提交。
- 调用
onFeedback回调,传入评分和内容。 - 更新本地反馈状态并在提交后隐藏模态框。
标注编辑模态框
EditReplyModal 允许编辑用于标注的问题-答案对:
- 支持编辑现有标注或添加新标注。
- 提供删除功能。
- 相应地触发回调:
onAnnotationEdited、onAnnotationAdded、onAnnotationRemoved。
来源: web/app/components/base/chat/chat/answer/operation.tsx:331-369
聊天上下文集成
Operation 组件通过 useChatContext 与聊天上下文集成,以获取配置和交互回调。
这种抽象方式将操作栏的交互处理器和配置与组件实现清晰地解耦。
总结
聊天界面消息交互利用 Operation 组件作为编排器,实现以下功能:
- 反馈收集,支持用户/管理员双模式。
- 文本转语音音频播放,具有健壮的状态管理。
- 消息操作,如复制内容、重新生成响应和管理标注。
- 基于内容和上下文的动态 UI 定位。
这些交互高度依赖于 React 状态、从聊天上下文传递的回调,以及与底层服务 API 的集成,以实现数据持久化和播放。
来源:
web/app/components/base/chat/chat/answer/operation.tsx:1-374web/app/components/base/audio-btn/index.tsx:1-112web/app/components/base/audio-btn/audio.player.manager.ts:1-100