feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
from __future__ import annotations
|
|
|
|
|
|
|
|
|
|
|
|
import asyncio
|
|
|
|
|
|
import time
|
|
|
|
|
|
|
|
|
|
|
|
from loguru import logger
|
|
|
|
|
|
|
|
|
|
|
|
from app.config import Settings
|
2026-04-23 20:42:21 +08:00
|
|
|
|
from sqlalchemy.ext.asyncio import async_sessionmaker
|
|
|
|
|
|
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
from app.database import AsyncSessionLocal
|
2026-04-23 20:42:21 +08:00
|
|
|
|
from app.domain.consumption import SurgeryConsumptionStored
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
from app.repositories.surgery_results import SurgeryResultRepository
|
2026-04-22 16:31:12 +08:00
|
|
|
|
from app.services.consumable_vision_algorithm import (
|
|
|
|
|
|
ConsumableVisionAlgorithmService,
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
PredictionResult,
|
|
|
|
|
|
)
|
2026-04-23 20:42:21 +08:00
|
|
|
|
from app.services.video.archive_persister import ArchivePersister
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
from app.services.video.backend_resolver import BackendResolver
|
2026-04-23 20:42:21 +08:00
|
|
|
|
from app.services.video.classification_handler import VisionClassificationHandler
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
from app.services.video.hikvision_runtime import HikvisionInitRefCount, HikvisionRuntime
|
2026-04-23 20:42:21 +08:00
|
|
|
|
from app.services.video.inference_aggregator import WindowInferenceAggregator
|
|
|
|
|
|
from app.services.video.session_registry import (
|
|
|
|
|
|
CameraStreamInferState,
|
|
|
|
|
|
PendingConsumableConfirmation,
|
|
|
|
|
|
RunningSurgery,
|
|
|
|
|
|
SurgerySessionRegistry,
|
|
|
|
|
|
SurgerySessionState,
|
|
|
|
|
|
)
|
|
|
|
|
|
from app.services.video.stream_worker import CameraStreamWorker, redact_rtsp_url
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
from app.services.video.types import VideoBackendKind
|
2026-04-24 14:27:56 +08:00
|
|
|
|
from app.schemas import SurgeryConsumptionDetail, build_consumption_summary
|
2026-04-23 16:09:20 +08:00
|
|
|
|
from app.services.consumption_tsv_log import (
|
|
|
|
|
|
append_consumption_log_summary,
|
|
|
|
|
|
init_consumption_log_file,
|
|
|
|
|
|
print_consumption_summary_markdown,
|
|
|
|
|
|
)
|
2026-04-23 14:24:20 +08:00
|
|
|
|
from app.services.voice_file_log import init_voice_log_file
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
from app.surgery_errors import SurgeryPipelineError
|
|
|
|
|
|
|
|
|
|
|
|
|
2026-04-23 20:42:21 +08:00
|
|
|
|
__all__ = [
|
|
|
|
|
|
"CameraSessionManager",
|
|
|
|
|
|
"CameraStreamInferState",
|
|
|
|
|
|
"PendingConsumableConfirmation",
|
|
|
|
|
|
"RunningSurgery",
|
|
|
|
|
|
"SurgerySessionState",
|
|
|
|
|
|
]
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class CameraSessionManager:
|
2026-04-23 20:42:21 +08:00
|
|
|
|
"""Per-surgery camera orchestration.
|
|
|
|
|
|
|
|
|
|
|
|
本类负责:
|
|
|
|
|
|
1. 开始/停止手术:创建 `SurgerySessionState`、拉起相机 worker、停录时收尾。
|
|
|
|
|
|
2. 把「语音确认所需的内存态」委托给 ``SurgerySessionRegistry``(实现 `PendingConfirmationStore`)。
|
|
|
|
|
|
3. 把「结果写库 + 失败重试 + durable fallback」委托给 ``ArchivePersister``。
|
|
|
|
|
|
|
|
|
|
|
|
对外接口保持不变,上游(``SurgeryPipeline`` / ``VoiceConfirmationService``)无需感知拆分。
|
|
|
|
|
|
"""
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
|
|
|
|
|
|
def __init__(
|
|
|
|
|
|
self,
|
|
|
|
|
|
*,
|
|
|
|
|
|
settings: Settings,
|
2026-04-22 16:31:12 +08:00
|
|
|
|
vision_algorithm: ConsumableVisionAlgorithmService,
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
hikvision_runtime: HikvisionRuntime | None,
|
|
|
|
|
|
result_repository: SurgeryResultRepository | None = None,
|
2026-04-23 20:42:21 +08:00
|
|
|
|
session_factory: async_sessionmaker | None = None,
|
|
|
|
|
|
registry: SurgerySessionRegistry | None = None,
|
|
|
|
|
|
archive_persister: ArchivePersister | None = None,
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
) -> None:
|
|
|
|
|
|
self._s = settings
|
2026-04-22 16:31:12 +08:00
|
|
|
|
self._vision = vision_algorithm
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
self._hik = hikvision_runtime
|
2026-04-23 20:42:21 +08:00
|
|
|
|
self._session_factory: async_sessionmaker = session_factory or AsyncSessionLocal
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
self._resolver = BackendResolver(settings, hikvision_runtime=hikvision_runtime)
|
2026-04-23 20:42:21 +08:00
|
|
|
|
self._registry = registry or SurgerySessionRegistry(settings=settings)
|
|
|
|
|
|
self._archive = archive_persister or ArchivePersister(
|
|
|
|
|
|
settings=settings,
|
|
|
|
|
|
repository=result_repository,
|
|
|
|
|
|
session_factory=self._session_factory,
|
|
|
|
|
|
)
|
|
|
|
|
|
self._aggregator = WindowInferenceAggregator(settings=settings)
|
|
|
|
|
|
self._classifier_handler = VisionClassificationHandler(
|
|
|
|
|
|
settings=settings,
|
|
|
|
|
|
registry=self._registry,
|
|
|
|
|
|
)
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
|
2026-04-23 20:42:21 +08:00
|
|
|
|
# ------------------------------------------------------------------
|
|
|
|
|
|
# 生命周期
|
|
|
|
|
|
# ------------------------------------------------------------------
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
async def start_archive_retry_loop(self) -> None:
|
2026-04-23 20:42:21 +08:00
|
|
|
|
await self._archive.recover_from_durable_fallback()
|
|
|
|
|
|
await self._archive.start_retry_loop()
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
|
|
|
|
|
|
async def shutdown(self) -> None:
|
2026-04-23 20:42:21 +08:00
|
|
|
|
await self._archive.shutdown()
|
|
|
|
|
|
ids = self._registry.active_ids()
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
for sid in ids:
|
|
|
|
|
|
try:
|
|
|
|
|
|
await self.stop_surgery(sid, require_active=False)
|
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
|
logger.warning("shutdown stop_surgery {}: {}", sid, exc)
|
|
|
|
|
|
|
2026-04-23 20:42:21 +08:00
|
|
|
|
# ------------------------------------------------------------------
|
|
|
|
|
|
# Surgery start / stop
|
|
|
|
|
|
# ------------------------------------------------------------------
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
async def start_surgery(
|
|
|
|
|
|
self,
|
|
|
|
|
|
surgery_id: str,
|
|
|
|
|
|
camera_ids: list[str],
|
|
|
|
|
|
candidate_consumables: list[str],
|
|
|
|
|
|
) -> None:
|
2026-04-23 20:42:21 +08:00
|
|
|
|
if self._registry.has_active(surgery_id):
|
|
|
|
|
|
raise SurgeryPipelineError(
|
|
|
|
|
|
"RECORDING_CANNOT_START",
|
|
|
|
|
|
"该手术已在录制中,请勿重复开始。",
|
|
|
|
|
|
)
|
|
|
|
|
|
stale = await self._archive.take_archived_details(surgery_id)
|
|
|
|
|
|
if stale is not None:
|
|
|
|
|
|
logger.warning(
|
|
|
|
|
|
"surgery_id={} 仍有未落库归档,尝试写入数据库后再开始新会话",
|
|
|
|
|
|
surgery_id,
|
|
|
|
|
|
)
|
|
|
|
|
|
if self._archive.repository is None:
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
logger.error(
|
|
|
|
|
|
"surgery_id={} 有内存归档但未配置数据库仓库,无法持久化;"
|
|
|
|
|
|
"开始新会话将丢弃该归档(仅开发/无库模式)",
|
|
|
|
|
|
surgery_id,
|
|
|
|
|
|
)
|
|
|
|
|
|
else:
|
2026-04-23 20:42:21 +08:00
|
|
|
|
ok = await self._archive.persist_or_archive(surgery_id, stale)
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
if not ok:
|
|
|
|
|
|
raise SurgeryPipelineError(
|
|
|
|
|
|
"RECORDING_CANNOT_START",
|
|
|
|
|
|
"该手术号存在尚未写入数据库的历史结果,请修复数据库或等待自动重试成功后再开始。",
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2026-04-23 20:42:21 +08:00
|
|
|
|
resolved = self._vision.effective_candidate_consumables(candidate_consumables)
|
|
|
|
|
|
if not resolved:
|
|
|
|
|
|
raise SurgeryPipelineError(
|
|
|
|
|
|
"RECORDING_CANNOT_START",
|
2026-04-24 11:05:17 +08:00
|
|
|
|
"耗材候选为空:请在请求中传入 candidate_consumables,或提供有效的 consumable_classifier_labels.yaml / 分类模型。",
|
2026-04-23 20:42:21 +08:00
|
|
|
|
)
|
|
|
|
|
|
if not any(str(x).strip() for x in candidate_consumables):
|
|
|
|
|
|
logger.info(
|
|
|
|
|
|
"surgery {}: candidate_consumables 未提供,使用默认全量 {} 项",
|
|
|
|
|
|
surgery_id,
|
|
|
|
|
|
len(resolved),
|
|
|
|
|
|
)
|
|
|
|
|
|
name_to_code = self._vision.build_name_mapping(resolved)
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
state = SurgerySessionState(
|
2026-04-23 20:42:21 +08:00
|
|
|
|
candidate_consumables=list(resolved),
|
2026-04-22 16:31:12 +08:00
|
|
|
|
name_to_code=name_to_code,
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
)
|
|
|
|
|
|
stop_event = asyncio.Event()
|
|
|
|
|
|
readies = [asyncio.Event() for _ in camera_ids]
|
|
|
|
|
|
tasks: list[asyncio.Task[None]] = []
|
|
|
|
|
|
open_timeout = self._s.video_open_timeout_sec + 5.0
|
|
|
|
|
|
|
|
|
|
|
|
for cam_id, ready in zip(camera_ids, readies, strict=True):
|
|
|
|
|
|
tasks.append(
|
|
|
|
|
|
asyncio.create_task(
|
|
|
|
|
|
self._camera_worker(
|
|
|
|
|
|
surgery_id=surgery_id,
|
|
|
|
|
|
camera_id=cam_id,
|
|
|
|
|
|
stream_ready=ready,
|
|
|
|
|
|
stop_event=stop_event,
|
|
|
|
|
|
state=state,
|
|
|
|
|
|
),
|
|
|
|
|
|
name=f"camera:{surgery_id}:{cam_id}",
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
run = RunningSurgery(stop_event=stop_event, state=state, tasks=tasks)
|
2026-04-23 14:24:20 +08:00
|
|
|
|
init_consumption_log_file(surgery_id)
|
|
|
|
|
|
init_voice_log_file(surgery_id, self._s)
|
2026-04-23 20:42:21 +08:00
|
|
|
|
await self._registry.register(surgery_id, run)
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
await asyncio.wait_for(
|
|
|
|
|
|
asyncio.gather(*(r.wait() for r in readies)),
|
|
|
|
|
|
timeout=open_timeout,
|
|
|
|
|
|
)
|
|
|
|
|
|
state.ready.set()
|
|
|
|
|
|
except TimeoutError as exc:
|
|
|
|
|
|
logger.error(
|
|
|
|
|
|
"Surgery {} cameras not all ready within {}s",
|
|
|
|
|
|
surgery_id,
|
|
|
|
|
|
open_timeout,
|
|
|
|
|
|
)
|
|
|
|
|
|
await self.stop_surgery(surgery_id, require_active=True)
|
|
|
|
|
|
raise SurgeryPipelineError(
|
|
|
|
|
|
"RECORDING_CANNOT_START",
|
|
|
|
|
|
"开录未能确认:部分摄像头在超时内未成功拉到首帧。",
|
|
|
|
|
|
) from exc
|
|
|
|
|
|
except Exception:
|
|
|
|
|
|
await self.stop_surgery(surgery_id, require_active=True)
|
|
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
async def stop_surgery(self, surgery_id: str, *, require_active: bool = True) -> None:
|
2026-04-23 20:42:21 +08:00
|
|
|
|
run = await self._registry.unregister(surgery_id)
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
if run is None:
|
|
|
|
|
|
if require_active:
|
|
|
|
|
|
raise SurgeryPipelineError(
|
|
|
|
|
|
"RECORDING_NOT_STOPPED",
|
|
|
|
|
|
"停录未能完成:当前没有该手术的活跃录制会话。",
|
|
|
|
|
|
)
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
|
|
run.stop_event.set()
|
|
|
|
|
|
results = await asyncio.gather(*run.tasks, return_exceptions=True)
|
|
|
|
|
|
for res in results:
|
|
|
|
|
|
if isinstance(res, BaseException):
|
|
|
|
|
|
logger.warning("surgery task finished with error: {}", res)
|
|
|
|
|
|
|
2026-04-24 14:27:56 +08:00
|
|
|
|
details = list(run.state.details)
|
|
|
|
|
|
detail_rows = [
|
|
|
|
|
|
SurgeryConsumptionDetail(
|
|
|
|
|
|
item_id=r.item_id,
|
|
|
|
|
|
item_name=r.item_name,
|
|
|
|
|
|
qty=r.qty,
|
|
|
|
|
|
doctor_id=r.doctor_id,
|
|
|
|
|
|
timestamp=r.timestamp,
|
|
|
|
|
|
)
|
|
|
|
|
|
for r in details
|
|
|
|
|
|
]
|
|
|
|
|
|
summ = build_consumption_summary(detail_rows)
|
|
|
|
|
|
totals = {s.item_id: (s.item_name, s.total_quantity) for s in summ}
|
2026-04-23 16:09:20 +08:00
|
|
|
|
append_consumption_log_summary(surgery_id, totals)
|
|
|
|
|
|
print_consumption_summary_markdown(totals)
|
2026-04-23 20:42:21 +08:00
|
|
|
|
await self._archive.persist_or_archive(surgery_id, details)
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
|
2026-04-23 20:42:21 +08:00
|
|
|
|
# ------------------------------------------------------------------
|
|
|
|
|
|
# PendingConfirmationStore 协议委托
|
|
|
|
|
|
# ------------------------------------------------------------------
|
|
|
|
|
|
def live_consumption_if_active(
|
|
|
|
|
|
self, surgery_id: str
|
|
|
|
|
|
) -> list[SurgeryConsumptionStored] | None:
|
|
|
|
|
|
return self._registry.live_consumption_if_active(surgery_id)
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
|
2026-04-23 20:42:21 +08:00
|
|
|
|
def archived_consumption_fallback(
|
|
|
|
|
|
self, surgery_id: str
|
|
|
|
|
|
) -> list[SurgeryConsumptionStored] | None:
|
|
|
|
|
|
return self._archive.archived_details(surgery_id)
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
|
|
|
|
|
|
def record_voice_trace(
|
|
|
|
|
|
self,
|
|
|
|
|
|
surgery_id: str,
|
|
|
|
|
|
*,
|
|
|
|
|
|
asr_text: str | None,
|
|
|
|
|
|
error: str | None,
|
|
|
|
|
|
) -> None:
|
2026-04-23 20:42:21 +08:00
|
|
|
|
self._registry.record_voice_trace(surgery_id, asr_text=asr_text, error=error)
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
|
|
|
|
|
|
def get_pending_confirmation_by_id(
|
|
|
|
|
|
self,
|
|
|
|
|
|
surgery_id: str,
|
|
|
|
|
|
confirmation_id: str,
|
|
|
|
|
|
) -> PendingConsumableConfirmation | None:
|
2026-04-23 20:42:21 +08:00
|
|
|
|
return self._registry.get_pending_confirmation_by_id(surgery_id, confirmation_id)
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
|
2026-04-22 16:31:12 +08:00
|
|
|
|
def get_surgery_candidate_consumables(self, surgery_id: str) -> list[str]:
|
2026-04-23 20:42:21 +08:00
|
|
|
|
return self._registry.get_surgery_candidate_consumables(surgery_id)
|
2026-04-22 16:31:12 +08:00
|
|
|
|
|
2026-04-23 14:24:20 +08:00
|
|
|
|
async def record_voice_parse_failure(
|
|
|
|
|
|
self, surgery_id: str, confirmation_id: str
|
|
|
|
|
|
) -> tuple[int, int]:
|
2026-04-23 20:42:21 +08:00
|
|
|
|
return await self._registry.record_voice_parse_failure(surgery_id, confirmation_id)
|
2026-04-23 14:24:20 +08:00
|
|
|
|
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
def next_pending_confirmation(
|
|
|
|
|
|
self, surgery_id: str
|
|
|
|
|
|
) -> PendingConsumableConfirmation | None:
|
2026-04-23 20:42:21 +08:00
|
|
|
|
return self._registry.next_pending_confirmation(surgery_id)
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
|
|
|
|
|
|
async def resolve_pending_confirmation(
|
|
|
|
|
|
self,
|
|
|
|
|
|
surgery_id: str,
|
|
|
|
|
|
confirmation_id: str,
|
|
|
|
|
|
*,
|
|
|
|
|
|
chosen_label: str | None,
|
|
|
|
|
|
rejected: bool,
|
|
|
|
|
|
) -> None:
|
2026-04-23 20:42:21 +08:00
|
|
|
|
await self._registry.resolve_pending_confirmation(
|
|
|
|
|
|
surgery_id,
|
|
|
|
|
|
confirmation_id,
|
|
|
|
|
|
chosen_label=chosen_label,
|
|
|
|
|
|
rejected=rejected,
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
)
|
|
|
|
|
|
|
2026-04-23 20:42:21 +08:00
|
|
|
|
# ------------------------------------------------------------------
|
|
|
|
|
|
# Camera worker(拉流 + 推理节流 + 时间窗分桶 + 分类结果处理)
|
|
|
|
|
|
# ------------------------------------------------------------------
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
async def _camera_worker(
|
|
|
|
|
|
self,
|
|
|
|
|
|
*,
|
|
|
|
|
|
surgery_id: str,
|
|
|
|
|
|
camera_id: str,
|
|
|
|
|
|
stream_ready: asyncio.Event,
|
|
|
|
|
|
stop_event: asyncio.Event,
|
|
|
|
|
|
state: SurgerySessionState,
|
|
|
|
|
|
) -> None:
|
|
|
|
|
|
kind = self._resolver.backend_for_camera(camera_id)
|
|
|
|
|
|
hik_user_id: int | None = None
|
|
|
|
|
|
hik_init_retained = False
|
|
|
|
|
|
try:
|
|
|
|
|
|
url, hik_user_id, hik_init_retained = await self._resolve_rtsp_url(
|
|
|
|
|
|
camera_id=camera_id,
|
|
|
|
|
|
kind=kind,
|
|
|
|
|
|
)
|
|
|
|
|
|
assert url is not None
|
2026-04-23 20:42:21 +08:00
|
|
|
|
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
last_infer = 0.0
|
2026-04-23 20:42:21 +08:00
|
|
|
|
|
|
|
|
|
|
async def _frame_handler(frame: object) -> None:
|
|
|
|
|
|
nonlocal last_infer
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
now = time.monotonic()
|
|
|
|
|
|
if now - last_infer < self._s.video_inference_interval_sec:
|
|
|
|
|
|
await asyncio.sleep(0.01)
|
2026-04-23 20:42:21 +08:00
|
|
|
|
return
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
last_infer = now
|
|
|
|
|
|
try:
|
2026-04-22 16:31:12 +08:00
|
|
|
|
snap = await asyncio.to_thread(
|
|
|
|
|
|
self._vision.infer_frame_bgr,
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
frame,
|
2026-04-22 16:31:12 +08:00
|
|
|
|
state.name_to_code,
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
)
|
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
|
logger.debug(
|
|
|
|
|
|
"Inference skip camera={} surgery={}: {}",
|
|
|
|
|
|
camera_id,
|
|
|
|
|
|
surgery_id,
|
|
|
|
|
|
exc,
|
|
|
|
|
|
)
|
2026-04-23 20:42:21 +08:00
|
|
|
|
return
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
|
2026-04-22 16:31:12 +08:00
|
|
|
|
if snap is None:
|
2026-04-23 20:42:21 +08:00
|
|
|
|
return
|
2026-04-22 16:31:12 +08:00
|
|
|
|
|
2026-04-23 14:24:20 +08:00
|
|
|
|
if self._s.video_log_inference_results:
|
|
|
|
|
|
logger.info(
|
|
|
|
|
|
"Vision result surgery={} camera={} top1={}({:.3f}) top2={}({:.3f}) top3={}({:.3f})",
|
|
|
|
|
|
surgery_id,
|
|
|
|
|
|
camera_id,
|
|
|
|
|
|
snap.t1_name,
|
|
|
|
|
|
snap.t1_conf,
|
|
|
|
|
|
snap.t2_name,
|
|
|
|
|
|
snap.t2_conf,
|
|
|
|
|
|
snap.t3_name,
|
|
|
|
|
|
snap.t3_conf,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2026-04-22 16:31:12 +08:00
|
|
|
|
async with state.lock:
|
2026-04-23 20:42:21 +08:00
|
|
|
|
ready_windows = self._aggregator.ingest_snapshot_and_collect_ready(
|
|
|
|
|
|
surgery_id=surgery_id,
|
|
|
|
|
|
camera_id=camera_id,
|
|
|
|
|
|
snap=snap,
|
|
|
|
|
|
state=state,
|
2026-04-22 16:31:12 +08:00
|
|
|
|
)
|
2026-04-23 20:42:21 +08:00
|
|
|
|
|
|
|
|
|
|
for win in ready_windows:
|
|
|
|
|
|
await self._classifier_handler.handle(
|
2026-04-22 16:31:12 +08:00
|
|
|
|
state=state,
|
2026-04-23 20:42:21 +08:00
|
|
|
|
cls_res=win.prediction,
|
|
|
|
|
|
ready=win,
|
|
|
|
|
|
surgery_id=surgery_id,
|
|
|
|
|
|
camera_id=camera_id,
|
2026-04-22 16:31:12 +08:00
|
|
|
|
)
|
2026-04-23 20:42:21 +08:00
|
|
|
|
|
|
|
|
|
|
worker = CameraStreamWorker(
|
|
|
|
|
|
settings=self._s,
|
|
|
|
|
|
surgery_id=surgery_id,
|
|
|
|
|
|
camera_id=camera_id,
|
|
|
|
|
|
url=url,
|
|
|
|
|
|
)
|
|
|
|
|
|
await worker.run(
|
|
|
|
|
|
stream_ready=stream_ready,
|
|
|
|
|
|
stop_event=stop_event,
|
|
|
|
|
|
frame_handler=_frame_handler,
|
|
|
|
|
|
)
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
finally:
|
|
|
|
|
|
if hik_user_id is not None and self._hik is not None:
|
|
|
|
|
|
await asyncio.to_thread(self._hik.logout, hik_user_id)
|
|
|
|
|
|
if hik_init_retained and self._hik is not None:
|
|
|
|
|
|
HikvisionInitRefCount.release(self._hik)
|
|
|
|
|
|
|
|
|
|
|
|
async def _handle_classification_result(
|
|
|
|
|
|
self,
|
|
|
|
|
|
*,
|
|
|
|
|
|
state: SurgerySessionState,
|
|
|
|
|
|
cls_res: PredictionResult,
|
|
|
|
|
|
) -> None:
|
2026-04-23 20:42:21 +08:00
|
|
|
|
"""Deprecated test-shim:沿用旧签名,转发给 ``VisionClassificationHandler``。
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
|
2026-04-23 20:42:21 +08:00
|
|
|
|
保留此方法是因为单元测试直接调用了它。新代码应使用 ``self._classifier_handler.handle``。
|
|
|
|
|
|
"""
|
|
|
|
|
|
await self._classifier_handler.handle(state=state, cls_res=cls_res)
|
feat: surgery pipeline API, video inference, voice confirm, and tests
- Add FastAPI routes for surgery start/end, results, pending confirmation (WAV upload), and health checks.
- Implement RTSP/Hikvision capture, consumable classification, session manager, MinIO/Baidu voice resolution, and DB persistence.
- Add documentation (client API, video backends, staging checklist) and sample camera/RTSP config.
- Add pytest suite (API contract, session manager, voice, repositories, pipeline persistence) and httpx dev dependency.
- Replace deprecated HTTP_422_UNPROCESSABLE_ENTITY with HTTP_422_UNPROCESSABLE_CONTENT.
- Fix SurgeryPipeline DB reads to use an explicit transaction with autobegin disabled.
Made-with: Cursor
2026-04-21 18:33:54 +08:00
|
|
|
|
|
|
|
|
|
|
async def _resolve_rtsp_url(
|
|
|
|
|
|
self,
|
|
|
|
|
|
*,
|
|
|
|
|
|
camera_id: str,
|
|
|
|
|
|
kind: VideoBackendKind,
|
|
|
|
|
|
) -> tuple[str, int | None, bool]:
|
|
|
|
|
|
"""Returns (url, hikvision_user_id, whether NET_DVR_Init refcount was retained)."""
|
|
|
|
|
|
if kind != VideoBackendKind.HIKVISION_SDK:
|
|
|
|
|
|
return self._resolver.rtsp_url_for_camera(camera_id), None, False
|
|
|
|
|
|
|
|
|
|
|
|
if self._hik is None:
|
|
|
|
|
|
if self._s.hikvision_sdk_fallback_to_rtsp:
|
|
|
|
|
|
logger.warning(
|
|
|
|
|
|
"Hikvision SDK not loaded; fallback to RTSP for camera {}",
|
|
|
|
|
|
camera_id,
|
|
|
|
|
|
)
|
|
|
|
|
|
return self._resolver.rtsp_url_for_camera(camera_id), None, False
|
|
|
|
|
|
raise RuntimeError("Hikvision SDK requested but libhcnetsdk.so not loaded")
|
|
|
|
|
|
|
|
|
|
|
|
if not (
|
|
|
|
|
|
self._s.hikvision_device_ip.strip()
|
|
|
|
|
|
and self._s.hikvision_user.strip()
|
|
|
|
|
|
and self._s.hikvision_password.strip()
|
|
|
|
|
|
):
|
|
|
|
|
|
if self._s.hikvision_sdk_fallback_to_rtsp:
|
|
|
|
|
|
logger.warning(
|
|
|
|
|
|
"Hikvision credentials incomplete; fallback to RTSP for camera {}",
|
|
|
|
|
|
camera_id,
|
|
|
|
|
|
)
|
|
|
|
|
|
return self._resolver.rtsp_url_for_camera(camera_id), None, False
|
|
|
|
|
|
raise RuntimeError("Hikvision SDK requires HIKVISION_DEVICE_IP, user, password")
|
|
|
|
|
|
|
|
|
|
|
|
HikvisionInitRefCount.retain(self._hik)
|
|
|
|
|
|
try:
|
|
|
|
|
|
login = await asyncio.to_thread(
|
|
|
|
|
|
lambda: self._hik.login_v30(
|
|
|
|
|
|
ip=self._s.hikvision_device_ip.strip(),
|
|
|
|
|
|
port=int(self._s.hikvision_device_port),
|
|
|
|
|
|
username=self._s.hikvision_user.strip(),
|
|
|
|
|
|
password=self._s.hikvision_password.strip(),
|
|
|
|
|
|
)
|
|
|
|
|
|
)
|
|
|
|
|
|
except Exception as exc:
|
|
|
|
|
|
HikvisionInitRefCount.release(self._hik)
|
|
|
|
|
|
if self._s.hikvision_sdk_fallback_to_rtsp:
|
|
|
|
|
|
logger.warning("Hikvision login failed ({}); fallback to RTSP", exc)
|
|
|
|
|
|
return self._resolver.rtsp_url_for_camera(camera_id), None, False
|
|
|
|
|
|
raise
|
|
|
|
|
|
|
|
|
|
|
|
url = self._resolver.rtsp_url_after_hikvision_login(camera_id)
|
|
|
|
|
|
return url, login.user_id, True
|