> ## Documentation Index
> Fetch the complete documentation index at: https://docs.unicontrol.me/llms.txt
> Use this file to discover all available pages before exploring further.

# alpr-server

> Serviço HTTP+WebSocket para reconhecimento de placas veiculares, rodando na rede do cliente

# alpr-server

O `alpr-server` é um serviço **standalone** que executa reconhecimento automático de placas (ALPR) a partir de streams RTSP. É distribuído por nós como imagem Docker, análogo ao `python-matter-server`: o cliente roda na própria rede e aponta a integração **LPR Genérico** do Portal para o endereço do serviço.

Baseado em [fast-alpr](https://github.com/ankandrew/fast-alpr) (YOLOv9-tiny + OCR CCT via ONNX Runtime).

## Instalação

### Docker (recomendado)

<CodeGroup>
  ```bash CPU theme={null}
  docker run -d \
    --name alpr-server \
    --restart unless-stopped \
    -p 8080:8080 \
    -e ALPR_API_TOKEN="um-token-forte" \
    -v alpr-models:/data/models \
    -v alpr-snapshots:/data/snapshots \
    ghcr.io/unisec/alpr-server:latest
  ```

  ```bash CUDA (NVIDIA GPU) theme={null}
  docker run -d \
    --name alpr-server \
    --restart unless-stopped \
    --gpus all \
    -p 8080:8080 \
    -e ALPR_DEVICE=cuda \
    -e ALPR_API_TOKEN="um-token-forte" \
    -v alpr-models:/data/models \
    ghcr.io/unisec/alpr-server:latest-cuda
  ```
</CodeGroup>

### Docker Compose

Baixe o `docker-compose.example.yml` do pacote e ajuste:

```yaml theme={null}
services:
  alpr-server:
    image: ghcr.io/unisec/alpr-server:latest
    container_name: alpr-server
    restart: unless-stopped
    ports:
      - "8080:8080"
    environment:
      ALPR_DEVICE: cpu
      ALPR_API_TOKEN: "troque-por-um-token-forte"
      ALPR_MAX_STREAMS: "10"
    volumes:
      - alpr-models:/data/models
      - alpr-snapshots:/data/snapshots

volumes:
  alpr-models:
  alpr-snapshots:
```

Rode com `docker compose up -d`.

## Variáveis de ambiente

| Variável | Default | Descrição |
| - | - | - |
| `ALPR_HOST` | `0.0.0.0` | Bind address |
| `ALPR_PORT` | `8080` | Porta HTTP |
| `ALPR_API_TOKEN` | *(vazio)* | Se setado, exige `Authorization: Bearer <token>`. Deixe vazio só em LAN confiável. |
| `ALPR_DEVICE` | `cpu` | `cpu`, `cuda`, `openvino`, `directml`, `qnn` |
| `ALPR_DETECTOR_MODEL` | `yolo-v9-t-384-license-plate-end2end` | Modelo detector (do Model Hub do fast-alpr) |
| `ALPR_OCR_MODEL` | `cct-xs-v2-global-model` | Modelo OCR |
| `ALPR_MODEL_CACHE` | `/data/models` | Cache dos modelos ONNX (monte como volume!) |
| `ALPR_SNAPSHOT_DIR` | `/data/snapshots` | Snapshots em disco |
| `ALPR_MAX_STREAMS` | `10` | Limite simultâneo de streams RTSP |
| `ALPR_LOG_LEVEL` | `info` | `debug`, `info`, `warning`, `error` |

<Note>
  Os modelos ONNX são baixados do GitHub Releases no primeiro `/v1/recognize` ou criação de stream (\~30 MB total). Monte `/data/models` como volume para não re-baixar a cada deploy.
</Note>

## API — resumo

| Endpoint | Descrição |
| - | - |
| `GET /healthz` | Liveness probe. Público. |
| `GET /v1/info` | Versão, modelos, device, streams carregados. Público. |
| `POST /v1/recognize` | One-shot: multipart JPEG → placas detectadas |
| `POST /v1/recognize/base64` | Mesma coisa com JSON `{"image_base64": "..."}` |
| `POST /v1/streams` | Cria stream RTSP persistente |
| `GET \| DELETE /v1/streams/{id}` | Inspeção e remoção |
| `POST /v1/streams/{id}/pause \| resume` | Pausa/retoma processamento |
| `WS /v1/streams/{id}/ws` | WebSocket de eventos (com `?token=...` se auth habilitado) |
| `GET /v1/streams/{id}/events` | SSE equivalente ao WS |
| `GET /v1/snapshots/{read_id}.jpg` | Snapshot de uma leitura |

Documentação OpenAPI interativa em `http://<host>:8080/docs`.

## Payload do evento

```json theme={null}
{
  "stream_id": "cfg-42",
  "plate": "abc-1d23",
  "normalized": "ABC1D23",
  "confidence": 0.94,
  "bbox": {"x": 123, "y": 456, "w": 180, "h": 60},
  "detected_at": "2026-10-10T12:34:56.789Z",
  "snapshot_url": "/v1/snapshots/8b2f.../plate.jpg",
  "vehicle": {"type": null, "color": null},
  "model": {
    "detector": "yolo-v9-t-384-license-plate-end2end",
    "ocr": "cct-xs-v2-global-model"
  }
}
```

## Performance esperada

Valores aproximados por frame (640x480, uma placa):

| Hardware | Tempo médio | Streams simultâneos a 1 fps |
| - | - | - |
| x86\_64 CPU moderno (4 cores) | 60-100 ms | 10+ |
| Raspberry Pi 5 (ARM64 CPU) | 300-500 ms | 2-3 |
| GPU NVIDIA (CUDA) | 10-20 ms | 50+ |
| Intel iGPU (OpenVINO) | 30-50 ms | 15-20 |

Filtro de movimento (habilitado por padrão) reduz carga drasticamente em cenas estáticas.

## Segurança

* Em LAN confiável, pode rodar sem token.
* Em qualquer rede não controlada, **defina `ALPR_API_TOKEN`** e exija pelo menos TLS no reverse proxy à frente.
* O serviço não tem noção de multi-tenancy — cada deploy serve uma unidade administrativa.

## Troubleshooting

* **`VideoCapture init failed`**: FFMPEG não conseguiu abrir o RTSP. Teste com `ffprobe rtsp://url` dentro do container.
* **`CUDA not available`**: imagem CPU; para GPU use a tag `-cuda` e `--gpus all`.
* **Modelos não baixam**: ambiente air-gapped. Pré-popule o volume `/data/models` manualmente a partir das releases do `fast-alpr`.

## Veja também

* [Integração LPR Genérico no Portal](/integracoes/lpr-generico)
* [fast-alpr no GitHub](https://github.com/ankandrew/fast-alpr)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.