mqtt切换为远程服务器部署,优化简单指令解析时长
This commit is contained in:
@@ -171,6 +171,7 @@ MODE_PROFILE_UPDATE_EXPLICIT_TARGET_PATTERN = re.compile(
|
||||
)
|
||||
WIRED_CAN_TRANSPORT = "wired_can"
|
||||
WIRELESS_MQTT_TRANSPORT = "wireless_mqtt"
|
||||
LOCAL_CONTROL_BUDGET_MS = 1000
|
||||
VEHICLE_CONTROL_TRANSPORTS = frozenset(
|
||||
{WIRED_CAN_TRANSPORT, WIRELESS_MQTT_TRANSPORT}
|
||||
)
|
||||
@@ -292,6 +293,7 @@ CONTROL_CLAUSE_SUBJECT_PATTERN = re.compile(
|
||||
r"座椅|座位|靠背|椅背|坐盆|坐垫|腿托|脚托|滑轨|"
|
||||
r"通风|加热|按摩|零重力|半躺|女王副驾|休闲躺椅|"
|
||||
r"遮阳帘|天幕帘|天幕|车窗|窗户|"
|
||||
r"(?:左前|前左|右前|前右|左后|后左|右后|后右)(?:排)?窗|"
|
||||
r"灯光|室内灯|车内灯|阅读灯|氛围灯|"
|
||||
r"空调|压缩机|温度|风量|风速|内循环|外循环|"
|
||||
r"车门|门锁|后备箱|前大灯|近光灯|远光灯|雾灯|转向灯|双闪|"
|
||||
@@ -302,10 +304,17 @@ CONTROL_CLAUSE_PREDICATE_PATTERN = re.compile(
|
||||
r"调整|调节|调到|调成|调为|调至|设置|设为|设到|切换|"
|
||||
r"移动|移到|移至|前移|后移|上移|下移|升高|降低|抬起|放倒|"
|
||||
r"调直|立直|竖直|归零|复位|锁上|上锁|落锁|解锁|"
|
||||
r"零重力|半躺|最大|最小|最高|最低|最前|最后|到底|"
|
||||
r"零重力|半躺|一半|半开|半关|最大|最小|最高|最低|最前|最后|到底|"
|
||||
r"(?:\d+(?:\.\d+)?|[零一二三四五六七八九十百两半]+)"
|
||||
r"(?:%|%|度|℃|档|级|秒|毫秒)"
|
||||
)
|
||||
# These verbs identify an independent request that may be outside the local
|
||||
# vehicle registry. They are used only to split mixed sentences so an
|
||||
# already deterministic clause never has to be repeated to a hosted model.
|
||||
CLOUD_REQUEST_CLAUSE_PATTERN = re.compile(
|
||||
r"播放|暂停播放|停止播放|导航|搜索|查找|查询|拨打|呼叫|发送|"
|
||||
r"提醒|推荐|讲解|介绍|告诉|规划"
|
||||
)
|
||||
RESTORE_MODE_PROFILE_PREFIX = re.compile(
|
||||
r"^(?:请(?:帮我)?|帮我)?(?:恢复|还原|重置|初始化)"
|
||||
r"(?P<name>[^,。,.!!\s]{1,64}?模式)"
|
||||
@@ -1613,9 +1622,11 @@ class SeatDemoService:
|
||||
on_commands_validated: Callable[[dict[str, Any]], None] | None = None,
|
||||
assistant_plan: dict[str, Any] | None = None,
|
||||
mode_profile_draft_context: dict[str, Any] | None = None,
|
||||
_cloud_instruction_context: dict[str, Any] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
"""Validate and execute deterministic controls before hosted parsing."""
|
||||
|
||||
local_stage_started = time.perf_counter()
|
||||
utterance = utterance.strip()
|
||||
if not utterance:
|
||||
raise ValueError("utterance must not be empty")
|
||||
@@ -1644,6 +1655,7 @@ class SeatDemoService:
|
||||
_on_commands_validated=on_commands_validated,
|
||||
_assistant_plan=assistant_plan,
|
||||
_mode_profile_draft_context=mode_profile_draft_context,
|
||||
_cloud_instruction_context=_cloud_instruction_context,
|
||||
)
|
||||
result.update(
|
||||
{
|
||||
@@ -1662,14 +1674,71 @@ class SeatDemoService:
|
||||
vehicle_profile,
|
||||
)
|
||||
clause_results = self._local_clause_results(utterance, context)
|
||||
unresolved_clauses = [
|
||||
locally_parsed_clauses = [
|
||||
clause
|
||||
for clause, _, status in clause_results
|
||||
if status != "unparsed"
|
||||
]
|
||||
locally_resolved_clauses = [
|
||||
clause
|
||||
for clause, _, status in clause_results
|
||||
if status == "complete"
|
||||
]
|
||||
locally_unresolved_clauses = [
|
||||
clause
|
||||
for clause, _, status in clause_results
|
||||
if status != "complete"
|
||||
]
|
||||
started = time.perf_counter()
|
||||
supplied_routing = (
|
||||
_cloud_instruction_context
|
||||
if isinstance(_cloud_instruction_context, dict)
|
||||
else {}
|
||||
)
|
||||
|
||||
def routing_clauses(key: str) -> list[str]:
|
||||
raw = supplied_routing.get(key)
|
||||
if not isinstance(raw, list):
|
||||
return []
|
||||
return [
|
||||
text
|
||||
for item in raw[:64]
|
||||
for text in [str(item).strip()[:1000]]
|
||||
if text
|
||||
]
|
||||
|
||||
def unique_clauses(*groups: list[str]) -> list[str]:
|
||||
return list(dict.fromkeys(item for group in groups for item in group))
|
||||
|
||||
parsed_clauses = unique_clauses(
|
||||
routing_clauses("parsed_clauses"),
|
||||
locally_parsed_clauses,
|
||||
)
|
||||
resolved_clauses = unique_clauses(
|
||||
routing_clauses("resolved_clauses"),
|
||||
locally_resolved_clauses,
|
||||
)
|
||||
unresolved_clauses = locally_unresolved_clauses
|
||||
routing_unresolved_clauses = unique_clauses(
|
||||
routing_clauses("unresolved_clauses"),
|
||||
locally_unresolved_clauses,
|
||||
)
|
||||
original_utterance = str(
|
||||
supplied_routing.get("original_utterance") or utterance
|
||||
).strip()[:1000]
|
||||
natural_language_routing = {
|
||||
"original_utterance": original_utterance,
|
||||
"parsed_clauses": parsed_clauses,
|
||||
"resolved_clauses": resolved_clauses,
|
||||
"unresolved_clauses": routing_unresolved_clauses,
|
||||
}
|
||||
local_dispatch_elapsed_ms: float | None = None
|
||||
|
||||
def publish_local_commands(validated: dict[str, Any]) -> None:
|
||||
nonlocal local_dispatch_elapsed_ms
|
||||
local_dispatch_elapsed_ms = round(
|
||||
(time.perf_counter() - local_stage_started) * 1000,
|
||||
3,
|
||||
)
|
||||
if on_commands_validated is None:
|
||||
return
|
||||
event = deepcopy(validated)
|
||||
@@ -1681,6 +1750,14 @@ class SeatDemoService:
|
||||
"supplement_required": bool(
|
||||
provider != "local" and unresolved_clauses
|
||||
),
|
||||
"natural_language_routing": deepcopy(
|
||||
natural_language_routing
|
||||
),
|
||||
"local_control_budget_ms": LOCAL_CONTROL_BUDGET_MS,
|
||||
"local_control_elapsed_ms": local_dispatch_elapsed_ms,
|
||||
"local_control_within_budget": (
|
||||
local_dispatch_elapsed_ms < LOCAL_CONTROL_BUDGET_MS
|
||||
),
|
||||
}
|
||||
)
|
||||
on_commands_validated(event)
|
||||
@@ -1702,8 +1779,17 @@ class SeatDemoService:
|
||||
_on_commands_validated=publish_local_commands,
|
||||
_assistant_plan=assistant_plan,
|
||||
_mode_profile_draft_context=mode_profile_draft_context,
|
||||
_cloud_instruction_context=natural_language_routing,
|
||||
)
|
||||
elapsed_ms = round(
|
||||
(time.perf_counter() - local_stage_started) * 1000,
|
||||
3,
|
||||
)
|
||||
local_control_elapsed_ms = (
|
||||
local_dispatch_elapsed_ms
|
||||
if local_dispatch_elapsed_ms is not None
|
||||
else elapsed_ms
|
||||
)
|
||||
elapsed_ms = round((time.perf_counter() - started) * 1000, 3)
|
||||
supplement_required = bool(
|
||||
provider != "local" and unresolved_clauses
|
||||
)
|
||||
@@ -1713,7 +1799,17 @@ class SeatDemoService:
|
||||
"provider_requested": provider,
|
||||
"preview_request_id": result["request_id"],
|
||||
"preview_elapsed_ms": elapsed_ms,
|
||||
"local_control_budget_ms": LOCAL_CONTROL_BUDGET_MS,
|
||||
"local_control_elapsed_ms": local_control_elapsed_ms,
|
||||
"local_control_within_budget": (
|
||||
local_control_elapsed_ms < LOCAL_CONTROL_BUDGET_MS
|
||||
),
|
||||
"parsed_clauses": parsed_clauses,
|
||||
"resolved_clauses": resolved_clauses,
|
||||
"unresolved_clauses": unresolved_clauses,
|
||||
"natural_language_routing": deepcopy(
|
||||
natural_language_routing
|
||||
),
|
||||
"supplement_required": supplement_required,
|
||||
}
|
||||
)
|
||||
@@ -1737,7 +1833,10 @@ class SeatDemoService:
|
||||
"hardware_client_id": hardware_client_id,
|
||||
"reasoning_effort": reasoning_effort,
|
||||
"control_transport": control_transport,
|
||||
"parsed_clauses": parsed_clauses,
|
||||
"resolved_clauses": resolved_clauses,
|
||||
"unresolved_clauses": unresolved_clauses,
|
||||
"natural_language_routing": natural_language_routing,
|
||||
"preview_control_signatures": result.get(
|
||||
"parsed_control_signatures", []
|
||||
),
|
||||
@@ -1802,6 +1901,34 @@ class SeatDemoService:
|
||||
for item in manifest.get("preview_control_signatures", [])
|
||||
if isinstance(item, list)
|
||||
}
|
||||
manifest_routing = manifest.get("natural_language_routing")
|
||||
natural_language_routing = (
|
||||
deepcopy(manifest_routing)
|
||||
if isinstance(manifest_routing, dict)
|
||||
else {
|
||||
"original_utterance": str(manifest.get("utterance") or ""),
|
||||
"parsed_clauses": list(manifest.get("parsed_clauses") or []),
|
||||
"resolved_clauses": list(manifest.get("resolved_clauses") or []),
|
||||
"unresolved_clauses": unresolved_clauses,
|
||||
}
|
||||
)
|
||||
routing_unresolved = natural_language_routing.get("unresolved_clauses")
|
||||
natural_language_routing["unresolved_clauses"] = list(
|
||||
dict.fromkeys(
|
||||
[
|
||||
str(item).strip()
|
||||
for item in (
|
||||
routing_unresolved
|
||||
if isinstance(routing_unresolved, list)
|
||||
else []
|
||||
)
|
||||
if str(item).strip()
|
||||
]
|
||||
+ unresolved_clauses
|
||||
)
|
||||
)
|
||||
cloud_utterance = ",".join(unresolved_clauses)
|
||||
natural_language_routing["cloud_input_utterance"] = cloud_utterance
|
||||
|
||||
def publish_cloud_commands(validated: dict[str, Any]) -> None:
|
||||
if on_commands_validated is None:
|
||||
@@ -1818,7 +1945,7 @@ class SeatDemoService:
|
||||
on_commands_validated(event)
|
||||
|
||||
supplement = self.process(
|
||||
",".join(unresolved_clauses),
|
||||
cloud_utterance,
|
||||
provider=selected_provider,
|
||||
conversation_id=str(manifest["conversation_id"]),
|
||||
execution_mode=str(manifest.get("execution_mode") or "dry_run"),
|
||||
@@ -1837,6 +1964,7 @@ class SeatDemoService:
|
||||
_model_parse_source="cloud_supplement",
|
||||
_allow_empty_control_result=True,
|
||||
_on_commands_validated=publish_cloud_commands,
|
||||
_cloud_instruction_context=natural_language_routing,
|
||||
)
|
||||
merged = self._merge_native_can_phases(preview, supplement)
|
||||
merged.update(
|
||||
@@ -1853,6 +1981,7 @@ class SeatDemoService:
|
||||
"supplement_request_id": supplement["request_id"],
|
||||
"supplement_required": False,
|
||||
"unresolved_clauses": unresolved_clauses,
|
||||
"natural_language_routing": natural_language_routing,
|
||||
}
|
||||
)
|
||||
self._persist(merged)
|
||||
@@ -2149,6 +2278,7 @@ class SeatDemoService:
|
||||
_speech_understanding: dict[str, Any] | None = None,
|
||||
_assistant_plan: dict[str, Any] | None = None,
|
||||
_mode_profile_draft_context: dict[str, Any] | None = None,
|
||||
_cloud_instruction_context: dict[str, Any] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
control_transport = self._validate_control_transport(control_transport)
|
||||
# Creating a reusable scene is a configuration workflow. Synthesize
|
||||
@@ -2197,6 +2327,7 @@ class SeatDemoService:
|
||||
_speech_understanding,
|
||||
assistant_plan=_assistant_plan,
|
||||
mode_profile_draft_context=_mode_profile_draft_context,
|
||||
cloud_instruction_context=_cloud_instruction_context,
|
||||
)
|
||||
if control_transport == WIRELESS_MQTT_TRANSPORT:
|
||||
# The head unit owns both physical CAN channels in wireless mode.
|
||||
@@ -2222,6 +2353,7 @@ class SeatDemoService:
|
||||
_speech_understanding,
|
||||
assistant_plan=_assistant_plan,
|
||||
mode_profile_draft_context=_mode_profile_draft_context,
|
||||
cloud_instruction_context=_cloud_instruction_context,
|
||||
)
|
||||
if hardware_access_bypass or self._driver_only_vehicle_execution_active(
|
||||
control_transport
|
||||
@@ -2247,6 +2379,7 @@ class SeatDemoService:
|
||||
_speech_understanding,
|
||||
assistant_plan=_assistant_plan,
|
||||
mode_profile_draft_context=_mode_profile_draft_context,
|
||||
cloud_instruction_context=_cloud_instruction_context,
|
||||
)
|
||||
authorized_client_id = self.hardware_access.ensure_authorized(hardware_client_id)
|
||||
with self.hardware_execution.reserve():
|
||||
@@ -2271,6 +2404,7 @@ class SeatDemoService:
|
||||
_speech_understanding,
|
||||
assistant_plan=_assistant_plan,
|
||||
mode_profile_draft_context=_mode_profile_draft_context,
|
||||
cloud_instruction_context=_cloud_instruction_context,
|
||||
)
|
||||
|
||||
def _process_once(
|
||||
@@ -2296,6 +2430,7 @@ class SeatDemoService:
|
||||
allow_fuzzy_mode_profile_match: bool = True,
|
||||
allow_scene_composition: bool = False,
|
||||
mode_profile_draft_context: dict[str, Any] | None = None,
|
||||
cloud_instruction_context: dict[str, Any] | None = None,
|
||||
) -> dict[str, Any]:
|
||||
control_transport = self._validate_control_transport(control_transport)
|
||||
utterance = utterance.strip()
|
||||
@@ -2626,6 +2761,7 @@ class SeatDemoService:
|
||||
model_parse_source=model_parse_source,
|
||||
assistant_plan=assistant_plan,
|
||||
allow_scene_composition=allow_scene_composition,
|
||||
cloud_instruction_context=cloud_instruction_context,
|
||||
)
|
||||
dynamic_mode_stop = self._is_dynamic_mode_stop_request(utterance)
|
||||
if dynamic_mode_stop:
|
||||
@@ -7280,6 +7416,11 @@ class SeatDemoService:
|
||||
and CONTROL_CLAUSE_PREDICATE_PATTERN.search(value)
|
||||
)
|
||||
|
||||
def looks_like_independent_request(value: str) -> bool:
|
||||
return looks_like_control(value) or bool(
|
||||
CLOUD_REQUEST_CLAUSE_PATTERN.search(value)
|
||||
)
|
||||
|
||||
def split_independent_controls(
|
||||
value: str,
|
||||
separator_pattern: str,
|
||||
@@ -7290,7 +7431,14 @@ class SeatDemoService:
|
||||
for index in range(1, len(tokens), 2):
|
||||
separator = tokens[index]
|
||||
next_item = tokens[index + 1].strip()
|
||||
if looks_like_control(current) and looks_like_control(next_item):
|
||||
if (
|
||||
looks_like_independent_request(current)
|
||||
and looks_like_independent_request(next_item)
|
||||
and (
|
||||
looks_like_control(current)
|
||||
or looks_like_control(next_item)
|
||||
)
|
||||
):
|
||||
if current:
|
||||
separated.append(current)
|
||||
current = next_item
|
||||
@@ -7600,6 +7748,7 @@ class SeatDemoService:
|
||||
model_parse_source: str = "cloud_model",
|
||||
assistant_plan: dict[str, Any] | None = None,
|
||||
allow_scene_composition: bool = False,
|
||||
cloud_instruction_context: dict[str, Any] | None = None,
|
||||
) -> tuple[dict[str, Any], str, str | None]:
|
||||
vehicle_profile = vehicle_profile or self.vehicle_profiles.default()
|
||||
if assistant_plan is not None and allow_scene_composition:
|
||||
@@ -7764,9 +7913,29 @@ class SeatDemoService:
|
||||
interpret_options = {}
|
||||
if reasoning_effort is not None:
|
||||
interpret_options["reasoning_effort"] = reasoning_effort
|
||||
hosted_context = deepcopy(context)
|
||||
if isinstance(cloud_instruction_context, dict):
|
||||
routing_context = deepcopy(cloud_instruction_context)
|
||||
else:
|
||||
routing_context = {
|
||||
"original_utterance": utterance,
|
||||
"parsed_clauses": [
|
||||
clause
|
||||
for clause, _, status in clause_results
|
||||
if status != "unparsed"
|
||||
],
|
||||
"resolved_clauses": [
|
||||
clause
|
||||
for clause, _, status in clause_results
|
||||
if status == "complete"
|
||||
],
|
||||
"unresolved_clauses": fallback_clauses,
|
||||
}
|
||||
routing_context["cloud_input_utterance"] = fallback_utterance
|
||||
hosted_context["natural_language_routing"] = routing_context
|
||||
plan = self.openai.interpret(
|
||||
fallback_utterance,
|
||||
context,
|
||||
hosted_context,
|
||||
self.capability_context,
|
||||
**interpret_options,
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user