from dataclasses import dataclass, field from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parents[2] @dataclass(frozen=True) class AppSettings: """FastAPI 基础配置。""" title: str = "Raspberry Pi Camera API" version: str = "0.1.0" description: str = "用于树莓派相机抓拍的 FastAPI 服务。" host: str = "0.0.0.0" port: int = 8002 @dataclass(frozen=True) class CameraSettings: """树莓派相机配置。""" camera_index: int = 0 width: int = 2048 height: int = 2048 frame_format: str = "RGB888" jpeg_quality: int = 95 warmup_seconds: float = 0.05 enable_continuous_autofocus: bool = True enable_auto_white_balance: bool = True @dataclass(frozen=True) class MqttSettings: """MQTT 配置。""" broker: str = "192.168.77.132" port: int = 1883 keep_alive_interval: int = 60 client_id_prefix: str = "arm_camera_api_" request_timeout_seconds: float = 40.0 connect_timeout_seconds: float = 5.0 default_cycles: int = 1 command_topic: str = "arm_card_dealer/command" camera_response_topic: str = "arm_card_dealer/camera/response" status_topic: str = "arm_card_dealer/status" error_topic: str = "arm_card_dealer/error" camera_command_topic: str = "arm_card_dealer/camera/command" @dataclass(frozen=True) class StaticSettings: """静态目录配置。""" root_dir: Path = field(default_factory=lambda: PROJECT_ROOT / "static") capture_dir_name: str = "captures" front_filename: str = "1.jpg" back_filename: str = "2.jpg" index_filename: str = "index.html" @property def capture_dir(self) -> Path: return self.root_dir / self.capture_dir_name @property def front_image_path(self) -> Path: return self.capture_dir / self.front_filename @property def back_image_path(self) -> Path: return self.capture_dir / self.back_filename @property def front_relative_path(self) -> Path: return Path(self.capture_dir_name) / self.front_filename @property def back_relative_path(self) -> Path: return Path(self.capture_dir_name) / self.back_filename @property def index_path(self) -> Path: return self.root_dir / self.index_filename def ensure_directories(self) -> None: self.capture_dir.mkdir(parents=True, exist_ok=True) @dataclass(frozen=True) class Settings: """项目总配置。""" app: AppSettings = field(default_factory=AppSettings) camera: CameraSettings = field(default_factory=CameraSettings) mqtt: MqttSettings = field(default_factory=MqttSettings) static: StaticSettings = field(default_factory=StaticSettings) settings = Settings()