changh95's picture
tt-model push meteor-p150 (container)
51defdc verified
Raw History Blame Contribute Delete
3.58 kB
# 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 <p> --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)