DroneMind/voice_drone/core/cloud_dialog_v1.py
2026-04-14 09:54:26 +08:00

79 lines
2.6 KiB
Python
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.

"""cloud_voice_dialog_v1dialog_result 约定(见 docs/CLOUD_VOICE_FLIGHT_CONFIRM_v1.md"""
from __future__ import annotations
from typing import Any
CLOUD_VOICE_DIALOG_V1 = "cloud_voice_dialog_v1"
MSG_CONFIRM_TIMEOUT = "未收到确认指令,请重新下发指令。"
MSG_CANCELLED = "已取消指令,请重新唤醒后下发指令。"
MSG_CONFIRM_EXECUTING = "开始执行飞控指令。"
MSG_PROMPT_LISTEN_TIMEOUT = "未检测到语音,请重新唤醒后再说。"
def normalize_phrase_text(s: str) -> str:
"""去首尾空白、合并连续空白。"""
return " ".join((s or "").strip().split())
def _strip_tail_punct(s: str) -> str:
return s.rstrip("。!!?, \t")
def match_phrase_list(norm: str, phrases: Any) -> bool:
"""
命中规则(适配「请回复确认或取消」类长提示 + 只说「确认」「取消」):
- 去尾标点后 **全等** 短语;或
- 短语为 **子串** 且整句长度 <= len(短语)+2避免用户复述整段提示时同时含「确认」「取消」而误触。
"""
if not isinstance(phrases, list) or not norm:
return False
base = _strip_tail_punct(normalize_phrase_text(norm))
if not base:
return False
for p in phrases:
raw = _strip_tail_punct((p or "").strip())
if not raw:
continue
if base == raw:
return True
if raw in base and len(base) <= len(raw) + 2:
return True
return False
def parse_confirm_dict(raw: Any) -> dict[str, Any] | None:
if not isinstance(raw, dict):
return None
required = raw.get("required")
if not isinstance(required, bool):
return None
try:
timeout_sec = float(raw.get("timeout_sec", 10))
except (TypeError, ValueError):
timeout_sec = 10.0
timeout_sec = max(1.0, min(120.0, timeout_sec))
cp = raw.get("confirm_phrases")
kp = raw.get("cancel_phrases")
if not isinstance(cp, list) or not cp:
return None
if not isinstance(kp, list) or not kp:
return None
pending = raw.get("pending_id")
if pending is not None and not isinstance(pending, str):
pending = str(pending)
cplist = [str(x) for x in cp if str(x).strip()]
kplist = [str(x) for x in kp if str(x).strip()]
if not cplist or not kplist:
return None
return {
"required": required,
"timeout_sec": timeout_sec,
"confirm_phrases": cplist,
"cancel_phrases": kplist,
"pending_id": pending,
"summary_for_user": raw.get("summary_for_user"),
"raw": raw,
}