mingyang22 commited on
Commit
37e9f73
·
verified ·
1 Parent(s): 10c5a9b

Upload folder using huggingface_hub

Browse files
Files changed (3) hide show
  1. persistence.py +111 -0
  2. requirements.txt +1 -0
  3. server.py +14 -30
persistence.py ADDED
@@ -0,0 +1,111 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import sqlite3
3
+ import json
4
+ import shutil
5
+ from pathlib import Path
6
+ from datetime import datetime
7
+
8
+ class PersistenceManager:
9
+ """
10
+ 带云端同步功能的持久化管理器
11
+ 支持本地 SQLite 存储,并可选择同步到 Hugging Face Dataset
12
+ """
13
+ def __init__(self, db_path="data.sqlite", dataset_repo=None, hf_token=None):
14
+ self.db_path = db_path
15
+ self.dataset_repo = dataset_repo or os.getenv("DATASET_REPO_ID")
16
+ self.hf_token = hf_token or os.getenv("HF_TOKEN")
17
+
18
+ # 初始化数据库表
19
+ self._init_db()
20
+
21
+ # 如果在 HF 环境且配置了仓库,则尝试恢复数据
22
+ if self.dataset_repo and self.hf_token:
23
+ self.restore_from_cloud()
24
+
25
+ def _init_db(self):
26
+ """初始化数据库结构"""
27
+ conn = sqlite3.connect(self.db_path)
28
+ cursor = conn.cursor()
29
+ cursor.execute('''
30
+ CREATE TABLE IF NOT EXISTS settings (
31
+ key TEXT PRIMARY KEY,
32
+ value TEXT,
33
+ updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
34
+ )
35
+ ''')
36
+ conn.commit()
37
+ conn.close()
38
+
39
+ def get_all_config(self, default_config):
40
+ """从数据库加载所有配置"""
41
+ conn = sqlite3.connect(self.db_path)
42
+ cursor = conn.cursor()
43
+ cursor.execute('SELECT key, value FROM settings')
44
+ rows = cursor.fetchall()
45
+ conn.close()
46
+
47
+ config = default_config.copy()
48
+ for key, value in rows:
49
+ try:
50
+ # 尝试解析 JSON(以支持列表和字典)
51
+ config[key] = json.loads(value)
52
+ except:
53
+ config[key] = value
54
+ return config
55
+
56
+ def save_config(self, config_dict):
57
+ """保存配置到数据库并同步到云端"""
58
+ conn = sqlite3.connect(self.db_path)
59
+ cursor = conn.cursor()
60
+ now = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
61
+
62
+ for key, value in config_dict.items():
63
+ val_str = json.dumps(value, ensure_ascii=False)
64
+ cursor.execute('''
65
+ INSERT OR REPLACE INTO settings (key, value, updated_at)
66
+ VALUES (?, ?, ?)
67
+ ''', (key, val_str, now))
68
+
69
+ conn.commit()
70
+ conn.close()
71
+
72
+ # 触发云端备份
73
+ if self.dataset_repo and self.hf_token:
74
+ self.save_to_cloud()
75
+
76
+ def restore_from_cloud(self):
77
+ """从 Hugging Face Dataset 下载数据库"""
78
+ try:
79
+ from huggingface_hub import hf_hub_download
80
+ print(f"[*] 正在从云端 Dataset [{self.dataset_repo}] 恢复数据库...")
81
+
82
+ downloaded_path = hf_hub_download(
83
+ repo_id=self.dataset_repo,
84
+ repo_type="dataset",
85
+ filename=self.db_path,
86
+ token=self.hf_token,
87
+ force_download=True
88
+ )
89
+
90
+ shutil.copy(downloaded_path, self.db_path)
91
+ print("✅ 数据库恢复成功")
92
+ except Exception as e:
93
+ print(f"⚠️ 云端恢复跳过或失败: {e}")
94
+
95
+ def save_to_cloud(self):
96
+ """将数据库上传到 Hugging Face Dataset"""
97
+ try:
98
+ from huggingface_hub import HfApi
99
+ api = HfApi(token=self.hf_token)
100
+ print(f"[*] 正在备份数据库到云端 [{self.dataset_repo}]...")
101
+
102
+ api.upload_file(
103
+ path_or_fileobj=self.db_path,
104
+ path_in_repo=self.db_path,
105
+ repo_id=self.dataset_repo,
106
+ repo_type="dataset",
107
+ commit_message=f"Persist Gemini cookies at {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}"
108
+ )
109
+ print("✅ 云端备份成功")
110
+ except Exception as e:
111
+ print(f"❌ 云端备份失败: {e}")
requirements.txt CHANGED
@@ -2,3 +2,4 @@ httpx>=0.25.0
2
  fastapi>=0.104.0
