# BADAS - Beyond ADAS

[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
[![PyTorch 2.0+](https://img.shields.io/badge/pytorch-2.0+-ee4c2c.svg)](https://pytorch.org/)
[![PyPI](https://img.shields.io/pypi/v/badas.svg)](https://pypi.org/project/badas/)

**BADAS** (Beyond ADAS) is a deep learning framework for predicting collision likelihood in dashcam video sequences. It supports multiple vision transformer backbones and deployment formats optimized for real-time inference.

## Installation

```bash
pip install badas
```

Optional extras for faster video decoding or alternative backends:

```bash
pip install decord           # Fast video decoding (falls back to OpenCV)
pip install onnxruntime-gpu  # ONNX backend
```

## Quick Start

```python
from badas.inference import BADAS, BADASConfig

predictor = BADAS.from_pretrained("nexar-ai/BADAS-Open")

# Batch prediction on a video
results = predictor.predict_video("dashcam.mp4", stride=1)
for r in results:
    print(f"[{r['timestamp']:.2f}s]  {r['risk_level']:<6}  p={r['probability']:.3f}")

# Streaming / moving-window inference
for pred in predictor.predict_stream("dashcam.mp4", stride=1):
    if pred['probability'] > 0.7:
        print(f"WARNING: High collision risk at {pred['timestamp']:.2f}s")
```

## Prediction Output

Each prediction is a dict:

```python
{
    'frame_index': 100,
    'timestamp': 4.17,
    'probability': 0.823,
    'risk_level': 'high',   # 'low' | 'medium' | 'high'
    'smoothed': True,
}
```

## Inference Backends

| Format | Load | Notes |
|--------|------|-------|
| `.ckpt` / `.pt` | `BADAS("model.ckpt")` | Full model + config, supports `torch.compile` |
| `.onnx` | `BADAS("model.onnx")` | CPU/GPU via ONNX Runtime |
| `.trt` / `.engine` | `BADAS("model.trt")` | NVIDIA GPU, lowest latency |

## Configuration

```python
from badas.inference import BADAS, BADASConfig, SmoothingConfig

config = BADASConfig(
    use_compile=True,       # torch.compile — slow first run, fast thereafter
    startup_ramp=True,      # yield predictions before the full window is buffered
    smoothing=SmoothingConfig(
        enabled=True,
        alpha_rise=0.7,     # smoothing when risk increases
        alpha_fall=0.3,     # smoothing when risk decreases
    ),
)
predictor = BADAS("model.ckpt", config=config)
```

## Available Models

### Open Source

| Model | Size | Notes |
|-------|------|-------|
| `nexar-ai/BADAS-Open` | ViT-L | Publicly available |

```python
predictor = BADAS.from_pretrained("nexar-ai/BADAS-Open")
```

### Commercial (Nexar)

| Model | Params | Architecture | Notes |
|-------|--------|--------------|-------|
| `nexar-ai/badas-2.0` | 330M | ViT-L | Best accuracy |
| `nexar-ai/badas-2.0-flash` | 86M | ViT-B | Fast, default |
| `nexar-ai/badas-2.0-flash-lite` | 22M | ViT-S | Fastest |
| `nexar-ai/badas-1.0` | 330M | ViT-L | Previous version |

To request access, visit [nexar-ai.com/badas](https://www.nexar-ai.com/badas).

## Inference API

For production use, BADAS is available as a hosted REST API at `https://badas-api.corp.nexars.ai`.
The `BADASClient` handles uploads, async job queuing, SSE streaming, and progress bars.

### Installation

`requests` and `tqdm` are included in the base `badas` package — no extra install needed.

### Setup

```python
from badas.client import BADASClient

client = BADASClient(api_key="nxr_live_...")

# Check that models are ready
health = client.health()
print(health["status"], health["models_loaded"])
```

### Predict (blocking)

Submits an async job and polls until complete. Returns a list of prediction dicts.

```python
preds = client.predict("dashcam.mp4")
for p in preds:
    print(f"[{p['timestamp']:.2f}s]  {p['risk_level']:<6}  p={p['probability']:.3f}")
```

### Stream (window-by-window)

Yields each prediction as soon as its window is processed. Reconnects automatically
if the gateway drops the connection.

```python
for pred in client.stream("dashcam.mp4"):
    print(f"[{pred['timestamp']:.1f}s] {pred['risk_level']} ({pred['probability']:.0%})")
```

### Async job (submit / poll / stream)

```python
# Submit returns a job ID immediately — processing runs in the background
job_id = client.submit("dashcam.mp4")

# Stream results as they arrive
for pred in client.stream_job(job_id):
    ...

# Or wait for completion and get all results at once
preds = client.poll_job(job_id)
```

### Inference options

| Parameter | Default | Description |
|-----------|---------|-------------|
| `model` | `badas-2.0-flash` | Model ID (see table above) |
| `stride` | `1` | Window stride in model-fps frames |
| `threshold` | `0.75` | Risk score that triggers heatmaps / VLM descriptions |
| `heatmaps` | `"none"` | `"none"` \| `"threshold"` \| `"always"` |
| `describe` | `False` | VLM hazard description on trigger windows (auto-sets `heatmaps="threshold"`) |
| `include_maps` | `False` | Include raw `hazard_map` / `attention_map` arrays |
| `progress` | `True` | Show tqdm progress bar (adapts to notebook / CLI) |

All options are available on `predict`, `stream`, and `submit`.

### Heatmaps and VLM descriptions

```python
import numpy as np

for pred in client.stream(
    "dashcam.mp4",
    describe=True,    # VLM hazard description for high-risk windows
    threshold=0.8,    # trigger threshold for heatmaps + descriptions
    include_maps=True,
):
    if pred.get("hazard_map") is not None:
        pred["hazard_map"] = np.array(pred["hazard_map"])  # H×W float array
    if pred.get("description"):
        print(f"[{pred['timestamp']:.1f}s] {pred['description']}")
```

### Large files (> 50 MB)

Files above 50 MB are automatically uploaded to GCS via a signed URL before inference —
no changes needed in calling code.

### Model comparison

```python
for model_id in ["nexar-ai/badas-2.0", "nexar-ai/badas-2.0-flash", "nexar-ai/badas-2.0-flash-lite"]:
    preds = client.predict("dashcam.mp4", model=model_id)
    peak  = max(p["probability"] for p in preds)
    print(f"{model_id}: {len(preds)} windows, peak={peak:.3f}")
```

### Available models

| Model | Params | Architecture | Notes |
|-------|--------|--------------|-------|
| `nexar-ai/badas-2.0` | 330M | ViT-L | Best accuracy |
| `nexar-ai/badas-2.0-flash` | 86M | ViT-B | Fast, default |
| `nexar-ai/badas-2.0-flash-lite` | 22M | ViT-S | Fastest |
| `nexar-ai/badas-1.0` | 330M | ViT-L | Previous version |

## Citation

```bibtex
@article{goldshmidt2025badas,
  title={BADAS: Context Aware Collision Prediction Using Real-World Dashcam Data},
  author={Goldshmidt, Roni and Scott, Hamish and Niccolini, Lorenzo and
          Zhu, Shizhan and Moura, Daniel and Zvitia, Orly},
  journal={arXiv preprint},
  year={2025}
}
```
