diff --git a/selfdrive/ui/layouts/home.py b/selfdrive/ui/layouts/home.py index 5037b8a57..19be4dda9 100644 --- a/selfdrive/ui/layouts/home.py +++ b/selfdrive/ui/layouts/home.py @@ -9,6 +9,7 @@ from openpilot.selfdrive.ui.widgets.drive_stats import DriveStatsDashboard from openpilot.selfdrive.ui.widgets.home_info_card import HomeInfoCard from openpilot.selfdrive.ui.widgets.setup import SetupWidget from openpilot.selfdrive.ui.lib.starpilot_version import starpilot_display_description +from openpilot.starpilot.common.model_lab import model_lab_pair_display_name_from_params from openpilot.system.ui.lib.text_measure import measure_text_cached from openpilot.system.ui.lib.application import gui_app, FontWeight, MousePos from openpilot.system.ui.lib.multilang import tr, trn @@ -264,7 +265,9 @@ class HomeLayout(Widget): description = starpilot_display_description(self.params.get("UpdaterCurrentDescription")) version_text = f"{brand} {description}" if description else brand - model_name = self.params.get("DrivingModelName", encoding="utf-8") or self.params.get_default_value("DrivingModelName") + model_name = (model_lab_pair_display_name_from_params(self.params) or + self.params.get("DrivingModelName", encoding="utf-8") or + self.params.get_default_value("DrivingModelName")) if isinstance(model_name, bytes): model_name = model_name.decode("utf-8", errors="ignore") model_name = str(model_name or "").replace("_default", "").replace("(Default)", "").strip() diff --git a/selfdrive/ui/mici/layouts/home.py b/selfdrive/ui/mici/layouts/home.py index a38f19125..c85b778bb 100644 --- a/selfdrive/ui/mici/layouts/home.py +++ b/selfdrive/ui/mici/layouts/home.py @@ -14,6 +14,7 @@ from openpilot.system.ui.lib.application import ASSETS_DIR, gui_app, FontWeight, from openpilot.selfdrive.ui.lib.mode_banner import ModeBannerVariant, get_mode_banner_variant, mode_atom_color from openpilot.selfdrive.ui.lib.starpilot_version import STARPILOT_DISPLAY_VERSION from openpilot.selfdrive.ui.ui_state import ui_state +from openpilot.starpilot.common.model_lab import model_lab_pair_display_name_from_params HEAD_BUTTON_FONT_SIZE = 40 HOME_PADDING = 8 @@ -196,7 +197,8 @@ class MiciHomeLayout(Widget): def _clean_model_name(value: str) -> str: return re.sub(r"[πŸ—ΊοΈπŸ‘€πŸ“‘]", "", value).replace("(Default)", "").strip() - current_name = _clean_model_name(ui_state.params.get("DrivingModelName", encoding="utf-8") or "") + current_name = (model_lab_pair_display_name_from_params(ui_state.params) or + _clean_model_name(ui_state.params.get("DrivingModelName", encoding="utf-8") or "")) if not current_name: default_name = ui_state.params.get_default_value("DrivingModelName") if isinstance(default_name, bytes): diff --git a/starpilot/common/model_lab.py b/starpilot/common/model_lab.py index d4fee326f..5d93714db 100644 --- a/starpilot/common/model_lab.py +++ b/starpilot/common/model_lab.py @@ -1,6 +1,7 @@ from __future__ import annotations import json +import re from typing import Any import numpy as np @@ -8,6 +9,7 @@ import numpy as np MODEL_LAB_CONFIG_PARAM = "ModelLabConfig" MODEL_LAB_RUNTIME_PARAM = "ModelLabRuntime" MODEL_LAB_MIN_MODEL_VERSION = 8 +MODEL_LAB_COMPACT_LABEL_MAX_LENGTH = 9 LATERAL_OUTPUT_KEYS = ( "desired_curvature", @@ -32,6 +34,65 @@ CURRENT_FRAME_OUTPUT_KEYS = ( "road_transform_stds", ) + +def compact_model_lab_label(label: Any) -> str: + text = str(label or "").replace("_default", "").replace("(Default)", "").strip() + text = re.sub(r"[πŸ—ΊοΈπŸ‘€πŸ“‘]", "", text) + text = re.sub(r"['’]s\b", "", text, flags=re.IGNORECASE) + text = re.sub(r"\bmodel\b", "", text, flags=re.IGNORECASE) + tokens = re.findall(r"[A-Za-z]+\d*|\d+", text) + if not tokens: + return "" + + joined = "".join(tokens) + if len(joined) <= MODEL_LAB_COMPACT_LABEL_MAX_LENGTH: + return joined + + compact = [] + for token in tokens: + if token.isdigit() or re.fullmatch(r"[vV]\d+", token): + compact.append(token) + elif token.isupper() and len(token) <= 3: + compact.append(token) + else: + compact.append(token[0].upper()) + return "".join(compact) + + +def model_lab_pair_display_name(lateral_label: Any, longitudinal_label: Any) -> str: + lateral = compact_model_lab_label(lateral_label) + longitudinal = compact_model_lab_label(longitudinal_label) + return f"{lateral} + {longitudinal}" if lateral and longitudinal else "" + + +def model_lab_pair_display_name_from_params(params) -> str: + config = load_model_lab_config(params) + if not config["enabled"]: + return "" + + def param_text(key: str) -> str: + try: + value = params.get(key) + except Exception: + return "" + if isinstance(value, bytes): + value = value.decode("utf-8", errors="ignore") + return str(value or "") + + model_ids = [entry.strip() for entry in param_text("AvailableModels").split(",")] + model_names = [entry.strip() for entry in param_text("AvailableModelNames").split(",")] + name_by_id = { + model_id: model_names[index] + for index, model_id in enumerate(model_ids) + if model_id and index < len(model_names) and model_names[index] + } + lateral_id = config["lateralModel"] + longitudinal_id = config["longitudinalModel"] + return model_lab_pair_display_name( + name_by_id.get(lateral_id, lateral_id), + name_by_id.get(longitudinal_id, longitudinal_id), + ) + LATERAL_PLAN_COLUMNS = (1, 4, 7, 11, 14) diff --git a/starpilot/common/tests/test_model_lab.py b/starpilot/common/tests/test_model_lab.py index b9c922ab2..6bf0ceda6 100644 --- a/starpilot/common/tests/test_model_lab.py +++ b/starpilot/common/tests/test_model_lab.py @@ -1,3 +1,4 @@ +import json from types import SimpleNamespace import numpy as np @@ -9,6 +10,8 @@ from openpilot.starpilot.common.model_lab import ( hybrid_action_values, is_small_model_metadata, model_lab_manifest_eligible, + model_lab_pair_display_name, + model_lab_pair_display_name_from_params, normalize_model_lab_config, validate_model_lab_selection, ) @@ -48,6 +51,32 @@ def test_config_normalization_is_closed_by_default(): } +def test_model_lab_pair_display_name_is_compact_and_reads_enabled_config(): + assert model_lab_pair_display_name("South Carolina", "Pop Model V2") == "SC + PopV2" + assert model_lab_pair_display_name("Falling Phoenix", "Down To Ride v6") == "FP + DTRv6" + + class FakeParams: + def __init__(self, values): + self.values = values + + def get(self, key): + return self.values.get(key) + + params = FakeParams({ + "ModelLabConfig": json.dumps({ + "enabled": True, + "lateralModel": "sc23", + "longitudinalModel": "pop223", + }), + "AvailableModels": "sc23,pop223", + "AvailableModelNames": "South Carolina,Pop Model V2", + }) + assert model_lab_pair_display_name_from_params(params) == "SC + PopV2" + + params.values["ModelLabConfig"] = json.dumps({"enabled": False}) + assert model_lab_pair_display_name_from_params(params) == "" + + @pytest.mark.parametrize( ("chestnut_ready", "catalog", "lateral", "longitudinal", "expected"), [ diff --git a/starpilot/system/the_galaxy/tests/test_dashboard_stats.py b/starpilot/system/the_galaxy/tests/test_dashboard_stats.py index 244c692e9..94358decb 100644 --- a/starpilot/system/the_galaxy/tests/test_dashboard_stats.py +++ b/starpilot/system/the_galaxy/tests/test_dashboard_stats.py @@ -1852,6 +1852,7 @@ def test_model_laboratory_api_uses_installed_models_and_enforces_hardware_size_v assert enabled.status_code == 200 assert params.values["ModelLabConfig"]["enabled"] is True assert params.values["Model"] == params.values["DrivingModel"] == "lat" + assert params.values["DrivingModelName"] == "LA + LA" assert params.values["ModelVersion"] == params.values["DrivingModelVersion"] == "v15" mixed_version = client.put("/api/model-laboratory", json={ diff --git a/starpilot/system/the_galaxy/the_galaxy.py b/starpilot/system/the_galaxy/the_galaxy.py index 74456a7dc..3b12cad4c 100644 --- a/starpilot/system/the_galaxy/the_galaxy.py +++ b/starpilot/system/the_galaxy/the_galaxy.py @@ -65,6 +65,7 @@ from openpilot.starpilot.common.model_lab import ( MODEL_LAB_RUNTIME_PARAM, is_small_model_metadata, model_lab_manifest_eligible, + model_lab_pair_display_name, normalize_model_lab_config, validate_model_lab_selection, ) @@ -6309,7 +6310,8 @@ def setup(app): lateral = model_by_key[config["lateralModel"]] params.put("Model", lateral["value"]) params.put("DrivingModel", lateral["value"]) - params.put("DrivingModelName", lateral["label"]) + longitudinal = model_by_key[config["longitudinalModel"]] + params.put("DrivingModelName", model_lab_pair_display_name(lateral["label"], longitudinal["label"])) if lateral.get("version"): params.put("ModelVersion", lateral["version"]) params.put("DrivingModelVersion", lateral["version"])