209 lines
8.3 KiB
Python
209 lines
8.3 KiB
Python
"""
|
||
配置管理模块
|
||
使用 pydantic-settings 从环境变量 / .env 文件加载配置
|
||
"""
|
||
|
||
from __future__ import annotations
|
||
|
||
from enum import Enum
|
||
from pathlib import Path
|
||
from typing import Optional
|
||
|
||
from pydantic import Field
|
||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||
|
||
|
||
class EmbeddingProvider(str, Enum):
|
||
"""嵌入模型提供商"""
|
||
OPENAI = "openai"
|
||
ZHIPU = "zhipu"
|
||
LOCAL_BGE = "local_bge"
|
||
DASHSCOPE = "dashscope"
|
||
MINIMAX = "minimax"
|
||
|
||
|
||
class OCRProvider(str, Enum):
|
||
"""OCR 识别提供商"""
|
||
PADDLEOCR = "paddleocr"
|
||
ALIYUN = "aliyun"
|
||
TENCENT = "tencent"
|
||
AUTO = "auto"
|
||
DEEPSEEK = "deepseek"
|
||
|
||
|
||
class Settings(BaseSettings):
|
||
"""
|
||
全局配置类,所有配置项均可通过环境变量覆盖。
|
||
环境变量优先级:系统环境变量 > .env 文件 > 默认值
|
||
"""
|
||
|
||
model_config = SettingsConfigDict(
|
||
env_file=".env",
|
||
env_file_encoding="utf-8",
|
||
case_sensitive=False,
|
||
extra="ignore",
|
||
)
|
||
|
||
# ──────────────────────────── 数据库 ────────────────────────────
|
||
DATABASE_URL: str = Field(
|
||
default="sqlite+aiosqlite:///./data/hui_brain.db",
|
||
description="SQLite 数据库连接字符串",
|
||
)
|
||
|
||
# ──────────────────────────── 嵌入模型 ────────────────────────────
|
||
EMBEDDING_PROVIDER: EmbeddingProvider = Field(
|
||
default=EmbeddingProvider.LOCAL_BGE,
|
||
description="嵌入模型提供商: openai / zhipu / local_bge / dashscope",
|
||
)
|
||
EMBEDDING_MODEL: str = Field(
|
||
default="BAAI/bge-large-zh-v1.5",
|
||
description="嵌入模型名称",
|
||
)
|
||
EMBEDDING_DIMENSIONS: int = Field(
|
||
default=1024,
|
||
description="嵌入向量维度",
|
||
)
|
||
|
||
# ── OpenAI ──
|
||
OPENAI_API_KEY: Optional[str] = Field(default=None, description="OpenAI API Key")
|
||
OPENAI_BASE_URL: Optional[str] = Field(
|
||
default=None,
|
||
description="OpenAI 兼容接口地址(可用于代理或第三方兼容服务)",
|
||
)
|
||
|
||
# ── 智谱 AI ──
|
||
ZHIPU_API_KEY: Optional[str] = Field(default=None, description="智谱 AI API Key")
|
||
|
||
# ── 阿里云 DashScope ──
|
||
DASHSCOPE_API_KEY: Optional[str] = Field(
|
||
default=None, description="阿里云 DashScope API Key"
|
||
)
|
||
|
||
# ── 本地 BGE 模型 ──
|
||
LOCAL_BGE_MODEL_PATH: Optional[str] = Field(
|
||
default=None,
|
||
description="本地 BGE 模型路径,为空则自动从 HuggingFace 下载",
|
||
)
|
||
|
||
# ──────────────────────────── OCR ────────────────────────────
|
||
OCR_PROVIDER: OCRProvider = Field(
|
||
default=OCRProvider.AUTO,
|
||
description="OCR 提供商: paddleocr / aliyun / tencent / auto",
|
||
)
|
||
|
||
# ── 阿里云 OCR ──
|
||
ALIYUN_OCR_ACCESS_KEY: Optional[str] = Field(
|
||
default=None, description="阿里云 OCR AccessKey ID"
|
||
)
|
||
ALIYUN_OCR_SECRET: Optional[str] = Field(
|
||
default=None, description="阿里云 OCR AccessKey Secret"
|
||
)
|
||
|
||
# ── 腾讯云 OCR ──
|
||
TENCENT_OCR_SECRET_ID: Optional[str] = Field(
|
||
default=None, description="腾讯云 OCR SecretId"
|
||
)
|
||
TENCENT_OCR_SECRET_KEY: Optional[str] = Field(
|
||
default=None, description="腾讯云 OCR SecretKey"
|
||
)
|
||
|
||
# ── MiniMax ──
|
||
MINIMAX_API_KEY: Optional[str] = Field(default=None, description="MiniMax API Key")
|
||
MINIMAX_BASE_URL: str = Field(
|
||
default="https://api.minimaxi.com/v1",
|
||
description="MiniMax API 地址",
|
||
)
|
||
MINIMAX_EMBEDDING_MODEL: str = Field(
|
||
default="MiniMax-Text-Embedding",
|
||
description="MiniMax 嵌入模型名称",
|
||
)
|
||
MINIMAX_CHAT_MODEL: str = Field(
|
||
default="MiniMax-M2",
|
||
description="MiniMax Chat 模型名称",
|
||
)
|
||
|
||
# ── DeepSeek ──
|
||
DEEPSEEK_API_KEY: Optional[str] = Field(default=None, description="DeepSeek API Key")
|
||
DEEPSEEK_BASE_URL: str = Field(
|
||
default="https://api.deepseek.com",
|
||
description="DeepSeek API 地址(自部署时改为你的服务器地址)",
|
||
)
|
||
DEEPSEEK_OCR_MODEL: str = Field(
|
||
default="deepseek-chat",
|
||
description="DeepSeek OCR 使用的模型名称",
|
||
)
|
||
|
||
# ── LLM(用于查询扩展、实体检测等) ──
|
||
LLM_PROVIDER: str = Field(
|
||
default="minimax",
|
||
description="LLM 提供商: minimax / deepseek / openai",
|
||
)
|
||
|
||
# ──────────────────────────── 数据目录 ────────────────────────────
|
||
DATA_DIR: str = Field(
|
||
default="/app/data",
|
||
description="数据根目录( transcripts / images / exports 的父目录)",
|
||
)
|
||
|
||
# ──────────────────────────── 文本分块 ────────────────────────────
|
||
CHUNK_SIZE: int = Field(default=300, description="文本分块大小(字符数)")
|
||
CHUNK_OVERLAP: int = Field(default=50, description="分块重叠字符数")
|
||
|
||
# ──────────────────────────── 图片搜索 ────────────────────────────
|
||
SEARCH_LIMIT: int = Field(default=3, description="图片搜索默认返回数量(1-10)")
|
||
JUDGE_BATCH_SIZE: int = Field(default=10, description="每次LLM判断的文章数量(1-50)")
|
||
|
||
# ──────────────────────────── OCR ────────────────────────────
|
||
OCR_CONCURRENCY: int = Field(default=1, ge=1, le=10, description="OCR 并发识别数量(1-10),多用户同时上传时控制并发")
|
||
|
||
# ──────────────────────────── CORS ────────────────────────────
|
||
CORS_ORIGINS: list[str] = Field(
|
||
default=["*"],
|
||
description="允许的跨域来源列表",
|
||
)
|
||
|
||
# ──────────────────────────── 企业微信智能机器人(WebSocket 长连接) ────────────────────────────
|
||
WEWORK_BOT_ENABLED: bool = Field(
|
||
default=False,
|
||
description="是否启用企业微信智能机器人(独立进程运行)",
|
||
)
|
||
WEWORK_BOT_ID: Optional[str] = Field(
|
||
default=None,
|
||
description="企业微信智能机器人 ID",
|
||
)
|
||
WEWORK_BOT_SECRET: Optional[str] = Field(
|
||
default=None,
|
||
description="企业微信智能机器人 Secret",
|
||
)
|
||
HUIBRAIN_BASE_URL: str = Field(
|
||
default="http://localhost:8765",
|
||
description="HuiBrain 后端服务地址,企业微信机器人通过此地址调用后端 API(搜索/OCR识别等)。当机器人与后端部署在同一台机器时使用默认值 http://localhost:8765;若机器人独立部署到其他服务器,需改为后端的实际访问地址(如 http://192.168.1.100:8765)",
|
||
)
|
||
|
||
# ──────────────────────────── 属性方法 ────────────────────────────
|
||
|
||
@property
|
||
def transcripts_dir(self) -> Path:
|
||
"""直播文字稿目录"""
|
||
return Path(self.DATA_DIR) / "transcripts"
|
||
|
||
@property
|
||
def images_dir(self) -> Path:
|
||
"""聊天截图目录"""
|
||
return Path(self.DATA_DIR) / "images"
|
||
|
||
@property
|
||
def exports_dir(self) -> Path:
|
||
"""导出文件目录"""
|
||
return Path(self.DATA_DIR) / "exports"
|
||
|
||
def ensure_dirs(self) -> None:
|
||
"""确保所有数据目录存在"""
|
||
for d in (self.transcripts_dir, self.images_dir, self.exports_dir):
|
||
d.mkdir(parents=True, exist_ok=True)
|
||
|
||
|
||
# ──────────────────────────── 全局单例 ────────────────────────────
|
||
|
||
settings = Settings()
|