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()
|