from pathlib import Path from typing import Annotated, Literal from pydantic import AfterValidator, Field from pydantic_settings import BaseSettings, SettingsConfigDict PROJECT_ROOT = Path(__file__).resolve().parents[1] def resolve_model_dir(value: Path) -> Path: """将模型目录解析为项目根目录下的绝对路径。""" path = value.expanduser() if not path.is_absolute(): path = PROJECT_ROOT / path path = path.resolve() if not path.is_dir(): raise ValueError(f"OCR模型目录不存在: {path}") return path ModelDir = Annotated[Path, AfterValidator(resolve_model_dir)] class Settings(BaseSettings): """应用配置""" model_config = SettingsConfigDict( env_file=PROJECT_ROOT / ".env", case_sensitive=False, extra="ignore", ) host: str = "0.0.0.0" port: int = 15651 debug: bool = False # OCR阶段 ocr_use_det: bool = True ocr_use_cls: bool = False ocr_use_rec: bool = True # 模型与常用调优参数 ocr_model_dir: ModelDir = Path("model") ocr_text_score: float = Field(default=0.5, ge=0.0, le=1.0) ocr_max_side_len: int = Field(default=2000, ge=32, le=16384) ocr_det_limit_side_len: int = Field(default=736, ge=32, le=8192) ocr_det_box_thresh: float = Field(default=0.5, ge=0.0, le=1.0) ocr_det_thresh: float = Field(default=0.3, ge=0.0, le=1.0) ocr_rec_batch_num: int = Field(default=6, ge=1, le=256) # 推理设备 ocr_device: Literal["cpu", "cuda", "dml", "tensorrt"] = "cpu" ocr_device_id: int = Field(default=0, ge=0) ocr_intra_threads: int = Field(default=4, ge=1) ocr_inter_threads: int = Field(default=2, ge=1) # 竖排文字补充通道(边缘带旋转90°检测,需 model/PP-OCRv4 目录下的 server 模型) ocr_enable_vertical: bool = False settings = Settings()