feat: 语音确认、联调与运维增强
- 语音:序数解析(第一个/第二个等)、解析失败计数与 API detail.retry_remaining; 百度 ASR 固定 dev_pid 为普通话;SurgeryPipelineError 支持 extra 并入 HTTP detail。 - Demo:demo 路由与假 RTSP、客户端 index 与 README;BackendResolver 与配置调整。 - 可观测:消耗 TSV 日志、语音文件日志、终端 Markdown 辅助;相关测试与依赖更新。 - 注意:.env 仍被 gitignore,本地密钥不会进入本提交。 Made-with: Cursor
This commit is contained in:
@@ -7,6 +7,9 @@ from pydantic import Field, field_validator
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
|
||||
_PACKAGE_DIR = Path(__file__).resolve().parent
|
||||
# 仓库根目录(含 .env)。用绝对路径读 .env,避免从子目录/IDE 启动时 cwd 不同导致联调项未生效。
|
||||
_REPO_ROOT = _PACKAGE_DIR.parent
|
||||
_DEFAULT_ENV_FILE = _REPO_ROOT / ".env"
|
||||
|
||||
|
||||
def _default_consumable_classifier_weights() -> str:
|
||||
@@ -74,9 +77,9 @@ class Settings(BaseSettings):
|
||||
video_inference_confidence_threshold: float = Field(
|
||||
default=0.35, ge=0.0, le=1.0
|
||||
)
|
||||
#: 达到或超过该置信度时,自动记一条耗材消耗(需通过候选清单校验)。
|
||||
video_auto_confirm_confidence: float = Field(default=0.55, ge=0.0, le=1.0)
|
||||
#: 置信度处于 [本值, video_auto_confirm_confidence) 时尝试语音追问(需有可播报的 top 候选)。
|
||||
#: 达到或超过该置信度且 Top1 在候选内时,自动记一条 vision 消耗;低于该值时走待确认(不低于 video_voice_confirm_min 且可展示候选项时)。默认 0.9:不足 0.9 的需人工确认。
|
||||
video_auto_confirm_confidence: float = Field(default=0.9, ge=0.0, le=1.0)
|
||||
#: 低于本值的帧不进入自动/待确认逻辑(与 `video_auto_confirm_confidence` 下沿之间的区间可入队待确认)。
|
||||
video_voice_confirm_min_confidence: float = Field(default=0.35, ge=0.0, le=1.0)
|
||||
#: 是否启用低置信度时的人工确认(客户端拉取待确认项并回传结果;不依赖服务端麦克风/扬声器)。
|
||||
voice_confirmation_enabled: bool = True
|
||||
@@ -96,6 +99,21 @@ class Settings(BaseSettings):
|
||||
video_jpeg_quality: int = Field(default=85, ge=40, le=100)
|
||||
#: 写入消耗明细时的 doctor_id(无外部医生 ID 来源时的占位)。
|
||||
video_result_doctor_id: str = "vision"
|
||||
#: 为 true 时,每次单帧分类得到 top1 等结果会打一条 INFO 日志(联调用;高流量时建议关)。
|
||||
video_log_inference_results: bool = False
|
||||
#: 为 true 时,将时间窗级识别写入文本日志(`start_surgery` 时按手术截断/初始化,窗内结果追加;Top2/3 仅名称;数量恒 1)。
|
||||
consumption_tsv_log_enabled: bool = True
|
||||
#: 路径模板,须含 `{surgery_id}`(每例手术独立文件)。不含占位时自动在扩展名前追加 `_<surgery_id>`。
|
||||
consumption_tsv_log_path: str = "logs/consumption_{surgery_id}.txt"
|
||||
#: 为 true 时,同一时间窗结果在终端以 Markdown 表格打印(Top1~3 分列 id / 名称 / 置信度)。
|
||||
consumption_log_markdown_terminal: bool = True
|
||||
#: 消耗日志「时间戳」列的时区,IANA 名如 `Asia/Shanghai`;空串则使用「当前系统时区」。
|
||||
consumption_log_timezone: str = ""
|
||||
|
||||
#: 为 true 时,语音确认(WAV/文本)的 ASR/解析结果写 TSV 文件,并在终端打 `VoiceConfirm` 行;`start_surgery` 时与消耗日志同寿命截断初始化。
|
||||
voice_file_log_enabled: bool = True
|
||||
#: 路径模板,须含 `{surgery_id}`,与 `consumption_tsv_log_path` 规则相同。
|
||||
voice_file_log_path: str = "logs/voice_{surgery_id}.txt"
|
||||
|
||||
#: 海康 SDK `.so` 所在目录(容器内可挂载 `/opt/hikvision/lib`)。
|
||||
hikvision_lib_dir: str = "/opt/hikvision/lib"
|
||||
@@ -121,6 +139,8 @@ class Settings(BaseSettings):
|
||||
baidu_speech_connection_timeout_ms: int | None = None
|
||||
#: 传输数据超时(毫秒)。未设置则使用 SDK 默认。
|
||||
baidu_speech_socket_timeout_ms: int | None = None
|
||||
#: 百度短语音识别 `dev_pid`,**始终**用于 ASR(调用方传入的 options 不会覆盖)。1537=普通话通用(与百度控制台一致;勿用 1737 英语、1837 粤语等)。
|
||||
baidu_speech_asr_dev_pid: int = Field(default=1537, ge=1000, le=99999)
|
||||
|
||||
# --- MinIO:语音确认原始 WAV 追溯存储 ---
|
||||
#: 为空则视为未配置 MinIO,语音确认接口将返回业务错误(联调需配置)。
|
||||
@@ -134,6 +154,8 @@ class Settings(BaseSettings):
|
||||
minio_region: str = ""
|
||||
#: 上传医生语音 WAV 的最大字节数(默认 10MB)。
|
||||
voice_upload_max_bytes: int = Field(default=10 * 1024 * 1024, ge=64, le=50 * 1024 * 1024)
|
||||
#: 同一条待确认在 ASR/文本解析为选项或耗材名失败时,计数的最大失败轮数。默认 2 表示首败后再允许 1 次「显式重试」语义(API 的 retry_remaining 首轮为 1、再败为 0);不阻止后续继续上传直至成功或否认。
|
||||
voice_confirm_max_failed_parse_rounds: int = Field(default=2, ge=1, le=20)
|
||||
|
||||
# --- Demo 客户端跨源(仅用于 scripts/demo_client 联调;生产置 false) ---
|
||||
#: 为 true 时挂载 CORSMiddleware,便于浏览器 demo 从另一个端口访问本服务。
|
||||
@@ -141,6 +163,15 @@ class Settings(BaseSettings):
|
||||
#: 逗号分隔的允许来源;`*` 表示允许全部来源(demo/联调用,生产应显式指定)。
|
||||
demo_cors_origins: str = "*"
|
||||
|
||||
# --- 一键联调:上传视频 → 起假 RTSP → 写 VIDEO_RTSP_URLS_JSON_FILE → 开始手术(仅开发;生产必须 false) ---
|
||||
#: 为 true 时注册 `POST /internal/demo/orchestrate-and-start`。
|
||||
demo_orchestrator_enabled: bool = False
|
||||
#: 假 RTSP(MediaMTX)在宿主机上映射的端口(与 scripts/demo_client 默认一致)。
|
||||
demo_orchestrator_rtsp_port: int = Field(default=18554, ge=1, le=65535)
|
||||
#: 手配假流时:写入 JSON 可把 `rtsp://127.0.0.1` 换成此主机,便于**别一进程**(如仅容器内的监控)访问宿主机推流。
|
||||
#: `POST /internal/demo/orchestrate-and-start` 在本进程起流+拉流,始终写 `127.0.0.1`,**不读**此字段。
|
||||
demo_orchestrator_rtsp_json_host: str = "host.docker.internal"
|
||||
|
||||
def parsed_demo_cors_origins(self) -> list[str]:
|
||||
raw = (self.demo_cors_origins or "").strip()
|
||||
if not raw:
|
||||
@@ -157,7 +188,7 @@ class Settings(BaseSettings):
|
||||
return str(value)
|
||||
|
||||
model_config = SettingsConfigDict(
|
||||
env_file=".env",
|
||||
env_file=(str(_DEFAULT_ENV_FILE),),
|
||||
env_file_encoding="utf-8",
|
||||
extra="ignore",
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user