Przejdź do treści

Whisper Self-Hosted Strategy

Insurance Intelligence System — Transkrypcja Audio

Status: Do wdrożenia w Fazie 2
Data decyzji: 2026-09-17
Priorytet: Po uruchomieniu Poziomu 1 (YouTube captions)


Architektura transkrypcji — 3 poziomy

Poziom 1 — YouTube captions (teraz, bezpłatne)
    youtube-transcript-api → tabela transcriptions
    source_type = 'youtube_captions'
    czas: natychmiastowy

Poziom 2 — faster-whisper small INT8 (Faza 2, bezkosztowy)
    nocny batch przez n8n (02:00 UTC)
    tylko filmy z transcription_queue = 'pending'
    source_type = 'whisper_small'
    czas: ~15-20 min / godzina audio

Poziom 3 — faster-whisper medium INT8 (opcjonalnie)
    dla kluczowych wywiadów C-suite
    source_type = 'whisper_medium'
    lepsza jakość polskiego języka

Instalacja faster-whisper (gdy czas)

cd /opt/youtube-mcp
source venv/bin/activate
pip install faster-whisper yt-dlp

# Model pobierze się automatycznie przy pierwszym użyciu
# small INT8: ~500MB RAM, ~244M parametrów
from faster_whisper import WhisperModel

model = WhisperModel(
    "small",
    device="cpu",
    compute_type="int8"  # kluczowe — 4x szybciej, minimal quality loss
)

segments, info = model.transcribe("audio.mp3", language="pl")

Benchmarki na CPU (bez GPU)

Model Czas / 60 min audio RAM Jakość PL
whisper tiny INT8 ~5 min ~250MB dostateczna
whisper small INT8 ~15-20 min ~500MB dobra
whisper medium INT8 ~35-40 min ~780MB bardzo dobra

Rekomendacja: small INT8 dla batch nocnego, medium INT8 dla wywiadów C-suite


Schemat kolejkowania — flagi w bazie

Dodatkowe kolumny w tabeli transcriptions

ALTER TABLE transcriptions ADD COLUMN IF NOT EXISTS
    transcription_status VARCHAR(20) DEFAULT 'none';
    -- 'none'      — nie sprawdzano
    -- 'captions'  — ma napisy YT, transkrypcja gotowa
    -- 'pending'   — brak napisów YT, czeka na Whisper
    -- 'processing'— Whisper w trakcie
    -- 'done'      — Whisper gotowy
    -- 'skipped'   — niewystarczający relevance score
    -- 'failed'    — błąd transkrypcji

ALTER TABLE transcriptions ADD COLUMN IF NOT EXISTS
    whisper_priority VARCHAR(10) DEFAULT 'normal';
    -- 'high'   — wywiad C-suite, wymienione TU w tytule
    -- 'normal' — standardowy film
    -- 'low'    — niska wartość domenowa

ALTER TABLE transcriptions ADD COLUMN IF NOT EXISTS
    whisper_queued_at TIMESTAMPTZ;
    -- kiedy dodano do kolejki Whisper

ALTER TABLE transcriptions ADD COLUMN IF NOT EXISTS
    whisper_model_used VARCHAR(20);
    -- 'small' | 'medium' | 'large-v3'

Logika przypisywania flagi (Agent 2 Classifier)

def assign_transcription_flag(video: dict) -> str:
    """
    Decyduje czy film idzie do kolejki Whisper i z jakim priorytetem.
    Wywoływany po próbie pobrania napisów YT.
    """
    title = video['title'].lower()
    relevance = video['relevance_score']

    # Ma napisy YT → nie potrzebujemy Whispera
    if video['has_youtube_captions']:
        return 'captions', None

    # Brak napisów YT → oceniamy czy warto transkrybować

    # Wysoki priorytet — sygnały C-suite
    high_priority_signals = [
        'prezes', 'ceo', 'cfo', 'cto', 'dyrektor',
        'wywiad', 'strategia', 'wyniki', 'konferencja',
        'pzu', 'warta', 'ergo', 'allianz', 'generali',
        'knf', 'piu', 'bancassurance'
    ]
    if any(s in title for s in high_priority_signals) or relevance >= 70:
        return 'pending', 'high'

    # Normalny priorytet
    if relevance >= 50:
        return 'pending', 'normal'

    # Zbyt niski relevance — pomijamy
    return 'skipped', None

Workflow n8n — nocny Whisper batch

Trigger: Cron 02:00 UTC (włączany/wyłączany przełącznikiem)
    ↓
Pobierz z bazy: SELECT * FROM transcriptions
    WHERE transcription_status = 'pending'
    ORDER BY whisper_priority DESC, whisper_queued_at ASC
    LIMIT 10
    ↓
Dla każdego filmu:
    1. Pobierz audio przez yt-dlp (MP3, max 192kbps)
    2. Uruchom faster-whisper (model zależny od priority)
    3. Zapisz transkrypcję do tabeli transcriptions
    4. Ustaw transcription_status = 'done'
    5. Usuń plik audio z dysku
    ↓
Log: ile przetworzone, ile błędów, czas CPU

Dashboard — widok kolejki

Widok w dashboardzie pokazujący: - Filmy czekające na Whisper (pending) z priorytetem - Historia transkrypcji (done) z czasem przetwarzania - Przycisk "Dodaj do kolejki high priority" dla ręcznego dodania - Toggle włącz/wyłącz nocny scheduler


Decyzje do podjęcia w Fazie 2

  1. Który model Whisper jako domyślny (small vs medium)?
  2. Limit filmów per noc (10? 20? zależnie od długości)?
  3. Czy medium tylko dla high priority, small dla normal?
  4. Czy chcemy diarization (kto mówi) — wymaga WhisperX?
  5. Retencja plików audio — usuwać po transkrypcji (tak)?