- 从服务器拉取完整代码 - 按框架规范整理项目结构 - 配置 Drone CI 测试环境部署 - 包含后端(FastAPI)、前端(Vue3)、管理端 技术栈: Vue3 + TypeScript + FastAPI + MySQL
6.8 KiB
6.8 KiB
与课程对话功能实施总结
完成时间:2025-10-14 功能状态:✅ 已完成实施
📋 功能概述
基于 Dify 对话流实现了与课程的智能对话功能,用户可以在课程中心点击"对话"按钮,与课程内容进行智能问答互动。
🎯 技术方案
架构设计
前端 chat-course.vue
↓ (SSE)
后端 /api/v1/course/chat
↓ (HTTP Stream)
Dify 对话流 API
核心特性
- 流式响应:使用 SSE(Server-Sent Events)实现实时对话
- 会话管理:conversation_id 由前端管理,支持多轮对话
- 无持久化:对话历史由 Dify 托管,系统不存储
- 纯文本:当前版本仅支持文本对话
📁 已修改文件
后端
-
配置文件:
kaopeilian-backend/app/core/config.py- 添加
DIFY_COURSE_CHAT_API_KEY = "app-lJzD6COkL8z7Eez8t6ZrYoJS"
- 添加
-
API 接口:
kaopeilian-backend/app/api/v1/course_chat.py(新建)POST /api/v1/course/chat- 与课程对话接口- 实现 SSE 流式代理
- 事件转换:Dify → 前端友好格式
-
路由注册:
kaopeilian-backend/app/api/v1/__init__.py- 注册
course_chat_router到/course前缀
- 注册
前端
-
API 封装:
kaopeilian-frontend/src/api/courseChat.ts(新建)courseChatApi.sendMessage()- 发送消息并返回 ReadableStream- TypeScript 类型定义:
CourseChatEvent
-
对话页面:
kaopeilian-frontend/src/views/trainee/chat-course.vue- 删除 Coze 集成代码
- 改用 Dify 对话流
- 前端管理
conversationId - SSE 事件处理(conversation_started / message_content / message_end)
测试
- 测试脚本:
test_course_chat.py(新建)- 测试登录 → 首次对话 → 续接对话
- 验证 SSE 事件流
- 验证会话管理
🔄 SSE 事件流程
Dify 原始事件
workflow_started → node_finished → workflow_finished → message_end
后端转换后的事件
// 1. 会话开始(首次对话)
{"event": "conversation_started", "conversation_id": "xxx"}
// 2. 消息块(逐字返回,实现打字机效果)
{"event": "message_chunk", "chunk": "这"}
{"event": "message_chunk", "chunk": "门"}
{"event": "message_chunk", "chunk": "课"}
...
// 3. 消息结束
{"event": "message_end"}
// 4. 错误(如有)
{"event": "error", "message": "错误信息"}
📊 数据流
首次对话
用户输入问题
↓
前端调用 courseChatApi.sendMessage({course_id, query})
↓
后端转发到 Dify (无 conversation_id)
↓
Dify 创建新会话
↓
SSE: conversation_started → 前端保存 conversation_id
SSE: message_content → 前端显示答案
SSE: message_end → 对话完成
续接对话
用户输入问题
↓
前端调用 courseChatApi.sendMessage({course_id, query, conversation_id})
↓
后端转发到 Dify (带 conversation_id)
↓
Dify 基于上下文回答
↓
SSE: message_content → 前端显示答案
SSE: message_end → 对话完成
🧪 测试步骤
1. 启动服务
# 后端
cd kaopeilian-backend
docker-compose up -d
# 前端
cd kaopeilian-frontend
npm run dev
2. 运行测试脚本
python test_course_chat.py
3. 手动测试
- 登录系统
- 进入课程中心:http://localhost:3001/trainee/course-center
- 点击课程卡片的"对话"按钮
- 输入问题并发送
- 验证:
- AI 回复显示正常
- 可以进行多轮对话
- 点击"清空对话"后会话重置
🎨 UI 特性
- ✅ 欢迎界面(首次进入时显示)
- ✅ 快速提问(预设问题点击发送)
- ✅ 消息加载动画(三个点跳动)
- ✅ 消息复制功能
- ✅ 消息收藏功能
- ✅ 侧边栏(知识要点、对话历史)
- ✅ 响应式设计(移动端适配)
⚠️ 注意事项
1. conversation_id 管理
- 前端使用
ref<string>保存 - 页面刷新后丢失(符合"每次进入对话页面都创建新会话"的需求)
- 点击"清空对话"时重置
2. 流式打字机效果
- ✅ 已实现!Dify streaming 模式支持
event: message逐字返回 - 前端通过
message_chunk事件逐字追加文本 - 实现类似 ChatGPT 的实时打字效果
3. 超时设置
- 后端:180 秒(httpx.Timeout)
- 前端:依赖浏览器默认(通常无限制)
4. 错误处理
- 网络错误:显示友好提示
- Dify API 错误:记录日志并返回错误事件
- 解析错误:跳过当前行,继续处理
📝 API 接口文档
POST /api/v1/course/chat
请求体:
{
"course_id": 1,
"query": "这门课程讲什么?",
"conversation_id": "可选,续接对话时传入"
}
响应(SSE):
data: {"event":"conversation_started","conversation_id":"xxx"}
data: {"event":"message_content","answer":"这门课程..."}
data: {"event":"message_end"}
🔍 关键代码片段
后端 SSE 生成
async def generate_stream():
async with client.stream("POST", url, headers=headers, json=payload) as response:
async for line in response.aiter_lines():
if line.startswith("data: "):
event_data = json.loads(line[6:])
# 处理事件...
yield f"data: {json.dumps(frontend_event)}\n\n"
前端 SSE 消费
const stream = await courseChatApi.sendMessage({...})
const reader = stream.getReader()
const decoder = new TextDecoder()
while (true) {
const { done, value } = await reader.read()
if (done) break
const text = decoder.decode(value)
// 解析 SSE 事件...
}
✅ 验收标准
- 后端配置添加完成
- 后端 API 接口实现
- 后端路由注册
- 前端 API 封装
- 前端页面改造
- SSE 流式响应正常
- 会话管理正常
- 错误处理完善
- 无 linter 错误
- 测试脚本创建
🚀 下一步
可选优化
- Markdown 渲染:如果 Dify 返回 Markdown 格式,前端可添加 Markdown 渲染器
- 会话持久化:如需要持久化历史,可在后端存储 conversation_id 与用户/课程的映射
- 实时打字效果:如 Dify 支持逐字返回,可修改事件处理逻辑
- 语音对话:未来可集成语音输入/输出
📚 相关文档
🎉 总结
成功将与课程对话功能从 Coze 迁移到 Dify 对话流,实现了:
✅ 完整的 SSE 流式对话
✅ 会话持续性(conversation_id 管理)
✅ 前后端解耦(API 代理模式)
✅ 良好的错误处理
✅ 友好的用户界面
代码质量:无 linter 错误,代码结构清晰,注释完善。