diff --git a/ai/views/oj.py b/ai/views/oj.py index a3b32b0..8779434 100644 --- a/ai/views/oj.py +++ b/ai/views/oj.py @@ -18,7 +18,6 @@ from problem.models import Problem from submission.models import Submission, JudgeStatus from account.decorators import login_required from ai.models import AIAnalysis -from textwrap import dedent # 常量定义 @@ -429,63 +428,42 @@ class AIAnalysisAPI(APIView): client = OpenAI(api_key=api_key, base_url="https://api.deepseek.com") - system_prompt =""" - 你是一个风趣的编程老师,学生使用判题狗平台进行编程练习。 - 请根据学生提供的详细数据和每周数据,给出用户的学习建议。 - 请使用 markdown 格式输出,不要在代码块中输出。 - 最后不要忘记写一句祝福语。 - """ - - user_prompt = f""" - 这段时间内的详细数据: {details} - 每周或每月的数据: {weekly} - """ + system_prompt = "你是一个风趣的编程老师,学生使用判题狗平台进行编程练习。请根据学生提供的详细数据和每周数据,给出用户的学习建议。请使用 markdown 格式输出,不要在代码块中输出。最后不要忘记写一句祝福语。" + user_prompt = f"这段时间内的详细数据: {details} \n每周或每月的数据: {weekly}" analysis_chunks = [] - saved = False - save_error = None - store_error_sent = False + saved_instance = None + completed = False - def try_save(): - nonlocal saved, save_error - if saved: - return - if not analysis_chunks: - saved = True - return - try: - AIAnalysis.objects.create( - user=user, - data={"details": details, "weekly": weekly}, - system_prompt=dedent(system_prompt).strip(), - user_prompt="这段时间内的详细数据, 每周或每月的数据", - analysis="".join(analysis_chunks).strip(), - ) - except Exception as exc: - save_error = str(exc) - finally: - saved = True + def save_analysis(): + nonlocal saved_instance + if analysis_chunks and not saved_instance: + try: + saved_instance = AIAnalysis.objects.create( + user=user, + provider="deepseek", + model="deepseek-chat", + data={"details": details, "weekly": weekly}, + system_prompt=system_prompt, + user_prompt=user_prompt, + analysis="".join(analysis_chunks).strip(), + ) + except Exception: + pass def stream_generator(): - nonlocal store_error_sent + nonlocal completed try: stream = client.chat.completions.create( model="deepseek-chat", messages=[ - { - "role": "system", - "content": system_prompt, - }, - { - "role": "user", - "content": user_prompt, - }, + {"role": "system", "content": system_prompt}, + {"role": "user", "content": user_prompt}, ], stream=True, ) except Exception as exc: - payload = json.dumps({"type": "error", "message": str(exc)}) - yield f"data: {payload}\n\n" + yield f"data: {json.dumps({'type': 'error', 'message': str(exc)})}\n\n" yield "event: end\n\n" return @@ -497,54 +475,26 @@ class AIAnalysisAPI(APIView): continue choice = chunk.choices[0] - finish_reason = getattr(choice, "finish_reason", None) - - delta = getattr(choice, "delta", None) - raw_content = getattr(delta, "content", None) - if raw_content: - if isinstance(raw_content, list): - text_content = "".join( - ( - item.get("text") - if isinstance(item, dict) - else getattr(item, "text", None) or "" - ) - for item in raw_content - ) - else: - text_content = str(raw_content) - - if text_content: - analysis_chunks.append(text_content) - payload = json.dumps( - {"type": "delta", "content": text_content} - ) - yield f"data: {payload}\n\n" - - if finish_reason: - try_save() - if save_error and not store_error_sent: - error_payload = json.dumps( - {"type": "store_error", "message": save_error} - ) - yield f"data: {error_payload}\n\n" - store_error_sent = True - - payload = json.dumps({"type": "done"}) - yield f"data: {payload}\n\n" + if choice.finish_reason: + completed = True + save_analysis() + yield f"data: {json.dumps({'type': 'done'})}\n\n" break - except Exception as exc: - payload = json.dumps({"type": "error", "message": str(exc)}) - yield f"data: {payload}\n\n" - finally: - try_save() - if save_error and not store_error_sent: - error_payload = json.dumps( - {"type": "store_error", "message": save_error} - ) - yield f"data: {error_payload}\n\n" - store_error_sent = True + content = choice.delta.content + if content: + analysis_chunks.append(content) + yield f"data: {json.dumps({'type': 'delta', 'content': content})}\n\n" + + except Exception as exc: + yield f"data: {json.dumps({'type': 'error', 'message': str(exc)})}\n\n" + finally: + save_analysis() + if saved_instance and not completed: + try: + saved_instance.delete() + except Exception: + pass yield "event: end\n\n" response = StreamingHttpResponse(