220 lines
9.3 KiB
Python
220 lines
9.3 KiB
Python
import os
|
||
from typing import Literal, Optional
|
||
|
||
from pydantic import model_validator
|
||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||
|
||
|
||
class Settings(BaseSettings):
|
||
"""应用配置"""
|
||
# 环境标识
|
||
ENV: Literal["dev", "uat", "prod"] = "dev"
|
||
DEBUG: bool = False
|
||
|
||
# 应用配置
|
||
APP_NAME: str = "FastAPI Demo"
|
||
APP_HOST: str = "0.0.0.0"
|
||
APP_PORT: int = 8000
|
||
|
||
# 数据库配置
|
||
DB_TYPE: Literal["postgresql", "mysql", "sqlserver"] = "postgresql" # 数据库类型
|
||
DB_HOST: str = "localhost"
|
||
DB_PORT: int = 5432
|
||
DB_USER: str = "postgres"
|
||
DB_PASSWORD: str = ""
|
||
DB_NAME: str = "fastapi_db"
|
||
|
||
# 数据库连接URL(可手动配置,否则根据 DB_TYPE 自动拼接)
|
||
DATABASE_URL: Optional[str] = None
|
||
|
||
# 分页配置
|
||
PAGE_SIZE: int = 20
|
||
PAGE_MAX_SIZE: int = 500
|
||
|
||
# 时区配置(IANA时区名称,如 Asia/Shanghai, America/New_York, UTC 等)
|
||
TIMEZONE: str = "Asia/Shanghai"
|
||
|
||
# Redis配置
|
||
REDIS_HOST: str = "localhost"
|
||
REDIS_PORT: int = 6379
|
||
REDIS_PASSWORD: str = ""
|
||
REDIS_DB: int = 0
|
||
REDIS_URL: Optional[str] = None
|
||
|
||
# 缓存配置
|
||
CACHE_DEFAULT_EXPIRE: int = 300 # 默认缓存过期时间(秒)
|
||
CACHE_PREFIX: str = "fastapi:" # 缓存key前缀
|
||
|
||
# JWT配置
|
||
JWT_SECRET_KEY: str = "your-strong-secret-key-change-in-production" # JWT密钥,生产环境必须修改
|
||
JWT_ALGORITHM: str = "HS256" # JWT算法
|
||
ACCESS_TOKEN_EXPIRE_MINUTES: int = 60 * 24 * 7 # Access Token过期时间(分钟)
|
||
REFRESH_TOKEN_EXPIRE_DAYS: int = 30 # Refresh Token过期时间(天)
|
||
ALLOW_MULTI_DEVICE_LOGIN: bool = True # 是否允许多设备同时登录(False=单设备登录,新登录会踢掉旧设备)
|
||
|
||
# 文件存储配置
|
||
FILE_STORAGE_TYPE: str = "minio" # local/oss/minio/azure
|
||
FILE_STORAGE_LOCAL_PATH: Optional[str] = None # 本地存储路径
|
||
# OSS配置
|
||
OSS_ENDPOINT: Optional[str] = None
|
||
OSS_ACCESS_KEY_ID: Optional[str] = None
|
||
OSS_ACCESS_KEY_SECRET: Optional[str] = None
|
||
OSS_BUCKET_NAME: Optional[str] = None
|
||
# Minio配置
|
||
MINIO_ENDPOINT: Optional[str] = None
|
||
MINIO_ACCESS_KEY: Optional[str] = None
|
||
MINIO_SECRET_KEY: Optional[str] = None
|
||
MINIO_BUCKET_NAME: Optional[str] = None
|
||
MINIO_SECURE: bool = False
|
||
# Azure配置
|
||
AZURE_ACCOUNT_NAME: Optional[str] = None
|
||
AZURE_ACCOUNT_KEY: Optional[str] = None
|
||
AZURE_CONTAINER_NAME: Optional[str] = None
|
||
|
||
# OAuth配置
|
||
GRANT_ADMIN_TO_OAUTH_USER: bool = True # 是否给OAuth用户授予管理员权限
|
||
OAUTH_DEFAULT_DEPT_ID: Optional[str] = 'fbsamU5f2VNtjAJhpGJdy' # OAuth用户默认部门ID
|
||
# Gitee OAuth
|
||
GITEE_CLIENT_ID: Optional[str] = None
|
||
GITEE_CLIENT_SECRET: Optional[str] = None
|
||
GITEE_REDIRECT_URI: Optional[str] = 'https://explorer.zq-platform.cn/oauth/gitee/callback'
|
||
# GitHub OAuth
|
||
GITHUB_CLIENT_ID: Optional[str] = None
|
||
GITHUB_CLIENT_SECRET: Optional[str] = None
|
||
GITHUB_REDIRECT_URI: Optional[str] = 'https://explorer.zq-platform.cn/oauth/github/callback'
|
||
# QQ OAuth
|
||
QQ_APP_ID: Optional[str] = None
|
||
QQ_APP_KEY: Optional[str] = None
|
||
QQ_REDIRECT_URI: Optional[str] = 'https://explorer.zq-platform.cn/oauth/qq/callback'
|
||
# Google OAuth
|
||
GOOGLE_CLIENT_ID: Optional[str] = None
|
||
GOOGLE_CLIENT_SECRET: Optional[str] = None
|
||
GOOGLE_REDIRECT_URI: Optional[str] = 'https://explorer.zq-platform.cn/oauth/google/callback'
|
||
# 微信 OAuth
|
||
WECHAT_APP_ID: Optional[str] = None
|
||
WECHAT_APP_SECRET: Optional[str] = None
|
||
WECHAT_REDIRECT_URI: Optional[str] = 'https://explorer.zq-platform.cn/oauth/wechat/callback'
|
||
# Microsoft OAuth
|
||
MICROSOFT_CLIENT_ID: Optional[str] = None
|
||
MICROSOFT_CLIENT_SECRET: Optional[str] = None
|
||
MICROSOFT_REDIRECT_URI: Optional[str] = 'https://explorer.zq-platform.cn/oauth/microsoft/callback'
|
||
# 钉钉 OAuth
|
||
DINGTALK_APP_ID: Optional[str] = None
|
||
DINGTALK_APP_SECRET: Optional[str] = None
|
||
DINGTALK_REDIRECT_URI: Optional[str] = 'https://localhost:5777/oauth/dingtalk/callback'
|
||
DINGTALK_H5_REDIRECT_URI: Optional[str] = 'http://localhost:5174/pages/oauth/dingtalk/callback' # uniapp H5 端回调地址
|
||
# 飞书 OAuth
|
||
FEISHU_APP_ID: Optional[str] = None
|
||
FEISHU_APP_SECRET: Optional[str] = None
|
||
FEISHU_REDIRECT_URI: Optional[str] = 'https://localhost:5777/oauth/feishu/callback'
|
||
FEISHU_H5_REDIRECT_URI: Optional[str] = 'http://localhost:5174/pages/oauth/feishu/callback' # uniapp H5 端回调地址
|
||
# 企业微信 OAuth
|
||
WECOM_CORP_ID: Optional[str] = None
|
||
WECOM_AGENT_ID: Optional[str] = None
|
||
WECOM_APP_SECRET: Optional[str] = None
|
||
WECOM_REDIRECT_URI: Optional[str] = 'https://localhost:5777/oauth/wecom/callback'
|
||
WECOM_H5_REDIRECT_URI: Optional[str] = 'http://localhost:5174/pages/oauth/wecom/callback' # uniapp H5 端回调地址
|
||
|
||
# SMTP 邮件配置
|
||
SMTP_HOST: Optional[str] = None
|
||
SMTP_PORT: int = 465
|
||
SMTP_USER: Optional[str] = None
|
||
SMTP_PASSWORD: Optional[str] = None
|
||
SMTP_USE_TLS: bool = True
|
||
SMTP_FROM_NAME: Optional[str] = None # 发件人显示名称,默认使用 APP_NAME
|
||
SMTP_FROM_EMAIL: Optional[str] = None # 发件人邮箱,默认使用 SMTP_USER
|
||
|
||
# 钉钉通知配置
|
||
DINGTALK_WEBHOOK_URL: Optional[str] = None # 群机器人 Webhook 地址
|
||
DINGTALK_WEBHOOK_SECRET: Optional[str] = None # 群机器人签名密钥
|
||
DINGTALK_AGENT_ID: Optional[str] = None # 企业内部应用 AgentId(工作通知需要)
|
||
DINGTALK_CORP_ID: Optional[str] = None # 企业 CorpId(工作通知需要)
|
||
DINGTALK_TODO_PC_URL: Optional[str] = None # 钉钉待办 PC 端跳转基础 URL
|
||
DINGTALK_TODO_APP_URL: Optional[str] = None # 钉钉待办移动端跳转基础 URL
|
||
|
||
# 飞书通知配置
|
||
FEISHU_WEBHOOK_URL: Optional[str] = None # 群机器人 Webhook 地址
|
||
FEISHU_WEBHOOK_SECRET: Optional[str] = None # 群机器人签名密钥
|
||
|
||
# 企业微信通知配置
|
||
WECOM_WEBHOOK_URL: Optional[str] = None # 群机器人 Webhook 地址
|
||
|
||
# 微信公众号模板消息配置(复用 WECHAT_APP_ID / WECHAT_APP_SECRET)
|
||
WECHAT_MP_TEMPLATE_ID: Optional[str] = None # 模板消息 ID
|
||
WECHAT_MP_URL: Optional[str] = None # 模板消息点击跳转链接
|
||
WECHAT_MP_MINI_APPID: Optional[str] = None # 跳转小程序 appid(可选)
|
||
WECHAT_MP_MINI_PAGE: Optional[str] = None # 跳转小程序页面路径(可选)
|
||
|
||
# 短信通知配置
|
||
SMS_PROVIDER: Optional[str] = None # 短信服务商: aliyun / tencent
|
||
# 阿里云短信
|
||
ALIYUN_SMS_ACCESS_KEY_ID: Optional[str] = None
|
||
ALIYUN_SMS_ACCESS_KEY_SECRET: Optional[str] = None
|
||
ALIYUN_SMS_SIGN_NAME: Optional[str] = None # 短信签名
|
||
ALIYUN_SMS_TEMPLATE_CODE: Optional[str] = None # 短信模板编号
|
||
# 腾讯云短信
|
||
TENCENT_SMS_SECRET_ID: Optional[str] = None
|
||
TENCENT_SMS_SECRET_KEY: Optional[str] = None
|
||
TENCENT_SMS_SDK_APP_ID: Optional[str] = None # 短信应用 SDKAppID
|
||
TENCENT_SMS_SIGN_NAME: Optional[str] = None # 短信签名
|
||
TENCENT_SMS_TEMPLATE_ID: Optional[str] = None # 短信模板 ID
|
||
|
||
# 系统通知用户(用于聊天通知渠道的发送者)
|
||
SYSTEM_NOTIFY_USER_ID: Optional[str] = None
|
||
|
||
# 向量数据库配置(Qdrant)
|
||
VECTOR_STORE_TYPE: str = "qdrant" # 向量存储类型
|
||
QDRANT_HOST: str = "pro.fuadmin.cn"
|
||
QDRANT_PORT: int = 6333
|
||
QDRANT_GRPC_PORT: int = 6334
|
||
QDRANT_API_KEY: Optional[str] = None
|
||
QDRANT_PREFER_GRPC: bool = False
|
||
|
||
# 语音,ocr模型key(优先从数据库 LLMProvider qwen 提供商获取,此处作为兜底)
|
||
DASHSCOPE_API_KEY: Optional[str] = None
|
||
|
||
model_config = SettingsConfigDict(
|
||
env_file=f"env/{os.getenv('ENV', 'dev')}.env",
|
||
env_file_encoding="utf-8",
|
||
case_sensitive=True,
|
||
extra="ignore",
|
||
)
|
||
|
||
@model_validator(mode="after")
|
||
def build_urls(self) -> "Settings":
|
||
"""自动拼接DATABASE_URL和REDIS_URL"""
|
||
if not self.DATABASE_URL:
|
||
if self.DB_TYPE == "mysql":
|
||
self.DATABASE_URL = (
|
||
f"mysql+aiomysql://{self.DB_USER}:{self.DB_PASSWORD}"
|
||
f"@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}?charset=utf8mb4"
|
||
)
|
||
elif self.DB_TYPE == "sqlserver":
|
||
self.DATABASE_URL = (
|
||
f"mssql+aioodbc://{self.DB_USER}:{self.DB_PASSWORD}"
|
||
f"@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"
|
||
f"?driver=ODBC+Driver+18+for+SQL+Server&TrustServerCertificate=yes"
|
||
)
|
||
else:
|
||
self.DATABASE_URL = (
|
||
f"postgresql+asyncpg://{self.DB_USER}:{self.DB_PASSWORD}"
|
||
f"@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"
|
||
)
|
||
if not self.REDIS_URL:
|
||
if self.REDIS_PASSWORD:
|
||
self.REDIS_URL = (
|
||
f"redis://:{self.REDIS_PASSWORD}@{self.REDIS_HOST}:{self.REDIS_PORT}/{self.REDIS_DB}"
|
||
)
|
||
else:
|
||
self.REDIS_URL = f"redis://{self.REDIS_HOST}:{self.REDIS_PORT}/{self.REDIS_DB}"
|
||
return self
|
||
|
||
|
||
def get_settings() -> Settings:
|
||
"""根据环境变量加载对应的配置文件"""
|
||
env = os.getenv("ENV", "dev")
|
||
return Settings(_env_file=f"env/{env}.env")
|
||
|
||
|
||
settings = get_settings()
|