#!/usr/bin/env python3 """ OSS排行榜管理器 - 从OSS读取和更新排行榜数据 """ import os import json import tempfile from datetime import datetime from pathlib import Path from typing import Dict, List, Any, Optional from .oss_file_manager import OSSFileManager class OSSLeaderboardManager: """OSS排行榜管理器 - 管理存储在OSS中的排行榜数据""" def __init__(self): """初始化OSS排行榜管理器""" self.oss_manager = OSSFileManager() # OSS路径配置 self.leaderboard_path = "atlas_eval/leaderboard/" self.backup_path = "atlas_eval/leaderboard/backup/" self.leaderboard_file = "leaderboard.json" # 完整的OSS路径 self.oss_leaderboard_file = f"{self.leaderboard_path}{self.leaderboard_file}" print(f"📊 OSS排行榜路径: oss://opencompass/{self.oss_leaderboard_file}") print(f"📦 OSS备份路径: oss://opencompass/{self.backup_path}") def load_leaderboard_from_oss(self) -> List[Dict[str, Any]]: """ 从OSS加载排行榜数据 Returns: 排行榜数据列表 """ try: print(f"📥 从OSS加载排行榜数据: {self.oss_leaderboard_file}") # 从OSS下载文件内容 content = self.oss_manager.download_file_content(self.oss_leaderboard_file) if content: leaderboard_data = json.loads(content.decode('utf-8')) print(f"✅ 成功加载 {len(leaderboard_data)} 条排行榜记录") return leaderboard_data else: print("⚠️ OSS中未找到排行榜文件,返回空列表") return [] except Exception as e: print(f"❌ 从OSS加载排行榜失败: {e}") return [] def save_leaderboard_to_oss(self, leaderboard_data: List[Dict[str, Any]], create_backup: bool = True) -> bool: """ 保存排行榜数据到OSS Args: leaderboard_data: 排行榜数据 create_backup: 是否创建备份 Returns: 是否保存成功 """ try: print(f"📤 保存排行榜数据到OSS: {self.oss_leaderboard_file}") # 创建备份(如果需要且现有文件存在) if create_backup: self._create_backup() # 创建临时文件 with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False) as temp_file: json.dump(leaderboard_data, temp_file, indent=2, ensure_ascii=False) temp_file_path = temp_file.name try: # 上传到OSS success = self.oss_manager.upload_file( local_file_path=temp_file_path, oss_file_path=self.oss_leaderboard_file ) if success: print(f"✅ 成功保存 {len(leaderboard_data)} 条排行榜记录到OSS") return True else: print("❌ 上传排行榜文件到OSS失败") return False finally: # 清理临时文件 try: os.unlink(temp_file_path) except: pass except Exception as e: print(f"❌ 保存排行榜到OSS失败: {e}") return False def _create_backup(self) -> bool: """ 创建当前排行榜文件的备份 Returns: 是否备份成功 """ try: # 检查原文件是否存在 if not self.oss_manager.file_exists(self.oss_leaderboard_file): print("📋 原排行榜文件不存在,跳过备份") return True # 生成备份文件名 timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") backup_filename = f"leaderboard.json.backup_{timestamp}" backup_path = f"{self.backup_path}{backup_filename}" # 复制文件到备份路径 success = self.oss_manager.copy_file( source_path=self.oss_leaderboard_file, target_path=backup_path ) if success: print(f"📦 创建备份成功: {backup_path}") return True else: print(f"❌ 创建备份失败: {backup_path}") return False except Exception as e: print(f"❌ 创建备份时出错: {e}") return False def add_evaluation_result(self, result_data: Dict[str, Any]) -> bool: """ 添加新的评测结果到排行榜 Args: result_data: 评测结果数据 Returns: 是否添加成功 """ try: # 加载现有排行榜 leaderboard_data = self.load_leaderboard_from_oss() # 检查是否已存在相同的提交(基于organization和submitted_time) existing_entry = None for i, entry in enumerate(leaderboard_data): if (entry.get("organization") == result_data.get("organization") and entry.get("submitted_time") == result_data.get("submitted_time")): existing_entry = i break if existing_entry is not None: print(f"🔄 更新现有排行榜条目: {result_data.get('organization')}") leaderboard_data[existing_entry] = result_data else: print(f"➕ 添加新的排行榜条目: {result_data.get('organization')}") leaderboard_data.append(result_data) # 按准确率排序 leaderboard_data.sort( key=lambda x: x.get("accuracy", 0), reverse=True ) # 保存到OSS return self.save_leaderboard_to_oss(leaderboard_data) except Exception as e: print(f"❌ 添加评测结果失败: {e}") return False def get_leaderboard_summary(self) -> Dict[str, Any]: """ 获取排行榜摘要信息 Returns: 排行榜摘要 """ try: leaderboard_data = self.load_leaderboard_from_oss() if not leaderboard_data: return {"total_entries": 0, "last_updated": None} # 统计信息 total_entries = len(leaderboard_data) # 获取最新更新时间 latest_time = None for entry in leaderboard_data: eval_time = entry.get("evaluation_timestamp") if eval_time and (latest_time is None or eval_time > latest_time): latest_time = eval_time # 获取最高分 top_scores = {} if leaderboard_data: top_entry = leaderboard_data[0] # 已按准确率排序 top_scores = { "accuracy": top_entry.get("accuracy", 0), "mg_pass_2": top_entry.get("mg_pass_2", 0), "mg_pass_4": top_entry.get("mg_pass_4", 0) } return { "total_entries": total_entries, "last_updated": latest_time, "top_scores": top_scores, "oss_path": self.oss_leaderboard_file } except Exception as e: print(f"❌ 获取排行榜摘要失败: {e}") return {"error": str(e)} def migrate_local_to_oss(self, local_file_path: str) -> bool: """ 将本地排行榜文件迁移到OSS Args: local_file_path: 本地文件路径 Returns: 是否迁移成功 """ try: if not os.path.exists(local_file_path): print(f"❌ 本地文件不存在: {local_file_path}") return False # 读取本地文件 with open(local_file_path, 'r', encoding='utf-8') as f: leaderboard_data = json.load(f) print(f"📤 迁移 {len(leaderboard_data)} 条记录到OSS") # 保存到OSS return self.save_leaderboard_to_oss(leaderboard_data, create_backup=False) except Exception as e: print(f"❌ 迁移文件到OSS失败: {e}") return False if __name__ == "__main__": # 测试OSS排行榜管理器 manager = OSSLeaderboardManager() # 打印摘要信息 summary = manager.get_leaderboard_summary() print(f"📊 排行榜摘要: {summary}") # 测试加载排行榜 leaderboard = manager.load_leaderboard_from_oss() print(f"📋 排行榜条目数: {len(leaderboard)}")