123 lines
4.3 KiB
Python
123 lines
4.3 KiB
Python
"""
|
||
FastAPI 应用配置管理
|
||
支持环境变量配置,生产级配置管理
|
||
"""
|
||
|
||
import os
|
||
from pathlib import Path
|
||
from typing import Optional
|
||
import logging
|
||
|
||
try:
|
||
from dotenv import load_dotenv
|
||
except Exception: # pragma: no cover
|
||
load_dotenv = None
|
||
|
||
# 项目根目录
|
||
BASE_DIR = Path(__file__).resolve().parent.parent.parent
|
||
|
||
# 加载 .env(不覆盖已存在的系统环境变量)
|
||
_dotenv_path = BASE_DIR / ".env"
|
||
if load_dotenv is not None and _dotenv_path.exists():
|
||
load_dotenv(dotenv_path=_dotenv_path, override=False)
|
||
|
||
# 环境变量
|
||
ENVIRONMENT = os.getenv('ENV', 'development')
|
||
DEBUG = os.getenv('DEBUG', 'False').lower() == 'true'
|
||
|
||
class Settings:
|
||
"""应用配置类"""
|
||
|
||
# FastAPI 基础配置
|
||
APP_TITLE = "时间序列数据分析系统"
|
||
APP_DESCRIPTION = "支持多格式数据上传、AI增强分析、多语言报告生成"
|
||
APP_VERSION = "2.0.0"
|
||
|
||
# API 暴露模式
|
||
# - full: 暴露 v1 + v2(默认)
|
||
# - v2: 仅暴露 v2 分析接口 + 基础状态接口(禁用 v1 上传/文件/图片接口)
|
||
API_MODE = os.getenv('API_MODE', 'full').strip().lower()
|
||
|
||
# 服务器配置
|
||
HOST = os.getenv('HOST', '0.0.0.0')
|
||
PORT = int(os.getenv('PORT', 60201))
|
||
RELOAD = DEBUG
|
||
|
||
# CORS 配置
|
||
CORS_ORIGINS = os.getenv('CORS_ORIGINS', '*').split(',')
|
||
CORS_ALLOW_CREDENTIALS = True
|
||
CORS_ALLOW_METHODS = ['*']
|
||
CORS_ALLOW_HEADERS = ['*']
|
||
|
||
# 文件上传配置
|
||
UPLOAD_DIR = Path(os.getenv('UPLOAD_DIR', BASE_DIR / 'uploads'))
|
||
UPLOAD_DIR.mkdir(exist_ok=True)
|
||
|
||
MAX_UPLOAD_SIZE = int(os.getenv('MAX_UPLOAD_SIZE', 16 * 1024 * 1024)) # 16MB
|
||
ALLOWED_EXTENSIONS = {'csv'}
|
||
|
||
# 临时文件配置
|
||
TEMP_DIR = Path(os.getenv('TEMP_DIR', BASE_DIR / 'temp'))
|
||
TEMP_DIR.mkdir(exist_ok=True)
|
||
|
||
# 字体配置
|
||
FONTS_DIR = Path(os.getenv('FONTS_DIR', BASE_DIR / 'resource' / 'fonts'))
|
||
FONTS_DIR.mkdir(parents=True, exist_ok=True)
|
||
|
||
# API 配置 (阿里云千问)
|
||
API_KEY = os.getenv('MY_API_KEY', '')
|
||
API_BASE = os.getenv('MY_API_BASE', 'https://dashscope.aliyuncs.com/compatible-mode/v1')
|
||
API_MODEL = os.getenv('MY_MODEL', 'qwen-turbo')
|
||
API_TIMEOUT = int(os.getenv('API_TIMEOUT', 30))
|
||
|
||
# 分析配置
|
||
LANGUAGE_DEFAULT = os.getenv('LANGUAGE_DEFAULT', 'zh')
|
||
ANALYSIS_TIMEOUT = int(os.getenv('ANALYSIS_TIMEOUT', 300)) # 5分钟
|
||
|
||
# 日志配置
|
||
LOG_LEVEL = os.getenv('LOG_LEVEL', 'INFO' if not DEBUG else 'DEBUG')
|
||
LOG_DIR = Path(os.getenv('LOG_DIR', BASE_DIR / 'logs'))
|
||
LOG_DIR.mkdir(exist_ok=True)
|
||
|
||
# 内存管理
|
||
MAX_MEMORY_MB = int(os.getenv('MAX_MEMORY_MB', 500))
|
||
|
||
# v2 (OSS URL) 配置
|
||
# 允许的域名白名单(逗号分隔)。为空时表示不启用域名白名单(仍会做私网/环回 IP 拦截)。
|
||
V2_ALLOWED_HOSTS = [h.strip() for h in os.getenv('V2_ALLOWED_HOSTS', '').split(',') if h.strip()]
|
||
# 是否允许 http(默认仅 https)
|
||
V2_ALLOW_HTTP = os.getenv('V2_ALLOW_HTTP', 'False').lower() == 'true'
|
||
# 是否允许私网/环回地址(仅用于本地开发/冒烟;生产建议保持 False)
|
||
V2_ALLOW_PRIVATE_NETWORKS = os.getenv('V2_ALLOW_PRIVATE_NETWORKS', 'False').lower() == 'true'
|
||
# 下载超时(秒)。requests 支持 (connect, read),这里统一使用 read 超时。
|
||
V2_DOWNLOAD_TIMEOUT_SECONDS = float(os.getenv('V2_DOWNLOAD_TIMEOUT_SECONDS', 30))
|
||
V2_CONNECT_TIMEOUT_SECONDS = float(os.getenv('V2_CONNECT_TIMEOUT_SECONDS', 5))
|
||
|
||
@classmethod
|
||
def get_upload_path(cls, filename: str) -> Path:
|
||
"""获取上传文件的完整路径"""
|
||
return cls.UPLOAD_DIR / filename
|
||
|
||
@classmethod
|
||
def get_temp_path(cls, filename: str) -> Path:
|
||
"""获取临时文件的完整路径"""
|
||
return cls.TEMP_DIR / filename
|
||
|
||
# 日志配置
|
||
def setup_logging():
|
||
"""设置日志系统"""
|
||
logging.basicConfig(
|
||
level=Settings.LOG_LEVEL,
|
||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||
handlers=[
|
||
logging.FileHandler(Settings.LOG_DIR / 'app.log'),
|
||
logging.StreamHandler()
|
||
]
|
||
)
|
||
|
||
# 创建全局配置实例
|
||
settings = Settings()
|
||
|
||
# 启用日志
|
||
setup_logging()
|