3
  uvicorn>=0.24.0
4
  openai>=1.0.0
 
 
2
  fastapi>=0.104.0
3
  uvicorn>=0.24.0
4
  openai>=1.0.0
5
+ huggingface_hub
server.py CHANGED
@@ -21,6 +21,15 @@ import httpx
21
  import hashlib
22
  import secrets
23
  import asyncio
 
 
 
 
 
 
 
 
 
24
 
25
  # ============ 配置 ============
26
  API_KEY = os.getenv("API_KEY", "sk-geminixxxxx")
@@ -139,7 +148,7 @@ DEFAULT_MODEL_IDS = {
139
  "thinking": "e051ce1aa80aa576",
140
  }
141
 
142
- # 配置存储
143
  _config = {
144
  "SNLM0E": "",
145
  "SECURE_1PSID": "",
@@ -532,39 +541,14 @@ def parse_tool_calls(content: str) -> tuple:
532
 
533
 
534
  def load_config():
535
- """
536
- 加载配置,优先级:
537
- 1. config_data.json (前端保存的配置)
538
- 2. config.py (本地开发配置,仅作为备用)
539
- """
540
  global _config
541
- loaded_from_json = False
542
-
543
- # 优先从 JSON 文件加载
544
- if os.path.exists(CONFIG_FILE):
545
- try:
546
- with open(CONFIG_FILE, "r", encoding="utf-8") as f:
547
- saved = json.load(f)
548
- if saved.get("SNLM0E") and saved.get("SECURE_1PSID"):
549
- _config.update(saved)
550
- loaded_from_json = True
551
- except:
552
- pass
553
-
554
- # 如果 JSON 没有有效配置,尝试从 config.py 加载
555
- if not loaded_from_json:
556
- try:
557
- import config
558
- for key in _config:
559
- if hasattr(config, key) and getattr(config, key):
560
- _config[key] = getattr(config, key)
561
- except:
562
- pass
563
 
564
 
565
  def save_config():
566
- with open(CONFIG_FILE, "w", encoding="utf-8") as f:
567
- json.dump(_config, f, indent=2, ensure_ascii=False)
568
 
569
 
570
  def get_client(auto_refresh: bool = True):
 
21
  import hashlib
22
  import secrets
23
  import asyncio
24
+ from persistence import PersistenceManager
25
+
26
+ # ============ 持久化配置 ============
27
+ # 如果要在 HF 上持久化,请设置 DATASET_REPO_ID 环境变量(例如: 'luoluoluo22/gemini-config')
28
+ pm = PersistenceManager(
29
+ db_path="data.sqlite",
30
+ dataset_repo=os.getenv("DATASET_REPO_ID"),
31
+ hf_token=os.getenv("HF_TOKEN")
32
+ )
33
 
34
  # ============ 配置 ============
35
  API_KEY = os.getenv("API_KEY", "sk-geminixxxxx")
 
148
  "thinking": "e051ce1aa80aa576",
149
  }
150
 
151
+ # 配置存储 (内存中的镜像,初始为默认值)
152
  _config = {
153
  "SNLM0E": "",
154
  "SECURE_1PSID": "",
 
541
 
542
 
543
  def load_config():
544
+ """从本地 SQLite 数据库加载配置"""
 
 
 
 
545
  global _config
546
+ _config = pm.get_all_config(_config)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
547
 
548
 
549
  def save_config():
550
+ """保存配置到 SQLite 并同步到云端"""
551
+ pm.save_config(_config)
552
 
553
 
554
  def get_client(auto_refresh: bool = True):