2026-04-08 19:32:23 +08:00
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
|
|
import asyncio
|
2026-04-16 11:38:30 +08:00
|
|
|
|
import threading
|
2026-04-08 19:32:23 +08:00
|
|
|
|
from dataclasses import dataclass, field
|
2026-04-09 11:54:30 +08:00
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
from typing import List, Optional
|
2026-04-08 19:32:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
|
class MeasureSnapshot:
|
|
|
|
|
|
result: List[dict]
|
|
|
|
|
|
video_left: str
|
|
|
|
|
|
video_right: str
|
|
|
|
|
|
updated_at: Optional[datetime] = None
|
|
|
|
|
|
error: Optional[str] = None
|
|
|
|
|
|
raw_prediction_path: Optional[str] = None
|
2026-04-14 20:55:15 +08:00
|
|
|
|
pred: Optional[float] = None # 最终预测的体重值
|
2026-04-16 11:38:30 +08:00
|
|
|
|
star: bool = False # DB 是唯一真相源:segment/batch 恒 False;final 行按参与聚合段的 dgcnn_summary 规则判定
|
2026-04-14 20:55:15 +08:00
|
|
|
|
#: 与 FishMeasure ``test_dgcnn_weight_estimator.py`` 终端输出一致的体重推算过程文本
|
|
|
|
|
|
calculation_log: Optional[str] = None
|
2026-04-08 19:32:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
|
class HealthSnapshot:
|
|
|
|
|
|
behavior_result: str
|
|
|
|
|
|
health_result: str
|
|
|
|
|
|
updated_at: Optional[datetime] = None
|
|
|
|
|
|
error: Optional[str] = None
|
|
|
|
|
|
raw_class_en: str = ""
|
2026-04-16 14:53:01 +08:00
|
|
|
|
video_path: str = ""
|
2026-04-08 19:32:23 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@dataclass
|
|
|
|
|
|
class AppState:
|
|
|
|
|
|
measure_lock: asyncio.Lock = field(default_factory=asyncio.Lock)
|
2026-04-16 11:38:30 +08:00
|
|
|
|
#: 与 ``run_full_measure`` 子进程串行化(跨 ``measure_watch`` / ingest 线程)
|
|
|
|
|
|
measure_thread_lock: threading.Lock = field(default_factory=threading.Lock)
|
2026-04-08 19:32:23 +08:00
|
|
|
|
action_lock: asyncio.Lock = field(default_factory=asyncio.Lock)
|
|
|
|
|
|
|
2026-04-09 11:54:30 +08:00
|
|
|
|
# job status for optional polling(业务结果见 SQLite)
|
2026-04-08 19:32:23 +08:00
|
|
|
|
measure_status: str = "idle"
|
|
|
|
|
|
action_status: str = "idle"
|
|
|
|
|
|
|
2026-04-16 11:38:30 +08:00
|
|
|
|
#: ZED 分段录制线程与协作停止事件(由 ``zed_recording_control`` 管理)
|
|
|
|
|
|
zed_recording_lock: threading.Lock = field(default_factory=threading.Lock)
|
|
|
|
|
|
zed_recording_stop_event: Optional[threading.Event] = None
|
|
|
|
|
|
zed_recording_thread: Optional[threading.Thread] = None
|
|
|
|
|
|
#: 当前会话(与 ``zed_recording_sessions`` 表对应)
|
|
|
|
|
|
zed_recording_session_row_id: Optional[int] = None
|
|
|
|
|
|
zed_recording_fish_id: Optional[int] = None
|
|
|
|
|
|
|
2026-04-08 19:32:23 +08:00
|
|
|
|
|
|
|
|
|
|
app_state = AppState()
|