"""智能问答路由(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/", 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//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//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//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//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)