Add File
This commit is contained in:
279
src/summeryanyfile/config/settings.py
Normal file
279
src/summeryanyfile/config/settings.py
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
"""
|
||||||
|
设置管理 - 处理配置文件和环境变量
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
from typing import Optional, Dict, Any
|
||||||
|
from pathlib import Path
|
||||||
|
import json
|
||||||
|
import logging
|
||||||
|
from dataclasses import dataclass, asdict
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
from ..core.models import ProcessingConfig, ChunkStrategy
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class Settings:
|
||||||
|
"""应用设置"""
|
||||||
|
# LLM配置
|
||||||
|
llm_model: str = "gpt-4o-mini"
|
||||||
|
llm_provider: str = "openai"
|
||||||
|
temperature: float = 0.7
|
||||||
|
max_tokens: int = 4000
|
||||||
|
|
||||||
|
# 处理配置
|
||||||
|
max_slides: int = 25
|
||||||
|
min_slides: int = 5 # 新增:最小页数
|
||||||
|
chunk_size: int = 3000
|
||||||
|
chunk_overlap: int = 200
|
||||||
|
chunk_strategy: str = "paragraph"
|
||||||
|
|
||||||
|
# API配置
|
||||||
|
openai_api_key: Optional[str] = None
|
||||||
|
openai_base_url: Optional[str] = None
|
||||||
|
anthropic_api_key: Optional[str] = None
|
||||||
|
azure_openai_api_key: Optional[str] = None
|
||||||
|
azure_openai_endpoint: Optional[str] = None
|
||||||
|
azure_openai_api_version: str = "2024-02-15-preview"
|
||||||
|
|
||||||
|
# 输出配置
|
||||||
|
output_format: str = "json"
|
||||||
|
output_file: Optional[str] = None
|
||||||
|
|
||||||
|
# 日志配置
|
||||||
|
log_level: str = "INFO"
|
||||||
|
log_file: Optional[str] = None
|
||||||
|
|
||||||
|
# 其他配置
|
||||||
|
progress_bar: bool = True
|
||||||
|
debug_mode: bool = False
|
||||||
|
|
||||||
|
def to_processing_config(self, target_language: str = "zh") -> ProcessingConfig:
|
||||||
|
"""转换为处理配置"""
|
||||||
|
return ProcessingConfig(
|
||||||
|
max_slides=self.max_slides,
|
||||||
|
min_slides=self.min_slides,
|
||||||
|
chunk_size=self.chunk_size,
|
||||||
|
chunk_overlap=self.chunk_overlap,
|
||||||
|
chunk_strategy=ChunkStrategy(self.chunk_strategy),
|
||||||
|
llm_model=self.llm_model,
|
||||||
|
llm_provider=self.llm_provider,
|
||||||
|
temperature=self.temperature,
|
||||||
|
max_tokens=self.max_tokens,
|
||||||
|
target_language=target_language,
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_llm_kwargs(self) -> Dict[str, Any]:
|
||||||
|
"""获取LLM相关的参数"""
|
||||||
|
kwargs = {}
|
||||||
|
|
||||||
|
if self.llm_provider == "openai":
|
||||||
|
if self.openai_api_key:
|
||||||
|
kwargs["api_key"] = self.openai_api_key
|
||||||
|
if self.openai_base_url:
|
||||||
|
kwargs["base_url"] = self.openai_base_url
|
||||||
|
elif self.llm_provider == "anthropic" and self.anthropic_api_key:
|
||||||
|
kwargs["api_key"] = self.anthropic_api_key
|
||||||
|
elif self.llm_provider == "azure":
|
||||||
|
if self.azure_openai_api_key:
|
||||||
|
kwargs["api_key"] = self.azure_openai_api_key
|
||||||
|
if self.azure_openai_endpoint:
|
||||||
|
kwargs["azure_endpoint"] = self.azure_openai_endpoint
|
||||||
|
kwargs["api_version"] = self.azure_openai_api_version
|
||||||
|
|
||||||
|
return kwargs
|
||||||
|
|
||||||
|
def save_to_file(self, file_path: str):
|
||||||
|
"""保存设置到文件"""
|
||||||
|
config_dict = asdict(self)
|
||||||
|
# 移除敏感信息
|
||||||
|
sensitive_keys = [
|
||||||
|
"openai_api_key",
|
||||||
|
"anthropic_api_key",
|
||||||
|
"azure_openai_api_key"
|
||||||
|
]
|
||||||
|
for key in sensitive_keys:
|
||||||
|
if key in config_dict:
|
||||||
|
config_dict[key] = "***"
|
||||||
|
|
||||||
|
with open(file_path, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(config_dict, f, indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
|
logger.info(f"设置已保存到: {file_path}")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_from_file(cls, file_path: str) -> "Settings":
|
||||||
|
"""从文件加载设置"""
|
||||||
|
if not os.path.exists(file_path):
|
||||||
|
logger.warning(f"配置文件不存在: {file_path}")
|
||||||
|
return cls()
|
||||||
|
|
||||||
|
try:
|
||||||
|
with open(file_path, 'r', encoding='utf-8') as f:
|
||||||
|
config_dict = json.load(f)
|
||||||
|
|
||||||
|
# 过滤掉不存在的字段
|
||||||
|
valid_fields = {field.name for field in cls.__dataclass_fields__.values()}
|
||||||
|
filtered_config = {k: v for k, v in config_dict.items() if k in valid_fields}
|
||||||
|
|
||||||
|
return cls(**filtered_config)
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"加载配置文件失败: {e}")
|
||||||
|
return cls()
|
||||||
|
|
||||||
|
|
||||||
|
def load_settings(
|
||||||
|
config_file: Optional[str] = None,
|
||||||
|
env_file: Optional[str] = None,
|
||||||
|
**overrides
|
||||||
|
) -> Settings:
|
||||||
|
"""
|
||||||
|
加载设置
|
||||||
|
|
||||||
|
Args:
|
||||||
|
config_file: 配置文件路径
|
||||||
|
env_file: 环境变量文件路径
|
||||||
|
**overrides: 覆盖参数
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
设置对象
|
||||||
|
"""
|
||||||
|
# 加载环境变量
|
||||||
|
if env_file and os.path.exists(env_file):
|
||||||
|
load_dotenv(env_file)
|
||||||
|
else:
|
||||||
|
# 尝试加载默认的.env文件
|
||||||
|
default_env_files = [".env", ".env.local"]
|
||||||
|
for env_path in default_env_files:
|
||||||
|
if os.path.exists(env_path):
|
||||||
|
load_dotenv(env_path)
|
||||||
|
break
|
||||||
|
|
||||||
|
# 从配置文件加载
|
||||||
|
if config_file:
|
||||||
|
settings = Settings.load_from_file(config_file)
|
||||||
|
else:
|
||||||
|
# 尝试加载默认配置文件
|
||||||
|
default_config_files = [
|
||||||
|
"config.json",
|
||||||
|
"settings.json",
|
||||||
|
os.path.expanduser("~/.summeryanyfile/config.json")
|
||||||
|
]
|
||||||
|
settings = Settings()
|
||||||
|
for config_path in default_config_files:
|
||||||
|
if os.path.exists(config_path):
|
||||||
|
settings = Settings.load_from_file(config_path)
|
||||||
|
break
|
||||||
|
|
||||||
|
# 从环境变量覆盖
|
||||||
|
env_mappings = {
|
||||||
|
"OPENAI_API_KEY": "openai_api_key",
|
||||||
|
"OPENAI_BASE_URL": "openai_base_url",
|
||||||
|
"OPENAI_MODEL": "llm_model", # 支持OPENAI_MODEL环境变量
|
||||||
|
"ANTHROPIC_API_KEY": "anthropic_api_key",
|
||||||
|
"AZURE_OPENAI_API_KEY": "azure_openai_api_key",
|
||||||
|
"AZURE_OPENAI_ENDPOINT": "azure_openai_endpoint",
|
||||||
|
"AZURE_OPENAI_API_VERSION": "azure_openai_api_version",
|
||||||
|
"LLM_MODEL": "llm_model",
|
||||||
|
"LLM_PROVIDER": "llm_provider",
|
||||||
|
"MAX_SLIDES": "max_slides",
|
||||||
|
"MIN_SLIDES": "min_slides",
|
||||||
|
"CHUNK_SIZE": "chunk_size",
|
||||||
|
"CHUNK_OVERLAP": "chunk_overlap",
|
||||||
|
"CHUNK_STRATEGY": "chunk_strategy",
|
||||||
|
"TEMPERATURE": "temperature",
|
||||||
|
"MAX_TOKENS": "max_tokens",
|
||||||
|
"LOG_LEVEL": "log_level",
|
||||||
|
"DEBUG_MODE": "debug_mode",
|
||||||
|
}
|
||||||
|
|
||||||
|
for env_key, attr_name in env_mappings.items():
|
||||||
|
env_value = os.getenv(env_key)
|
||||||
|
if env_value is not None:
|
||||||
|
# 类型转换
|
||||||
|
if attr_name in ["max_slides", "min_slides", "chunk_size", "chunk_overlap", "max_tokens"]:
|
||||||
|
try:
|
||||||
|
env_value = int(env_value)
|
||||||
|
except ValueError:
|
||||||
|
logger.warning(f"无效的整数值 {env_key}={env_value}")
|
||||||
|
continue
|
||||||
|
elif attr_name == "temperature":
|
||||||
|
try:
|
||||||
|
env_value = float(env_value)
|
||||||
|
except ValueError:
|
||||||
|
logger.warning(f"无效的浮点值 {env_key}={env_value}")
|
||||||
|
continue
|
||||||
|
elif attr_name == "debug_mode":
|
||||||
|
env_value = env_value.lower() in ("true", "1", "yes", "on")
|
||||||
|
|
||||||
|
setattr(settings, attr_name, env_value)
|
||||||
|
|
||||||
|
# 应用覆盖参数
|
||||||
|
for key, value in overrides.items():
|
||||||
|
if hasattr(settings, key):
|
||||||
|
setattr(settings, key, value)
|
||||||
|
else:
|
||||||
|
logger.warning(f"未知的设置参数: {key}")
|
||||||
|
|
||||||
|
return settings
|
||||||
|
|
||||||
|
|
||||||
|
def get_default_config_dir() -> Path:
|
||||||
|
"""获取默认配置目录"""
|
||||||
|
config_dir = Path.home() / ".summeryanyfile"
|
||||||
|
config_dir.mkdir(exist_ok=True)
|
||||||
|
return config_dir
|
||||||
|
|
||||||
|
|
||||||
|
def create_default_config():
|
||||||
|
"""创建默认配置文件"""
|
||||||
|
config_dir = get_default_config_dir()
|
||||||
|
config_file = config_dir / "config.json"
|
||||||
|
|
||||||
|
if not config_file.exists():
|
||||||
|
settings = Settings()
|
||||||
|
settings.save_to_file(str(config_file))
|
||||||
|
print(f"默认配置文件已创建: {config_file}")
|
||||||
|
else:
|
||||||
|
print(f"配置文件已存在: {config_file}")
|
||||||
|
|
||||||
|
|
||||||
|
def create_env_template():
|
||||||
|
"""创建环境变量模板文件"""
|
||||||
|
template_content = """# LLM API Keys
|
||||||
|
OPENAI_API_KEY=your_openai_api_key_here
|
||||||
|
# OPENAI_BASE_URL=https://api.openai.com/v1 # 自定义OpenAI API端点(可选)
|
||||||
|
ANTHROPIC_API_KEY=your_anthropic_api_key_here
|
||||||
|
|
||||||
|
# Azure OpenAI (if using Azure)
|
||||||
|
AZURE_OPENAI_API_KEY=your_azure_openai_api_key_here
|
||||||
|
AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/
|
||||||
|
AZURE_OPENAI_API_VERSION=2024-02-15-preview
|
||||||
|
|
||||||
|
# LLM Configuration
|
||||||
|
LLM_MODEL=gpt-4o-mini
|
||||||
|
LLM_PROVIDER=openai
|
||||||
|
TEMPERATURE=0.7
|
||||||
|
MAX_TOKENS=4000
|
||||||
|
|
||||||
|
# Processing Configuration
|
||||||
|
MAX_SLIDES=25
|
||||||
|
MIN_SLIDES=5
|
||||||
|
CHUNK_SIZE=3000
|
||||||
|
CHUNK_OVERLAP=200
|
||||||
|
CHUNK_STRATEGY=paragraph
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
LOG_LEVEL=INFO
|
||||||
|
DEBUG_MODE=false
|
||||||
|
"""
|
||||||
|
|
||||||
|
env_file = Path(".env.template")
|
||||||
|
with open(env_file, 'w', encoding='utf-8') as f:
|
||||||
|
f.write(template_content)
|
||||||
|
|
||||||
|
print(f"环境变量模板已创建: {env_file}")
|
||||||
|
print("请复制为 .env 文件并填入您的API密钥")
|
||||||
Reference in New Issue
Block a user