mirror of
https://github.com/firestar5683/StarPilot.git
synced 2026-08-20 07:43:48 +08:00
Add GPU model gating and v24 manifest support
This commit is contained in:
@@ -19,7 +19,9 @@ from openpilot.starpilot.assets.model_manager import (
|
||||
MODEL_DOWNLOAD_PARAM,
|
||||
ModelManager,
|
||||
canonical_model_key,
|
||||
external_gpu_available,
|
||||
is_builtin_model_key,
|
||||
model_uses_external_gpu,
|
||||
model_key_aliases,
|
||||
)
|
||||
from openpilot.starpilot.common.starpilot_variables import MODELS_PATH, update_starpilot_toggles
|
||||
@@ -103,6 +105,7 @@ class ModelCatalogEntry:
|
||||
partial: bool
|
||||
community_favorite: bool
|
||||
user_favorite: bool
|
||||
requires_external_gpu: bool = False
|
||||
|
||||
|
||||
def _clean_model_name(name: str) -> str:
|
||||
@@ -637,6 +640,8 @@ class DrivingModelManagerView(AetherInteractiveMixin, Widget):
|
||||
badge_parts.append(tr("Built-in"))
|
||||
if entry.partial:
|
||||
badge_parts.append(tr("Incomplete"))
|
||||
if entry.requires_external_gpu:
|
||||
badge_parts.append(tr("GPU required"))
|
||||
if entry.user_favorite:
|
||||
badge_parts.append(tr("Saved"))
|
||||
elif entry.community_favorite:
|
||||
@@ -963,6 +968,7 @@ class StarPilotDrivingModelLayout(_SettingsPage):
|
||||
partial=partial,
|
||||
community_favorite=(key in self._community_favorites),
|
||||
user_favorite=(key in self._user_favorites),
|
||||
requires_external_gpu=model_uses_external_gpu(key),
|
||||
)
|
||||
|
||||
def _update_model_metadata(self):
|
||||
@@ -1176,6 +1182,9 @@ class StarPilotDrivingModelLayout(_SettingsPage):
|
||||
if entry is None or not entry.installed:
|
||||
gui_app.push_widget(alert_dialog(tr("Model is not available on this device.")))
|
||||
return False
|
||||
if entry.requires_external_gpu and not external_gpu_available():
|
||||
gui_app.push_widget(alert_dialog(tr("This model requires a detected external GPU.")))
|
||||
return False
|
||||
if self._params.get_bool("ModelRandomizer"):
|
||||
gui_app.push_widget(alert_dialog(tr("Turn off Model Randomizer to choose a model manually.")))
|
||||
return False
|
||||
@@ -1209,6 +1218,9 @@ class StarPilotDrivingModelLayout(_SettingsPage):
|
||||
if entry is None:
|
||||
gui_app.push_widget(alert_dialog(tr("Unknown model.")))
|
||||
return False
|
||||
if entry.requires_external_gpu and not external_gpu_available():
|
||||
gui_app.push_widget(alert_dialog(tr("This model requires a detected external GPU.")))
|
||||
return False
|
||||
if entry.installed:
|
||||
gui_app.push_widget(alert_dialog(tr("Model is already on this device.")))
|
||||
return False
|
||||
|
||||
@@ -9,6 +9,7 @@ from pathlib import Path
|
||||
|
||||
from openpilot.common.file_chunker import get_chunk_name, get_manifest_path
|
||||
from openpilot.common.params import Params
|
||||
from openpilot.starpilot.assets.model_manager import external_gpu_available, model_uses_external_gpu
|
||||
from openpilot.selfdrive.ui.mici.widgets.button import BigButton
|
||||
from openpilot.selfdrive.ui.mici.widgets.dialog import BigDialog, BigDialogBase, BigMultiOptionDialog
|
||||
from openpilot.selfdrive.ui.ui_state import ui_state
|
||||
@@ -62,6 +63,7 @@ class ModelEntry:
|
||||
version: str
|
||||
released: str
|
||||
community_favorite: bool
|
||||
requires_external_gpu: bool = False
|
||||
|
||||
|
||||
def _clean_model_name(name: str) -> str:
|
||||
@@ -515,6 +517,10 @@ class DrivingModelBigButton(BigButton):
|
||||
return entry_list
|
||||
|
||||
def _start_model_download(self, model_key: str):
|
||||
entry = next((item for item in self._load_model_entries() if item.key == model_key), None)
|
||||
if entry is not None and entry.requires_external_gpu and not external_gpu_available():
|
||||
self._show_message("GPU required", "This model requires a detected external GPU.", return_to_manager=True)
|
||||
return
|
||||
if not self._start_worker("download", self._run_download_one, model_key):
|
||||
self._show_message("Model manager busy", "Please wait for the current task.", return_to_manager=True)
|
||||
return
|
||||
@@ -546,6 +552,10 @@ class DrivingModelBigButton(BigButton):
|
||||
self._show_message("Model unavailable", "Refresh manifest and try again.", return_to_manager=True)
|
||||
return
|
||||
|
||||
if entry.requires_external_gpu and not external_gpu_available():
|
||||
self._show_message("GPU required", "This model requires a detected external GPU.", return_to_manager=True)
|
||||
return
|
||||
|
||||
if not self._is_model_installed(entry.key, entry.version):
|
||||
self._show_message("Model not downloaded", "Download this model first.", return_to_manager=True)
|
||||
return
|
||||
@@ -662,6 +672,7 @@ class DrivingModelBigButton(BigButton):
|
||||
version=version,
|
||||
released=released,
|
||||
community_favorite=(key in community_favs),
|
||||
requires_external_gpu=model_uses_external_gpu(key),
|
||||
))
|
||||
|
||||
return entries
|
||||
|
||||
@@ -22,8 +22,9 @@ from openpilot.starpilot.common.model_versions import (
|
||||
)
|
||||
from openpilot.starpilot.common.starpilot_utilities import delete_file
|
||||
from openpilot.starpilot.common.starpilot_variables import MODELS_PATH
|
||||
from openpilot.system.hardware.usb import chestnut_firmware_ready
|
||||
|
||||
MANIFEST_CANDIDATES = ("v23",)
|
||||
MANIFEST_CANDIDATES = ("v24",)
|
||||
MODEL_NAMESPACE_SUFFIX = "3"
|
||||
DEFAULT_MODEL_KEY = "rdf43"
|
||||
LOCAL_MODEL_PREFIX = "local-"
|
||||
@@ -100,6 +101,14 @@ def model_uses_external_gpu(model_key: str) -> bool:
|
||||
return bool(load_model_artifact_metadata(model_key).get("uses_external_gpu", False))
|
||||
|
||||
|
||||
def external_gpu_available() -> bool:
|
||||
"""Return whether the supported external GPU link is ready for modeld."""
|
||||
try:
|
||||
return bool(chestnut_firmware_ready())
|
||||
except Exception:
|
||||
return False
|
||||
|
||||
|
||||
class ModelManager:
|
||||
def __init__(self, params, params_memory, boot_run=False):
|
||||
self.params = params
|
||||
@@ -377,6 +386,8 @@ class ModelManager:
|
||||
canonical_key = self._canonical_model_key(model_key)
|
||||
if canonical_key in blacklisted_keys or canonical_key in seen_keys:
|
||||
continue
|
||||
if model_uses_external_gpu(canonical_key) and not external_gpu_available():
|
||||
continue
|
||||
|
||||
model_version = version_map.get(model_key) or version_map.get(canonical_key) or ""
|
||||
if not model_version and is_builtin_model_key(canonical_key):
|
||||
@@ -484,6 +495,13 @@ class ModelManager:
|
||||
return
|
||||
|
||||
selected = self._selected_model()
|
||||
if model_uses_external_gpu(selected) and not external_gpu_available():
|
||||
default_name = self._default_param_text("DrivingModelName") or "Regret Driven Framework V4"
|
||||
default_version = self._default_param_text("ModelVersion") or self._default_param_text("DrivingModelVersion") or "v15"
|
||||
self._set_model_param_keys(DEFAULT_MODEL_KEY, default_name, default_version)
|
||||
print(f"Model {selected} requires an external GPU; selected built-in model instead.")
|
||||
return
|
||||
|
||||
if is_builtin_model_key(selected):
|
||||
self._sync_selected_model_version()
|
||||
return
|
||||
@@ -673,6 +691,11 @@ class ModelManager:
|
||||
self.downloading_model = False
|
||||
return
|
||||
|
||||
if model_uses_external_gpu(model_to_download) and not external_gpu_available():
|
||||
handle_error(None, "External GPU required...", "This model requires a detected external GPU.", MODEL_DOWNLOAD_PARAM, DOWNLOAD_PROGRESS_PARAM, self.params_memory)
|
||||
self.downloading_model = False
|
||||
return
|
||||
|
||||
# Local models have no upstream URL; a download attempt would 404 and then
|
||||
# delete_file() the artifact on verification failure.
|
||||
if is_local_model_key(model_to_download):
|
||||
@@ -787,6 +810,9 @@ class ModelManager:
|
||||
if is_local_model_key(model_key):
|
||||
continue
|
||||
|
||||
if model_uses_external_gpu(model_key) and not external_gpu_available():
|
||||
continue
|
||||
|
||||
artifact_format = artifact_format_map.get(model_key, "")
|
||||
if self._is_model_downloaded(model_key, artifact_format):
|
||||
continue
|
||||
|
||||
@@ -15,12 +15,12 @@ from openpilot.starpilot.assets.model_manager import MANIFEST_CANDIDATES, ModelM
|
||||
from openpilot.starpilot.common.model_versions import UNIFIED_ARTIFACT_FORMAT
|
||||
|
||||
|
||||
def test_v23_is_the_only_manifest_candidate():
|
||||
assert MANIFEST_CANDIDATES == ("v23",)
|
||||
def test_v24_is_the_only_manifest_candidate():
|
||||
assert MANIFEST_CANDIDATES == ("v24",)
|
||||
|
||||
|
||||
def test_v23_manifest_is_loaded_from_models_checkout():
|
||||
assert ModelManager._manifest_paths("v23") == ("Models/model_names_v23.json",)
|
||||
def test_v24_manifest_is_loaded_from_models_checkout():
|
||||
assert ModelManager._manifest_paths("v24") == ("Models/model_names_v24.json",)
|
||||
|
||||
|
||||
def test_old_manifest_ids_resolve_to_v23_namespace():
|
||||
|
||||
@@ -48,7 +48,13 @@ from openpilot.system.version import get_build_metadata
|
||||
from openpilot.tools.longitudinal_maneuvers.capabilities import get_longitudinal_maneuver_support
|
||||
from panda import Panda
|
||||
|
||||
from openpilot.starpilot.assets.model_manager import canonical_model_key, is_builtin_model_key, model_key_aliases
|
||||
from openpilot.starpilot.assets.model_manager import (
|
||||
canonical_model_key,
|
||||
external_gpu_available,
|
||||
is_builtin_model_key,
|
||||
model_key_aliases,
|
||||
model_uses_external_gpu,
|
||||
)
|
||||
from openpilot.starpilot.assets.theme_manager import HOLIDAY_THEME_PATH, THEME_COMPONENT_PARAMS
|
||||
from openpilot.starpilot.common.accel_profile import (
|
||||
CUSTOM_ACCEL_PROFILE_INITIALIZED_KEY,
|
||||
@@ -5008,6 +5014,8 @@ def setup(app):
|
||||
selected_model = canonical_model_key(str_val.strip())
|
||||
if not selected_model:
|
||||
return jsonify({"error": "Driving model cannot be empty."}), 400
|
||||
if model_uses_external_gpu(selected_model) and not external_gpu_available():
|
||||
return jsonify({"error": "This model requires a detected external GPU."}), 409
|
||||
|
||||
params.put("Model", selected_model)
|
||||
params.put("DrivingModel", selected_model)
|
||||
@@ -5376,6 +5384,8 @@ def setup(app):
|
||||
|
||||
if model["installed"]:
|
||||
return jsonify({"message": f"\"{model['label']}\" is already installed."}), 200
|
||||
if model["requiresGpu"] and not model["gpuAvailable"]:
|
||||
return jsonify({"error": "This model requires a detected external GPU."}), 409
|
||||
|
||||
params_memory.remove(MODEL_CANCEL_DOWNLOAD_PARAM)
|
||||
params_memory.remove(MODEL_DOWNLOAD_ALL_PARAM)
|
||||
@@ -5392,7 +5402,7 @@ def setup(app):
|
||||
if params_memory.get_bool(MODEL_DOWNLOAD_ALL_PARAM) or (params_memory.get(MODEL_DOWNLOAD_PARAM, encoding="utf-8") or ""):
|
||||
return jsonify({"error": "A model download is already in progress."}), 409
|
||||
|
||||
missing_models = [model for model in get_model_catalog() if not model["installed"]]
|
||||
missing_models = [model for model in get_model_catalog() if not model["installed"] and (not model["requiresGpu"] or model["gpuAvailable"])]
|
||||
if not missing_models:
|
||||
return jsonify({"message": "All models are already installed."}), 200
|
||||
|
||||
@@ -5684,6 +5694,7 @@ def setup(app):
|
||||
except Exception:
|
||||
on_disk_files = set()
|
||||
|
||||
external_gpu_present = external_gpu_available()
|
||||
models_by_key = {}
|
||||
for i, key in enumerate(available):
|
||||
canonical_key = canonical_model_key(key)
|
||||
@@ -5695,6 +5706,8 @@ def setup(app):
|
||||
artifact_format = artifact_formats[i] if i < len(artifact_formats) else ""
|
||||
model_series = series[i] if i < len(series) and series[i] else "Custom Series"
|
||||
released = released_dates[i] if i < len(released_dates) else ""
|
||||
requires_external_gpu = model_uses_external_gpu(canonical_key)
|
||||
gpu_available = not requires_external_gpu or external_gpu_present
|
||||
|
||||
existing = models_by_key.get(canonical_key)
|
||||
if existing is None:
|
||||
@@ -5704,6 +5717,8 @@ def setup(app):
|
||||
"series": model_series,
|
||||
"version": model_version,
|
||||
"artifactFormat": artifact_format,
|
||||
"requiresGpu": requires_external_gpu,
|
||||
"gpuAvailable": gpu_available,
|
||||
"released": released,
|
||||
"builtin": is_builtin_model_key(canonical_key),
|
||||
"communityFavorite": canonical_key in community_favorites,
|
||||
@@ -5724,6 +5739,8 @@ def setup(app):
|
||||
existing["builtin"] = existing["builtin"] or is_builtin_model_key(canonical_key)
|
||||
existing["communityFavorite"] = existing["communityFavorite"] or canonical_key in community_favorites
|
||||
existing["userFavorite"] = existing["userFavorite"] or canonical_key in user_favorites
|
||||
existing["requiresGpu"] = existing["requiresGpu"] or requires_external_gpu
|
||||
existing["gpuAvailable"] = not existing["requiresGpu"] or external_gpu_present
|
||||
|
||||
default_key = _default_model_key()
|
||||
default_entry = models_by_key.setdefault(default_key, {
|
||||
@@ -5732,6 +5749,8 @@ def setup(app):
|
||||
"series": "Custom Series",
|
||||
"version": _default_model_version(),
|
||||
"artifactFormat": "tinygrad_single_v1",
|
||||
"requiresGpu": False,
|
||||
"gpuAvailable": True,
|
||||
"released": "",
|
||||
"builtin": True,
|
||||
"communityFavorite": default_key in community_favorites,
|
||||
|
||||
Reference in New Issue
Block a user