Fullfør oppgave 7.1: faster-whisper Docker-oppsett for norsk STT
Satt opp faster-whisper-server (fedirz/faster-whisper-server:latest-cpu) som Docker-tjeneste på produksjonsserveren. Ingen GPU tilgjengelig — bruker CPU med int8-kvantisering og large-v3 modell for best norsk kvalitet. Verifisert: - Transkripsjon fungerer via OpenAI-kompatibelt API - verbose_json med segmenter og tidskoder OK - Docker DNS-oppslag fra sidelinja-net fungerer - Maskinrommet har WHISPER_URL=http://faster-whisper:8000 - RAM-bruk ~2.5 GB med modell lastet Konfigurasjon: - Image: fedirz/faster-whisper-server:latest-cpu - Modell: large-v3 (norsk), int8, CPU - CAS montert read-only for direkte filtilgang - Healthcheck via python3 (curl ikke tilgjengelig i image) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
8613b90f2c
commit
443f60a518
5 changed files with 134 additions and 3 deletions
|
|
@ -25,5 +25,9 @@ AUTH_SECRET= # openssl rand -base64 33
|
||||||
# URL til SpacetimeDB-instansen (server eller lokal)
|
# URL til SpacetimeDB-instansen (server eller lokal)
|
||||||
VITE_SPACETIMEDB_URL=ws://sidelinja.org/spacetime
|
VITE_SPACETIMEDB_URL=ws://sidelinja.org/spacetime
|
||||||
|
|
||||||
|
# === Whisper (STT) ===
|
||||||
|
# URL til faster-whisper-server (Docker-internt)
|
||||||
|
# WHISPER_URL=http://faster-whisper:8000
|
||||||
|
|
||||||
# === Database (kun ved lokal PG, ellers via server) ===
|
# === Database (kun ved lokal PG, ellers via server) ===
|
||||||
# DATABASE_URL=postgres://sidelinja:localdev@localhost:5432/sidelinja
|
# DATABASE_URL=postgres://sidelinja:localdev@localhost:5432/sidelinja
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ Formålet er å treffe raskere blink med neste komponent. Hver fil dekker én te
|
||||||
| `adapter_moenster.md` | Adapter/factory for PG↔SpacetimeDB, hybrid-tilnærming |
|
| `adapter_moenster.md` | Adapter/factory for PG↔SpacetimeDB, hybrid-tilnærming |
|
||||||
| `authentik_oidc.md` | Authentik sub-claim format, @auth/sveltekit JWT-quirks |
|
| `authentik_oidc.md` | Authentik sub-claim format, @auth/sveltekit JWT-quirks |
|
||||||
| `authentik_oppsett.md` | OIDC-provider/app-konfigurasjon, endepunkter, redirect URIs, API-admin |
|
| `authentik_oppsett.md` | OIDC-provider/app-konfigurasjon, endepunkter, redirect URIs, API-admin |
|
||||||
|
| `faster_whisper_oppsett.md` | Docker-oppsett, CPU vs GPU, modellvalg, API-bruk, healthcheck-quirks |
|
||||||
|
|
||||||
## Retningslinjer
|
## Retningslinjer
|
||||||
|
|
||||||
|
|
|
||||||
111
docs/erfaringer/faster_whisper_oppsett.md
Normal file
111
docs/erfaringer/faster_whisper_oppsett.md
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
## 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]
|
||||||
|
```
|
||||||
|
|
@ -7,6 +7,7 @@ Denne oppskriften tar en fersk Ubuntu VPS fra null til en komplett Synops-instal
|
||||||
- Hetzner VPS med Ubuntu 24.04 LTS (8 vCPU, 16 GB RAM minimum)
|
- Hetzner VPS med Ubuntu 24.04 LTS (8 vCPU, 16 GB RAM minimum)
|
||||||
- DNS A-records som peker til VPS-ens IP:
|
- DNS A-records som peker til VPS-ens IP:
|
||||||
- `sidelinja.org` + `*.sidelinja.org`
|
- `sidelinja.org` + `*.sidelinja.org`
|
||||||
|
- `synops.no` + `*.synops.no`
|
||||||
- `vegard.info` + `*.vegard.info`
|
- `vegard.info` + `*.vegard.info`
|
||||||
- SSH-tilgang med nøkkelpar (passordautentisering deaktiveres i steg 1)
|
- SSH-tilgang med nøkkelpar (passordautentisering deaktiveres i steg 1)
|
||||||
|
|
||||||
|
|
@ -61,6 +62,7 @@ newgrp docker
|
||||||
sudo mkdir -p /srv/synops/{config,data,media,logs}
|
sudo mkdir -p /srv/synops/{config,data,media,logs}
|
||||||
sudo mkdir -p /srv/synops/config/{caddy,authentik}
|
sudo mkdir -p /srv/synops/config/{caddy,authentik}
|
||||||
sudo mkdir -p /srv/synops/data/{postgres,spacetimedb,forgejo,authentik}
|
sudo mkdir -p /srv/synops/data/{postgres,spacetimedb,forgejo,authentik}
|
||||||
|
sudo mkdir -p /srv/synops/data/whisper-models
|
||||||
sudo mkdir -p /srv/synops/media/podcast
|
sudo mkdir -p /srv/synops/media/podcast
|
||||||
sudo mkdir -p /srv/synops/logs/caddy
|
sudo mkdir -p /srv/synops/logs/caddy
|
||||||
sudo chown -R sidelinja:sidelinja /srv/synops
|
sudo chown -R sidelinja:sidelinja /srv/synops
|
||||||
|
|
@ -78,6 +80,7 @@ Resultat:
|
||||||
│ ├── postgres/
|
│ ├── postgres/
|
||||||
│ ├── spacetimedb/
|
│ ├── spacetimedb/
|
||||||
│ ├── forgejo/
|
│ ├── forgejo/
|
||||||
|
│ ├── whisper-models/
|
||||||
│ └── authentik/
|
│ └── authentik/
|
||||||
├── media/
|
├── media/
|
||||||
│ └── podcast/
|
│ └── podcast/
|
||||||
|
|
@ -128,6 +131,10 @@ SPACETIMEDB_URL=http://spacetimedb:3000
|
||||||
SPACETIMEDB_DATABASE=synops
|
SPACETIMEDB_DATABASE=synops
|
||||||
SPACETIMEDB_TOKEN=<generert av spacetime identity token>
|
SPACETIMEDB_TOKEN=<generert av spacetime identity token>
|
||||||
|
|
||||||
|
# === Whisper (STT) ===
|
||||||
|
# Modell lastes ned automatisk ved oppstart. large-v3 gir best norsk kvalitet.
|
||||||
|
# Ved GPU: bytt image til fedirz/faster-whisper-server:latest-cuda og WHISPER__COMPUTE_TYPE=float16
|
||||||
|
|
||||||
# === Intern ===
|
# === Intern ===
|
||||||
# Ingen porter eksponeres utenom 80/443. Alt rutes internt via Docker-nettverket.
|
# Ingen porter eksponeres utenom 80/443. Alt rutes internt via Docker-nettverket.
|
||||||
EOF
|
EOF
|
||||||
|
|
@ -182,6 +189,7 @@ services:
|
||||||
maskinrommet: # Rust/axum API, intern port 3100, proxyet via Caddy
|
maskinrommet: # Rust/axum API, intern port 3100, proxyet via Caddy
|
||||||
livekit: # Intern port, proxyet via Caddy
|
livekit: # Intern port, proxyet via Caddy
|
||||||
sveltekit: # Intern port, proxyet via Caddy
|
sveltekit: # Intern port, proxyet via Caddy
|
||||||
|
faster-whisper: # STT via OpenAI-kompatibelt API, intern port 8000
|
||||||
workers: # Rust job workers, ingen porter
|
workers: # Rust job workers, ingen porter
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -225,6 +233,13 @@ git.sidelinja.org {
|
||||||
reverse_proxy forgejo:3000
|
reverse_proxy forgejo:3000
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# === Synops (plattformdomene) ===
|
||||||
|
# Subdomener (api.synops.no, auth.synops.no osv.) legges til individuelt
|
||||||
|
# etter behov — HTTP-challenge fungerer per subdomain uten DNS-plugin.
|
||||||
|
synops.no {
|
||||||
|
respond "synops.no — plattform under utvikling" 200
|
||||||
|
}
|
||||||
|
|
||||||
# === Vegard.info ===
|
# === Vegard.info ===
|
||||||
vegard.info {
|
vegard.info {
|
||||||
respond "vegard.info — under construction" 200
|
respond "vegard.info — under construction" 200
|
||||||
|
|
@ -454,6 +469,7 @@ fra PG inn i STDB (warmup). Caddy proxyer `api.sidelinja.org` til port 3100.
|
||||||
- [x] `https://sidelinja.org/api/health` returnerer 200
|
- [x] `https://sidelinja.org/api/health` returnerer 200
|
||||||
- [x] Authentik OIDC-innlogging fungerer fra nettleser (verifisert 2025-03-15)
|
- [x] Authentik OIDC-innlogging fungerer fra nettleser (verifisert 2025-03-15)
|
||||||
- [x] Chat: meldinger sendes og vises med riktig brukernavn (verifisert 2025-03-15)
|
- [x] Chat: meldinger sendes og vises med riktig brukernavn (verifisert 2025-03-15)
|
||||||
|
- [ ] `https://synops.no` viser placeholder
|
||||||
- [ ] `https://vegard.info` svarer
|
- [ ] `https://vegard.info` svarer
|
||||||
- [ ] SpacetimeDB: WebSocket-tilkobling fra nettleser fungerer
|
- [ ] SpacetimeDB: WebSocket-tilkobling fra nettleser fungerer
|
||||||
- [ ] LiveKit: Test-rom med video/lyd fungerer
|
- [ ] LiveKit: Test-rom med video/lyd fungerer
|
||||||
|
|
|
||||||
5
tasks.md
5
tasks.md
|
|
@ -93,8 +93,7 @@ Uavhengige faser kan fortsatt plukkes.
|
||||||
|
|
||||||
## Fase 7: Lyd-pipeline
|
## Fase 7: Lyd-pipeline
|
||||||
|
|
||||||
- [~] 7.1 faster-whisper oppsett: Docker-container, GPU hvis tilgjengelig, norsk modell. Ref: `docs/erfaringer/`.
|
- [x] 7.1 faster-whisper oppsett: Docker-container, GPU hvis tilgjengelig, norsk modell. Ref: `docs/erfaringer/`.
|
||||||
> Påbegynt: 2026-03-17T17:13
|
|
||||||
- [ ] 7.2 Transkripsjons-pipeline: lydfil i CAS → maskinrommet trigger Whisper → resultat i `content`-feltet.
|
- [ ] 7.2 Transkripsjons-pipeline: lydfil i CAS → maskinrommet trigger Whisper → resultat i `content`-feltet.
|
||||||
- [ ] 7.3 Voice memo i frontend: opptak-knapp i input-komponenten → upload → CAS → transkripsjon.
|
- [ ] 7.3 Voice memo i frontend: opptak-knapp i input-komponenten → upload → CAS → transkripsjon.
|
||||||
- [ ] 7.4 Lyd-avspilling: spiller av original lyd fra CAS-node. Waveform-visning.
|
- [ ] 7.4 Lyd-avspilling: spiller av original lyd fra CAS-node. Waveform-visning.
|
||||||
|
|
@ -137,7 +136,7 @@ Uavhengige faser kan fortsatt plukkes.
|
||||||
- [ ] 14.1 Tera-templates: innebygde temaer (avis, magasin, blogg, tidsskrift) med Tera i Rust. Artikkelmal + forside-mal per tema. CSS-variabler for theme_config-overstyring. Ref: `docs/concepts/publisering.md` § "Temaer".
|
- [ ] 14.1 Tera-templates: innebygde temaer (avis, magasin, blogg, tidsskrift) med Tera i Rust. Artikkelmal + forside-mal per tema. CSS-variabler for theme_config-overstyring. Ref: `docs/concepts/publisering.md` § "Temaer".
|
||||||
- [ ] 14.2 HTML-rendering av enkeltartikler: maskinrommet rendrer `metadata.document` til HTML via Tera, lagrer i CAS. Noden får `metadata.rendered.html_hash` + `renderer_version`. SEO-metadata (OG-tags, canonical, JSON-LD).
|
- [ ] 14.2 HTML-rendering av enkeltartikler: maskinrommet rendrer `metadata.document` til HTML via Tera, lagrer i CAS. Noden får `metadata.rendered.html_hash` + `renderer_version`. SEO-metadata (OG-tags, canonical, JSON-LD).
|
||||||
- [ ] 14.3 Forside-rendering: maskinrommet spør PG for hero/featured/strøm (tre indekserte spørringer), appliserer tema-template, rendrer til CAS (statisk modus) eller serverer med in-memory cache (dynamisk modus). `index_mode` og `index_cache_ttl` i trait-konfig.
|
- [ ] 14.3 Forside-rendering: maskinrommet spør PG for hero/featured/strøm (tre indekserte spørringer), appliserer tema-template, rendrer til CAS (statisk modus) eller serverer med in-memory cache (dynamisk modus). `index_mode` og `index_cache_ttl` i trait-konfig.
|
||||||
- [ ] 14.4 Caddy-ruting for synops.no/pub: statisk serving av CAS-rendret HTML. Rute `synops.no/pub/{slug}/{id}` → artikkel-CAS, `synops.no/pub/{slug}` → forside. Kategori/arkiv/søk rutes til maskinrommet for dynamisk respons.
|
- [ ] 14.4 Caddy-ruting for synops.no/pub: Caddy reverse-proxyer til maskinrommet som gjør slug→hash-oppslag og streamer CAS-fil. `Cache-Control: immutable` for artikler. Kategori/arkiv/søk serveres dynamisk av maskinrommet med kortere cache-TTL.
|
||||||
- [ ] 14.5 Slot-håndtering i maskinrommet: `slot` og `slot_order` i `belongs_to`-edge metadata. Ved ny hero → gammel hero flyttes til strøm. Ved featured over `featured_max` → FIFO tilbake til strøm. `pinned`-flagg forhindrer automatisk fjerning.
|
- [ ] 14.5 Slot-håndtering i maskinrommet: `slot` og `slot_order` i `belongs_to`-edge metadata. Ved ny hero → gammel hero flyttes til strøm. Ved featured over `featured_max` → FIFO tilbake til strøm. `pinned`-flagg forhindrer automatisk fjerning.
|
||||||
- [ ] 14.6 Forside-admin i frontend: visuell editor for hero/featured/strøm. Drag-and-drop mellom plasser. Pin-knapp. Forhåndsvisning. Oppdaterer edge-metadata via maskinrommet.
|
- [ ] 14.6 Forside-admin i frontend: visuell editor for hero/featured/strøm. Drag-and-drop mellom plasser. Pin-knapp. Forhåndsvisning. Oppdaterer edge-metadata via maskinrommet.
|
||||||
- [ ] 14.7 Publiseringsflyt i frontend (personlig): publiseringsknapp på noder i samlinger med `publishing`-trait der `require_approval: false`. Forhåndsvisning, slug-editor, bekreftelse. Avpublisering ved fjerning av edge.
|
- [ ] 14.7 Publiseringsflyt i frontend (personlig): publiseringsknapp på noder i samlinger med `publishing`-trait der `require_approval: false`. Forhåndsvisning, slug-editor, bekreftelse. Avpublisering ved fjerning av edge.
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue