175 lines
4.9 KiB
Python
175 lines
4.9 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
# -*- coding: utf-8 -*-
|
|||
|
|
|
|||
|
|
"""
|
|||
|
|
统一配置加载器
|
|||
|
|
合并分散的配置文件为统一接口
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
import os
|
|||
|
|
import json
|
|||
|
|
import logging
|
|||
|
|
from pathlib import Path
|
|||
|
|
from typing import Any, Dict, Optional
|
|||
|
|
from functools import lru_cache
|
|||
|
|
|
|||
|
|
logger = logging.getLogger(__name__)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class UnifiedConfig:
|
|||
|
|
"""
|
|||
|
|
统一配置管理器
|
|||
|
|
|
|||
|
|
合并多个配置文件,提供统一的访问接口
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
_instance: Optional['UnifiedConfig'] = None
|
|||
|
|
|
|||
|
|
def __new__(cls, config_dir: str = "config"):
|
|||
|
|
if cls._instance is None:
|
|||
|
|
cls._instance = super().__new__(cls)
|
|||
|
|
cls._instance._initialized = False
|
|||
|
|
return cls._instance
|
|||
|
|
|
|||
|
|
def __init__(self, config_dir: str = "config"):
|
|||
|
|
if self._initialized:
|
|||
|
|
return
|
|||
|
|
|
|||
|
|
self._config_dir = Path(config_dir)
|
|||
|
|
self._config: Dict[str, Any] = {}
|
|||
|
|
self._load_all_configs()
|
|||
|
|
self._initialized = True
|
|||
|
|
|
|||
|
|
def _load_all_configs(self):
|
|||
|
|
"""加载所有配置文件"""
|
|||
|
|
config_files = [
|
|||
|
|
("ai_model", "ai_model.json"),
|
|||
|
|
("database", "database.json"),
|
|||
|
|
("paths", "paths.json"),
|
|||
|
|
("resource", "resource.json"),
|
|||
|
|
("system", "system.json"),
|
|||
|
|
("cookies", "cookies.json"),
|
|||
|
|
("engines", "engines.json"),
|
|||
|
|
("poster_gen", "poster_gen.json"),
|
|||
|
|
]
|
|||
|
|
|
|||
|
|
for key, filename in config_files:
|
|||
|
|
filepath = self._config_dir / filename
|
|||
|
|
if filepath.exists():
|
|||
|
|
try:
|
|||
|
|
with open(filepath, 'r', encoding='utf-8') as f:
|
|||
|
|
self._config[key] = json.load(f)
|
|||
|
|
logger.debug(f"已加载配置: {filename}")
|
|||
|
|
except Exception as e:
|
|||
|
|
logger.warning(f"加载配置失败 {filename}: {e}")
|
|||
|
|
self._config[key] = {}
|
|||
|
|
else:
|
|||
|
|
self._config[key] = {}
|
|||
|
|
|
|||
|
|
# 加载环境变量覆盖
|
|||
|
|
self._apply_env_overrides()
|
|||
|
|
|
|||
|
|
logger.info(f"配置加载完成,共 {len(self._config)} 个配置组")
|
|||
|
|
|
|||
|
|
def _apply_env_overrides(self):
|
|||
|
|
"""应用环境变量覆盖"""
|
|||
|
|
env_mappings = {
|
|||
|
|
"DATABASE_HOST": ("database", "host"),
|
|||
|
|
"DATABASE_PORT": ("database", "port"),
|
|||
|
|
"DATABASE_USER": ("database", "user"),
|
|||
|
|
"DATABASE_PASSWORD": ("database", "password"),
|
|||
|
|
"DATABASE_NAME": ("database", "database"),
|
|||
|
|
"AI_MODEL_API_KEY": ("ai_model", "api_key"),
|
|||
|
|
"AI_MODEL_BASE_URL": ("ai_model", "base_url"),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for env_key, (config_group, config_key) in env_mappings.items():
|
|||
|
|
value = os.environ.get(env_key)
|
|||
|
|
if value:
|
|||
|
|
if config_group not in self._config:
|
|||
|
|
self._config[config_group] = {}
|
|||
|
|
self._config[config_group][config_key] = value
|
|||
|
|
logger.debug(f"环境变量覆盖: {env_key}")
|
|||
|
|
|
|||
|
|
def get(self, key: str, default: Any = None) -> Any:
|
|||
|
|
"""
|
|||
|
|
获取配置值
|
|||
|
|
|
|||
|
|
支持点号分隔的路径,如 "database.host"
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
key: 配置键
|
|||
|
|
default: 默认值
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
配置值
|
|||
|
|
"""
|
|||
|
|
parts = key.split(".")
|
|||
|
|
value = self._config
|
|||
|
|
|
|||
|
|
for part in parts:
|
|||
|
|
if isinstance(value, dict) and part in value:
|
|||
|
|
value = value[part]
|
|||
|
|
else:
|
|||
|
|
return default
|
|||
|
|
|
|||
|
|
return value
|
|||
|
|
|
|||
|
|
def get_group(self, group: str) -> Dict[str, Any]:
|
|||
|
|
"""
|
|||
|
|
获取配置组
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
group: 配置组名称
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
配置组字典
|
|||
|
|
"""
|
|||
|
|
return self._config.get(group, {})
|
|||
|
|
|
|||
|
|
@property
|
|||
|
|
def database(self) -> Dict[str, Any]:
|
|||
|
|
"""数据库配置"""
|
|||
|
|
return self.get_group("database")
|
|||
|
|
|
|||
|
|
@property
|
|||
|
|
def ai_model(self) -> Dict[str, Any]:
|
|||
|
|
"""AI 模型配置"""
|
|||
|
|
return self.get_group("ai_model")
|
|||
|
|
|
|||
|
|
@property
|
|||
|
|
def paths(self) -> Dict[str, Any]:
|
|||
|
|
"""路径配置"""
|
|||
|
|
return self.get_group("paths")
|
|||
|
|
|
|||
|
|
@property
|
|||
|
|
def poster_gen(self) -> Dict[str, Any]:
|
|||
|
|
"""海报生成配置"""
|
|||
|
|
return self.get_group("poster_gen")
|
|||
|
|
|
|||
|
|
@property
|
|||
|
|
def engines(self) -> Dict[str, Any]:
|
|||
|
|
"""引擎配置"""
|
|||
|
|
return self.get_group("engines")
|
|||
|
|
|
|||
|
|
@property
|
|||
|
|
def system(self) -> Dict[str, Any]:
|
|||
|
|
"""系统配置"""
|
|||
|
|
return self.get_group("system")
|
|||
|
|
|
|||
|
|
def reload(self):
|
|||
|
|
"""重新加载配置"""
|
|||
|
|
self._config.clear()
|
|||
|
|
self._load_all_configs()
|
|||
|
|
logger.info("配置已重新加载")
|
|||
|
|
|
|||
|
|
def to_dict(self) -> Dict[str, Any]:
|
|||
|
|
"""导出所有配置"""
|
|||
|
|
return self._config.copy()
|
|||
|
|
|
|||
|
|
|
|||
|
|
@lru_cache(maxsize=1)
|
|||
|
|
def get_unified_config() -> UnifiedConfig:
|
|||
|
|
"""获取统一配置实例"""
|
|||
|
|
return UnifiedConfig()
|