# SPDX-License-Identifier: Apache-2.0 """ASGI serving app of meteor-p150 on one Tenstorrent Blackhole p150: the HTTP contract of the Autoware collection (vendored ``ttaw.server.app``, BUNDLE_CONVENTIONS.md section 7) bound to :class:`METEOR`. Served by tt-model-manager as ``kind: tt-dit-server``:: python -m uvicorn --host 0.0.0.0 --port
--lifespan on tt_meteor.server.app:app Routes: ``GET /``, ``/health`` and ``/v1/health`` (always 200: ``ok`` / ``starting`` / ``error``), ``/info``, ``/v1/models`` (stub), ``POST /predict``; errors 400 / 422 / 503 / 500 (SERVING.md section 3). Everything that touches the device happens in the lifespan: weights -> device (ETH dispatch, 12x10) -> graph -> trace capture of every warm-up variant, so uvicorn's ``Application startup complete`` (the line ``tt-model serve`` waits for) means warm; SIGTERM (``tt-model stop``, 120 s) closes the model under the lock. ``/predict`` calls the Python API, so it returns exactly what ``model(...)`` returns. Importing this module has no side effects beyond importing fastapi and pydantic (the image's ``verify:`` imports it without a device); the environment is read in the lifespan only. METEOR's request adds one top-level field, ``ego_speed`` (m/s, the graph's ``v0``), decoded into the call kwargs (``METEOR.EXTRA_INPUTS``). ``images`` must hold all eight cameras with their calibration (``ttaw.io.decode_cameras`` with ``CAMERA_ORDER``); an absent narrow camera is sent as an all-zero image (METEOR's data convention: the host replaces its calibration by the donor's). Host tests swap the model before starting the app: ``app.state.ttaw.model_factory = Stub``; ``app.state.ttaw.predict(request)`` is the route handler itself. """ from pathlib import Path from typing import Any, Dict, Optional from .. import __version__ from ..api import METEOR from ..ttaw.server.app import PredictRequest, ServerSpec, create_app, parse_mesh_shape __all__ = ["SPEC", "app", "PredictRequest", "MeteorRequest", "parse_mesh_shape"] class MeteorRequest(PredictRequest): """``POST /predict`` of METEOR: the common envelope + ``ego_speed`` (m/s).""" ego_speed: Optional[float] = None def decode_extra(req: MeteorRequest, kwargs: Dict[str, Any], max_bytes: int) -> None: if req.ego_speed is not None: kwargs["ego_speed"] = float(req.ego_speed) SPEC = ServerSpec( model_name=METEOR.MODEL_NAME, env_prefix=METEOR.ENV_PREFIX, model_cls=METEOR, task="multi-camera multi-task driving perception and end-to-end planning", default_weights=METEOR.DEFAULT_REPO, owner="changh95", io="eight surround-view camera images (768x432 RGB, raw and unrectified) with intrinsics, camera extrinsics and the ego speed in; a BEV lane map, 3D boxes (vehicle / VRU) with stationary flags and agent futures, per-camera 2D boxes, 2D segmentation and depth, 3D occupancy, the ego-relevant traffic light, a risk field and three ego paths with steer / accel / brake out", autoware={"package": "none (METEOR runtime: tier4/METEOR deploy/cpp)", "path": "deploy/cpp", "autoware_universe": "dc193a81e9959de57b751e269127ae9b67e3f300"}, source={"repo": "https://huggingface.co/changh95/meteor-p150", "license": "Apache-2.0"}, calib_dir=Path(__file__).resolve().parents[1] / "calib", version=__version__, description="METEOR (TIER IV, AutowareFoundation/meteor) on one Tenstorrent Blackhole p150. " "Not an OpenAI-compatible API.", request_model=MeteorRequest, decode_extra=decode_extra, ) app = create_app(SPEC)