Build lightweight AI agent admin

This commit is contained in:
Codex
2026-06-08 18:14:59 +08:00
commit e164840f43
2530 changed files with 435693 additions and 0 deletions
+219
View File
@@ -0,0 +1,219 @@
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()