diff --git a/launch_chffrplus.sh b/launch_chffrplus.sh index 7c78bea69..8844dd53d 100755 --- a/launch_chffrplus.sh +++ b/launch_chffrplus.sh @@ -155,6 +155,8 @@ from pathlib import Path import sys import time +from openpilot.common.file_chunker import get_existing_chunks + start = time.monotonic() last = start log_path = os.environ.get("SP_BOOT_TIMING_LOG") @@ -193,12 +195,14 @@ for mod in mods: log_step(f"import:{mod}") repo_root = Path.cwd().parents[1] -required_files = [ +required_model_artifacts = [ repo_root / "selfdrive/modeld/models/driving_tinygrad.pkl", repo_root / "selfdrive/modeld/models/dmonitoring_model_metadata.pkl", repo_root / "selfdrive/modeld/models/dmonitoring_model_tinygrad.pkl", repo_root / "selfdrive/modeld/models/dm_warp_1928x1208_tinygrad.pkl", repo_root / "selfdrive/modeld/models/dm_warp_1344x760_tinygrad.pkl", +] +required_files = [ repo_root / "selfdrive/pandad/pandad_api_impl.so", repo_root / "selfdrive/controls/lib/lateral_mpc_lib/c_generated_code/acados_ocp_solver_pyx.so", repo_root / "selfdrive/controls/lib/lateral_mpc_lib/c_generated_code/libacados_ocp_solver_lat.so", @@ -207,6 +211,17 @@ required_files = [ repo_root / "opendbc_repo/opendbc/dbc/gm_global_a_powertrain_generated.dbc", ] +for path in required_model_artifacts: + try: + artifact_paths = [Path(p) for p in get_existing_chunks(path)] + except Exception as e: + raise FileNotFoundError(f"Missing prebuilt runtime artifact: {path}") from e + missing_chunks = [p for p in artifact_paths if not p.is_file()] + if missing_chunks: + missing = ", ".join(str(p) for p in missing_chunks) + raise FileNotFoundError(f"Missing prebuilt runtime artifact chunks for {path}: {missing}") +log_step("required_model_artifacts") + for path in required_files: if not path.is_file(): raise FileNotFoundError(f"Missing prebuilt runtime artifact: {path}") diff --git a/selfdrive/ui/layouts/settings/starpilot/driving_model.py b/selfdrive/ui/layouts/settings/starpilot/driving_model.py index c50379575..2c8601b62 100644 --- a/selfdrive/ui/layouts/settings/starpilot/driving_model.py +++ b/selfdrive/ui/layouts/settings/starpilot/driving_model.py @@ -10,6 +10,7 @@ import time import pyray as rl +from openpilot.common.file_chunker import get_chunk_name, get_manifest_path from openpilot.selfdrive.ui.ui_state import ui_state from openpilot.starpilot.assets.model_manager import ( CANCEL_DOWNLOAD_PARAM, @@ -844,6 +845,21 @@ class StarPilotDrivingModelLayout(_SettingsPage): except Exception: return set() + def _artifact_installed(self, filename: str, on_disk_files: set[str]) -> bool: + if filename in on_disk_files: + return True + + manifest = get_manifest_path(filename) + if manifest not in on_disk_files: + return False + + try: + num_chunks = int((self._model_dir / manifest).read_text().strip()) + except Exception: + return False + + return all(get_chunk_name(filename, idx, num_chunks) in on_disk_files for idx in range(num_chunks)) + def _is_model_installed(self, key: str, version: str = "", on_disk_files: set[str] | None = None) -> bool: model_key = canonical_model_key(str(key or "").strip()) if not model_key: @@ -853,7 +869,7 @@ class StarPilotDrivingModelLayout(_SettingsPage): return True files = on_disk_files if on_disk_files is not None else self._load_on_disk_files() - return f"{model_key}_driving_tinygrad.pkl" in files + return self._artifact_installed(f"{model_key}_driving_tinygrad.pkl", files) def _required_files_for_version(self, key: str, version: str) -> list[str]: del version diff --git a/selfdrive/ui/mici/layouts/settings/driving_model.py b/selfdrive/ui/mici/layouts/settings/driving_model.py index 4365c26ec..665fde49f 100644 --- a/selfdrive/ui/mici/layouts/settings/driving_model.py +++ b/selfdrive/ui/mici/layouts/settings/driving_model.py @@ -7,6 +7,7 @@ from dataclasses import dataclass from collections.abc import Callable from pathlib import Path +from openpilot.common.file_chunker import get_chunk_name, get_manifest_path from openpilot.common.params import Params from openpilot.selfdrive.ui.mici.widgets.button import BigButton from openpilot.selfdrive.ui.mici.widgets.dialog import BigDialog, BigDialogBase, BigMultiOptionDialog @@ -698,7 +699,23 @@ class DrivingModelBigButton(BigButton): if not required_files: return False - return all((MODELS_PATH / filename).is_file() for filename in required_files) + return all(self._artifact_installed(filename) for filename in required_files) + + @staticmethod + def _artifact_installed(filename: str) -> bool: + if (MODELS_PATH / filename).is_file(): + return True + + manifest = get_manifest_path(filename) + if not (MODELS_PATH / manifest).is_file(): + return False + + try: + num_chunks = int((MODELS_PATH / manifest).read_text().strip()) + except Exception: + return False + + return all((MODELS_PATH / get_chunk_name(filename, idx, num_chunks)).is_file() for idx in range(num_chunks)) def _is_builtin_default_model(self, key: str) -> bool: default_key = self._params.get_default_value("DrivingModel") or self._params.get_default_value("Model")