from __future__ import annotations from functools import lru_cache from pathlib import Path from typing import Tuple, Type from pydantic import Field from pydantic_settings import BaseSettings, SettingsConfigDict from pydantic_settings.sources import ( DotEnvSettingsSource, EnvSettingsSource, PydanticBaseSettingsSource, ) def _repo_root() -> Path: # services/ingest_service/app/core/config.py -> .../MNOTE return Path(__file__).resolve().parents[4] class Settings(BaseSettings): """Ingest Service 配置(优先读取仓库根目录的 .env.local/.env)。""" model_config = SettingsConfigDict( env_file=( str(_repo_root() / ".env.local"), str(_repo_root() / ".env"), ), env_file_encoding="utf-8", case_sensitive=False, extra="ignore", ) # 服务基础 app_name: str = Field("AIMNOTE Ingest Service", env="INGEST_APP_NAME") environment: str = Field("development", env="INGEST_ENV") api_prefix: str = "/api" # Supabase(通过 Kong: http://127.0.0.1:18000) supabase_url: str = Field("http://127.0.0.1:18000", env="SUPABASE_URL") supabase_service_role_key: str = Field("", env="SUPABASE_SERVICE_ROLE_KEY") # LightRAG(独立服务 7777) lightrag_url: str = Field("http://127.0.0.1:7777", env="LIGHTRAG_URL") lightrag_api_key: str = Field("", env="LIGHTRAG_API_KEY") # 自动入库(rag_index_sources -> LightRAG) auto_index_enabled: bool = Field(True, env="AUTO_INDEX_ENABLED") auto_index_interval_seconds: int = Field(5, env="AUTO_INDEX_INTERVAL_SECONDS") auto_index_batch_size: int = Field(5, env="AUTO_INDEX_BATCH_SIZE") auto_index_max_attempts: int = Field(6, env="AUTO_INDEX_MAX_ATTEMPTS") # 删除宽限期(用于“可撤销删除”):例如用户误删后 10 分钟内可恢复,宽限期内不清理 OCR / Storage / LightRAG 资源 delete_grace_seconds: int = Field(600, env="DELETE_GRACE_SECONDS") # MinerU(用于 OCR / PDF 结构化解析) mineru_enabled: bool = Field(True, env="MINERU_ENABLED") mineru_endpoint: str = Field("", env="MINERU_ENDPOINT") @classmethod def settings_customise_sources( cls, settings_cls: Type[BaseSettings], init_settings: PydanticBaseSettingsSource, env_settings: EnvSettingsSource, dotenv_settings: DotEnvSettingsSource, file_secret_settings: PydanticBaseSettingsSource, ) -> Tuple[PydanticBaseSettingsSource, ...]: # 关键点:优先使用 .env.local/.env 覆盖系统环境变量,避免被机器上的全局 env 污染。 return ( dotenv_settings, env_settings, init_settings, file_secret_settings, ) @lru_cache() def get_settings() -> Settings: return Settings()