config.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. from dataclasses import dataclass, field
  2. from pathlib import Path
  3. PROJECT_ROOT = Path(__file__).resolve().parents[2]
  4. @dataclass(frozen=True)
  5. class AppSettings:
  6. """FastAPI 基础配置。"""
  7. title: str = "Raspberry Pi Camera API"
  8. version: str = "0.1.0"
  9. description: str = "用于树莓派相机抓拍的 FastAPI 服务。"
  10. host: str = "0.0.0.0"
  11. port: int = 8002
  12. @dataclass(frozen=True)
  13. class CameraSettings:
  14. """树莓派相机配置。"""
  15. camera_index: int = 0
  16. width: int = 2048
  17. height: int = 2048
  18. frame_format: str = "RGB888"
  19. jpeg_quality: int = 95
  20. warmup_seconds: float = 0.05
  21. enable_continuous_autofocus: bool = True
  22. enable_auto_white_balance: bool = True
  23. @dataclass(frozen=True)
  24. class MqttSettings:
  25. """MQTT 配置。"""
  26. broker: str = "192.168.77.132"
  27. port: int = 1883
  28. keep_alive_interval: int = 60
  29. client_id_prefix: str = "arm_camera_api_"
  30. request_timeout_seconds: float = 40.0
  31. connect_timeout_seconds: float = 5.0
  32. default_cycles: int = 1
  33. command_topic: str = "arm_card_dealer/command"
  34. camera_response_topic: str = "arm_card_dealer/camera/response"
  35. status_topic: str = "arm_card_dealer/status"
  36. error_topic: str = "arm_card_dealer/error"
  37. camera_command_topic: str = "arm_card_dealer/camera/command"
  38. @dataclass(frozen=True)
  39. class StaticSettings:
  40. """静态目录配置。"""
  41. root_dir: Path = field(default_factory=lambda: PROJECT_ROOT / "static")
  42. capture_dir_name: str = "captures"
  43. front_filename: str = "front.jpg"
  44. back_filename: str = "back.jpg"
  45. index_filename: str = "index.html"
  46. @property
  47. def capture_dir(self) -> Path:
  48. return self.root_dir / self.capture_dir_name
  49. @property
  50. def front_image_path(self) -> Path:
  51. return self.capture_dir / self.front_filename
  52. @property
  53. def back_image_path(self) -> Path:
  54. return self.capture_dir / self.back_filename
  55. @property
  56. def front_relative_path(self) -> Path:
  57. return Path(self.capture_dir_name) / self.front_filename
  58. @property
  59. def back_relative_path(self) -> Path:
  60. return Path(self.capture_dir_name) / self.back_filename
  61. @property
  62. def index_path(self) -> Path:
  63. return self.root_dir / self.index_filename
  64. def ensure_directories(self) -> None:
  65. self.capture_dir.mkdir(parents=True, exist_ok=True)
  66. @dataclass(frozen=True)
  67. class CloudSettings:
  68. """MinIO 与卡牌识别服务配置。"""
  69. minio_endpoint: str = "192.168.77.249:9000"
  70. minio_access_key: str = "pZEwCGnpNN05KPnmC2Yh"
  71. minio_secret_key: str = "KfJRuWiv9pVxhIMcFqbkv8hZT9SnNTZ6LPx592D4"
  72. minio_secure: bool = False
  73. minio_bucket: str = "grading"
  74. minio_base_prefix: str = "raspi_img_data"
  75. recognize_api_url: str = "http://192.168.77.249:18084/internal/any/card/image/rerank"
  76. recognize_timeout_seconds: float = 15.0
  77. data_prefix: str = "http://192.168.31.114/reverseSearch/sample/zip?file_path="
  78. @property
  79. def minio_public_base_url(self) -> str:
  80. return f"http://{self.minio_endpoint}/{self.minio_bucket}/{self.minio_base_prefix}"
  81. @dataclass(frozen=True)
  82. class Settings:
  83. """项目总配置。"""
  84. app: AppSettings = field(default_factory=AppSettings)
  85. camera: CameraSettings = field(default_factory=CameraSettings)
  86. mqtt: MqttSettings = field(default_factory=MqttSettings)
  87. static: StaticSettings = field(default_factory=StaticSettings)
  88. cloud: CloudSettings = field(default_factory=CloudSettings)
  89. settings = Settings()