""" ParamHub 工具函数 """ import json import base64 from pathlib import Path from datetime import datetime from werkzeug.utils import secure_filename from config import ( ALLOWED_EXTENSIONS, DEFAULT_CONFIG, CONFIG_FILE, IMAGES_DIR, DATA_DIR ) def allowed_file(filename: str) -> bool: """检查文件扩展名是否允许""" return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS def load_data(file_path: Path): """加载JSON数据文件""" if file_path.exists(): return json.loads(file_path.read_text(encoding='utf-8')) return [] def save_data(file_path: Path, data): """保存JSON数据到文件""" file_path.write_text(json.dumps(data, ensure_ascii=False, indent=2), encoding='utf-8') def load_config() -> dict: """加载网站配置,合并默认值""" if CONFIG_FILE.exists(): loaded = json.loads(CONFIG_FILE.read_text(encoding='utf-8')) result = DEFAULT_CONFIG.copy() result.update(loaded) return result return DEFAULT_CONFIG.copy() def save_config(config: dict): """保存网站配置""" CONFIG_FILE.write_text(json.dumps(config, ensure_ascii=False, indent=2), encoding='utf-8') def get_items_file(category_id: str) -> Path: """获取动态分类的数据文件路径""" return DATA_DIR / f'items_{category_id}.json' def get_llm_config() -> dict: """从 config.json 动态读取 LLM 配置""" config = load_config() return { 'base_url': config.get('llm_base_url', DEFAULT_CONFIG['llm_base_url']), 'api_key': config.get('llm_api_key', DEFAULT_CONFIG['llm_api_key']), 'model': config.get('llm_model', DEFAULT_CONFIG['llm_model']), 'vision_model': config.get('llm_vision_model', DEFAULT_CONFIG['llm_vision_model']), } def parse_date_to_timestamp(date_str: str) -> float | None: """将日期字符串转换为 Unix 时间戳""" if not date_str: return None for fmt in ['%Y-%m-%d', '%Y-%m-%d %H:%M:%S', '%Y/%m/%d']: try: return datetime.strptime(date_str, fmt).timestamp() except (ValueError, TypeError): pass return None def safe_sort_key(x: dict, key: str): """排序时安全获取字段值,缺失时返回合理默认值""" val = x.get(key) if val is None: if key in ['parameters', 'context_length', 'mmlu', 'views']: return 0 elif key in ['publish_date', 'created_at', 'updated_at']: return '' return '' return val def read_image_base64(img_src: str) -> str | None: """将图片路径/base64/URL转换为base64 data URI""" import base64 as b64 if img_src.startswith('data:'): return img_src if img_src.startswith('http'): return img_src # URL 直接传给 LLM # 本地路径 try: img_path = IMAGES_DIR / img_src.replace('/static/uploads/', '') if img_path.exists(): with open(img_path, 'rb') as f: img_data = b64.b64encode(f.read()).decode() ext = img_path.suffix.lower().lstrip('.') mime = f'image/{"jpeg" if ext == "jpg" else ext}' return f'data:{mime};base64,{img_data}' except Exception: pass return None