diff --git a/bruno/survey/report-callback.bru b/bruno/survey/report-callback.bru new file mode 100644 index 0000000..17007c4 --- /dev/null +++ b/bruno/survey/report-callback.bru @@ -0,0 +1,15 @@ +meta { + name: report-callback + type: http + seq: 3 +} + +post { + url: http://120.26.23.172/api/report-callback + body: none + auth: inherit +} + +settings { + encodeUrl: true +} diff --git a/enhanced_survey_system.py b/enhanced_survey_system.py index 2f2fde3..bfebfb7 100644 --- a/enhanced_survey_system.py +++ b/enhanced_survey_system.py @@ -176,36 +176,22 @@ class ReportGenerator: analysis_data = self.generate_analysis_text({'id': session_id}) # 调用自定义API生成报告 - report_result = self.call_report_api(analysis_data) + # 构造回调URL + report_result = self.call_report_api(analysis_data, session_id) - if report_result: - # 提取学员信息用于更新报告数据 - student_info = analysis_data['student_info'] - report_result['studentInfo']['name'] = student_info.get('name', '未知') - report_result['studentInfo']['school'] = student_info.get('school', '未知') - report_result['studentInfo']['grade'] = student_info.get('grade', '未知') - report_result['studentInfo']['subject'] = '科学' - report_result['studentInfo']['testDate'] = get_east8_time().strftime('%Y年%m月%d日') - - # 构造报告数据 - report_data = { - 'studentInfo': report_result['studentInfo'], - 'report': report_result['report'], - 'generated_at': get_east8_time().isoformat(), - 'session_id': session_id, - 'analysis_data': analysis_data - } - - # 保存报告到数据库 - self.save_report_to_db(session_id, report_data, analysis_data) + if report_result and report_result.get('success'): + # API调用成功,异步生成中 + # 保存分析数据用于后续回调处理 + self.save_analysis_data_for_regeneration(session_id, analysis_data) return { 'success': True, - 'report_data': report_data, + 'message': '报告异步生成中', + 'session_id': session_id, 'analysis_data': analysis_data } else: - raise Exception("API返回空内容") + raise Exception("API调用失败") except Exception as e: print(f"生成报告失败: {e}") @@ -218,87 +204,42 @@ class ReportGenerator: 'can_regenerate': True } - def call_report_api(self, analysis_data): + def call_report_api(self, analysis_data, session_id): """调用自定义报告API生成报告""" # 构建请求数据 request_data = { - "analysis_text": analysis_data['analysis_text'] + "analysis_text": analysis_data['analysis_text'], + "session_id": session_id } - + # 实现重试机制 max_retries = 3 retry_delay = 2 # 秒 - for attempt in range(max_retries): - try: - print(f"调用报告生成API (尝试 {attempt + 1}/{max_retries})...") - print(f" API端点: {self.api_url}") - print(f" 数据长度: {len(request_data['analysis_text'])} 字符") + try: + print(f"调用报告生成API...") + print(f" API端点: {self.api_url}") + print(f" Session ID: {session_id}") + print(f" 数据长度: {len(request_data['analysis_text'])} 字符") + + response = requests.post( + self.api_url, + headers=self.headers, + json=request_data, + timeout=10 # 简化超时时间 + ) + + if response.status_code == 200: + result = response.json() + print(f"✅ API调用成功,已提交异步报告生成请求") + print(f" 响应内容: {str(result)[:200]}...") + return {"success": True, "message": "异步报告生成请求已提交"} + else: + raise Exception(f"API调用失败: HTTP {response.status_code} - {response.text}") - response = requests.post( - self.api_url, - headers=self.headers, - json=request_data, - timeout=self.timeout - ) - - if response.status_code == 200: - result = response.json() - - # 验证响应格式 - if 'studentInfo' in result and 'report' in result: - print(f"✅ API调用成功,生成报告数据") - return result - else: - print(f"⚠️ API响应格式异常,但继续处理") - print(f" 响应内容: {str(result)[:200]}...") - return result - - elif response.status_code == 401: - raise Exception("API密钥无效或已过期") - - elif response.status_code == 429: - # 速率限制,增加等待时间 - wait_time = retry_delay * (2 ** attempt) - print(f"API速率限制,等待 {wait_time} 秒后重试...") - time.sleep(wait_time) - continue - - elif response.status_code >= 500: - # 服务器错误,重试 - wait_time = retry_delay * (2 ** attempt) - print(f"API服务器错误 ({response.status_code}),{wait_time} 秒后重试...") - time.sleep(wait_time) - continue - - else: - raise Exception(f"API调用失败: HTTP {response.status_code} - {response.text}") - - except requests.exceptions.Timeout: - wait_time = retry_delay * (2 ** attempt) - print(f"API请求超时,{wait_time} 秒后重试...") - if attempt < max_retries - 1: - time.sleep(wait_time) - else: - raise Exception(f"API请求超时,已达到最大重试次数 ({self.timeout}秒)") - - except requests.exceptions.ConnectionError: - wait_time = retry_delay * (2 ** attempt) - print(f"API连接错误,{wait_time} 秒后重试...") - if attempt < max_retries - 1: - time.sleep(wait_time) - else: - raise Exception("API连接失败,已达到最大重试次数") - - except Exception as e: - if attempt == max_retries - 1: - raise Exception(f"API调用失败: {str(e)}") - else: - wait_time = retry_delay * (2 ** attempt) - print(f"API调用出错: {e},{wait_time} 秒后重试...") - time.sleep(wait_time) - - return None + except Exception as e: + print(f"API调用出错: {e}") + raise Exception(f"报告生成API调用失败: {str(e)}") def save_report_to_db(self, session_id, report_data, analysis_data): """保存报告到数据库""" @@ -499,7 +440,7 @@ class EnhancedSurveySystem: analysis_data = json.loads(result[0]) # 调用API生成报告 - report_result = self.report_generator.call_report_api(analysis_data) + report_result = self.report_generator.call_report_api(analysis_data, session_id) if report_result: # 提取学员信息用于更新报告数据 @@ -551,4 +492,4 @@ class EnhancedSurveySystem: conn.close() # 全局系统实例 -enhanced_system = EnhancedSurveySystem() \ No newline at end of file +enhanced_system = EnhancedSurveySystem() diff --git a/main.py b/main.py index 1392017..e10a375 100644 --- a/main.py +++ b/main.py @@ -14,7 +14,7 @@ from pydantic import BaseModel from typing import Dict, List, Optional, Any import asyncio import threading -from enhanced_survey_system import enhanced_system, get_east8_time_string +from enhanced_survey_system import enhanced_system, get_east8_time_string, get_east8_time app = FastAPI(title="Enhanced Survey System") @@ -49,6 +49,10 @@ class SaveAnswersRequest(BaseModel): class GenerateReportRequest(BaseModel): sessionId: str +class ReportCallbackRequest(BaseModel): + session_id: str + data: Dict[str, Any] + class SessionResponse(BaseModel): success: bool sessionId: str @@ -1030,6 +1034,80 @@ def generate_quiz_page(session_data: sqlite3.Row, session_id: str) -> str: ''' +@app.post("/api/report-callback", response_model=ApiResponse) +async def report_callback(request: ReportCallbackRequest): + """接收异步报告生成完成的回调数据""" + session_id = request.session_id + report_data = request.data + + if not session_id or not report_data: + raise HTTPException(status_code=400, detail="session_id和data不能为空") + + try: + # 验证会话是否存在 + conn = sqlite3.connect('data/survey.db') + cursor = conn.cursor() + + cursor.execute(''' + SELECT id FROM quiz_sessions WHERE id = ? + ''', (session_id,)) + + session_exists = cursor.fetchone() + if not session_exists: + conn.close() + raise HTTPException(status_code=404, detail="会话不存在") + + # 获取分析数据(如果有保存的话) + cursor.execute(''' + SELECT analysis_data FROM temp_analysis_data + WHERE session_id = ? + ORDER BY created_at DESC + LIMIT 1 + ''', (session_id,)) + + analysis_result = cursor.fetchone() + analysis_data = json.loads(analysis_result[0]) if analysis_result else {} + + # 构造完整的报告数据 + full_report_data = { + 'studentInfo': report_data.get('studentInfo', {}), + 'report': report_data.get('report', {}), + 'generated_at': get_east8_time().isoformat(), + 'session_id': session_id, + 'analysis_data': analysis_data + } + + # 保存报告到数据库 + report_id = str(uuid.uuid4()) + cursor.execute(''' + INSERT INTO reports (id, session_id, report_data, analysis_data, generated_at) + VALUES (?, ?, ?, ?, ?) + ''', (report_id, session_id, json.dumps(full_report_data), json.dumps(analysis_data), get_east8_time_string())) + + # 更新会话状态为已完成 + cursor.execute(''' + UPDATE quiz_sessions + SET status = 'completed', completed_at = ? + WHERE id = ? + ''', (get_east8_time_string(), session_id)) + + conn.commit() + conn.close() + + print(f"✅ 回调处理成功: {session_id}") + print(f" 报告ID: {report_id}") + + return ApiResponse( + success=True, + message='回调数据处理成功' + ) + + except HTTPException: + raise + except Exception as e: + print(f"❌ 回调处理失败: {e}") + raise HTTPException(status_code=500, detail=f"回调处理失败: {str(e)}") + if __name__ == "__main__": import uvicorn uvicorn.run("main:app", host="0.0.0.0", port=8000, reload=True) \ No newline at end of file