240 lines
8.0 KiB
Python
240 lines
8.0 KiB
Python
# 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:
|
||
current_app.logger.info(f"获取MultiAgents对话列表成功: user_id={user_id}, json={response.json()}")
|
||
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
|
||
}
|