baodan/api/insurance/chat/routes.py
2026-07-12 14:17:18 +08:00

181 lines
6.3 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""智能问答路由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 推荐追问
GET /chat/app-opening 获取应用开场配置
"""
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()
if not data:
return jsonify({"code": 1001, "message": "请求体不能为空", "data": None}), 400
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():
"""获取当前用户的会话列表。"""
page = max(1, request.args.get("page", 1, type=int))
page_size = min(100, max(1, request.args.get("page_size", 20, type=int)))
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()
if not data:
return jsonify({"code": 1001, "message": "请求体不能为空", "data": None}), 400
rating = data.get("rating", "")
correction = data.get("correction", "")
user_id = request.user_id
if rating not in ("helpful", "not_helpful"):
return jsonify({"code": 1001, "message": "评分值无效", "data": None}), 400
result = chat_service.submit_feedback(user_id, message_id, rating, correction)
return jsonify(result)
@chat_bp.route("/suggest", methods=["POST"])
@jwt_required
def suggest():
"""基于当前回答生成推荐追问。"""
data = request.get_json()
if not data:
return jsonify({"code": 1001, "message": "请求体不能为空", "data": None}), 400
message = data.get("message", "")
if not message:
return jsonify({"code": 1001, "message": "请输入回答内容", "data": None}), 400
result = chat_service.get_suggestions(message)
return jsonify(result)
@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)
@chat_bp.route("/sessions/<session_id>/rename", methods=["PUT"])
@jwt_required
def rename_session(session_id):
"""重命名会话。"""
data = request.get_json()
if not data:
return jsonify({"code": 1001, "message": "请求体不能为空", "data": None}), 400
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()
if not data:
return jsonify({"code": 1001, "message": "请求体不能为空", "data": None}), 400
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)