# myapp/services/course_service.py import re import requests import json from typing import Dict, List, Optional from flask import current_app from urllib.parse import urlparse from datetime import datetime from bson import ObjectId def save_learning_progress(chatmanager, user_id: str) -> bool: """ 保存用户学习进度到MongoDB 参数: - chatmanager: ChatManager实例,包含学习进度数据 - user_id: 用户ID 返回: - bool: 保存是否成功 """ try: # 获取MongoDB连接 mongo = current_app.extensions["mongo"] # 获取MultiAgents框架中的对话列表 dialog_list = get_multiagents_dialog_list(user_id) his_data = dialog_list['data'] # 构建学习进度数据 progress_data = { "user_id": user_id, "material_id": chatmanager.material_id, "chapter_name": chatmanager.chapter_name, "lesson_name": chatmanager.lesson_name, "chapter_chain_now": chatmanager.chapter_chain_now, "chat_historys": chatmanager.chat_historys, "scores": chatmanager.scores, "multiagents_dialogs": his_data, "chapter_chain_length": len(chatmanager.chapter_chain), "updated_at": datetime.now() } # 保存到MongoDB,使用upsert操作(如果存在则更新,不存在则插入) mongo.db.learning_progress.update_one( { "user_id": user_id, "material_id": chatmanager.material_id, "chapter_name": chatmanager.chapter_name, "lesson_name": chatmanager.lesson_name }, {"$set": progress_data}, upsert=True ) current_app.logger.info(f"学习进度保存成功: user_id={user_id}, lesson={chatmanager.lesson_name}") return True except Exception as e: current_app.logger.error(f"保存学习进度失败: {str(e)}") return False def get_multiagents_dialog_list(user_id: str) -> List[Dict]: """ 从MultiAgents框架获取用户对话列表 参数: - user_id: 用户ID 返回: - Dict[List]: 对话列表(key 为 History database) """ try: # 从配置中获取ASE引擎URL和token config = current_app.config url_token = config.get("ASE_ENGINE_URL_TOKEN", "") # 构建请求URL base_url = config.get("ASE_ENGINE_URL", "") api_url = f"{base_url}/api/sync/download" # 构建请求参数 payload = { "namespace_url": url_token, # 使用配置中的token作为namespace_url "user_id": user_id } # 发送POST请求 response = requests.post( api_url, json=payload, headers={"Content-Type": "application/json"}, timeout=10 ) # 检查响应 if response.status_code == 200: return response.json() else: current_app.logger.error(f"获取MultiAgents对话列表失败: HTTP {response.status_code}") return [] except Exception as e: current_app.logger.error(f"获取MultiAgents对话列表异常: {str(e)}") return [] def load_learning_progress(user_id: str, material_id: str, chapter_name: str, lesson_name: str) -> Dict: """ 加载用户学习进度 参数: - user_id: 用户ID - material_id: 课程ID - chapter_name: 章节名 - lesson_name: 课时名 返回: - Dict: 学习进度数据,包含以下字段: - exists: bool,表示学习记录是否存在 - data: Dict,学习进度详细数据,包含chat_historys、scores、chapter_chain_now等字段 - message: str,操作结果描述 """ try: mongo = current_app.extensions["mongo"] progress = mongo.db.learning_progress.find_one({ "user_id": user_id, "material_id": material_id, "chapter_name": chapter_name, "lesson_name": lesson_name }) if progress: # 转换ObjectId为字符串 if "_id" in progress: progress["_id"] = str(progress["_id"]) return { "exists": True, "data": progress, "message": "学习记录加载成功" } # 返回默认值,确保即使没有学习记录也有完整的结构 return { "exists": False, "data": { "user_id": user_id, "material_id": material_id, "chapter_name": chapter_name, "lesson_name": lesson_name, "chat_historys": [], "scores": [], "chapter_chain_now": None, "chapter_chain_length": 0, "updated_at": datetime.now().isoformat() }, "message": "未找到学习记录,返回默认值" } except Exception as e: error_msg = f"加载学习进度失败: {str(e)}" current_app.logger.error(error_msg) # 发生错误时返回默认结构,确保系统稳定性 return { "exists": False, "data": { "user_id": user_id, "material_id": material_id, "chapter_name": chapter_name, "lesson_name": lesson_name, "chat_historys": [], "scores": [], "chapter_chain_now": None, "chapter_chain_length": 0, "updated_at": datetime.now().isoformat() }, "message": error_msg } def upload_learning_progress_to_cloud(progress: Dict) -> Dict: """ 将学习进度上传到云服务 参数: - progress: 学习进度数据字典{'databases':{}, 'global_databases':{}, 'session_info_out':{}} 返回: - Dict: 上传结果,包含success和message字段 """ try: # 从配置中获取ASE引擎URL和token config = current_app.config url_token = config.get("ASE_ENGINE_URL_TOKEN", "") # 构建请求URL base_url = config.get("ASE_ENGINE_URL", "") api_url = f"{base_url}/api/sync/upload" # 导入JSON序列化工具 from ...utils.json_serializer import json_serialize_dict # 序列化进度数据,处理datetime等特殊类型 serialized_progress = json_serialize_dict(progress['multiagents_dialogs']) # 构建请求参数 payload = { "namespace_url": url_token, # 使用配置中的token作为namespace_url "user_id": progress.get("user_id", ""), "data": serialized_progress } # 发送POST请求 response = requests.post( api_url, json=payload, headers={"Content-Type": "application/json"}, timeout=10 ) # 处理响应 if response.status_code == 200: result = response.json() current_app.logger.info(f"学习进度上传成功: user_id={progress.get('user_id')}, 内容:{serialized_progress}") return { "success": True, "message": "学习进度上传成功", "data": result } else: error_msg = f"上传失败,HTTP状态码: {response.status_code}" current_app.logger.error(f"学习进度上传失败: {error_msg}") return { "success": False, "message": error_msg } except Exception as e: error_msg = f"上传异常: {str(e)}" current_app.logger.error(f"学习进度上传异常: {error_msg}") return { "success": False, "message": error_msg }