yu commited on
Commit
930cea8
·
1 Parent(s): 8172aec

feat: 支持 Hugging Face Spaces 和容器持久化存储

Browse files

- 自动检测环境:HF Pro 使用 /data,本地使用 ./data
- 统一所有数据文件路径:
- accounts.json: data/accounts.json
- settings.yaml: data/settings.yaml
- stats.json: data/stats.json
- images/: data/images/

Files changed (4) hide show
  1. Dockerfile +4 -2
  2. core/account.py +5 -2
  3. core/config.py +7 -1
  4. main.py +31 -8
Dockerfile CHANGED
@@ -8,12 +8,14 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
8
  && apt-get autoremove -y \
9
  && rm -rf /var/lib/apt/lists/*
10
  COPY main.py .
11
- # 复制 uptime_tracker 模块
12
- COPY uptime_tracker.py .
13
  # 复制 core 模块
14
  COPY core ./core
15
  # 复制 util 目录
16
  COPY util ./util
 
 
 
 
17
  # 创建数据目录
18
  RUN mkdir -p ./data/images
19
  # 声明数据卷(运行时需要 -v 挂载才能持久化)
 
8
  && apt-get autoremove -y \
9
  && rm -rf /var/lib/apt/lists/*
10
  COPY main.py .
 
 
11
  # 复制 core 模块
12
  COPY core ./core
13
  # 复制 util 目录
14
  COPY util ./util
15
+ # 复制 templates 目录
16
+ COPY templates ./templates
17
+ # 复制 static 目录
18
+ COPY static ./static
19
  # 创建数据目录
20
  RUN mkdir -p ./data/images
21
  # 声明数据卷(运行时需要 -v 挂载才能持久化)
core/account.py CHANGED
@@ -18,8 +18,11 @@ if TYPE_CHECKING:
18
 
19
  logger = logging.getLogger(__name__)
20
 
21
- # 配置文件路径
22
- ACCOUNTS_FILE = "accounts.json"
 
 
 
23
 
24
 
25
  @dataclass
 
18
 
19
  logger = logging.getLogger(__name__)
20
 
21
+ # 配置文件路径 - 自动检测环境
22
+ if os.path.exists("/data"):
23
+ ACCOUNTS_FILE = "/data/accounts.json" # HF Pro 持久化
24
+ else:
25
+ ACCOUNTS_FILE = "data/accounts.json" # 本地存储(统一到 data 目录)
26
 
27
 
28
  @dataclass
core/config.py CHANGED
@@ -87,7 +87,13 @@ class AppConfig(BaseModel):
87
  class ConfigManager:
88
  """配置管理器(单例)"""
89
 
90
- def __init__(self, yaml_path: str = "data/settings.yaml"):
 
 
 
 
 
 
91
  self.yaml_path = Path(yaml_path)
92
  self._config: Optional[AppConfig] = None
93
  self.load()
 
87
  class ConfigManager:
88
  """配置管理器(单例)"""
89
 
90
+ def __init__(self, yaml_path: str = None):
91
+ # 自动检测环境并设置默认路径
92
+ if yaml_path is None:
93
+ if os.path.exists("/data"):
94
+ yaml_path = "/data/settings.yaml" # HF Pro 持久化
95
+ else:
96
+ yaml_path = "data/settings.yaml" # 本地存储
97
  self.yaml_path = Path(yaml_path)
98
  self._config: Optional[AppConfig] = None
99
  self.load()
main.py CHANGED
@@ -1,4 +1,4 @@
1
- import json, time, os, asyncio, uuid, ssl, re, yaml
2
  from datetime import datetime, timezone, timedelta
3
  from typing import List, Optional, Union, Dict, Any
4
  from pathlib import Path
@@ -15,6 +15,27 @@ from util.streaming_parser import parse_json_array_stream_async
15
  from collections import deque
16
  from threading import Lock
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  # 导入认证模块
19
  from core.auth import verify_api_key
20
  from core.session_auth import is_logged_in, login_user, logout_user, require_login, generate_session_secret
@@ -59,7 +80,6 @@ log_buffer = deque(maxlen=3000)
59
  log_lock = Lock()
60
 
61
  # 统计数据持久化
62
- STATS_FILE = "data/stats.json"
63
  stats_lock = asyncio.Lock() # 改为异步锁
64
 
65
  async def load_stats():
@@ -142,12 +162,6 @@ CHAT_URL = config.public_display.chat_url
142
  IMAGE_GENERATION_ENABLED = config.image_generation.enabled
143
  IMAGE_GENERATION_MODELS = config.image_generation.supported_models
144
 
145
- # ---------- 图片存储配置 ----------
146
- if os.path.exists("/data"):
147
- IMAGE_DIR = "/data/images" # HF Pro持久化存储
148
- else:
149
- IMAGE_DIR = "./data/images" # 本地持久化存储
150
-
151
  # ---------- 重试配置 ----------
152
  MAX_NEW_SESSION_TRIES = config.retry.max_new_session_tries
153
  MAX_REQUEST_RETRIES = config.retry.max_request_retries
@@ -315,6 +329,15 @@ async def startup_event():
315
  """应用启动时初始化后台任务"""
316
  global global_stats
317
 
 
 
 
 
 
 
 
 
 
318
  # 加载统计数据
319
  global_stats = await load_stats()
320
  logger.info(f"[SYSTEM] 统计数据已加载: {global_stats['total_requests']} 次请求, {global_stats['total_visitors']} 位访客")
 
1
+ import json, time, os, asyncio, uuid, ssl, re, yaml, shutil
2
  from datetime import datetime, timezone, timedelta
3
  from typing import List, Optional, Union, Dict, Any
4
  from pathlib import Path
 
15
  from collections import deque
16
  from threading import Lock
17
 
18
+ # ---------- 数据目录配置 ----------
19
+ # 自动检测环境:HF Spaces Pro 使用 /data,本地使用 ./data
20
+ if os.path.exists("/data"):
21
+ DATA_DIR = "/data" # HF Pro 持久化存储
22
+ logger_prefix = "[HF-PRO]"
23
+ else:
24
+ DATA_DIR = "./data" # 本地持久化存储
25
+ logger_prefix = "[LOCAL]"
26
+
27
+ # 确保数据目录存在
28
+ os.makedirs(DATA_DIR, exist_ok=True)
29
+
30
+ # 统一的数据文件路径
31
+ ACCOUNTS_FILE = os.path.join(DATA_DIR, "accounts.json")
32
+ SETTINGS_FILE = os.path.join(DATA_DIR, "settings.yaml")
33
+ STATS_FILE = os.path.join(DATA_DIR, "stats.json")
34
+ IMAGE_DIR = os.path.join(DATA_DIR, "images")
35
+
36
+ # 确保图片目录存在
37
+ os.makedirs(IMAGE_DIR, exist_ok=True)
38
+
39
  # 导入认证模块
40
  from core.auth import verify_api_key
41
  from core.session_auth import is_logged_in, login_user, logout_user, require_login, generate_session_secret
 
80
  log_lock = Lock()
81
 
82
  # 统计数据持久化
 
83
  stats_lock = asyncio.Lock() # 改为异步锁
84
 
85
  async def load_stats():
 
162
  IMAGE_GENERATION_ENABLED = config.image_generation.enabled
163
  IMAGE_GENERATION_MODELS = config.image_generation.supported_models
164
 
 
 
 
 
 
 
165
  # ---------- 重试配置 ----------
166
  MAX_NEW_SESSION_TRIES = config.retry.max_new_session_tries
167
  MAX_REQUEST_RETRIES = config.retry.max_request_retries
 
329
  """应用启动时初始化后台任务"""
330
  global global_stats
331
 
332
+ # 文件迁移逻辑:将根目录的旧文件迁移到 data 目录
333
+ old_accounts = "accounts.json"
334
+ if os.path.exists(old_accounts) and not os.path.exists(ACCOUNTS_FILE):
335
+ try:
336
+ shutil.copy(old_accounts, ACCOUNTS_FILE)
337
+ logger.info(f"{logger_prefix} 已迁移 {old_accounts} -> {ACCOUNTS_FILE}")
338
+ except Exception as e:
339
+ logger.warning(f"{logger_prefix} 文件迁移失败: {e}")
340
+
341
  # 加载统计数据
342
  global_stats = await load_stats()
343
  logger.info(f"[SYSTEM] 统计数据已加载: {global_stats['total_requests']} 次请求, {global_stats['total_visitors']} 位访客")