martin3r / platforms-whisper
Whisper Module for Platform - Browser audio recording with AssemblyAI transcription + speaker diarization + LLM summary
dev-main
2026-04-09 07:20 UTC
This package is auto-updated.
Last update: 2026-04-09 07:20:36 UTC
README
Audio-Aufnahme im Browser → AssemblyAI Transkription mit Speaker Diarization → LLM-Zusammenfassung. Audio-Datei wird nicht dauerhaft gespeichert, nur Transkript + Segmente + Summary bleiben persistent.
Features
- Browser-Recorder via MediaRecorder API (Opus, mono)
- Speaker Diarization: AssemblyAI markiert Sprecher (A, B, C, …) pro Äußerung
- LLM-Summary: automatischer Titel + Bullet-Point-Zusammenfassung via OpenAI
- Queue-basiert: Upload kehrt sofort zurück, Job verarbeitet im Hintergrund
- Organization-Linking:
HasOrganizationContexts(morph_aliaswhisper_recording), nutzbar über die Core-LLM-Tools
Voraussetzungen (Host-App)
1. Composer
"require": { "martin3r/platforms-whisper": "dev-main" }, "repositories": [ { "type": "vcs", "url": "git@github.com:martin3r-me/platforms-whisper.git" } ]
composer update martin3r/platforms-whisper php artisan migrate
2. API Keys
# Transkription + Diarization ASSEMBLYAI_API_KEY=... # LLM-Summary (wiederverwendet OpenAiService der Platform) OPENAI_API_KEY=sk-...
3. Queue Worker
php artisan queue:work --timeout=1800 --tries=1
Das Polling gegen AssemblyAI läuft während handle(). --timeout=1800 deckt auch stundenlange Meetings ab.
4. PHP Limits
In php.ini (oder .user.ini):
upload_max_filesize = 500M post_max_size = 500M max_execution_time = 300 memory_limit = 256M
Datenmodell
Tabelle whisper_recordings (Kern-Felder):
| Feld | Typ | Bemerkung |
|---|---|---|
| id / uuid | PK | UuidV7 |
| team_id / created_by_user_id | FK | Team-Scope |
| title | string | LLM-generiert (Fallback: erster Satz) |
| transcript | longText | Fließtext-Transkript |
| summary | longText | LLM-Bullet-Points |
| segments | json | [{speaker, start, end, text}, …] |
| speakers_count | int | Anzahl erkannter Sprecher |
| language | string | ISO-Code, AssemblyAI-detected |
| duration_seconds | int | |
| model | string | z. B. assemblyai:universal |
| provider_id | string | AssemblyAI transcript id |
| status | enum | pending / processing / completed / failed |
| error_message | text | bei failed |
Workflow
- User klickt Aufnehmen auf
/whisper - Browser nimmt Mic auf (Opus, mono)
- Stop → Blob wird per
fetch()an/whisper/uploadPOSTet - Controller speichert Blob in
storage/app/whisper-tmp/{uuid}.webm, legt Recording mitstatus=pendingan, dispatchedTranscribeRecordingJob, redirected User zur Show-Page - Job (Worker):
- Status →
processing AssemblyAiTranscriptionService::transcribe(): Upload → Submit (mitspeaker_labels=true) → Polling biscompletedWhisperSummaryService::summarize(): LLM erzeugt Titel + Summary- Recording bekommt
transcript,segments,speakers_count,summary,title, Status →completed - Tmp-Datei wird gelöscht (
finally-Block)
- Status →
- Show-Page pollt alle 3 s während
pending/processing, zeigt danach Sprecher-Blöcke + Summary + Fließtext
Fehler-Handling
- Kein
ASSEMBLYAI_API_KEY→ Job wirft Exception → Statusfailed - AssemblyAI-Fehler (Upload/Submit/Poll) → Status
failed,error_messagemit API-Response - Polling-Timeout (
WHISPER_AAI_MAX_WAIT) → Statusfailed - Bei
failed: Tmp-Datei wird trotzdem aufgeräumt
LLM-Tools
whisper.overview.GET— Modul-Übersichtwhisper.recordings.GET— Liste aller Aufnahmenwhisper.recording.GET— Einzel-Aufnahme (inkl. Segmente)whisper.recordings.PUT— Metadaten updatenwhisper.recordings.DELETE— Aufnahme löschenwhisper.recordings.search.GET— Volltextsuchewhisper.recording.transcript.GET— Nur Transkript + Summary + Segments (LLM-freundlich)
Config Overrides
WHISPER_AAI_REQUEST_TIMEOUT=120 # HTTP-Timeout pro AssemblyAI-Call WHISPER_AAI_POLL_INTERVAL=3 # Polling-Intervall in Sekunden WHISPER_AAI_MAX_WAIT=1500 # Maximale Polling-Dauer WHISPER_AAI_SPEAKER_LABELS=true # Diarization an/aus WHISPER_AAI_SPEAKERS_EXPECTED=0 # 0 = automatisch, sonst erwartete Anzahl
Out-of-Scope
- Editierbares Transkript
- Echtzeit-Streaming
- Speaker-Identifikation (Zuordnung zu Personen/Namen) — liefert nur
A,B,C…