优化前端,优化前端指令,优化自定义控制

This commit is contained in:
minghanchen
2026-08-24 09:40:16 +08:00
parent fff7657fea
commit 8d05815773
130 changed files with 5543 additions and 2206 deletions
+175 -36
View File
@@ -175,6 +175,108 @@ operations:
finally:
self.service.mode_profiles = original_registry
def test_mode_card_editor_endpoint_persists_generated_can_flow(self) -> None:
original_registry = self.service.mode_profiles
original_artifact_root = self.service.artifact_root
with tempfile.TemporaryDirectory() as directory:
base = Path(directory)
preset_root = base / "presets"
user_root = base / "user-modes"
preset = preset_root / "vehicles" / "denza_n7" / "office.yaml"
preset.parent.mkdir(parents=True)
preset.write_text(
"""
id: office
name: 办公模式
scope:
vehicle_ids: [denza_n7]
operations:
- domain: climate
capability: climate.set_temperature
target_scope: passenger
parameters:
temperature_c: 24
""".strip()
+ "\n",
encoding="utf-8",
)
request_id = "req-mode-editor-api-001"
instruction = "副驾空调温度设置为24度"
artifact_root = base / "runs"
request_dir = artifact_root / request_id
request_dir.mkdir(parents=True)
result = {
"request_id": request_id,
"utterance": instruction,
"execution_mode": "dry_run",
"control_transport": "wireless_mqtt",
"function_configs": {
"native_climate": {
"spec": {
"domain": "climate",
"operations": [
{
"id": "passenger_temperature",
"capability": "climate.set_temperature",
"target": {"zone": "passenger"},
"parameters": {"temperature_c": 24},
}
],
}
}
},
"command_plans": {
"native_climate": {
"spec": {
"commands": [
{
"message": "Native_0x1DE",
"signals": {
"frame_id": "0x1DE",
"data_hex": "00 00 00 00 00 18 00 00",
},
}
]
}
}
},
"execution_report": {"spec": {"results": []}},
}
(request_dir / "result.json").write_text(
json.dumps(result, ensure_ascii=False), encoding="utf-8"
)
self.service.mode_profiles = ModeProfileRegistry(
preset_root, user_root=user_root
)
self.service.artifact_root = artifact_root
try:
request = urllib.request.Request(
f"{self.base_url}/api/mode-profiles/office",
method="POST",
headers={"Content-Type": "application/json"},
data=json.dumps(
{
"name": "专注办公模式",
"instruction": instruction,
"source_request_id": request_id,
"vehicle_id": "denza_n7",
},
ensure_ascii=False,
).encode("utf-8"),
)
with self.opener.open(request, timeout=3) as response:
payload = json.loads(response.read().decode("utf-8"))
self.assertEqual(response.status, 200)
self.assertEqual(payload["storage"], "persistent_yaml")
self.assertEqual(payload["mode_profile"]["origin"], "customized")
self.assertEqual(payload["mode_profile"]["instruction"], instruction)
self.assertTrue(
(user_root / "vehicles" / "denza_n7" / "user" / "office.yaml").is_file()
)
finally:
self.service.mode_profiles = original_registry
self.service.artifact_root = original_artifact_root
def test_head_unit_display_sync_tracks_tasks_and_usb_catalog(self) -> None:
task_request = urllib.request.Request(
f"{self.base_url}/api/requests",
@@ -230,18 +332,18 @@ operations:
def test_static_console_and_runtime_endpoint(self) -> None:
with self.opener.open(f"{self.base_url}/", timeout=3) as response:
html = response.read().decode("utf-8")
with self.opener.open(f"{self.base_url}/app.js?v=dual-seat-90", timeout=3) as response:
with self.opener.open(f"{self.base_url}/app.js?v=dual-seat-101", timeout=3) as response:
app_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/gesture-control.js?v=android-pad-8", timeout=3
f"{self.base_url}/gesture-control.js?v=android-pad-9", timeout=3
) as response:
gesture_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/console-v2.js?v=sync-layout-27", timeout=3
f"{self.base_url}/console-v2.js?v=sync-layout-41", timeout=3
) as response:
console_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/console-v2.css?v=sync-layout-27", timeout=3
f"{self.base_url}/console-v2.css?v=sync-layout-40", timeout=3
) as response:
console_styles = response.read().decode("utf-8")
with self.opener.open(
@@ -263,7 +365,7 @@ operations:
with self.opener.open(f"{self.base_url}/api/runtime", timeout=3) as response:
runtime = json.loads(response.read().decode("utf-8"))
self.assertIn("Cognitive Agent", html)
self.assertIn("511工程-智能座舱", html)
self.assertIn('id="seatTwinCanvas"', html)
self.assertIn('data-vehicle-model="byd-tang-2024-reference"', html)
self.assertIn("整车孪生界面", html)
@@ -276,12 +378,15 @@ operations:
self.assertIn("CMD 0x431 · FB 0x41A · CH1", html)
self.assertIn("CMD 0x431 · FB 0x388 · CH1", html)
self.assertNotIn("透明车体 · 实体设备", html)
self.assertIn('src="/app.js?v=dual-seat-90"', html)
self.assertIn('href="/styles.css?v=dual-seat-10"', html)
self.assertIn('src="/gesture-control.js?v=android-pad-8"', html)
self.assertIn('src="/app.js?v=dual-seat-101"', html)
self.assertIn('href="/styles.css?v=dual-seat-16"', html)
self.assertIn('src="/gesture-control.js?v=android-pad-9"', html)
self.assertNotIn('class="vehicle-system-hud"', html)
self.assertIn('src="/console-v2.js?v=sync-layout-27"', html)
self.assertIn('href="/console-v2.css?v=sync-layout-27"', html)
self.assertIn('src="/console-v2.js?v=sync-layout-41"', html)
self.assertIn('href="/console-v2.css?v=sync-layout-40"', html)
self.assertIn('<body class="console-v2">', html)
self.assertIn('id="v2BootScreen"', html)
self.assertIn('正在加载车机控制与实时状态', html)
self.assertIn('src="/self-extension.js?v=sync-layout-26"', html)
self.assertIn('href="/self-extension.css?v=sync-layout-26"', html)
self.assertNotIn("self-calibration", html)
@@ -291,7 +396,7 @@ operations:
self.assertIn('aria-label="执行车舱控制指令"', html)
self.assertNotIn('"admin"', console_script)
self.assertNotIn("v2RoleSelect", console_script)
self.assertIn('id="v2SidebarToggle"', console_script)
self.assertIn('sidebarToggle.id = "v2SidebarToggle"', console_script)
self.assertIn('id = "v2ModuleSwitcher"', console_script)
self.assertIn(
'panelHeading.classList.add("v2-operation-heading", "v2-module-heading")',
@@ -316,28 +421,33 @@ operations:
)
self.assertIn('511工程-智能座舱', console_script)
self.assertIn('网页控制链路', console_script)
self.assertIn('<span>Hi,</span><strong>user</strong>', console_script)
self.assertIn('["self-orchestration", "self-extension"]', console_script)
self.assertNotIn('label: "自诊断"', console_script)
self.assertIn('<small>手势模型</small>', console_script)
self.assertIn('id="v2GestureModelValue">MediaPipe GR</strong>', console_script)
self.assertIn('id="v2GestureModelNote">Tasks Vision · 0.10.14</small>', console_script)
self.assertIn('<span class="v2-field-caption">配置信息</span>', console_script)
self.assertIn('state.id = "v2VehicleState"', console_script)
self.assertIn('fetch("/api/extension/health"', console_script)
self.assertNotIn('runtimeControls.id = "v2RuntimeControls"', console_script)
self.assertIn('function prepareRuntimeControls(originalForm)', console_script)
self.assertIn('executionField.hidden = false', console_script)
self.assertIn('insertVisibleControl(executionField, "v2-sync-execution-field")', console_script)
self.assertIn('insertVisibleControl(simulationFaultField, "v2-sync-simulation-fault-field")', console_script)
self.assertNotIn('class="v2-profile"', console_script)
self.assertNotIn('class="v2-control-switch"', console_script)
self.assertNotIn('class="v2-config-stack"', console_script)
self.assertNotIn('id="v2GestureModelValue"', console_script)
self.assertNotIn('id="v2VehicleState"', console_script)
self.assertIn('actionRail.append(cameraToggle)', console_script)
self.assertIn("function enhanceConfiguredDropdowns()", console_script)
self.assertNotIn("function enhanceConfiguredDropdowns()", console_script)
self.assertIn("function updateModeEdgeHints()", console_script)
self.assertIn('classList.toggle("v2-twin-active", definition.index === 0)', console_script)
self.assertIn('label: "执行结果与硬件回读"', console_script)
self.assertIn("function requestUserSafeExecutionMode()", console_script)
self.assertIn('const dryRunButton = $(\'[data-execution-mode="dry_run"]\')', console_script)
self.assertIn('if (!dryRunButton.classList.contains("active")) dryRunButton.click()', console_script)
self.assertIn('userTargetText.textContent = "执行目标:虚拟 CAN"', console_script)
self.assertIn("user 固定使用虚拟 CAN 安全执行环境", console_script)
self.assertNotIn("user 演示固定使用真实台架", console_script)
self.assertIn("function keepRunButtonAvailable()", console_script)
self.assertIn('window.setTimeout(() => $("#v2BootScreen")?.remove(), 220)', console_script)
self.assertNotIn("function requestUserSafeExecutionMode()", console_script)
self.assertNotIn('dryRunButton.click()', console_script)
self.assertIn('const DEFAULT_EXECUTION_MODE = "hardware"', app_script)
self.assertIn('preferredExecutionMode: DEFAULT_EXECUTION_MODE', app_script)
self.assertIn('selectExecutionMode(modeAvailable ? preferredMode : "dry_run", { remember: false })', app_script)
self.assertIn('class="mode-option active" id="hardwareMode"', html)
self.assertIn('grid-template-columns: clamp(245px, 18.5vw, 310px)', console_styles)
self.assertIn('.v2-control-switch {', console_styles)
self.assertNotIn('.v2-control-switch {', console_styles)
self.assertIn('.v2-module-switcher {', console_styles)
self.assertIn('grid-template-columns: repeat(2, minmax(0, 1fr))', console_styles)
self.assertIn(
@@ -364,7 +474,7 @@ operations:
self.assertIn('width: clamp(48px, 45%, 72px)', console_styles)
self.assertIn('font-weight: 800', console_styles)
self.assertIn('white-space: nowrap', console_styles)
self.assertIn('.v2-gesture-model-field', console_styles)
self.assertNotIn('.v2-gesture-model-field', console_styles)
self.assertIn('.v2-inline-gesture .v2-camera-toggle', console_styles)
self.assertIn('.v2-inline-gesture .v2-gesture-action-rail', console_styles)
self.assertIn('grid-template-rows: 42px 10px 42px', console_styles)
@@ -373,9 +483,8 @@ operations:
self.assertIn('.v2-inline-gesture #gestureStopButton', console_styles)
self.assertIn('.v2-inline-gesture .v2-gesture-result-stack', console_styles)
self.assertIn('.v2-inline-gesture .v2-gesture-execution-slot', console_styles)
self.assertIn('grid-template-columns: 1fr;', console_styles)
self.assertIn('.v2-page-rail', console_styles)
self.assertIn('.v2-dropdown-menu', console_styles)
self.assertNotIn('.v2-dropdown-menu', console_styles)
self.assertIn('.v2-edge-fade-left', console_styles)
self.assertIn('.v2-edge-fade-right', console_styles)
self.assertIn('.mode-group-divider', console_styles)
@@ -385,8 +494,8 @@ operations:
self.assertIn('.joint-seat-panel .thermal-states', console_styles)
self.assertIn('.joint-twin-shell .domain-readouts', console_styles)
self.assertIn('grid-template-columns: repeat(2, minmax(0, 1fr))', console_styles)
self.assertIn('.v2-config-section > .v2-field-caption', console_styles)
self.assertIn('.console-v2 .v2-config-card {', console_styles)
self.assertNotIn('.v2-config-section', console_styles)
self.assertNotIn('.console-v2 .v2-config-card {', console_styles)
self.assertIn('.console-v2.v2-sidebar-collapsed .workspace', console_styles)
self.assertNotIn('id="hardwareAccessField"', html)
self.assertNotIn('id="hardwareClientLabel"', html)
@@ -406,8 +515,14 @@ operations:
self.assertIn('data-control-transport="wireless_mqtt"', html)
self.assertIn('control_transport: state.controlTransport', app_script)
self.assertIn('const transportField = $("#vehicleTransportField", originalForm)', console_script)
self.assertIn('configStack.append(transportField)', console_script)
self.assertNotIn('runtimeControls.append(transportField)', console_script)
self.assertIn('insertVisibleControl(transportField, "v2-sync-transport-field")', console_script)
self.assertIn('.v2-sync-execution-field .execution-mode-options', console_styles)
self.assertIn('grid-template-columns: repeat(3, minmax(0, 1fr))', console_styles)
self.assertNotIn('class="v2-sync-protocol"', console_script)
self.assertIn('.console-v2 .v2-transport-field .vehicle-transport-options', console_styles)
self.assertIn('.v2-sync-transport-field .mode-option', console_styles)
self.assertIn('overflow-wrap: anywhere', console_styles)
self.assertIn('button.disabled = false', app_script)
self.assertIn('button.setAttribute("aria-pressed", String(selected))', app_script)
self.assertNotIn(
@@ -497,7 +612,7 @@ operations:
self.assertIn('client_type: "web_console"', app_script)
self.assertIn('canvas.addEventListener("webglcontextlost"', app_script)
self.assertIn('"cognitive-agent:module-change"', app_script)
self.assertIn('const CACHE_VERSION = "cognitive-agent-pad-v179"', service_worker)
self.assertIn('const CACHE_VERSION = "cognitive-agent-pad-v202"', service_worker)
self.assertIn('"/assets/pets/self-extension-cat.png?v=3"', service_worker)
self.assertIn(".then(() => self.skipWaiting())", service_worker)
self.assertNotIn("const cached = await caches.match(request)", service_worker)
@@ -544,6 +659,13 @@ operations:
self.assertIn('id="modeGallery"', html)
self.assertIn('id="modeGalleryGroups"', html)
self.assertIn("全部功能模式", html)
self.assertIn('id="modeEditorBackdrop"', html)
self.assertIn('id="modeEditorName"', html)
self.assertIn('id="modeEditorInstruction"', html)
self.assertIn('id="modeEditorExecute"', html)
self.assertIn('id="modeEditorComplete"', html)
self.assertIn('id="modeEditorFlowPreview"', html)
self.assertIn('class="mode-editor-flow-preview empty"', html)
self.assertIn('id="saveModeSource"', html)
self.assertNotIn("主驾 24℃", html)
populate_modes = app_script[
@@ -568,6 +690,17 @@ operations:
self.assertIn('deleteUserModeProfile(deleteButton.dataset.modeDelete)', app_script)
self.assertIn('method: "DELETE"', app_script)
self.assertIn('deleteButton.dataset.modeDelete = mode.id', app_script)
self.assertIn('editButton.dataset.modeEdit = mode.id', app_script)
self.assertIn("function openModeEditor", app_script)
self.assertIn("function executeModeEditorInstruction", app_script)
self.assertIn("function completeModeEditor", app_script)
self.assertIn("function modeEditorReadableCommands", app_script)
self.assertIn("function modeEditorMessagesForOperation", app_script)
self.assertIn("function modeEditorAppendCommandCard", app_script)
self.assertIn('title.textContent = flow?.control_transport === "wireless_mqtt" ? "MQTT 消息序列"', app_script)
self.assertIn("message.payload", app_script)
self.assertIn("source_request_id: editor.sourceRequestId", app_script)
self.assertIn('method: "POST"', app_script)
self.assertIn('data-domain-panel="climate"', html)
self.assertIn('data-domain-panel="roof"', html)
self.assertIn('data-domain-panel="ambient_light"', html)
@@ -624,7 +757,10 @@ operations:
self.assertNotIn('id="transmittanceValue"', html)
self.assertNotIn('id="roofMotorState"', html)
self.assertIn('id="ambientBrightness"', html)
self.assertIn("坐垫脚托夹角133度", html)
self.assertNotIn('class="example-group"', html)
self.assertNotIn('id="safetyStrip"', html)
self.assertNotIn('class="pipeline"', html)
self.assertNotIn('class="topbar"', html)
self.assertNotIn('data-axis="height"', html)
self.assertEqual(runtime["domain"], "cabin")
self.assertEqual(
@@ -632,6 +768,7 @@ operations:
(
runtime["hardware"]["configured"]
or runtime["vehicle_can"]["configured"]
or runtime["vehicle_mqtt"]["configured"]
),
)
self.assertEqual(runtime["hardware"]["supported_targets"], ["front_right"])
@@ -686,11 +823,13 @@ operations:
for item in runtime["capabilities"]
if item["name"].startswith("seat.")
and not item["name"].startswith("seat.set_driver_")
and item["name"] != "seat.recall_driver_memory_native"
]
driver_seat_capabilities = [
item
for item in runtime["capabilities"]
if item["name"].startswith("seat.set_driver_")
or item["name"] == "seat.recall_driver_memory_native"
]
self.assertTrue(passenger_seat_capabilities)
self.assertTrue(
@@ -713,7 +852,7 @@ operations:
) as response:
extension_script = response.read().decode("utf-8")
with self.opener.open(
f"{self.base_url}/app.js?v=dual-seat-90", timeout=3
f"{self.base_url}/app.js?v=dual-seat-101", timeout=3
) as response:
app_script = response.read().decode("utf-8")
@@ -1152,7 +1291,7 @@ operations:
headers={"Content-Type": "application/json"},
data=json.dumps(
{
"utterance": "打开副驾座椅通风",
"utterance": "打开副驾座椅通风,同时播放音乐",
"provider": "openai",
"conversation_id": "conv-e2e-gpt-fallback",
"execution_mode": "dry_run",