优化语音输入/普通文本输入
This commit is contained in:
@@ -532,6 +532,8 @@ class SeatDemoHandler(BaseHTTPRequestHandler):
|
||||
speech_utterance_id = str(
|
||||
payload.get("speech_utterance_id", "")
|
||||
).strip()
|
||||
speech_understanding: dict[str, object] | None = None
|
||||
speech_peripheral_route = False
|
||||
if speech_utterance_id:
|
||||
if path != "/api/requests":
|
||||
raise ValueError(
|
||||
@@ -540,13 +542,28 @@ class SeatDemoHandler(BaseHTTPRequestHandler):
|
||||
speech_understanding = self.speech.cached_result(
|
||||
speech_utterance_id
|
||||
)
|
||||
if str(speech_understanding.get("clean_text", "")).strip() != utterance:
|
||||
clean_text = str(
|
||||
speech_understanding.get("clean_text", "")
|
||||
).strip()
|
||||
raw_text = str(
|
||||
speech_understanding.get("raw_text", "")
|
||||
).strip()
|
||||
peripheral_routing = self._speech_peripheral_routing(raw_text)
|
||||
peripheral_transcript = bool(
|
||||
peripheral_routing.get("execution_eligible") and raw_text
|
||||
)
|
||||
expected_text = raw_text if peripheral_transcript else clean_text
|
||||
if utterance != expected_text:
|
||||
raise SpeechRecognitionError(
|
||||
"speech_text_changed",
|
||||
"语音文本已被修改,请确认修改后的内容再执行。",
|
||||
status=409,
|
||||
)
|
||||
if speech_understanding.get("execution_eligible") is not True:
|
||||
speech_peripheral_route = peripheral_transcript
|
||||
if (
|
||||
speech_understanding.get("execution_eligible") is not True
|
||||
and not speech_peripheral_route
|
||||
):
|
||||
raise SpeechRecognitionError(
|
||||
"speech_not_executable",
|
||||
"语音意图尚未通过能力或参数校验,已拒绝执行。",
|
||||
@@ -554,7 +571,8 @@ class SeatDemoHandler(BaseHTTPRequestHandler):
|
||||
)
|
||||
provider = "local"
|
||||
common_arguments["provider"] = provider
|
||||
common_arguments["_speech_understanding"] = speech_understanding
|
||||
if not speech_peripheral_route:
|
||||
common_arguments["_speech_understanding"] = speech_understanding
|
||||
if (
|
||||
path != "/api/can/commands"
|
||||
and "application/x-ndjson" in self.headers.get("Accept", "")
|
||||
@@ -620,6 +638,14 @@ class SeatDemoHandler(BaseHTTPRequestHandler):
|
||||
)
|
||||
else:
|
||||
result = self.service.process(**common_arguments)
|
||||
if speech_peripheral_route and speech_understanding is not None:
|
||||
result["speech_understanding"] = {
|
||||
"utterance_id": speech_utterance_id,
|
||||
"raw_text": speech_understanding.get("raw_text"),
|
||||
"clean_text": speech_understanding.get("clean_text"),
|
||||
"semantic_status": speech_understanding.get("semantic_status"),
|
||||
"routing": "validated_peripheral_text",
|
||||
}
|
||||
utterance = str(result.get("utterance") or utterance)
|
||||
self.vehicle_display_sync.update_task(
|
||||
status=str(result.get("status", "succeeded")),
|
||||
@@ -815,6 +841,54 @@ class SeatDemoHandler(BaseHTTPRequestHandler):
|
||||
)
|
||||
return result
|
||||
|
||||
def _speech_peripheral_routing(self, utterance: str) -> dict[str, object]:
|
||||
"""Validate whether an ASR transcript may enter peripheral routing.
|
||||
|
||||
Vehicle speech keeps using its cached structured semantic payload. A
|
||||
learned peripheral cannot be represented by the static vehicle
|
||||
capability catalog, so it may instead reuse the exact server-owned ASR
|
||||
transcript only after the live NFC binding and learned action resolve.
|
||||
"""
|
||||
|
||||
text = str(utterance or "").strip()
|
||||
if not text:
|
||||
return {"execution_eligible": False, "action_count": 0}
|
||||
try:
|
||||
catalog = self.extension.list_peripheral_capabilities()
|
||||
nfc_snapshot = self.nfc.snapshot()
|
||||
partition = partition_active_peripheral_intent(
|
||||
text,
|
||||
catalog,
|
||||
nfc_snapshot,
|
||||
)
|
||||
entries = list(partition.get("peripheral_actions") or [])
|
||||
unresolved = list(
|
||||
partition.get("unresolved_peripheral_clauses") or []
|
||||
)
|
||||
denied = list(partition.get("denied_peripheral_actions") or [])
|
||||
plan_catalog = active_peripheral_plan_catalog(
|
||||
text,
|
||||
catalog,
|
||||
nfc_snapshot,
|
||||
)
|
||||
direct = None
|
||||
if not entries and not plan_catalog and not unresolved and not denied:
|
||||
direct = resolve_active_peripheral_command(
|
||||
text,
|
||||
catalog,
|
||||
nfc_snapshot,
|
||||
)
|
||||
except (ExtensionIntegrationError, GatewayError, ValueError):
|
||||
return {"execution_eligible": False, "action_count": 0}
|
||||
action_count = len(entries) or (1 if direct is not None else 0)
|
||||
if plan_catalog:
|
||||
action_count = max(action_count, 1)
|
||||
return {
|
||||
"execution_eligible": bool(action_count and not unresolved and not denied),
|
||||
"action_count": action_count,
|
||||
"has_ordered_plan": bool(plan_catalog),
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _residual_has_vehicle_language(utterance: str) -> bool:
|
||||
"""Recognize only obvious vehicle-domain text in a claimed mixed request."""
|
||||
@@ -2206,6 +2280,14 @@ class SeatDemoHandler(BaseHTTPRequestHandler):
|
||||
self.rfile.read(content_length),
|
||||
utterance_id=self.headers.get("X-Speech-Utterance-Id"),
|
||||
)
|
||||
raw_text = str(result.get("raw_text") or "").strip()
|
||||
peripheral_routing = self._speech_peripheral_routing(raw_text)
|
||||
if peripheral_routing.get("execution_eligible"):
|
||||
result = {
|
||||
**result,
|
||||
"routing_text": raw_text,
|
||||
"peripheral_routing": peripheral_routing,
|
||||
}
|
||||
self._json(result)
|
||||
except SpeechRecognitionError as exc:
|
||||
self._json(
|
||||
|
||||
Reference in New Issue
Block a user