"""历史记录管理服务,负责管理算法调用历史和用户操作历史""" from typing import List, Dict, Any, Optional from datetime import datetime, timedelta import json import logging from sqlalchemy.orm import Session from sqlalchemy import and_, or_, desc from app.models.models import AlgorithmCall, User, Algorithm from app.utils.file import file_storage logger = logging.getLogger(__name__) class HistoryManager: """历史记录管理器,处理算法调用历史和其他用户操作历史""" def __init__(self): pass def get_user_call_history( self, db: Session, user_id: str, algorithm_id: Optional[str] = None, start_date: Optional[datetime] = None, end_date: Optional[datetime] = None, status: Optional[str] = None, skip: int = 0, limit: int = 100 ) -> List[AlgorithmCall]: """获取用户的调用历史""" query = db.query(AlgorithmCall).filter(AlgorithmCall.user_id == user_id) # 添加过滤条件 if algorithm_id: query = query.filter(AlgorithmCall.algorithm_id == algorithm_id) if start_date: query = query.filter(AlgorithmCall.created_at >= start_date) if end_date: query = query.filter(AlgorithmCall.created_at <= end_date) if status: query = query.filter(AlgorithmCall.status == status) # 按创建时间倒序排列 query = query.order_by(desc(AlgorithmCall.created_at)) # 分页 history = query.offset(skip).limit(limit).all() return history def get_algorithm_call_history( self, db: Session, algorithm_id: str, user_id: Optional[str] = None, start_date: Optional[datetime] = None, end_date: Optional[datetime] = None, status: Optional[str] = None, skip: int = 0, limit: int = 100 ) -> List[AlgorithmCall]: """获取特定算法的调用历史""" query = db.query(AlgorithmCall).filter(AlgorithmCall.algorithm_id == algorithm_id) # 添加过滤条件 if user_id: query = query.filter(AlgorithmCall.user_id == user_id) if start_date: query = query.filter(AlgorithmCall.created_at >= start_date) if end_date: query = query.filter(AlgorithmCall.created_at <= end_date) if status: query = query.filter(AlgorithmCall.status == status) # 按创建时间倒序排列 query = query.order_by(desc(AlgorithmCall.created_at)) # 分页 history = query.offset(skip).limit(limit).all() return history def get_call_statistics( self, db: Session, user_id: Optional[str] = None, algorithm_id: Optional[str] = None ) -> Dict[str, Any]: """获取调用统计信息""" query = db.query(AlgorithmCall) if user_id: query = query.filter(AlgorithmCall.user_id == user_id) if algorithm_id: query = query.filter(AlgorithmCall.algorithm_id == algorithm_id) # 总调用次数 total_calls = query.count() # 按状态统计 status_counts = db.query( AlgorithmCall.status, db.func.count(AlgorithmCall.id) ).filter( AlgorithmCall.user_id == user_id if user_id else AlgorithmCall.algorithm_id == algorithm_id ).group_by(AlgorithmCall.status).all() status_dict = {status: count for status, count in status_counts} # 成功率 success_count = status_dict.get('success', 0) success_rate = (success_count / total_calls * 100) if total_calls > 0 else 0 # 平均响应时间 avg_response_time = db.query( db.func.avg(AlgorithmCall.response_time) ).filter( AlgorithmCall.response_time.isnot(None), AlgorithmCall.user_id == user_id if user_id else AlgorithmCall.algorithm_id == algorithm_id ).scalar() # 今日调用次数 today_start = datetime.combine(datetime.today().date(), datetime.min.time()) today_calls = query.filter(AlgorithmCall.created_at >= today_start).count() return { "total_calls": total_calls, "status_counts": status_dict, "success_rate": round(success_rate, 2), "avg_response_time": round(avg_response_time, 3) if avg_response_time else None, "today_calls": today_calls } def get_comparison_data( self, db: Session, call_ids: List[str] ) -> List[Dict[str, Any]]: """获取用于对比的历史数据""" calls = db.query(AlgorithmCall).filter(AlgorithmCall.id.in_(call_ids)).all() comparison_data = [] for call in calls: comparison_data.append({ "id": call.id, "algorithm_id": call.algorithm_id, "algorithm_name": getattr(call.algorithm, 'name', 'Unknown'), "version_id": call.version_id, "input_data": call.input_data, "output_data": call.output_data, "params": call.params, "status": call.status, "response_time": call.response_time, "created_at": call.created_at.isoformat() if call.created_at else None, "error_message": call.error_message }) return comparison_data def export_history( self, db: Session, user_id: str, algorithm_id: Optional[str] = None, start_date: Optional[datetime] = None, end_date: Optional[datetime] = None, format_type: str = "json" ) -> Optional[str]: """导出历史记录""" history = self.get_user_call_history( db=db, user_id=user_id, algorithm_id=algorithm_id, start_date=start_date, end_date=end_date, skip=0, limit=10000 # 限制导出数量 ) # 转换为可序列化的格式 export_data = [] for call in history: export_data.append({ "id": call.id, "user_id": call.user_id, "algorithm_id": call.algorithm_id, "algorithm_name": getattr(call.algorithm, 'name', 'Unknown'), "version_id": call.version_id, "version_number": getattr(call.version, 'version', 'Unknown'), "input_data": call.input_data, "output_data": call.output_data, "params": call.params, "status": call.status, "response_time": call.response_time, "created_at": call.created_at.isoformat() if call.created_at else None, "updated_at": call.updated_at.isoformat() if call.updated_at else None, "error_message": call.error_message }) try: if format_type.lower() == "json": json_str = json.dumps(export_data, ensure_ascii=False, default=str) file_path = f"exports/history_{user_id}_{datetime.utcnow().strftime('%Y%m%d_%H%M%S')}.json" # 上传到存储 success = file_storage.upload_from_bytes(json_str.encode('utf-8'), file_path) if success: return file_path else: logger.error("Failed to upload exported history") return None else: logger.error(f"Unsupported export format: {format_type}") return None except Exception as e: logger.error(f"Error exporting history: {str(e)}") return None def delete_old_history( self, db: Session, days_old: int, user_id: Optional[str] = None, algorithm_id: Optional[str] = None ) -> int: """删除旧的历史记录""" cutoff_date = datetime.utcnow() - timedelta(days=days_old) query = db.query(AlgorithmCall).filter(AlgorithmCall.created_at < cutoff_date) if user_id: query = query.filter(AlgorithmCall.user_id == user_id) if algorithm_id: query = query.filter(AlgorithmCall.algorithm_id == algorithm_id) deleted_count = query.delete() db.commit() logger.info(f"Deleted {deleted_count} old history records") return deleted_count # 全局历史记录管理器实例 history_manager = HistoryManager()