2026-07-02 23:13:23 +08:00
|
|
|
|
"""智能问答路由(A2)
|
|
|
|
|
|
|
|
|
|
|
|
POST /chat/message 发送消息(SSE 流式)
|
|
|
|
|
|
GET /chat/sessions 会话列表
|
|
|
|
|
|
POST /chat/sessions 创建会话
|
|
|
|
|
|
DELETE /chat/sessions/{id} 删除会话
|
|
|
|
|
|
GET /chat/sessions/{id}/messages 消息记录
|
|
|
|
|
|
POST /chat/messages/{id}/feedback 提交反馈
|
|
|
|
|
|
POST /chat/suggest 推荐追问
|
2026-07-12 14:17:18 +08:00
|
|
|
|
GET /chat/app-opening 获取应用开场配置
|
2026-07-02 23:13:23 +08:00
|
|
|
|
"""
|
|
|
|
|
|
import json
|
|
|
|
|
|
from flask import Blueprint, request, jsonify, Response, current_app
|
|
|
|
|
|
from insurance.chat.service import ChatService
|
|
|
|
|
|
from insurance.middleware.auth_middleware import jwt_required
|
|
|
|
|
|
|
|
|
|
|
|
chat_bp = Blueprint("chat", __name__)
|
|
|
|
|
|
chat_service = ChatService()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@chat_bp.route("/message", methods=["POST"])
|
|
|
|
|
|
@jwt_required
|
|
|
|
|
|
def send_message():
|
|
|
|
|
|
"""发送消息,SSE 流式返回 AI 回答。"""
|
|
|
|
|
|
data = request.get_json()
|
2026-07-12 14:17:18 +08:00
|
|
|
|
if not data:
|
|
|
|
|
|
return jsonify({"code": 1001, "message": "请求体不能为空", "data": None}), 400
|
2026-07-02 23:13:23 +08:00
|
|
|
|
message = data.get("message", "")
|
|
|
|
|
|
session_id = data.get("session_id", "")
|
|
|
|
|
|
filters = data.get("filters", {})
|
|
|
|
|
|
api_token = data.get("api_token", "")
|
|
|
|
|
|
|
|
|
|
|
|
if not message:
|
|
|
|
|
|
return jsonify({"code": 1001, "message": "请输入问题内容", "data": None}), 400
|
|
|
|
|
|
|
|
|
|
|
|
user_id = request.user_id
|
|
|
|
|
|
|
|
|
|
|
|
# 在请求上下文内提前读取配置和捕获 app 对象(生成器运行时上下文已销毁)
|
|
|
|
|
|
default_api_key = current_app.config.get("BAODAN_CHAT_API_KEY", "")
|
|
|
|
|
|
base_url = current_app.config.get("BAODAN_API_URL", "http://localhost:5001")
|
|
|
|
|
|
flask_app = current_app._get_current_object()
|
|
|
|
|
|
|
|
|
|
|
|
def generate():
|
|
|
|
|
|
# 在整个生成器执行期间保持应用上下文
|
|
|
|
|
|
with flask_app.app_context():
|
|
|
|
|
|
try:
|
|
|
|
|
|
for event in chat_service.send_message_stream(
|
|
|
|
|
|
user_id=user_id,
|
|
|
|
|
|
message=message,
|
|
|
|
|
|
session_id=session_id,
|
|
|
|
|
|
filters=filters,
|
|
|
|
|
|
api_token=api_token or default_api_key,
|
|
|
|
|
|
base_url=base_url,
|
|
|
|
|
|
):
|
|
|
|
|
|
yield f"data: {event}\n\n"
|
|
|
|
|
|
except GeneratorExit:
|
|
|
|
|
|
# 客户端断开连接,静默退出
|
|
|
|
|
|
pass
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
import logging
|
|
|
|
|
|
logging.exception(f"SSE 生成器异常: {e}")
|
|
|
|
|
|
yield f"data: {json.dumps({'type': 'error', 'data': {'message': '服务器内部错误'}})}\n\n"
|
|
|
|
|
|
|
|
|
|
|
|
response = Response(generate(), content_type="text/event-stream")
|
|
|
|
|
|
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
|
|
|
|
|
|
response.headers["X-Accel-Buffering"] = "no"
|
|
|
|
|
|
response.headers["Connection"] = "keep-alive"
|
|
|
|
|
|
return response
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@chat_bp.route("/sessions", methods=["GET"])
|
|
|
|
|
|
@jwt_required
|
|
|
|
|
|
def get_sessions():
|
|
|
|
|
|
"""获取当前用户的会话列表。"""
|
2026-07-12 14:17:18 +08:00
|
|
|
|
page = max(1, request.args.get("page", 1, type=int))
|
|
|
|
|
|
page_size = min(100, max(1, request.args.get("page_size", 20, type=int)))
|
2026-07-02 23:13:23 +08:00
|
|
|
|
user_id = request.user_id
|
|
|
|
|
|
result = chat_service.get_sessions(user_id, page, page_size)
|
|
|
|
|
|
return jsonify(result)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@chat_bp.route("/sessions", methods=["POST"])
|
|
|
|
|
|
@jwt_required
|
|
|
|
|
|
def create_session():
|
|
|
|
|
|
"""创建新会话。"""
|
|
|
|
|
|
user_id = request.user_id
|
|
|
|
|
|
result = chat_service.create_session(user_id)
|
|
|
|
|
|
return jsonify(result)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@chat_bp.route("/sessions/<session_id>", methods=["DELETE"])
|
|
|
|
|
|
@jwt_required
|
|
|
|
|
|
def delete_session(session_id):
|
|
|
|
|
|
"""软删除会话。"""
|
|
|
|
|
|
user_id = request.user_id
|
|
|
|
|
|
result = chat_service.delete_session(user_id, session_id)
|
|
|
|
|
|
return jsonify(result)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@chat_bp.route("/sessions/<session_id>/messages", methods=["GET"])
|
|
|
|
|
|
@jwt_required
|
|
|
|
|
|
def get_messages(session_id):
|
|
|
|
|
|
"""获取会话消息记录。"""
|
|
|
|
|
|
user_id = request.user_id
|
|
|
|
|
|
result = chat_service.get_messages(user_id, session_id)
|
|
|
|
|
|
return jsonify(result)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@chat_bp.route("/messages/<message_id>/feedback", methods=["POST"])
|
|
|
|
|
|
@jwt_required
|
|
|
|
|
|
def submit_feedback(message_id):
|
|
|
|
|
|
"""提交回答评分或纠错。"""
|
|
|
|
|
|
data = request.get_json()
|
2026-07-12 14:17:18 +08:00
|
|
|
|
if not data:
|
|
|
|
|
|
return jsonify({"code": 1001, "message": "请求体不能为空", "data": None}), 400
|
2026-07-02 23:13:23 +08:00
|
|
|
|
rating = data.get("rating", "")
|
2026-07-12 14:17:18 +08:00
|
|
|
|
correction = data.get("correction", "")
|
2026-07-02 23:13:23 +08:00
|
|
|
|
user_id = request.user_id
|
|
|
|
|
|
|
|
|
|
|
|
if rating not in ("helpful", "not_helpful"):
|
|
|
|
|
|
return jsonify({"code": 1001, "message": "评分值无效", "data": None}), 400
|
|
|
|
|
|
|
2026-07-12 14:17:18 +08:00
|
|
|
|
result = chat_service.submit_feedback(user_id, message_id, rating, correction)
|
2026-07-02 23:13:23 +08:00
|
|
|
|
return jsonify(result)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@chat_bp.route("/suggest", methods=["POST"])
|
|
|
|
|
|
@jwt_required
|
|
|
|
|
|
def suggest():
|
|
|
|
|
|
"""基于当前回答生成推荐追问。"""
|
|
|
|
|
|
data = request.get_json()
|
2026-07-12 14:17:18 +08:00
|
|
|
|
if not data:
|
|
|
|
|
|
return jsonify({"code": 1001, "message": "请求体不能为空", "data": None}), 400
|
2026-07-02 23:13:23 +08:00
|
|
|
|
message = data.get("message", "")
|
|
|
|
|
|
if not message:
|
|
|
|
|
|
return jsonify({"code": 1001, "message": "请输入回答内容", "data": None}), 400
|
|
|
|
|
|
|
|
|
|
|
|
result = chat_service.get_suggestions(message)
|
|
|
|
|
|
return jsonify(result)
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-07-12 14:17:18 +08:00
|
|
|
|
@chat_bp.route("/app-opening", methods=["GET"])
|
|
|
|
|
|
@jwt_required
|
|
|
|
|
|
def get_app_opening():
|
|
|
|
|
|
"""获取 Dify 应用的开场配置(开场白 + 推荐问题)。"""
|
|
|
|
|
|
api_token = request.args.get("api_token", "")
|
|
|
|
|
|
result = chat_service.get_app_opening(api_token)
|
|
|
|
|
|
return jsonify(result)
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-07-02 23:13:23 +08:00
|
|
|
|
@chat_bp.route("/sessions/<session_id>/rename", methods=["PUT"])
|
|
|
|
|
|
@jwt_required
|
|
|
|
|
|
def rename_session(session_id):
|
|
|
|
|
|
"""重命名会话。"""
|
|
|
|
|
|
data = request.get_json()
|
2026-07-12 14:17:18 +08:00
|
|
|
|
if not data:
|
|
|
|
|
|
return jsonify({"code": 1001, "message": "请求体不能为空", "data": None}), 400
|
2026-07-02 23:13:23 +08:00
|
|
|
|
name = data.get("name", "")
|
|
|
|
|
|
if not name:
|
|
|
|
|
|
return jsonify({"code": 1001, "message": "请输入会话名称", "data": None}), 400
|
|
|
|
|
|
|
|
|
|
|
|
user_id = request.user_id
|
|
|
|
|
|
result = chat_service.rename_session(user_id, session_id, name)
|
|
|
|
|
|
return jsonify(result)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@chat_bp.route("/sessions/<session_id>/auto-name", methods=["POST"])
|
|
|
|
|
|
@jwt_required
|
|
|
|
|
|
def auto_name_session(session_id):
|
|
|
|
|
|
"""根据首条消息自动命名会话。"""
|
|
|
|
|
|
data = request.get_json()
|
2026-07-12 14:17:18 +08:00
|
|
|
|
if not data:
|
|
|
|
|
|
return jsonify({"code": 1001, "message": "请求体不能为空", "data": None}), 400
|
2026-07-02 23:13:23 +08:00
|
|
|
|
first_message = data.get("message", "")
|
|
|
|
|
|
if not first_message:
|
|
|
|
|
|
return jsonify({"code": 1001, "message": "请输入消息内容", "data": None}), 400
|
|
|
|
|
|
|
|
|
|
|
|
user_id = request.user_id
|
|
|
|
|
|
result = chat_service.auto_name_session(user_id, session_id, first_message)
|
|
|
|
|
|
return jsonify(result)
|