From 4e0f72466194fcbba0bdbc609839016b69f10b26 Mon Sep 17 00:00:00 2001 From: wuzhuorong <973204353@qq.com> Date: Fri, 12 Jun 2026 14:26:15 +0800 Subject: [PATCH] =?UTF-8?q?feat(server)=EF=BC=9A=E8=A1=A5=E5=85=85?= =?UTF-8?q?=E6=96=B0=E5=A2=9ERTSP=E9=85=8D=E7=BD=AE=E7=B1=BB=EF=BC=9B?= =?UTF-8?q?=E9=9B=86=E6=88=90=20RTSP=20StreamManager=20=E5=88=9D=E5=A7=8B?= =?UTF-8?q?=E5=8C=96=E4=B8=8E=E8=B7=AF=E7=94=B1=E6=B3=A8=E5=86=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/server/core/settings.py | 76 ++++++++++++++++++++++++++++++++++++ apps/server/main.py | 11 ++++++ 2 files changed, 87 insertions(+) diff --git a/apps/server/core/settings.py b/apps/server/core/settings.py index b879cf4..463f9e7 100644 --- a/apps/server/core/settings.py +++ b/apps/server/core/settings.py @@ -86,6 +86,74 @@ class EventEngineSettings(BaseSettings): max_active_events: int = Field(default=1000, ge=1) +class RTSPSettings(BaseSettings): + """RTSP 流接入相关配置 (MVP-2)。""" + + model_config = SettingsConfigDict(env_prefix="RTSP_", extra="ignore") + + max_streams: int = Field(default=16, ge=1, description="最大同时接入流数量") + buffer_capacity: int = Field(default=300, ge=1, description="每路流帧缓冲区容量") + reconnect_attempts: int = Field(default=10, ge=0, description="最大重连次数,0=无限") + reconnect_interval_base: float = Field(default=2.0, ge=0.5, description="首次重连间隔(秒)") + reconnect_interval_max: float = Field(default=60.0, ge=1.0, description="最大重连间隔(秒)") + reconnect_backoff_factor: float = Field(default=2.0, ge=1.0, description="退避因子") + frame_skip: int = Field(default=0, ge=0, description="帧采样间隔,0=每帧都取") + read_timeout: float = Field(default=5.0, ge=1.0, description="单帧读取超时(秒)") + detect_interval: float = Field(default=0.0, ge=0.0, description="检测轮询间隔(秒),0=每帧检测") + + +class MQTTSettings(BaseSettings): + """MQTT 预警发布相关配置 (MVP-2 / D16-D18)。""" + + model_config = SettingsConfigDict(env_prefix="MQTT_", extra="ignore") + + enabled: bool = Field(default=False, description="是否启用 MQTT 发布") + broker_host: str = Field(default="localhost", description="MQTT broker 主机") + broker_port: int = Field(default=1883, ge=1, le=65535, description="MQTT broker 端口") + client_id: str = Field(default="jc-video-recognize", description="MQTT 客户端ID") + username: Optional[str] = Field(default=None, description="MQTT 用户名") + password: Optional[str] = Field(default=None, description="MQTT 密码") + keepalive: int = Field(default=60, ge=10, description="心跳间隔(秒)") + qos: int = Field(default=1, ge=0, le=2, description="QoS 等级") + retain: bool = Field(default=False, description="是否保留消息") + # 主题模板 + alert_topic_prefix: str = Field(default="video/alerts", description="预警主题前缀") + # 重连 + reconnect_min_delay: float = Field(default=1.0, ge=0.1, description="最小重连间隔(秒)") + reconnect_max_delay: float = Field(default=60.0, ge=1.0, description="最大重连间隔(秒)") + + +class TrackingSettings(BaseSettings): + """目标跟踪 (ByteTrack) 配置 (MVP-2 / D19)。""" + + model_config = SettingsConfigDict(env_prefix="TRACKING_", extra="ignore") + + enabled: bool = Field(default=True, description="是否启用目标跟踪") + track_thresh: float = Field(default=0.5, ge=0.0, le=1.0, description="跟踪置信度阈值") + high_thresh: float = Field(default=0.6, ge=0.0, le=1.0, description="高置信度阈值") + match_thresh: float = Field(default=0.8, ge=0.0, le=1.0, description="IOU 匹配阈值") + max_lost_frames: int = Field(default=30, ge=1, description="目标丢失最大帧数") + min_box_area: float = Field(default=10.0, ge=0.0, description="最小框面积") + + +class AggregatorSettings(BaseSettings): + """事件聚合器扩展配置 (MVP-2 / D20)。""" + + model_config = SettingsConfigDict(env_prefix="AGGREGATOR_", extra="ignore") + + enable_spatial_merge: bool = Field(default=True, description="是否启用空间邻近合并") + spatial_iou_threshold: float = Field( + default=0.3, ge=0.0, le=1.0, description="空间合并 IOU 阈值" + ) + confidence_fusion_strategy: str = Field( + default="weighted", + description="置信度融合策略: weighted/max/avg", + ) + fusion_decay_factor: float = Field( + default=0.9, ge=0.0, le=1.0, description="历史置信度衰减因子" + ) + + class LoggingSettings(BaseSettings): """日志配置。""" @@ -145,6 +213,10 @@ class Settings(BaseSettings): default_factory=ActionDetectionSettings ) event_engine: EventEngineSettings = Field(default_factory=EventEngineSettings) + rtsp: RTSPSettings = Field(default_factory=RTSPSettings) + mqtt: MQTTSettings = Field(default_factory=MQTTSettings) + tracking: TrackingSettings = Field(default_factory=TrackingSettings) + aggregator: AggregatorSettings = Field(default_factory=AggregatorSettings) logging: LoggingSettings = Field(default_factory=LoggingSettings) paths: PathSettings = Field(default_factory=PathSettings) @@ -167,6 +239,10 @@ __all__ = [ "DetectionSettings", "ActionDetectionSettings", "EventEngineSettings", + "RTSPSettings", + "MQTTSettings", + "TrackingSettings", + "AggregatorSettings", "LoggingSettings", "PathSettings", "get_settings", diff --git a/apps/server/main.py b/apps/server/main.py index 574fd1d..638b6da 100644 --- a/apps/server/main.py +++ b/apps/server/main.py @@ -9,6 +9,8 @@ import sys import logging from api import detection, models +from api.alerts import get_broadcaster +from api.rtsp import init_stream_manager from services.model_service import ModelService from services.camera_service import CameraService @@ -64,12 +66,21 @@ async def lifespan(app: FastAPI): global camera_service camera_service = CameraService(model_service) + + # 初始化 RTSP StreamManager (MVP-2) + rtsp_manager = init_stream_manager(model_service) + from api.rtsp import router as rtsp_router + from api.alerts import router as alerts_router + app.include_router(rtsp_router, prefix="/api") + app.include_router(alerts_router, prefix="") # WebSocket 路径已带 /ws 前缀 + yield # 关闭时清理资源 logger.info("正在关闭服务,清理资源...") if camera_service: await camera_service.stop() + await rtsp_manager.stop_all() app = FastAPI( title="视频模型检测平台",