feat(scenes): add deterministic romantic cinema template
This commit is contained in:
@@ -116,7 +116,10 @@ from cognitive_agent.application.native_can_runtime import ( # noqa: E402
|
||||
NativeCanExecutor,
|
||||
NativeCanRuntime,
|
||||
)
|
||||
from cognitive_agent.application.scene_templates import SceneTemplateRegistry # noqa: E402
|
||||
from cognitive_agent.application.scene_templates import ( # noqa: E402
|
||||
PRESERVE_BASE_EXTERNAL_LIGHT_TEMPLATE_IDS,
|
||||
SceneTemplateRegistry,
|
||||
)
|
||||
from cognitive_agent.application.schedule_intent import ( # noqa: E402
|
||||
is_schedule_stop,
|
||||
needs_mode_schedule,
|
||||
@@ -745,14 +748,14 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
merged[existing] = action
|
||||
return merged
|
||||
|
||||
def _n7_cinema_base_scene(
|
||||
def _n7_cinema_base_profile(
|
||||
self,
|
||||
incoming_scene: Mapping[str, Any],
|
||||
) -> dict[str, Any] | None:
|
||||
) -> ModeProfile | None:
|
||||
if self._is_n7_cinema_base_scene(incoming_scene):
|
||||
return None
|
||||
vehicle_id = self.vehicle_profiles.default().id
|
||||
candidates: list[tuple[int, dict[str, Any]]] = []
|
||||
candidates: list[tuple[int, ModeProfile]] = []
|
||||
for public_profile in self.mode_profiles.public_modes(vehicle_id):
|
||||
try:
|
||||
profile = self.mode_profiles.get_profile(
|
||||
@@ -774,12 +777,26 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
):
|
||||
continue
|
||||
priority = 0 if str(source_scene.get("id") or "") == "cinema" else 1
|
||||
candidates.append((priority, deepcopy(dict(source_scene))))
|
||||
candidates.append((priority, profile))
|
||||
if not candidates:
|
||||
return None
|
||||
candidates.sort(key=lambda item: (item[0], str(item[1].get("id") or "")))
|
||||
candidates.sort(key=lambda item: (item[0], item[1].id))
|
||||
return candidates[0][1]
|
||||
|
||||
def _n7_cinema_base_scene(
|
||||
self,
|
||||
incoming_scene: Mapping[str, Any],
|
||||
) -> dict[str, Any] | None:
|
||||
profile = self._n7_cinema_base_profile(incoming_scene)
|
||||
if profile is None:
|
||||
return None
|
||||
source_scene = (
|
||||
profile.command_flow.get("source_scene")
|
||||
if isinstance(profile.command_flow, Mapping)
|
||||
else None
|
||||
)
|
||||
return deepcopy(dict(source_scene)) if isinstance(source_scene, Mapping) else None
|
||||
|
||||
@staticmethod
|
||||
def _is_n7_cinema_video_launch_action(action: Mapping[str, Any]) -> bool:
|
||||
parameters = action.get("parameters")
|
||||
@@ -1428,9 +1445,22 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
|
||||
requests = self.mode_profiles.requests_for_profiles([profile])
|
||||
if profile.sync_origin != MQTT_MODE_SCENE_INGRESS_TOPIC:
|
||||
transfer_actions = self._local_cinema_n7_transfer_actions(
|
||||
profile.name,
|
||||
profile.instruction,
|
||||
stored_transfer_actions = (
|
||||
profile.command_flow.get("n7_transfer_actions")
|
||||
if isinstance(profile.command_flow, Mapping)
|
||||
else None
|
||||
)
|
||||
transfer_actions = (
|
||||
[
|
||||
deepcopy(dict(action))
|
||||
for action in stored_transfer_actions[:256]
|
||||
if isinstance(action, Mapping)
|
||||
]
|
||||
if isinstance(stored_transfer_actions, list)
|
||||
else self._local_cinema_n7_transfer_actions(
|
||||
profile.name,
|
||||
profile.instruction,
|
||||
)
|
||||
)
|
||||
transfer_selectors = {
|
||||
self._n7_transfer_operation_selector(
|
||||
@@ -2020,8 +2050,22 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
raise ValueError("动态模式更新必须保留完整时间轴,请按阶段重新生成预览。")
|
||||
if schedule is not None:
|
||||
operations = [deepcopy(op) for phase in schedule.phases for op in phase.operations]
|
||||
source_template_id = (
|
||||
str(source_draft.get("source_template_id") or "").strip()
|
||||
if isinstance(source_draft, Mapping)
|
||||
else ""
|
||||
)
|
||||
preview_transfer_candidates = source_result.get("n7_transfer_candidates")
|
||||
n7_transfer_actions = (
|
||||
self._local_cinema_n7_transfer_actions(
|
||||
[
|
||||
deepcopy(dict(action))
|
||||
for action in preview_transfer_candidates[:256]
|
||||
if isinstance(action, Mapping)
|
||||
]
|
||||
if schedule is None
|
||||
and source_template_id in PRESERVE_BASE_EXTERNAL_LIGHT_TEMPLATE_IDS
|
||||
and isinstance(preview_transfer_candidates, list)
|
||||
else self._local_cinema_n7_transfer_actions(
|
||||
clean_name,
|
||||
clean_instruction,
|
||||
)
|
||||
@@ -6966,13 +7010,34 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
mode_name,
|
||||
vehicle_id=vehicle_profile.id,
|
||||
)
|
||||
if scene_template is not None and existing_profile is not None:
|
||||
preserve_base_external_lights = bool(
|
||||
scene_template is not None
|
||||
and scene_template.id in PRESERVE_BASE_EXTERNAL_LIGHT_TEMPLATE_IDS
|
||||
)
|
||||
if (
|
||||
scene_template is not None
|
||||
and existing_profile is not None
|
||||
and not preserve_base_external_lights
|
||||
):
|
||||
raise ValueError("同名功能模式已创建,请重新提交以载入最新模式。")
|
||||
source_profile = (
|
||||
existing_profile
|
||||
if not requested_instruction and source_draft is None
|
||||
and not preserve_base_external_lights
|
||||
else None
|
||||
)
|
||||
if (
|
||||
source_profile is None
|
||||
and source_draft is None
|
||||
and not requested_instruction
|
||||
and preserve_base_external_lights
|
||||
):
|
||||
source_profile = self._n7_cinema_base_profile(
|
||||
{
|
||||
"id": scene_template.id,
|
||||
"name": mode_name,
|
||||
}
|
||||
)
|
||||
if source_profile is None and source_draft is None and not requested_instruction and scene_template is None:
|
||||
source_name = mode_creation_source_name(mode_name)
|
||||
if source_name != mode_name:
|
||||
@@ -7000,7 +7065,18 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
# of appending a model prompt to the user's utterance. The latter was
|
||||
# being parsed as a second control clause on the assistant's local fast
|
||||
# path, turning a valid nine-action mode into an incomplete draft.
|
||||
source_utterance = requested_instruction or f"进入{draft_mode_name}"
|
||||
draft_instruction = requested_instruction or f"进入{draft_mode_name}"
|
||||
inherited_n7_cinema_profile = bool(
|
||||
source_profile is not None
|
||||
and scene_template is not None
|
||||
and scene_template.id in PRESERVE_BASE_EXTERNAL_LIGHT_TEMPLATE_IDS
|
||||
and source_profile.sync_origin == MQTT_MODE_SCENE_INGRESS_TOPIC
|
||||
)
|
||||
source_utterance = (
|
||||
f"进入{source_profile.name}"
|
||||
if inherited_n7_cinema_profile
|
||||
else draft_instruction
|
||||
)
|
||||
if requested_instruction and selected_seats is not None and len(selected_seats) == 1:
|
||||
# Qualify only explicit seat-device clauses, never an HVAC/window
|
||||
# zone or unrelated control. General one-shot controls keep their
|
||||
@@ -7056,7 +7132,19 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
self._persist(result)
|
||||
return result
|
||||
try:
|
||||
if scene_template is not None and selected_seats is not None:
|
||||
preserve_unscoped_template_seats = bool(
|
||||
scene_template is not None
|
||||
and scene_template.id in PRESERVE_BASE_EXTERNAL_LIGHT_TEMPLATE_IDS
|
||||
and resolve_explicit_seat_scopes(
|
||||
utterance,
|
||||
assume_seat_context=True,
|
||||
) is None
|
||||
)
|
||||
if (
|
||||
scene_template is not None
|
||||
and selected_seats is not None
|
||||
and not preserve_unscoped_template_seats
|
||||
):
|
||||
assistant_plan = project_seed_plan(assistant_plan, selected_seats)
|
||||
source_result = self._process_once(
|
||||
source_utterance,
|
||||
@@ -7070,7 +7158,9 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
direct_mode_profile_id=(
|
||||
source_profile.id if source_profile is not None else None
|
||||
),
|
||||
mode_creation_scopes=selected_seats,
|
||||
mode_creation_scopes=(
|
||||
None if preserve_unscoped_template_seats else selected_seats
|
||||
),
|
||||
assistant_plan=assistant_plan,
|
||||
# ``source_utterance`` is synthesized for a name-only, unknown
|
||||
# scene. It must not fall back to substring matching (for example
|
||||
@@ -7086,7 +7176,11 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
# already passed the ordinary text/target authorization path.
|
||||
# Its old display name cannot veto an explicitly requested new
|
||||
# seat. This override is internal, never accepted from payloads.
|
||||
scene_scope_utterance="" if source_draft is not None else utterance,
|
||||
scene_scope_utterance=(
|
||||
""
|
||||
if source_draft is not None or preserve_unscoped_template_seats
|
||||
else utterance
|
||||
),
|
||||
)
|
||||
except ModeCreationSeatPolicyError as exc:
|
||||
return self._mode_creation_seat_failure(utterance, conversation_id, vehicle_profile, str(exc))
|
||||
@@ -7219,6 +7313,16 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
typed_source_actions = [
|
||||
action for action in source_actions if isinstance(action, dict)
|
||||
] if isinstance(source_actions, list) else []
|
||||
if (
|
||||
inherited_n7_cinema_profile
|
||||
and source_result.get("status") == "partially_succeeded"
|
||||
and typed_source_actions
|
||||
and source_result.get("n7_transfer_candidates")
|
||||
):
|
||||
# N7-only actions are intentionally deferred during a dry-run. They
|
||||
# remain part of the received cinema base and are persisted as
|
||||
# transfer actions, so their presence is not a partial draft.
|
||||
source_result["status"] = "succeeded"
|
||||
if (
|
||||
source_result.get("status") == "succeeded"
|
||||
and generation_source
|
||||
@@ -7228,6 +7332,7 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
"scene_template_copy",
|
||||
}
|
||||
and assistant_plan is not None
|
||||
and not inherited_n7_cinema_profile
|
||||
and (
|
||||
self._scene_plan_signatures(assistant_plan)
|
||||
!= self._scene_action_signatures(typed_source_actions)
|
||||
@@ -7372,9 +7477,10 @@ class SeatDemoService(ModeScheduleServiceMixin):
|
||||
if source_draft is not None
|
||||
else 0
|
||||
)
|
||||
source_result["utterance"] = draft_instruction
|
||||
source_result["mode_profile_draft"] = {
|
||||
"name": draft_mode_name,
|
||||
"instruction": source_utterance,
|
||||
"instruction": draft_instruction,
|
||||
"source_request_id": source_request_id,
|
||||
"vehicle_id": vehicle_profile.id,
|
||||
"domains": domains,
|
||||
|
||||
Reference in New Issue
Block a user