#!/usr/bin/env python3 import sys import requests import json import os from datetime import datetime # 配置项 API_URL = "https://api.valavala.com/v2/user/unit/learn/info" OPERATOR = "Kingson" # 存储目录配置 BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) OUTPUT_DIR = os.path.join(BASE_DIR, "output") TEMPLATE_PATH = os.path.join(BASE_DIR, "assets/template.html") TEST_DATA_PATH = os.path.join(BASE_DIR, "assets/test.json") def init_dirs(): """初始化必要的目录""" if not os.path.exists(OUTPUT_DIR): os.makedirs(OUTPUT_DIR) def parse_params(): """解析并验证输入参数 支持两种模式: 1. 正常模式:python analysis.py [角色ID] [Level] [Unit] 2. 测试模式:python analysis.py test """ if len(sys.argv) == 2 and sys.argv[1].lower() == "test": # 测试模式 return "test", None, None if len(sys.argv) != 4: print("参数错误!使用方式:") print(" 正常模式:python analysis.py [角色ID] [Level] [Unit]") print(" 测试模式:python analysis.py test") sys.exit(1) role_id = sys.argv[1] level = sys.argv[2] unit = sys.argv[3] # 验证角色ID是数字 if not role_id.isdigit(): print("错误:角色ID必须是数字") sys.exit(1) # 处理Level参数,支持Level1/L1/1等格式 level = level.lower().replace("level", "").replace("l", "") if not level.isdigit() or int(level) not in [1, 2]: print("错误:Level只能是1或2,支持格式:Level1/L1/1/Level2/L2/2") sys.exit(1) # 处理Unit参数,支持Unit1/U1/1等格式 unit = unit.lower().replace("unit", "").replace("u", "") if not unit.isdigit() or int(unit) < 1: print("错误:Unit必须是正整数,支持格式:Unit1/U1/1") sys.exit(1) return int(role_id), int(level), int(unit) def request_api(role_id, level, unit): """请求学情分析API 调用接口: https://api.valavala.com/v2/user/unit/learn/info 参数: - operator: Kingson (固定值) - level: L1 或 L2 (根据传入的level参数) - userId: 用户角色ID - unitIndex: 单元号 """ params = { "operator": OPERATOR, "level": f"L{level}", "userId": role_id, "unitIndex": unit } try: response = requests.get(API_URL, params=params, timeout=30) response.raise_for_status() return response.json() except requests.exceptions.Timeout: print("API请求超时,请稍后重试") sys.exit(1) except requests.exceptions.ConnectionError: print("API连接失败,请检查网络连接") sys.exit(1) except requests.exceptions.HTTPError as e: print(f"API返回错误状态码:{e.response.status_code}") sys.exit(1) except Exception as e: print(f"API请求失败:{str(e)}") sys.exit(1) def load_test_data(): """加载测试数据""" try: with open(TEST_DATA_PATH, "r", encoding="utf-8") as f: return json.load(f) except FileNotFoundError: print(f"错误:测试数据文件不存在 {TEST_DATA_PATH}") sys.exit(1) except json.JSONDecodeError as e: print(f"错误:测试数据文件格式不正确 - {str(e)}") sys.exit(1) except Exception as e: print(f"加载测试数据失败:{str(e)}") sys.exit(1) def save_data(role_id, level, unit, data): """保存API返回的原始数据""" timestamp = datetime.now().strftime("%Y%m%d%H%M%S") filename = f"{role_id}_L{level}_U{unit}_{timestamp}.json" file_path = os.path.join(OUTPUT_DIR, filename) with open(file_path, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) return file_path def save_test_data(data): """保存测试数据副本""" timestamp = datetime.now().strftime("%Y%m%d%H%M%S") filename = f"test_data_{timestamp}.json" file_path = os.path.join(OUTPUT_DIR, filename) with open(file_path, "w", encoding="utf-8") as f: json.dump(data, f, ensure_ascii=False, indent=2) return file_path def generate_html(role_id, level, unit, data): """生成可视化HTML报告""" timestamp = datetime.now().strftime("%Y%m%d%H%M%S") filename = f"study_report_{role_id}_L{level}_U{unit}_{timestamp}.html" html_path = os.path.join(OUTPUT_DIR, filename) # 读取模板 with open(TEMPLATE_PATH, "r", encoding="utf-8") as f: template = f.read() # 替换模板中的数据占位符 html_content = template.replace("{{DATA}}", json.dumps(data, ensure_ascii=False)) html_content = html_content.replace("{{ROLE_ID}}", str(role_id)) html_content = html_content.replace("{{LEVEL}}", str(level)) html_content = html_content.replace("{{UNIT}}", str(unit)) html_content = html_content.replace("{{GENERATE_TIME}}", datetime.now().strftime("%Y-%m-%d %H:%M:%S")) # 保存HTML文件 with open(html_path, "w", encoding="utf-8") as f: f.write(html_content) return html_path def main(): init_dirs() role_id, level, unit = parse_params() # 判断是否为测试模式 is_test_mode = role_id == "test" if is_test_mode: print("【测试模式】使用本地测试数据生成报告...") api_data = load_test_data() # 测试模式使用默认值或从数据中读取 role_id = api_data.get("role_id", 99999) level = api_data.get("level", 1) unit = api_data.get("unit", 1) print(f"测试数据:用户{role_id} Level{level} Unit{unit}") else: print(f"正在分析用户{role_id} Level{level} Unit{unit}的学习情况...") # 请求API api_data = request_api(role_id, level, unit) print("API数据获取成功") # 保存原始数据 if is_test_mode: data_path = save_test_data(api_data) else: data_path = save_data(role_id, level, unit, api_data) print(f"原始数据已保存到:{data_path}") # 生成HTML报告 html_path = generate_html(role_id, level, unit, api_data) print(f"可视化报告已生成:{html_path}") print(f"请访问以下地址查看报告:file://{html_path}") if __name__ == "__main__": main()