| # badrex Ethio-ASR Inference Endpoint | |
| Custom HuggingFace Inference Endpoint handler for **badrex Ethio-ASR** | |
| (wav2vec2-bert CTC) models β the endpoint counterpart of | |
| `src/transcribers/badrex.py`. Native Tigrinya ASR that beat MMS in the | |
| 2026-06-14 eval. | |
| The model served is chosen by the **`BADREX_MODEL`** environment variable | |
| (default `badrex/Ethio-ASR-multilingual-1B`). The handler holds no weights β | |
| they're pulled from the Hub on cold start, same as the MMS endpoint. | |
| Long audio is chunked **inside the HF ASR pipeline** (`chunk_length_s=30`, | |
| `stride_length_s=5`), so a full broadcast goes through in one request β no | |
| client-side splitting, and no OOM on hour-long audio. | |
| --- | |
| ## Deploy | |
| ### 1. Create a HuggingFace repo | |
| huggingface.co β New model β e.g. `badrex-endpoint`. | |
| ### 2. Push this directory | |
| ```bash | |
| cd endpoint-badrex/ | |
| git init | |
| git remote add origin https://huggingface.co/YOUR_USERNAME/badrex-endpoint | |
| git add handler.py requirements.txt config.json | |
| git commit -m "add badrex custom handler" | |
| git push origin main | |
| ``` | |
| ### 3. Create the Inference Endpoint | |
| [ui.endpoints.huggingface.co](https://ui.endpoints.huggingface.co) β New endpoint: | |
| | Setting | Value | | |
| |---|---| | |
| | Model repository | `YOUR_USERNAME/badrex-endpoint` | | |
| | Task | `Custom` | | |
| | Hardware | `GPU Β· T4 Β· 1x` | | |
| | Min replicas | `0` (scale to zero) | | |
| | Max replicas | `1` | | |
| **Pick the model** under the endpoint's **Environment variables**: | |
| | Variable | Value | | |
| |---|---| | |
| | `BADREX_MODEL` | `badrex/Ethio-ASR-multilingual-1B` (default; auto-detects am/ti, robust to Amharic-leakage on bilingual ti channels) | | |
| | | or `badrex/Ethio-ASR-tigrinya` (lighter, monolingual, slightly cleaner on pure Tigrinya) | | |
| ### 4. Point newsgrab at it | |
| In `channels.yaml`: | |
| ```yaml | |
| settings: | |
| asr_routing: {ti: badrex} # send Tigrinya to badrex; everything else stays on MMS | |
| badrex: | |
| device: api | |
| api_url: https://YOUR-ENDPOINT-ID.endpoints.huggingface.cloud | |
| api_token: null # set HF_TOKEN environment variable instead | |
| ``` | |
| In `api` mode the endpoint **is** the model, so `badrex.models` / | |
| `badrex.default_model` are ignored β the served checkpoint is whatever | |
| `BADREX_MODEL` selects. | |
| --- | |
| ## Updating / rolling back | |
| Same as the MMS endpoint: push the new `handler.py`, then **Settings β Revision** | |
| (pin a commit SHA, or track `main`) β **Update Endpoint**. The URL is unchanged, | |
| so `channels.yaml` needs no edit. Switching the served model is just an env-var | |
| change (`BADREX_MODEL`) + endpoint restart β no code push. | |
| --- | |
| ## Request format | |
| ```python | |
| import base64, requests | |
| with open("audio.webm", "rb") as f: | |
| b64 = base64.b64encode(f.read()).decode() | |
| r = requests.post( | |
| "https://YOUR-ENDPOINT-ID.endpoints.huggingface.cloud", | |
| headers={"Authorization": "Bearer hf_...", "Content-Type": "application/json"}, | |
| json={"inputs": b64}, | |
| ) | |
| print(r.json()["text"]) # the multilingual model's leading [TIR] tag is stripped client-side | |
| ``` | |
| No `language` parameter β the deployed model is the language selector. The | |
| multilingual model emits a leading `[TIR]`/`[AMH]` tag; the newsgrab client | |
| (`src/transcribers/badrex.py`) strips it. If you call the endpoint directly, | |
| strip `^\s*\[[A-Za-z]{2,4}\]\s*` yourself. | |
| --- | |
| ## Hardware | |
| **Use T4** (16 GB). The 1B checkpoint fits comfortably; the 0.6B models more so. | |
| Scale-to-zero (`min replicas: 0`) means no idle cost; cold start (model load) | |
| is ~60β90 s. HF Endpoints accept up to ~100 MB per request β fine for full | |
| broadcasts as base64. | |
| --- | |
| ## Notes | |
| - `torch`/`torchaudio` are pre-installed in the HF endpoint base image; only | |
| `transformers>=4.44.0` is declared (wav2vec2-bert + pipeline support). | |
| - Tags transcripts `Source: badrex-api` on the newsgrab side β distinct from | |
| `mms`/`gcp`, so `recheck-captions` and `prefer_mms` are untouched. | |