该文件提供 AI 聊天相关的全部接口,包括:
所有接口(除 get_user_recommend_question 外)都需要 Token 认证。
路由前缀:/apiv1(以 routers/__init__.py 中注册为准)
/apiv1/send_deepseek_message — 发送消息(非流式)功能说明: 发送消息并获取 AI 回复。支持 4 种业务类型:
0: AI 问答(意图识别 + RAG 检索)1: PPT 大纲生成2: AI 写作3: 考试工坊(题目生成)自动创建对话或关联到已有对话。
是否需要认证: 是
请求方式: POST
请求体(JSON): | 字段 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | message | string | 是 | - | 用户消息内容 | | conversation_id | int | 否 | null | 对话 ID,为空则新建对话 | | business_type | int | 否 | 0 | 业务类型:0=AI问答, 1=PPT大纲, 2=AI写作, 3=考试工坊 | | exam_name | string | 否 | "" | 考试名称(business_type=3 时有效) | | ai_message_id | int | 否 | 0 | AI 消息 ID |
测试用例:
// 请求
POST /apiv1/send_deepseek_message
token: <有效Token>
Content-Type: application/json
{
"message": "隧道施工有哪些安全注意事项?",
"business_type": 0
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"conversation_id": 1,
"response": "<AI回答文本>",
"user_id": 100,
"business_type": 0
}
}
// 请求
POST /apiv1/send_deepseek_message
token: <有效Token>
Content-Type: application/json
{
"message": "桥梁施工安全培训 PPT",
"business_type": 1
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"conversation_id": 2,
"response": "<PPT大纲文本>",
"user_id": 100,
"business_type": 1
}
}
// 请求
POST /apiv1/send_deepseek_message
token: <有效Token>
Content-Type: application/json
{
"message": "新写一篇关于路桥隧施工安全管理的报告",
"business_type": 2
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"conversation_id": 3,
"response": "<写作文本>",
"user_id": 100,
"business_type": 2
}
}
// 请求
POST /apiv1/send_deepseek_message
token: <有效Token>
Content-Type: application/json
{
"message": "生成10道关于隧道施工安全的单选题",
"business_type": 3,
"exam_name": "隧道施工安全考试"
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"conversation_id": 4,
"response": "<JSON格式题目>",
"user_id": 100,
"business_type": 3
}
}
// 请求
POST /apiv1/send_deepseek_message
token: <有效Token>
Content-Type: application/json
{
"message": "继续上面的话题",
"conversation_id": 1,
"business_type": 0
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"conversation_id": 1,
"response": "<AI回答>",
"user_id": 100,
"business_type": 0
}
}
// 请求
POST /apiv1/send_deepseek_message
token: <有效Token>
Content-Type: application/json
{
"message": "",
"business_type": 0
}
// 预期响应 (HTTP 200, 业务码 400)
{
"statusCode": 400,
"msg": "消息不能为空"
}
// 请求
POST /apiv1/send_deepseek_message
token: <有效Token>
Content-Type: application/json
{
"message": "测试消息",
"business_type": 99
}
// 预期响应 (HTTP 200, 业务码 400)
{
"statusCode": 400,
"msg": "不支持的业务类型: 99"
}
// 请求(不带 Token)
POST /apiv1/send_deepseek_message
Content-Type: application/json
{
"message": "测试"
}
// 预期响应 (HTTP 401)
{
"statusCode": 401,
"msg": "未提供认证Token"
}
/apiv1/get_history_record — 获取对话历史记录列表功能说明: 获取当前用户的对话历史列表,按创建时间倒序排列,最多返回 50 条。
是否需要认证: 是
请求方式: GET
请求路径: /apiv1/get_history_record
请求参数: 无
测试用例:
// 请求
GET /apiv1/get_history_record
token: <有效Token>
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": [
{
"id": 5,
"content": "隧道施工有哪些安全注意事项?...",
"business_type": 0,
"exam_name": "",
"created_at": 1700000000
}
]
}
注意:
content字段最多截取前 50 个字符并添加...后缀。
// 请求
GET /apiv1/get_history_record
token: <有效Token(新用户)>
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": []
}
// 请求
GET /apiv1/get_history_record
// 预期响应 (HTTP 401)
{
"statusCode": 401,
"msg": "未提供认证Token"
}
/apiv1/delete_conversation — 删除对话(软删除)功能说明: 软删除对话记录及其所有关联的消息(设置 is_deleted = 1)。
是否需要认证: 是
请求方式: POST
请求体(JSON): | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | ai_conversation_id | int | 是 | 要删除的对话 ID |
测试用例:
// 请求
POST /apiv1/delete_conversation
token: <有效Token>
Content-Type: application/json
{
"ai_conversation_id": 1
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "删除成功"
}
// 请求
POST /apiv1/delete_conversation
token: <用户A的Token>
Content-Type: application/json
{
"ai_conversation_id": 999
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "删除成功"
}
注意:代码中未检查是否实际匹配到记录,update 0 条也不报错。
// 请求
POST /apiv1/delete_conversation
// 预期响应 (HTTP 401)
{
"statusCode": 401,
"msg": "未提供认证Token"
}
/apiv1/delete_history_record — 删除历史记录(软删除)功能说明: 仅软删除对话记录本身,不删除关联消息。
是否需要认证: 是
请求方式: POST
请求体(JSON): | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | ai_conversation_id | int | 是 | 要删除的对话 ID |
测试用例:
// 请求
POST /apiv1/delete_history_record
token: <有效Token>
Content-Type: application/json
{
"ai_conversation_id": 2
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "删除成功"
}
// 请求
POST /apiv1/delete_history_record
// 预期响应 (HTTP 401)
{
"statusCode": 401,
"msg": "未提供认证Token"
}
/apiv1/stream/chat — 流式聊天(SSE,不写 DB)功能说明: 流式输出 AI 回复,不保存到数据库。内部先做意图识别,按需执行 RAG 检索,再流式输出回答。
是否需要认证: 是(由中间件处理)
请求方式: POST
请求体(JSON): | 字段 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | message | string | 是 | - | 用户消息 | | model | string | 否 | "" | 模型名称(预留,目前未使用) |
响应格式: SSE(Server-Sent Events,text/event-stream)
SSE 事件流格式:
data: {"content": "回答的第一段.."}
data: {"content": "回答的第二段..."}
data: [DONE]
测试用例:
// 请求
POST /apiv1/stream/chat
token: <有效Token>
Content-Type: application/json
{
"message": "什么是预应力混凝土?"
}
// 预期响应 (HTTP 200, text/event-stream)
// SSE 流:
data: {"content": "预应力混凝土是.."}
data: {"content": "在施工中..."}
data: [DONE]
// 请求
POST /apiv1/stream/chat
token: <有效Token>
Content-Type: application/json
{
"message": ""
}
// 预期响应 (HTTP 200, JSON)
{
"statusCode": 400,
"msg": "消息不能为空"
}
/apiv1/stream/chat-with-db — 带 DB 的流式聊天(SSE)功能说明: 主聊天接口。完整流程:
initial 事件(返回 ai_conversation_id 和 ai_message_id)[DONE] 结束标记是否需要认证: 是
请求方式: POST
请求体(JSON): | 字段 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | message | string | 是 | - | 用户消息 | | ai_conversation_id | int | 否 | 0 | 对话 ID,0 则新建 | | business_type | int | 否 | 0 | 业务类型 | | exam_name | string | 否 | "" | 考试名称 | | ai_message_id | int | 否 | 0 | AI 消息 ID | | online_search_content | string | 否 | "" | 联网搜索结果内容(由前端传入) |
响应格式: SSE(text/event-stream)
SSE 事件流格式:
data: {"type": "initial", "ai_conversation_id": 1, "ai_message_id": 10}
data: 回答的第一段文本..
data: 回答的第二段文本...
data: [DONE]
测试用例:
// 请求
POST /apiv1/stream/chat-with-db
token: <有效Token>
Content-Type: application/json
{
"message": "隧道围岩分类有哪些?",
"business_type": 0
}
// 预期 SSE 流响应
data: {"type": "initial", "ai_conversation_id": 5, "ai_message_id": 20}
data: 隧道围岩根据...
data: [DONE]
// 请求
POST /apiv1/stream/chat-with-db
token: <有效Token>
Content-Type: application/json
{
"message": "详细说明III类围岩",
"ai_conversation_id": 5
}
// 预期 SSE 流响应
data: {"type": "initial", "ai_conversation_id": 5, "ai_message_id": 21}
data: III类围岩...
data: [DONE]
// 请求
POST /apiv1/stream/chat-with-db
token: <有效Token>
Content-Type: application/json
{
"message": "最新的桥梁施工规范",
"online_search_content": "根据2024年最新《公路桥梁施工技术规范》..."
}
// 预期 SSE 流响应(正常流式输出)
// 请求
POST /apiv1/stream/chat-with-db
token: <有效Token>
Content-Type: application/json
{
"message": ""
}
// 预期响应 (HTTP 200, JSON)
{
"statusCode": 400,
"msg": "消息不能为空"
}
// 请求
POST /apiv1/stream/chat-with-db
// 预期响应 (HTTP 200, JSON)
{
"statusCode": 401,
"msg": "未授权"
}
/apiv1/guess_you_want — 猜你想问功能说明: 根据 AI 回答内容生成 3 个关联推荐问题,保存到 AIMessage.guess_you_want 字段。
是否需要认证: 是
请求方式: POST
请求体(JSON): | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | ai_message_id | int | 是 | AI 消息 ID |
测试用例:
// 请求
POST /apiv1/guess_you_want
token: <有效Token>
Content-Type: application/json
{
"ai_message_id": 10
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"ai_message_id": 10,
"questions": [
"隧道围岩分类的具体标准是什么?",
"不同围岩类别的支护方式有什么区别?",
"如何进行现场围岩判定?"
]
}
}
// 请求
POST /apiv1/guess_you_want
token: <有效Token>
Content-Type: application/json
{
"ai_message_id": 99999
}
// 预期响应 (HTTP 200, 业务码 404)
{
"statusCode": 404,
"msg": "消息不存在"
}
// 请求
POST /apiv1/guess_you_want
// 预期响应 (HTTP 401)
{
"statusCode": 401,
"msg": "未提供认证Token"
}
/apiv1/online_search — 在线搜索功能说明: 先通过 Qwen 提炼关键词,再调用 Dify 工作流执行在线搜索,返回搜索摘要。
是否需要认证: 是
请求方式: GET
请求参数(Query): | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | question | string | 是 | 搜索问题 |
测试用例:
// 请求
GET /apiv1/online_search?question=最新桥梁施工安全规范
token: <有效Token>
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"keywords": "桥梁 施工 安全 规范 最新",
"result": "<搜索摘要文本>"
}
}
// 请求(服务端未配置 Dify)
GET /apiv1/online_search?question=测试
token: <有效Token>
// 预期响应 (HTTP 200, 业务码 500)
{
"statusCode": 500,
"msg": "Dify 配置未设置"
}
// 请求
GET /apiv1/online_search?question=测试
// 预期响应 (HTTP 401)
{
"statusCode": 401,
"msg": "未提供认证Token"
}
/apiv1/save_online_search_result — 保存联网搜索结果功能说明: 将联网搜索结果保存到 AIMessage.search_source 字段。
是否需要认证: 是
请求方式: POST
请求体(JSON): | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | ai_message_id | int | 是 | AI 消息 ID | | search_result | string | 是 | 搜索结果文本 |
测试用例:
// 请求
POST /apiv1/save_online_search_result
token: <有效Token>
Content-Type: application/json
{
"ai_message_id": 10,
"search_result": "根据最新《公路桥梁施工技术规范》(JTG/T 3650-2020)..."
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "保存成功"
}
// 请求
POST /apiv1/save_online_search_result
// 预期响应 (HTTP 401)
{
"statusCode": 401,
"msg": "未提供认证Token"
}
/apiv1/intent_recognition — 意图识别功能说明: 对用户消息进行意图识别。若意图为问候/FAQ 且 save_to_db=True,则自动将用户消息和 AI 直接回复存入数据库。
是否需要认证: 是
请求方式: POST
请求体(JSON): | 字段 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | message | string | 是 | - | 用户消息 | | save_to_db | bool | 否 | false | 是否保存到数据库(仅 greeting/faq 类型有效) | | ai_conversation_id | int | 否 | 0 | 对话 ID,0 则新建 |
测试用例:
// 请求
POST /apiv1/intent_recognition
token: <有效Token>
Content-Type: application/json
{
"message": "隧道施工有哪些危险源?"
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"intent_type": "query_knowledge_base",
"response": "",
"saved_to_db": false
}
}
// 请求
POST /apiv1/intent_recognition
token: <有效Token>
Content-Type: application/json
{
"message": "你好",
"save_to_db": true
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"intent_type": "greeting",
"response": "你好,请问有什么可以帮助您的?",
"ai_conversation_id": 6,
"ai_message_id": 25,
"saved_to_db": true
}
}
// 请求
POST /apiv1/intent_recognition
token: <有效Token>
Content-Type: application/json
{
"message": "你好啊",
"save_to_db": true,
"ai_conversation_id": 6
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": {
"intent_type": "greeting",
"response": "你好,请问有什么可以帮助您的?",
"ai_conversation_id": 6,
"ai_message_id": 26,
"saved_to_db": true
}
}
// 请求
POST /apiv1/intent_recognition
// 预期响应 (HTTP 401)
{
"statusCode": 401,
"msg": "未提供认证Token"
}
/apiv1/get_user_recommend_question — 获取推荐问题功能说明: 从 RecommendQuestion 表中获取推荐问题列表,支持关键词模糊查询。
是否需要认证: 否(代码中未检查 user 状态,但中间件仍会校验 Token,需注意实际部署路径是否在白名单中)
请求方式: GET
请求参数(Query): | 字段 | 类型 | 必填 | 默认值 | 说明 | |------|------|------|--------|------| | keyword | string | 否 | "" | 模糊查询关键词 | | limit | int | 否 | 10 | 返回数量上限 |
测试用例:
// 请求
GET /apiv1/get_user_recommend_question
token: <有效Token>
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": [
{
"id": 1,
"question": "隧道施工安全有哪些注意事项?",
"created_at": 1700000000
},
{
"id": 2,
"question": "桥梁施工中的常见危险源有哪些?",
"created_at": 1700000100
}
]
}
// 请求
GET /apiv1/get_user_recommend_question?keyword=隧道&limit=5
token: <有效Token>
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": [
{
"id": 1,
"question": "隧道施工安全有哪些注意事项?",
"created_at": 1700000000
}
]
}
// 请求
GET /apiv1/get_user_recommend_question?keyword=不存在的关键词
token: <有效Token>
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "success",
"data": []
}
/apiv1/save_ppt_outline — 保存 PPT 大纲内容功能说明: 更新指定 AI 消息的 content 字段,用于保存用户编辑后的 PPT 大纲。
是否需要认证: 是
请求方式: POST
请求体(JSON): | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | ai_message_id | int | 是 | AI 消息 ID | | content | string | 是 | PPT 大纲内容 |
测试用例:
// 请求
POST /apiv1/save_ppt_outline
token: <有效Token>
Content-Type: application/json
{
"ai_message_id": 10,
"content": "# 桥梁施工安全培训\n## 一、概述\n## 二、安全要点\n..."
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "保存成功"
}
// 请求
POST /apiv1/save_ppt_outline
// 预期响应 (HTTP 401)
{
"statusCode": 401,
"msg": "未提供认证Token"
}
/apiv1/save_edit_document — 保存编辑文档内容功能说明: 更新指定 AI 消息的 content 字段,用于保存用户编辑后的文档。功能和参数与 save_ppt_outline 完全一致。
是否需要认证: 是
请求方式: POST
请求体(JSON): | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | ai_message_id | int | 是 | AI 消息 ID | | content | string | 是 | 文档内容 |
测试用例:
// 请求
POST /apiv1/save_edit_document
token: <有效Token>
Content-Type: application/json
{
"ai_message_id": 11,
"content": "修改后的文档内容..."
}
// 预期响应 (HTTP 200)
{
"statusCode": 200,
"msg": "保存成功"
}
// 请求
POST /apiv1/save_edit_document
// 预期响应 (HTTP 401)
{
"statusCode": 401,
"msg": "未提供认证Token"
}
| 依赖项 | 说明 |
|---|---|
database.get_db / SessionLocal |
SQLAlchemy 数据库会话 |
models.chat.AIConversation |
对话模型(字段:id, user_id, content, business_type, exam_name, created_at, updated_at, is_deleted) |
models.chat.AIMessage |
消息模型(字段:id, ai_conversation_id, user_id, type, content, prev_user_id, guess_you_want, search_source, created_at, updated_at, is_deleted) |
models.total.RecommendQuestion |
推荐问题模型(字段:id, question, is_deleted, created_at) |
services.qwen_service |
Qwen AI 服务(chat, stream_chat, intent_recognition, extract_keywords) |
utils.prompt_loader.load_prompt |
Prompt 模板加载器(final_answer, ppt_outline, document_writing, guess_questions) |
httpx |
HTTP 异步客户端(用于 RAG 检索和 Dify 调用) |
settings.search.api_url |
RAG 搜索 API 地址 |
settings.dify |
Dify 工作流配置(workflow_url, auth_token, workflow_id) |
| 函数 | 说明 |
|---|---|
_rag_search(message, top_k=5) |
调用搜索 API 做 RAG 检索,返回知识库上下文文本。失败时静默返回空字符串。 |
_build_history_messages(conv_id, limit=10) |
从数据库读取最近对话历史,构建 messages 列表(注意:此函数在文件中定义但未在任何接口中直接调用)。 |