Files
xiaoxia-saas/apps/api/app/core/config.py
T
Xiaoxia AI 749ef7f55a
Tests / test (push) Failing after 30s
Tests / lint (push) Failing after 31s
chore: add production environment configuration system
2026-06-15 18:32:05 +08:00

126 lines
3.7 KiB
Python

from pydantic_settings import BaseSettings, SettingsConfigDict
from typing import Optional
import os
class AppSettings(BaseSettings):
"""应用配置"""
# 基础配置
app_name: str = "xiaoxia-saas"
app_env: str = "development" # development / staging / production
app_version: str = "0.1.0"
debug: bool = True
# API 配置
api_host: str = "0.0.0.0"
api_port: int = 8000
api_prefix: str = "/api/v1"
# 数据库配置
database_url: str = "postgresql+psycopg://postgres:postgres@localhost:5432/xiaoxia_saas"
database_pool_size: int = 20
database_max_overflow: int = 40
database_pool_timeout: int = 30
database_pool_recycle: int = 3600
# Redis 配置
redis_url: str = "redis://localhost:6379/0"
redis_max_connections: int = 50
# Celery 配置
celery_broker_url: str = "redis://localhost:6379/0"
celery_result_backend: str = "redis://localhost:6379/1"
celery_worker_concurrency: int = 4
celery_worker_max_tasks_per_child: int = 1000
# MinIO 配置
minio_endpoint: str = "localhost:9000"
minio_access_key: str = "admin"
minio_secret_key: str = "xiaoxia2026"
minio_bucket: str = "xiaoxia-assets"
minio_secure: bool = False
minio_public_url: str = "http://localhost:9000"
# 日志配置
log_level: str = "INFO"
log_format: str = "json" # json / text
log_file: Optional[str] = None
# CORS 配置
cors_origins: str = "http://localhost:3000,http://localhost:8000"
cors_allow_credentials: bool = True
# 文件上传限制
max_upload_size_mb: int = 1000
allowed_file_types: str = "video/mp4,video/quicktime,video/x-msvideo,audio/mpeg,audio/wav,image/jpeg,image/png,image/gif"
# 安全配置
secret_key: str = "change-me-in-production"
access_token_expire_minutes: int = 60
refresh_token_expire_days: int = 7
# 监控配置(可选)
sentry_dsn: Optional[str] = None
prometheus_port: Optional[int] = None
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
case_sensitive=False,
extra="ignore",
)
@property
def cors_origins_list(self) -> list[str]:
"""解析 CORS origins 为列表"""
return [origin.strip() for origin in self.cors_origins.split(",")]
@property
def allowed_file_types_list(self) -> list[str]:
"""解析允许的文件类型为列表"""
return [ft.strip() for ft in self.allowed_file_types.split(",")]
@property
def is_production(self) -> bool:
"""是否为生产环境"""
return self.app_env == "production"
@property
def is_staging(self) -> bool:
"""是否为 staging 环境"""
return self.app_env == "staging"
@property
def is_development(self) -> bool:
"""是否为开发环境"""
return self.app_env == "development"
# 全局配置实例
_settings: Optional[AppSettings] = None
def get_settings() -> AppSettings:
"""获取配置实例(单例模式)"""
global _settings
if _settings is None:
# 根据环境加载不同的 .env 文件
env = os.getenv("APP_ENV", "development")
env_file = f".env.{env}" if env != "development" else ".env"
# 如果环境特定的配置文件存在,则使用它
if os.path.exists(env_file):
_settings = AppSettings(_env_file=env_file)
else:
_settings = AppSettings()
return _settings
def reload_settings():
"""重新加载配置(用于测试)"""
global _settings
_settings = None
return get_settings()