Spaces:
Sleeping
Sleeping
| #!/usr/bin/env python3 | |
| import os | |
| import sys | |
| import shutil | |
| import json | |
| import sqlite3 | |
| import tarfile | |
| import tempfile | |
| import subprocess | |
| import datetime | |
| from huggingface_hub import HfApi, login, hf_hub_download | |
| DB_TARGET = "/app/server/data/freeapi.db" | |
| DATASET_REPO = "lydgs/freellm-backup" | |
| CONFIG_PREFIX = "config_export" | |
| BACKUP_PREFIX = "freeapi_backup" | |
| def import_json_to_db(json_dir, db_path): | |
| """从 JSON 文件目录重建数据库""" | |
| if not os.path.exists(json_dir): | |
| return False | |
| os.makedirs(os.path.dirname(db_path), exist_ok=True) | |
| if os.path.exists(db_path): | |
| os.remove(db_path) | |
| conn = sqlite3.connect(db_path) | |
| cursor = conn.cursor() | |
| for json_file in os.listdir(json_dir): | |
| if not json_file.endswith('.json'): | |
| continue | |
| table_name = json_file[:-5] | |
| with open(os.path.join(json_dir, json_file), 'r', encoding='utf-8') as f: | |
| data = json.load(f) | |
| if not data: | |
| continue | |
| # 获取列名 | |
| columns = list(data[0].keys()) | |
| # 创建表 | |
| cursor.execute(f"DROP TABLE IF EXISTS {table_name}") | |
| cursor.execute(f"CREATE TABLE {table_name} ({', '.join(columns)})") | |
| # 插入数据 | |
| placeholders = ', '.join('?' for _ in columns) | |
| for row in data: | |
| values = [row[col] for col in columns] | |
| cursor.execute(f"INSERT INTO {table_name} VALUES ({placeholders})", values) | |
| conn.commit() | |
| conn.close() | |
| return True | |
| def restore_from_json(): | |
| """优先尝试从 JSON 包恢复,成功返回 True""" | |
| token = os.getenv("HF_TOKEN") | |
| if not token: | |
| return False | |
| login(token=token) | |
| api = HfApi() | |
| try: | |
| files = api.list_repo_files(repo_id=DATASET_REPO, repo_type="dataset") | |
| config_files = [f for f in files if f.startswith(CONFIG_PREFIX) and f.endswith('.tar.gz')] | |
| if not config_files: | |
| return False | |
| config_files.sort(reverse=True) | |
| latest_config = config_files[0] | |
| print(f"🔄 发现 JSON 配置包: {latest_config},重建数据库...") | |
| with tempfile.TemporaryDirectory() as tmpdir: | |
| downloaded = hf_hub_download( | |
| repo_id=DATASET_REPO, | |
| filename=latest_config, | |
| repo_type="dataset", | |
| local_dir=tmpdir | |
| ) | |
| extract_dir = os.path.join(tmpdir, "extract") | |
| os.makedirs(extract_dir, exist_ok=True) | |
| with tarfile.open(downloaded, "r:gz") as tar: | |
| tar.extractall(extract_dir) | |
| if import_json_to_db(extract_dir, DB_TARGET): | |
| print(f"✅ 数据库从 JSON 配置重建成功: {DB_TARGET}") | |
| return True | |
| else: | |
| print("⚠️ JSON 导入失败") | |
| return False | |
| except Exception as e: | |
| print(f"⚠️ JSON 恢复出错: {e}") | |
| return False | |
| def restore_from_binary(): | |
| """回退:从二进制 .db 文件恢复""" | |
| token = os.getenv("HF_TOKEN") | |
| if not token: | |
| return False | |
| login(token=token) | |
| api = HfApi() | |
| try: | |
| files = api.list_repo_files(repo_id=DATASET_REPO, repo_type="dataset") | |
| db_files = [f for f in files if f.endswith(".db") and f.startswith(BACKUP_PREFIX)] | |
| if not db_files: | |
| return False | |
| db_files.sort() | |
| latest = db_files[-1] | |
| print(f"🔄 使用二进制备份恢复: {latest}") | |
| downloaded = hf_hub_download( | |
| repo_id=DATASET_REPO, | |
| filename=latest, | |
| repo_type="dataset", | |
| local_dir="/tmp" | |
| ) | |
| os.makedirs(os.path.dirname(DB_TARGET), exist_ok=True) | |
| shutil.copy(downloaded, DB_TARGET) | |
| print(f"✅ 数据库从二进制备份恢复成功: {DB_TARGET}") | |
| os.remove(downloaded) | |
| return True | |
| except Exception as e: | |
| print(f"❌ 二进制恢复失败: {e}") | |
| return False | |
| def create_full_backup(): | |
| """调用备份脚本,生成完整的 .db 和 JSON 包""" | |
| backup_script = "/app/scripts/backup_to_dataset.py" | |
| if not os.path.exists(backup_script): | |
| print("⚠️ 备份脚本不存在,无法创建初始备份") | |
| return False | |
| try: | |
| subprocess.run(["python3", backup_script], check=True) | |
| print("✅ 已执行完整备份(包括 JSON 包)") | |
| return True | |
| except subprocess.CalledProcessError as e: | |
| print(f"❌ 执行备份脚本失败: {e}") | |
| return False | |
| def restore_latest_backup(): | |
| # 1. 优先尝试 JSON 恢复 | |
| if restore_from_json(): | |
| return | |
| # 2. 回退到二进制恢复 | |
| if restore_from_binary(): | |
| return | |
| # 3. 完全无备份,但本地数据库存在 -> 创建完整备份 | |
| if os.path.exists(DB_TARGET): | |
| print("🔄 无任何备份,检测到本地数据库,将创建完整备份(包括 JSON 包)...") | |
| create_full_backup() | |
| else: | |
| print("ℹ️ 本地数据库也不存在,跳过恢复") | |
| if __name__ == "__main__": | |
| restore_latest_backup() |