Implementerer komplett pipeline for automatisk transkripsjon av lydfiler: - PostgreSQL jobbkø (job_queue-tabell med status, retry, backoff) - Worker-loop i maskinrommet som poller hvert 2. sekund - Whisper-integrasjon: leser CAS-fil, sender multipart til faster-whisper API - Postprosessering: filtrerer hallusinerte segmenter (no_speech_prob > 0.6) - Oppdaterer media-nodens content-felt med transkripsjon og metadata - Automatisk trigger: upload_media enqueuer jobb for audio/*-filer Testet ende-til-ende på server: jobb plukkes opp, Whisper prosesserer, node oppdateres. Retry med eksponentiell backoff ved feil. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
124 lines
4 KiB
Markdown
124 lines
4 KiB
Markdown
# Erfaring: faster-whisper oppsett
|
||
**Dato:** 2026-03-17
|
||
|
||
## Kontekst
|
||
Oppgave 7.1 — sette opp faster-whisper som Docker-tjeneste for norsk tale-til-tekst (STT).
|
||
Serveren er en Hetzner VPS (8 vCPU, 16 GB RAM) uten GPU.
|
||
|
||
## Valg
|
||
|
||
### Image: `fedirz/faster-whisper-server`
|
||
- Gir OpenAI-kompatibelt HTTP API (`/v1/audio/transcriptions`)
|
||
- CPU-variant: `fedirz/faster-whisper-server:latest-cpu`
|
||
- GPU-variant: `fedirz/faster-whisper-server:latest-cuda` (for fremtidig bruk)
|
||
- Laster modell automatisk fra HuggingFace ved første request (lazy loading)
|
||
|
||
### Modell: `large-v3`
|
||
- Best norsk kvalitet blant standard Whisper-modeller
|
||
- ~2.5 GB RAM med int8-kvantisering (CPU)
|
||
- Treigere enn `medium` på CPU, men akseptabelt for bakgrunnsjobber
|
||
- Alternativ: `NbAiLab/nb-whisper-large` (norsk-finjustert) — ikke testet
|
||
|
||
### Kvantisering: `int8`
|
||
- Halverer RAM-bruk vs float32, minimal kvalitetstap
|
||
- Obligatorisk for CPU — float16 krever GPU
|
||
|
||
## Docker Compose-konfigurasjon
|
||
|
||
```yaml
|
||
faster-whisper:
|
||
image: fedirz/faster-whisper-server:latest-cpu
|
||
restart: unless-stopped
|
||
environment:
|
||
WHISPER__MODEL: large-v3
|
||
WHISPER__INFERENCE_DEVICE: cpu
|
||
WHISPER__COMPUTE_TYPE: int8
|
||
volumes:
|
||
- /srv/synops/data/whisper-models:/root/.cache/huggingface
|
||
- /srv/synops/media/cas:/srv/synops/media/cas:ro
|
||
networks:
|
||
- sidelinja-net
|
||
healthcheck:
|
||
test: ["CMD", "python3", "-c", "import urllib.request; urllib.request.urlopen(\"http://localhost:8000/health\")"]
|
||
interval: 30s
|
||
timeout: 10s
|
||
retries: 3
|
||
start_period: 120s
|
||
```
|
||
|
||
## API-bruk
|
||
|
||
Endepunkt fra Docker-nettverket: `http://faster-whisper:8000`
|
||
|
||
```bash
|
||
# Enkel transkripsjon
|
||
curl -X POST http://faster-whisper:8000/v1/audio/transcriptions \
|
||
-F "file=@lydfil.wav" \
|
||
-F "model=large-v3" \
|
||
-F "language=no" \
|
||
-F "response_format=verbose_json"
|
||
```
|
||
|
||
Respons (verbose_json):
|
||
```json
|
||
{
|
||
"task": "transcribe",
|
||
"language": "no",
|
||
"duration": 1.0,
|
||
"text": "...",
|
||
"segments": [
|
||
{
|
||
"id": 1,
|
||
"start": 0.0,
|
||
"end": 3.5,
|
||
"text": "...",
|
||
"no_speech_prob": 0.01
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
## Ressursbruk
|
||
- **RAM:** ~2.5 GB (idle, modell lastet)
|
||
- **CPU:** Minimal ved idle. Bruker alle tilgjengelige kjerner under transkripsjon.
|
||
- **Disk:** ~3 GB for large-v3 modell (i `/srv/synops/data/whisper-models/`)
|
||
|
||
## Gotchas
|
||
1. **Healthcheck:** Containeren har ikke `curl` installert. Bruk python3 urllib i stedet.
|
||
2. **Modellnedlasting:** Første request etter oppstart trigger modellnedlasting (~3 GB).
|
||
`start_period: 120s` i healthcheck gir tid til dette.
|
||
3. **CAS-tilgang:** Containeren monterer CAS read-only for direkte filtilgang.
|
||
Alternativt kan maskinrommet sende filer via multipart upload.
|
||
4. **Hallusinering:** Whisper hallusinerer tekst på stille/tone-filer (høy `no_speech_prob`).
|
||
Filtrér segmenter med `no_speech_prob > 0.6` i postprosessering.
|
||
|
||
## Integrasjon med maskinrommet (oppgave 7.2)
|
||
|
||
Transkripsjons-pipelinen er implementert i maskinrommet via jobbkøen:
|
||
|
||
1. **Trigger:** Når `upload_media` mottar en lydfil (MIME `audio/*`), opprettes en `whisper_transcribe`-jobb i `job_queue`.
|
||
2. **Worker:** Maskinrommet kjører en intern worker-loop som poller `job_queue` hvert 2. sekund.
|
||
3. **Prosessering:** Worker leser lydfilen fra CAS, sender den som multipart til faster-whisper API (`verbose_json`-format).
|
||
4. **Postprosessering:** Segmenter med `no_speech_prob > 0.6` filtreres bort (hallusinering).
|
||
5. **Lagring:** Transkripsjonstekst skrives til nodens `content`-felt. Metadata (`duration`, `language`, `segment_count`, `transcribed_at`) legges i `metadata.transcription`.
|
||
6. **Retry:** Ved feil, eksponentiell backoff (30s × 2^n), maks 3 forsøk.
|
||
|
||
Kode: `maskinrommet/src/transcribe.rs`, `maskinrommet/src/jobs.rs`
|
||
|
||
## Ved GPU-oppgradering
|
||
Bytt til CUDA-image og float16:
|
||
```yaml
|
||
faster-whisper:
|
||
image: fedirz/faster-whisper-server:latest-cuda
|
||
environment:
|
||
WHISPER__MODEL: large-v3
|
||
WHISPER__INFERENCE_DEVICE: cuda
|
||
WHISPER__COMPUTE_TYPE: float16
|
||
deploy:
|
||
resources:
|
||
reservations:
|
||
devices:
|
||
- driver: nvidia
|
||
count: 1
|
||
capabilities: [gpu]
|
||
```
|