Files
operating-room-monitor-server/.env.example
Kevin 69980d8073 feat: align surgery API with schemas and extend client tooling
- Refactor app API and schemas; adjust surgery pipeline, repository, and session manager.

- Improve consumption TSV logging and consumable vision integration; trim voice resolution.

- Add Baidu Face 1:N search script, .env.example entries, and client API integration doc.

- Update demo client, staging checklist, surgery interface doc, and related tests; add sample face image.

Made-with: Cursor
2026-04-23 16:09:20 +08:00

162 lines
9.0 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Copy to `.env` and adjust. Loaded by pydantic-settings (field names → UPPER_SNAKE_CASE env vars).
# Used by local `start.sh` and Docker Compose. See also docs/video-backends.md.
# --- PostgreSQL ---
POSTGRES_USER=postgres
POSTGRES_PASSWORD=postgres
POSTGRES_DB=operation_room
POSTGRES_HOST=localhost
POSTGRES_PORT=35432
# Optional: full async SQLAlchemy URL (overrides POSTGRES_* when set and matches defaults logic — see Settings).
# DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:35432/operation_room
# --- YOLO 视觉推理(内部调用,无独立 HTTP---
# 耗材分类权重默认 app/resources/consumable_classifier.pt手部检测为空时退化为全帧分类。
# CONSUMABLE_CLASSIFIER_WEIGHTS=/absolute/path/to/consumable_classifier.pt
CONSUMABLE_CLASSIFIER_IMGSZ=224
CONSUMABLE_CLASSIFIER_DEVICE=
# 视觉待确认 options 最多为模型 top3 与 candidate_consumables 的交集(非本变量)。
CONSUMABLE_CLASSIFIER_TOPK=5
# CONSUMABLE_MIN_CLS_CONFIDENCE=0.5
# 时间窗(秒):窗内多次推理取众数后再走自动记账 / 待确认。
# CONSUMABLE_VISION_WINDOW_SEC=15
# 可选Excel「商品名称」「产品编码」表空则物品 id 用名称。
# CONSUMABLE_CATALOG_XLSX_PATH=/path/to/视频中的商品信息表.xlsx
# HAND_DETECTION_WEIGHTS=/absolute/path/to/hand_detect.pt
# HAND_DETECTION_IMGSZ=640
# HAND_DETECTION_CONF=0.25
# HAND_DETECTION_PAD_RATIO=0.30
# HAND_DETECTION_MIN_CROP_PX=64
# HAND_DETECTION_DEVICE=
# Device: empty → auto (macOS MPS if available; Linux CUDA if available). Docker image uses CPU torch unless you change it.
# --- Surgery recording API retries ---
# SURGERY_RECORDING_MAX_ATTEMPTS=3
# SURGERY_RECORDING_RETRY_DELAY_SECONDS=1.0
# --- Video: RTSP + optional Hikvision HCNetSDK (Linux x86_64 + glibc recommended) ---
# Client `camera_ids` must match keys in your RTSP map (sample IDs: or-cam-01, or-cam-02).
#
# VIDEO_DEFAULT_BACKEND=rtsp
# Values: rtsp | hikvision_sdk | auto (auto: SDK .so loaded and HIKVISION_SDK_ENABLED=true → prefer SDK)
#
# Per-camera backend override (JSON object):
# VIDEO_CAMERA_BACKEND_OVERRIDES_JSON={"or-cam-01":"rtsp","or-cam-02":"hikvision_sdk"}
#
# RTSP URL resolution (first match wins per camera_id):
# 1) VIDEO_RTSP_URLS_JSON_FILE — JSON file: {"or-cam-01":"rtsp://...","or-cam-02":"rtsp://..."}
# 2) merged with VIDEO_RTSP_URLS_JSON (inline JSON string; overrides same keys from file)
# 3) else VIDEO_RTSP_URL_TEMPLATE with {camera_id}
# Example file (committed): app/resources/camera_rtsp_urls.sample.json
# VIDEO_RTSP_URLS_JSON_FILE=app/resources/camera_rtsp_urls.sample.json
# In Docker (WORKDIR /app): VIDEO_RTSP_URLS_JSON_FILE=/app/app/resources/camera_rtsp_urls.sample.json
# WARNING: if VIDEO_RTSP_URLS_JSON_FILE is set but the path is missing, the app will fail to start.
#
# VIDEO_RTSP_URL_TEMPLATE=rtsp://user:pass@192.168.1.64:554/Streaming/Channels/101
# VIDEO_RTSP_URLS_JSON={"or-cam-01":"rtsp://user:pass@192.168.1.101:554/Streaming/Channels/101","or-cam-02":"rtsp://user:pass@192.168.1.102:554/Streaming/Channels/101"}
#
# VIDEO_OPEN_TIMEOUT_SEC=15
# 连续读帧失败次数达到阈值后释放 RTSP 并重连。
# VIDEO_READ_FAILURE_RECONNECT_THRESHOLD=15
# VIDEO_RECONNECT_BACKOFF_SECONDS=1.0
# VIDEO_INFERENCE_INTERVAL_SEC=2
# VIDEO_INFERENCE_CONFIDENCE_THRESHOLD=0.35
# 置信度 >= 此值且命中候选清单时自动 vision 记账。提高到 0.9 可减少自动记账、更多走待确认。
# 默认 0.9Top1 置信度不足该值时入队待确认;达到且标签在 candidate_consumables 内则直接记 vision。
# VIDEO_AUTO_CONFIRM_CONFIDENCE=0.9
# 与 VIDEO_VOICE_CONFIRM_MIN_CONFIDENCE 共同决定何时自动 / 待确认(见 app/config 注释)。
# VIDEO_VOICE_CONFIRM_MIN_CONFIDENCE=0.35
# 待确认话术由服务端生成prompt_textTTS 一般在客户端播放;医生 WAV 上传后服务端 ASR 解析。
# 解析顺序:① pending 里展示的 topk序号/名称);② 仍不匹配时,对「开始手术」请求体中的 candidate_consumables 全文做名称子串匹配——医生报清单内其它耗材也以医生为准入账。
# 是否启用低置信度人工确认(客户端播报 + resolve 回传;服务端无麦克风/扬声器要求)。
# VOICE_CONFIRMATION_ENABLED=true
# 同一条待确认在语音/文本「解析失败」时累计的允许失败轮次(默认 2首败后再给 1 次重试提示;见 422 的 detail.retry_remaining
# VOICE_CONFIRM_MAX_FAILED_PARSE_ROUNDS=2
# VIDEO_VOICE_CONFIRM_DOCTOR_ID=voice
# (已弃用)服务端本机录音 / ffmpeg 音频输入;当前闭环不依赖。
# VOICE_RECORD_SECONDS=5
# VOICE_FFMPEG_INPUT=
# 停录后写库失败时,后台重试落库间隔(秒)。
# ARCHIVE_PERSIST_RETRY_INTERVAL_SECONDS=30
# VIDEO_DETAIL_COOLDOWN_SEC=15
# VIDEO_JPEG_QUALITY=85
# VIDEO_RESULT_DOCTOR_ID=vision
# 每次单帧分类得到 top13 时打一条 INFO联调开生产建议 false
# VIDEO_LOG_INFERENCE_RESULTS=true
# 时间窗级消耗文本日志(制表符列;每例手术 start 时截断+表头,窗内结果追加;终端 Rich 为可读时间戳,文件内为 ISO 时间戳列)
# CONSUMPTION_TSV_LOG_ENABLED=true
# 须含 {surgery_id},如 logs/consumption_{surgery_id}.txt
# CONSUMPTION_TSV_LOG_PATH=logs/consumption_{surgery_id}.txt
# 同一时间窗结果在终端以 Markdown 表格打印Top13 分列 id / 名称 / 置信度)
# CONSUMPTION_LOG_MARKDOWN_TERMINAL=true
# 消耗日志时间戳列的时区IANA如 Asia/Shanghai不设置则用运行环境的系统时区
# CONSUMPTION_LOG_TIMEZONE=Asia/Shanghai
#
# 语音确认stderr 中可 grep 的 `VoiceConfirm ...` 行 + 每例手术 TSV与 `start_surgery` 同次截断写表头;成功/ASR/解析失败均追加一行)
# VOICE_FILE_LOG_ENABLED=true
# 须含 {surgery_id},如 logs/voice_{surgery_id}.txt
# VOICE_FILE_LOG_PATH=logs/voice_{surgery_id}.txt
# --- Hikvision: mount vendor Linux x86_64 .so at runtime (do not commit proprietary binaries) ---
# HIKVISION_LIB_DIR=/opt/hikvision/lib
# Optional: single library path (overrides directory search in code)
# HIKVISION_LIB_PATH=
# HIKVISION_SDK_ENABLED=false
# HIKVISION_DEVICE_IP=
# HIKVISION_DEVICE_PORT=8000
# HIKVISION_USER=
# HIKVISION_PASSWORD=
# HIKVISION_CHANNEL=1
# After SDK login, OpenCV still pulls frames via RTSP; template placeholders: {ip} {user} {password} {channel} {camera_id}
# HIKVISION_PREVIEW_RTSP_TEMPLATE=rtsp://{user}:{password}@{ip}:554/Streaming/Channels/101
# Per-camera RTSP when using SDK path (same shape as VIDEO_RTSP_URLS_JSON):
# HIKVISION_CAMERA_RTSP_URLS_JSON={"or-cam-01":"rtsp://...","or-cam-02":"rtsp://..."}
# HIKVISION_SDK_FALLBACK_TO_RTSP=true
# --- Baidu Speech可选遗留当前手术闭环由客户端完成 TTS/ASR服务端可不配置---
# BAIDU_SPEECH_APP_ID=
# BAIDU_SPEECH_API_KEY=
# BAIDU_SPEECH_SECRET_KEY=
# BAIDU_SPEECH_CONNECTION_TIMEOUT_MS=
# BAIDU_SPEECH_SOCKET_TIMEOUT_MS=
# 短语音识别模型:固定普通话(默认 1537勿用 1737 英语等)。代码会始终带上此 dev_pid。
# BAIDU_SPEECH_ASR_DEV_PID=1537
# --- Baidu Face可选仅 `scripts/baidu_face_1n_search.py` 批量人脸 1N 搜索;需在控制台创建应用并开通人脸识别)---
# BAIDU_FACE_APP_ID=
# BAIDU_FACE_API_KEY=
# BAIDU_FACE_SECRET_KEY=
# 搜索的人脸组 id逗号分隔最多 10 个;未传命令行 --groups 时使用此项
# 仅允许英文/数字/下划线(与控制台「用户组 id」一致不能中文否则 API 会报 222005
# BAIDU_FACE_GROUP_ID_LIST=my_group_1
# BAIDU_FACE_MAX_USER_NUM=1
# BAIDU_FACE_MATCH_THRESHOLD=80
# BAIDU_FACE_QUALITY_CONTROL=NONE
# BAIDU_FACE_LIVENESS_CONTROL=NONE
# BAIDU_FACE_CONNECTION_TIMEOUT_MS=
# BAIDU_FACE_SOCKET_TIMEOUT_MS=
# --- MinIO语音 WAV 存桶;`docker-compose.dev.yml` 内已含 `minio` 服务;本机只跑 API 时填 127.0.0.1:9000---
# docker compose -f docker-compose.dev.yml up -d minio
# MINIO_ENDPOINT=127.0.0.1:9000
# MINIO_ACCESS_KEY=minioadmin
# MINIO_SECRET_KEY=minioadmin
# MINIO_BUCKET=operation-room-voice
# MINIO_SECURE=false
# optional: MINIO_REGION=
# --- Demo 浏览器客户端 / 一键联调假 RTSP仅开发生产关---
# demo_client/index.html 跨源访问本服务 / 一键开录
# DEMO_CORS_ENABLED=true
# DEMO_CORS_ORIGINS=*
# 为 true 时提供 POST /internal/demo/orchestrate-and-start需能执行 docker+ffmpeg 的**同一进程**内起 MediaMTX通常=在宿主机直接跑 main.py或容器挂载 /var/run/docker.sock
# DEMO_ORCHESTRATOR_ENABLED=false
# VIDEO_RTSP_URLS_JSON_FILE 必须设成**可写**的 JSON 文件Docker 中请 bind-mount 宿主机文件,与一键覆盖写入的映射一致
# DEMO_ORCHESTRATOR_RTSP_PORT=18554
# 手配假流、只改 JSON 给「另一进程」用时:可把 127.0.0.1 换成 host.docker.internal 等。
# 一键联调 orchestrate-and-start 在本进程起流+拉流,固定写 127.0.0.1,不读此项。
# DEMO_ORCHESTRATOR_RTSP_JSON_HOST=host.docker.internal
# 一键起 MediaMTX 后,等待本机 RTSP 端口可连接的最长时间(秒)
# MEDIAMTX_TCP_READY_SEC=30