This commit is contained in:
Kevin
2026-04-28 10:41:48 +08:00
parent 482b016872
commit 15884bd68e
60 changed files with 2092 additions and 1994 deletions

View File

@@ -42,6 +42,11 @@ from app.surgery_errors import SurgeryPipelineError
router = APIRouter()
# 上传 WAV 后 ASR/解析失败HTTP 200 + status=failed待确认项仍留在 FIFO 队首,便于桌面端重试。
_RECOVERABLE_VOICE_RESOLVE_CODES = frozenset(
{"VOICE_ASR_FAILED", "VOICE_TEXT_EMPTY", "VOICE_PARSE_FAILED"}
)
def _pipeline_error_detail(exc: SurgeryPipelineError, surgery_id: str) -> dict:
d: dict = {
@@ -367,7 +372,7 @@ async def get_surgery_result(
tags=["client"],
summary="拉取待确认耗材(含 TTS 音频)",
description=(
"返回当前 FIFO 队首的一条低置信度识别;"
"返回当前 FIFO 队首的一条低置信度识别;`pending_queue_length` 为仍排队中的 pending 条数(含本条)。"
"响应内 `prompt_audio_mp3_base64` 为与 `prompt_text` 一致的 MP3Base64客户端可直接解码播放。"
"无待确认项时返回 404提示文本为空为 422未配置百度或 TTS 失败为 503不返回空音频兜底"
"医生确认后请使用 `POST .../resolve` 上传 WAV。"
@@ -416,6 +421,7 @@ async def get_pending_consumable_confirmation(
"multipart/form-data 上传单个 WAV 文件(字段名 `audio`)。"
"服务端将音频存入 MinIO、调用百度 ASR 识别、解析候选项并完成确认。"
"解析并确认后记一条消耗明细;若语音表示否认全部候选则不记消耗。"
"ASR/解析可重试失败时仍返回 HTTP 200`status`=`failed`,队首待确认项不弹出,便于桌面端重试。"
),
)
async def resolve_pending_consumable_confirmation(
@@ -467,6 +473,21 @@ async def resolve_pending_consumable_confirmation(
content_type=audio.content_type,
)
except SurgeryPipelineError as exc:
if exc.code in _RECOVERABLE_VOICE_RESOLVE_CODES:
extra = exc.extra or {}
asr_txt = extra.get("asr_text")
akey = extra.get("audio_object_key")
return SurgeryPendingConfirmationResolveResponse(
surgery_id=surgery_id,
confirmation_id=confirmation_id,
status="failed",
message=exc.message,
resolved_label=None,
rejected=False,
asr_text=asr_txt if isinstance(asr_txt, str) else None,
audio_object_key=akey if isinstance(akey, str) else None,
error_code=exc.code,
)
_raise_confirmation_http(exc, surgery_id)
return SurgeryPendingConfirmationResolveResponse(
surgery_id=surgery_id,
@@ -477,4 +498,5 @@ async def resolve_pending_consumable_confirmation(
rejected=result.rejected,
asr_text=result.asr_text,
audio_object_key=result.audio_object_key,
error_code=None,
)