Lokalna aplikacja do transkrypcji audio i strukturyzowania treści
Stefka przetwarza pliki audio i tekstowe na uporządkowane, ustrukturyzowane treści. Strukturyzację wykonuje PLLuM — oficjalny polski model językowy (CYFRAGOVPL), uruchamiany lokalnie przez Ollamę. Transkrypcję realizuje mlx-whisper. Wszystkie modele AI działają w 100% lokalnie — żadne dane nie opuszczają maszyny użytkownika.
🍎 Działa WYŁĄCZNIE na macOS z Apple Silicon (M1/M2/M3/M4). Aplikacja jest zbudowana wokół frameworka MLX i akceleracji GPU Apple — nie uruchomi się na Linux, Windows ani Intel Macu. To wymóg twardy, nie zalecenie.
🇵🇱 Rdzeń to PLLuM — całe strukturyzowanie treści opiera się na polskim modelu
CYFRAGOVPL/PLLuM-12B-nc-instruct. Model jest niekomercyjny (CC-BY-NC-4.0) — szczegóły w sekcji Licencja.
ℹ️ Charakter projektu: to prototyp / dowód koncepcji zbudowany w kilka godzin, a nie produkcyjny system. Działa i realizuje pełny pipeline (transkrypcja → strukturyzacja → eksport), ale ma świadome ograniczenia: jeden użytkownik na raz, brak kolejki zadań, niestabilna jakość outputu modelu 12B (szczegóły w sekcji Znane ograniczenia).
- Pełna prywatność danych — zero komunikacji z zewnętrznymi API, całe przetwarzanie na localhost
- Transkrypcja audio — mlx-whisper zoptymalizowany pod Apple Silicon (10–15x szybciej niż real-time na M4 Pro)
- Strukturyzowanie tekstu — polski model językowy PLLuM-12B porządkuje i strukturyzuje treść
- Przetwarzanie plików tekstowych — import z TXT, MD, DOCX, PDF
- Eksport wieloformatowy — zapis wyniku do Markdown, PDF lub DOCX
- Interfejs webowy — prosta strona z uploadem, paskiem postępu (SSE) i pobieraniem wyniku
- Automatyczne czyszczenie — pliki tymczasowe usuwane po przetworzeniu, wyniki po 24h
+---------------------------------------------------------+
| PRZEGLĄDARKA |
| Upload pliku (audio/tekst) -> Progress bar -> Download |
+----------------------------+----------------------------+
| HTTP / SSE
+----------------------------+----------------------------+
| FastAPI Backend |
| |
| /api/upload /api/status/{id} /api/download |
| | ^ |
| +-----v-----------+ +---------------------+--+ |
| | Transkrypcja | | Eksport | |
| | (mlx-whisper) | | (MD / PDF / DOCX) | |
| +-----+------------+ +-----^-----------------+ |
| | | |
| +-----v----------------------+--+ |
| | Serwis LLM (Ollama / PLLuM) | |
| | chunk-summarize pipeline | |
| +--------------------------------+ |
+---------------------------------------------------------+
|
+---------------------------------------------------------+
| Lokalne Modele AI |
| mlx-whisper Ollama |
| large-v3-turbo PLLuM-12B-instruct |
| (~809M param.) (GGUF Q8, ~13GB) |
+---------------------------------------------------------+
| Komponent | Technologia | Uwagi |
|---|---|---|
| Backend | Python 3.11+ / FastAPI | Async, SSE do raportowania postępu |
| Transkrypcja | mlx-whisper (large-v3-turbo) | Natywna akceleracja GPU na Apple Silicon |
| Model językowy | PLLuM-12B-nc-instruct via Ollama | Oficjalny model z CYFRAGOVPL/HuggingFace, GGUF Q8 |
| Przetwarzanie audio | ffmpeg + pydub | Konwersja do WAV 16kHz, dzielenie na segmenty |
| Eksport PDF | WeasyPrint | Konwersja HTML/CSS na PDF |
| Eksport DOCX | python-docx | Generowanie dokumentów Word z zachowaniem formatowania |
| Ekstrakcja tekstu | PyPDF2, python-docx | Odczyt uploadowanych PDF i DOCX |
| Frontend | Vanilla HTML/CSS/JS + Jinja2 | Zero zależności frontendowych |
| Komponent | RAM | Uwagi |
|---|---|---|
| mlx-whisper large-v3-turbo | ~3-4 GB | Ładowany na czas transkrypcji |
| PLLuM-12B-instruct (Q8) | ~13 GB | Ollama zarządza pamięcią |
| System + FastAPI | ~4-6 GB | macOS + Python runtime |
| Łącznie | ~20-23 GB | Komfortowo przy 48 GB RAM |
- macOS z Apple Silicon (M1 / M2 / M3 / M4)
- Python 3.11+
- Homebrew
- Min. 32 GB RAM (zalecane 48 GB)
- ~20 GB wolnego miejsca na dysku (modele AI)
git clone <repo-url> stefka
cd stefka
chmod +x setup.sh run.sh
./setup.shSkrypt setup.sh automatycznie:
- Sprawdza i instaluje zależności systemowe (ffmpeg, Ollama, pango, llama.cpp)
- Tworzy środowisko wirtualne Python i instaluje zależności
- Pobiera oficjalny model PLLuM-12B-nc-instruct z CYFRAGOVPL/HuggingFace
- Konwertuje model do formatu GGUF Q8_0 i importuje do Ollama
Pierwsze uruchomienie setup.sh może potrwać kilkanaście minut (pobranie ~24 GB + konwersja modelu).
./run.shAplikacja dostępna pod: http://localhost:8000
Skrypt run.sh uruchamia Ollama (jeśli nie działa) oraz serwer FastAPI na porcie 8000. Aplikacja nasłuchuje wyłącznie na 127.0.0.1 — nie jest dostępna z sieci.
Upload audio (.mp3, .wav, .m4a, ...)
|
v
Walidacja formatu i rozmiaru (max 500 MB)
|
v
Konwersja do WAV 16kHz mono (ffmpeg)
|
v
Dzielenie na segmenty ~30s z 2s overlap
|
v
Transkrypcja każdego segmentu (mlx-whisper)
+ usuwanie halucynacji Whisper
+ deduplikacja overlappującego tekstu
|
v
Strukturyzowanie przez PLLuM (chunk-summarize)
|
v
Eksport do wybranego formatu (MD / PDF / DOCX)
|
v
Pobranie wyniku z przeglądarki
Upload tekstu (.txt, .md, .docx, .pdf)
|
v
Ekstrakcja tekstu z pliku
|
v
Strukturyzowanie przez PLLuM (chunk-summarize)
|
v
Eksport do wybranego formatu
|
v
Pobranie wyniku z przeglądarki
Stefka używa podejścia chunk-summarize do przetwarzania tekstu przez PLLuM-12B:
Tekst wejściowy jest dzielony na fragmenty po ~6000 znaków (CHUNK_SIZE) z 400-znakowym nakładaniem (CHUNK_OVERLAP). Cięcie odbywa się na granicach zdań. Ostatni fragment, jeśli jest krótszy niż 40% docelowego rozmiaru, jest łączony z poprzednim.
Każdy fragment jest przetwarzany osobno przez PLLuM z promptem systemowym:
Streść poniższy fragment spotkania w akapitach. Zachowaj imiona, nazwiska, daty, kwoty, nazwy. Nie anonimizuj. Nie pisz dialogu. Nie kopiuj surowego tekstu. Zacznij od treści.
| Parametr | Wartość | Uzasadnienie |
|---|---|---|
temperature |
0.0 | Deterministyczny output, brak kreatywności |
num_predict |
4096 | Maks. długość odpowiedzi |
num_ctx |
16384 | Okno kontekstu |
top_p |
0.7 | Ograniczenie losowości |
repeat_penalty |
1.1 | Kara za powtórzenia |
repeat_last_n |
128 | Zakres detekcji powtórzeń |
Odpowiedzi LLM przechodzą przez rozbudowane czyszczenie:
- Usuwanie artefaktów
[INST]/[/INST] - Usuwanie preambuł i meta-komentarzy
- Usuwanie formatu dialogowego (
[Osoba 1]: ...) - Usuwanie halucynowanych imion i nazwisk (porównanie z tekstem źródłowym)
- Wykrywanie zdegenerowanych odpowiedzi (powtórzenia, garbage output)
- Wykrywanie surowych kopii wejścia (>60% overlap → odrzucenie)
- Łączenie krótkich akapitów-sierot z poprzednimi
Streszczenia fragmentów są łączone w kodzie (bez dodatkowego wywołania LLM) w ustandaryzowany, ustrukturyzowany dokument z datą przetworzenia.
Parametry konfiguracyjne znajdują się w app/config.py:
| Parametr | Wartość domyślna | Opis |
|---|---|---|
OLLAMA_BASE_URL |
http://localhost:11434 |
Adres serwera Ollama |
OLLAMA_MODEL |
pllum-12b-instruct |
Nazwa modelu w Ollama |
WHISPER_MODEL |
mlx-community/whisper-large-v3-turbo |
Model Whisper (HuggingFace) |
MAX_UPLOAD_SIZE_MB |
500 |
Maks. rozmiar uploadu w MB |
AUDIO_CHUNK_SECONDS |
30 |
Długość segmentu audio w sekundach |
AUDIO_OVERLAP_SECONDS |
2 |
Nakładanie między segmentami |
Logi aplikacji zapisywane są do logs/stefka.log (rotacja co 5 MB, 3 kopie zapasowe). Poziom logowania można ustawić zmienną LOG_LEVEL (domyślnie INFO).
| Typ | Formaty |
|---|---|
| Audio | .mp3, .wav, .m4a, .flac, .ogg, .webm, .wma, .aac |
| Tekst | .txt, .md, .docx, .pdf |
| Format | Zastosowanie |
|---|---|
Markdown (.md) |
Lekki, czytelny, łatwy do dalszej edycji |
PDF (.pdf) |
Gotowy do druku i archiwizacji |
DOCX (.docx) |
Edytowalny w Microsoft Word / LibreOffice |
stefka/
|-- CLAUDE.md # Specyfikacja projektu
|-- README.md # Ten plik
|-- requirements.txt # Zależności Python
|-- requirements-dev.txt # Zależności deweloperskie (testy)
|-- setup.sh # Skrypt instalacyjny
|-- run.sh # Skrypt uruchomieniowy
|-- Modelfile.pllum # Definicja modelu dla Ollama
|
|-- app/
| |-- __init__.py
| |-- main.py # FastAPI — punkt wejścia
| |-- config.py # Konfiguracja (modele, ścieżki, limity)
| |
| |-- routers/
| | |-- upload.py # POST /api/upload
| | |-- status.py # GET /api/status/{job_id} (SSE)
| | +-- download.py # GET /api/download/{job_id}
| |
| |-- services/
| | |-- transcription.py # Transkrypcja mlx-whisper + czyszczenie
| | |-- audio_processing.py # Konwersja audio, chunking (ffmpeg)
| | |-- text_extraction.py # Ekstrakcja tekstu z DOCX/PDF/TXT
| | |-- llm.py # Pipeline chunk-summarize (Ollama/PLLuM)
| | +-- export.py # Eksport MD / PDF / DOCX
| |
| |-- models/
| | +-- schemas.py # Modele Pydantic
| |
| |-- templates/
| | +-- index.html # Interfejs webowy
| |
| +-- static/
| |-- css/style.css
| +-- js/app.js
|
|-- tests/
| +-- test_smoke.py # Smoke testy czystej logiki pipeline'u
|
|-- data/
| |-- uploads/ # Pliki tymczasowe (czyszczone po przetworzeniu)
| +-- outputs/ # Wygenerowane wyniki (czyszczone po 24h)
|
|-- logs/
| +-- stefka.log # Logi aplikacji (rotacja 5 MB)
|
+-- models/
+-- pllum-12b-nc-instruct-q8_0.gguf # Model PLLuM (generowany przez setup.sh)
- Model 12B parametrów może generować powtórzenia w dłuższych odpowiedziach — aplikacja aktywnie je wykrywa i filtruje
- Zdarzają się halucynacje imion i nazwisk — post-processing usuwa nazwiska nieobecne w tekście źródłowym (czasem zbyt agresywnie — może usunąć prawdziwe imię)
- Przy złożonych tematach technicznych streszczenia mogą być uproszczone
- Okno kontekstu ograniczone do 16K tokenów na zapytanie (ograniczenie wydajnościowe, nie modelowe)
- Brak kroku łączenia (merge) streszczeń — wynik jest składany w kodzie, nie przez LLM
- Na cichych fragmentach audio model generuje halucynacje ("Dziękuję za oglądanie", "Subskrybuj" itp.) — aplikacja je filtruje
- Powtarzające się słowa na granicach segmentów — deduplikacja przez dopasowanie dokładne i rozmyte (SequenceMatcher)
- Transkrypcja ustawiona na język polski (
language="pl") — inne języki nie są obsługiwane condition_on_previous_text=Falsezapobiega propagacji błędów między segmentami kosztem większej liczby powtórzeń na granicach
- Aplikacja obsługuje jednego użytkownika na raz (brak kolejki zadań)
- Przetwarzanie długich nagrań (>30 min) może trwać kilka minut
- Eksport PDF wymaga zainstalowanego
pango(instalowany przezsetup.sh) - Tylko macOS z Apple Silicon — brak wsparcia dla Linux / Windows / Intel Mac
| Endpoint | Metoda | Opis |
|---|---|---|
/ |
GET | Interfejs webowy |
/api/upload |
POST | Upload pliku (multipart/form-data) |
/api/status/{job_id} |
GET | Status przetwarzania (SSE stream) |
/api/download/{job_id} |
GET | Pobranie wygenerowanego wyniku |
/api/health |
GET | Sprawdzenie stanu Ollama i modelu |
Smoke testy obejmują czystą logikę pipeline'u (chunkowanie, detekcja zdegenerowanego outputu, składanie noty) — nie wymagają uruchomionej Ollamy ani modeli.
pip install -r requirements-dev.txt
pytestKod aplikacji: MIT (patrz LICENSE).
⚠️ Uwaga o modelu: domyślny model językowyCYFRAGOVPL/PLLuM-12B-nc-instructjest na licencji CC-BY-NC-4.0 (niekomercyjnej). Użycie aplikacji z tym modelem do celów komercyjnych jest niedozwolone. Do zastosowań komercyjnych należy podmienić model na wariant permisywny (np.CYFRAGOVPL/PLLuM-12B-instruct, Apache-2.0). Szczegóły w pliku NOTICE.