Highlight-Trigger:
- diagnostic/index.html: Settings-Sektion + Trigger-Liste-Handler raus
- diagnostic/server.js: get_triggers / save_triggers Action-Handler +
TRIGGERS_FILE Konstante + handleGetTriggers/handleSaveTriggers Funktionen weg
- README.md: highlight_triggers.json aus dem Datenverzeichnis-Diagram entfernt
Die Auswertung war seit Piper-Removal eh tot — die Datei wurde nur noch
geschrieben aber nirgends gelesen.
Piper-Reste:
- bridge/aria_bridge.py: Modul-Docstring auf F5-TTS aktualisiert,
Ramona/Thorsten-Erwaehnungen raus, Inline-Kommentar zu "Komponenten
TTS" gefixt
- aria-data/config/AGENT.md: Stimmen-Tabelle (Ramona/Thorsten) durch
Hinweis auf F5-TTS Voice-Cloning ersetzt
- aria-data/config/BOOTSTRAP.md: gleiche Tabelle weg, Bridge-Beschreibung
auf "orchestriert STT/TTS via Gamebox-Bridges" geaendert
Erledigt-Eintraege in issue.md + README markiert (historisch erhalten).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Erweitert den Foreground-Service um den microphone-Type damit nicht nur
TTS, sondern auch Wake-Word-Lauschen und aktive Aufnahmen weiterlaufen
wenn die App im Hintergrund ist.
Slot-System (backgroundAudio.ts):
- 'tts' : ARIA spricht
- 'rec' : Aufnahme laeuft
- 'wake' : Wake-Word lauscht passiv (Ohr aktiv)
Mehrere Slots koennen unabhaengig acquired/released werden, der Service
laeuft solange mindestens einer aktiv ist. Notification-Text passt sich
dynamisch an den hoechstprioren Slot an (tts > rec > wake).
Wiring (ChatScreen):
- onPlaybackStarted/Finished → 'tts' Slot
- audioService.onStateChange (recording) → 'rec' Slot
- wakeWordService.onStateChange (off→armed/conversing) → 'wake' Slot
AndroidManifest:
- foregroundServiceType="mediaPlayback|microphone" (Pflicht ab Android 14
fuer Background-Mic-Zugriff)
- FOREGROUND_SERVICE_MICROPHONE Permission
Doku:
- issue.md Erledigt-Sektion in "Bugs / Fixes", "App Features" und
"Infrastruktur" gesplittet
- README: Background-Service-Beschreibung erweitert
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
ARIAs Antwort wird jetzt auch dann fertig vorgelesen wenn der User die
App im Hintergrund schickt. Vorher hat Android den Prozess kurz nach
dem Minimieren eingefroren — TTS verstummte mitten im Satz.
Native:
- AriaPlaybackService.kt: Service mit foregroundServiceType=mediaPlayback,
zeigt persistente Notification "ARIA spricht — antippen oeffnet die App"
(channel low-priority, ongoing, tap → MainActivity)
- BackgroundAudioModule.kt: RN-Bridge mit start()/stop()
- AndroidManifest: FOREGROUND_SERVICE + FOREGROUND_SERVICE_MEDIA_PLAYBACK
+ POST_NOTIFICATIONS Permissions, Service deklariert
JS:
- backgroundAudio.ts: idempotenter Wrapper (active-Flag verhindert
doppelte start/stop calls)
- ChatScreen onPlaybackStarted → startBackgroundAudio
- ChatScreen onPlaybackFinished → stopBackgroundAudio
- audio.ts stopPlayback ruft auch stopBackgroundAudio damit die
Notification bei Cancel/Barge-In/Anruf nicht haengen bleibt
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug: Nach Wake-Word "Computer" → conversing → User drueckt manuell den
Mikro-Button um zu stoppen → Audio wird gesendet, aber state bleibt
'conversing'. Nach ARIAs Antwort oeffnet sich automatisch wieder das
Mikro fuer Multi-Turn — obwohl der User explizit den Knopf gedrueckt
hat um zu signalisieren "ich bin fertig".
Fix: Im handleVoiceRecording (= manueller Stop ueber VoiceButton) wird
nach dem Send wakeWordService.endConversation() gerufen wenn aktuell
in conversing-State. Das setzt zurueck auf 'armed' und startet
openWakeWord wieder fuer passives Lauschen. ARIAs Antwort kommt durch,
TTS spielt, aber resume() ist dann no-op weil state schon 'armed'.
Bei VAD-Auto-Stop (silence-callback im Wake-Word-Pfad) bleibt das
Multi-Turn-Verhalten unveraendert — das ist die "natuerliche" Pause
und passt zum Konversations-Modus.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
App: GPS-Toggle in Settings → Allgemein → Standort wird jetzt korrekt
in AsyncStorage persistiert (key: aria_gps_enabled). ChatScreen pollt
den Wert mit den anderen Settings im 2s-Intervall.
Bridge: chat/audio-Handler nutzen jetzt einen gemeinsamen _build_core_text
Helper, der je nach Kontext einen Hint vorschaltet:
- Barge-In ("[Hinweis: Stefan hat dich unterbrochen ...]")
- GPS ("[Stefans aktuelle GPS-Position: lat, lon. Nutze die nur wenn
die Frage sich auf seinen Standort bezieht. Erwaehne sie nicht
von dir aus, ausser er fragt explizit danach.]")
ARIA weiss bei "wo bin ich?" / "Wetter hier?" automatisch was zu tun ist
— bei normalen Fragen kommt die Position aber nicht ungefragt vor. Der
User sieht im Chat-Verlauf nichts von der GPS-Info, nur ARIAs Antwort
kann darauf eingehen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug: Wenn beim Aufnahmestart sofort gesprochen wurde (z.B. Wake-Word-
Echo noch im Mikro) ODER der Hintergrund vorruebergehend laut war,
verschob die avg-basierte Baseline die Stille-Schwelle so weit nach
oben, dass normale Hintergrundgeraeusche dauerhaft als "Sprache"
zaehlten — VAD feuerte nie, Aufnahme lief unendlich.
Fix:
- Baseline = MINIMUM der 5 Samples statt Mittelwert (ruhigster Moment)
- Cap auf sinnvollen Bereich:
- Silence-Schwelle: -50dB bis -28dB (vorher unbegrenzt)
- Speech-Schwelle: -40dB bis -18dB
- Erweitertes Log: zeigt sowohl raw als auch geclamp-te Werte
Damit gibt's keine "tote" VAD-Konfiguration mehr — selbst wenn die
Baseline-Messung Schrott ist, bleiben die Schwellen praktikabel.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Der pauschale 30s-Timeout vom Vorgaenger-Commit haette bei einer
5-Minuten-Aufnahme schon getriggert waehrend Whisper noch transkribiert
(Whisper braucht auf der Gamebox-GPU grob real-time/5, plus Bridge-
Roundtrip).
Neue Formel: 60s Buffer + 1x Aufnahmedauer.
- 5s Aufnahme → 65s Wait
- 5min Aufnahme → 6 min Wait
- 30min Aufnahme → 31 min Wait
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug: Wenn eine Aufnahme leer war, nur Wake-Word-Echo enthielt oder STT
sonstwie nichts erkannt hat, sendet die Bridge KEIN stt-Event zurueck —
die Placeholder-Bubble "Spracheingabe wird verarbeitet" blieb fuer immer
im Chat. Folge-Aufnahmen matchten dann via Substring-Fallback die ALTE
Placeholder, der echte Text landete in der falschen Bubble.
Fix: nach jedem audio-send einen 30s-Timer starten. Wenn nach Ablauf die
Bubble (per audioRequestId identifiziert) immer noch "verarbeitet" ist,
wird sie entfernt + Toast "nicht erkannt" zeigt das dem User.
So bleibt der State sauber + audioRequestId-Match auf zukuenftige
Aufnahmen findet die richtige Bubble (statt die hinterbliebene Placeholder).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Du kannst jetzt "Computer" sagen waehrend ARIA noch redet — TTS
verstummt, neue Aufnahme startet. Vorher musste man warten oder
manuell den Voice-Button tappen.
Native (OpenWakeWordModule.kt):
- AudioRecord-Source von MIC auf VOICE_COMMUNICATION (aktiviert auf
den meisten Geraeten Echo-Cancellation + Noise-Suppression)
- Zusaetzlich AcousticEchoCanceler/NoiseSuppressor/AutomaticGainControl
explizit aktiviert wenn vorhanden — robuster auf Geraeten wo die
VOICE_COMMUNICATION-Source die Effects nicht automatisch mitbringt
- releaseAudioEffects() im stop/dispose
JS (wakeword.ts):
- Neue API: startBargeListening / stopBargeListening — Wake-Word
parallel aktivieren, ohne den State 'conversing' zu verlassen
- onWakeDetected unterscheidet jetzt: in 'conversing' → barge-in-
Callback (nicht der normale wake-callback). Sonst Standard-Pfad.
- onBargeIn-Subscriber-API + isBargeListening-Getter
Lifecycle-Wiring (audio.ts + ChatScreen):
- audioService.onPlaybackStarted callback (neu)
- ChatScreen: Bei TTS-Start → wakeWord.startBargeListening
- ChatScreen: Bei TTS-Ende → wakeWord.stopBargeListening (sonst kein
AudioRecord fuer die naechste Aufnahme)
- ChatScreen: Bei BargeIn → haltAllPlayback + cancel_request +
150ms-Pause + neue Aufnahme starten
issue.md + README aktualisiert.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
issue.md: drei neue Erledigt-Eintraege (Placeholder-Race per
audioRequestId, Mikro-Offen-Toast erst nach Recording-Start, Bereit-
Sound mit Toggle). Neuer Offen-Eintrag: Wake-Word parallel zu TTS
mit AcousticEchoCanceler.
README: Wake-Word-Bedienung erweitert um Ding-Dong + "🎤 sprich
jetzt"-Toast. Roadmap mit den beiden neuen Features ergaenzt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Kurzer akustischer Hinweis (Airplane Ding-Dong, 20KB MP3) bei
audioService.startRecording-Erfolg im Wake-Word-Pfad — User weiss
exakt ab wann er reden darf, statt das Toast nur zu sehen.
Quelldatei: android/sounds/Airplane-ding-dong.mp2 → ffmpeg-konvertiert
zu MP3 64kbps, abgelegt in android/app/src/main/res/raw/ damit Android
sie als Resource laden kann.
Toggle in App-Settings → Wake-Word, default aktiv. Bei Aktivierung
spielt direkt eine Vorschau ab damit man weiss wie's klingt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug: Bei zwei Sprachnachrichten kurz hintereinander wurde der STT-Text
der zweiten in die Bubble der ersten geschrieben. Ursache: findIndex
matchte ueber Substring "Spracheingabe wird verarbeitet" → bei zwei
offenen Placeholders nahm er immer die ERSTE, egal welches STT-Result
gerade kam.
Fix: jede Aufnahme bekommt eine eindeutige audioRequestId, App pusht
sie in die Placeholder-Bubble + ans audio-Event. Bridge gibt sie
unveraendert ans STT-Result zurueck. App matcht primaer per ID, fallback
auf Substring (Kompatibilitaet zu alten Bridge-Versionen).
Bonus: Toast "Wake-Word erkannt" entfernt, dafuer "🎤 Mikro offen —
sprich jetzt" erst wenn audioService.startRecording wirklich erfolgreich
war. So weiss der User exakt ab wann er reden darf — vorher war der Toast
schon ~400ms vorher da.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Settings ist jetzt ein Hauptmenue mit 8 Kategorien — beim Tippen klappt
nur die gewaehlte Sektion auf, "<-Back-Button kehrt zur Uebersicht zurueck.
Gruppen:
- 🔌 Verbindung (Server, Token, Status, Verbindungslog)
- ⚙️ Allgemein (Betriebsmodus, GPS-Standort)
- 🎙️ Spracheingabe (Stille-Toleranz, Aufnahmedauer)
- 👂 Wake-Word (Wake-Word-Auswahl)
- 🔊 Sprachausgabe (Stimmen, Pre-Roll, Geschwindigkeit)
- 📁 Speicher (Anhang-Speicherort, Auto-Download)
- 📜 Protokoll (Privatsphaere, Backup)
- ℹ️ Ueber (App-Version, Update)
Implementierung absichtlich ohne react-navigation-Stack: ein einzelner
currentSection-State, conditional rendering pro Sektion. So bleibt aller
geteilte State (rvs.config, voices-Liste, Toggles) im selben Component-
Closure ohne props-drilling oder Context.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
handlePressIn/Out + onResponderGrant/Release/Terminate weg. Push-to-
Talk lief parallel zu Tap-to-Talk und triggerte je nach Touch-Timing
unkontrollierbar. Stefan kennt das Verhalten ohnehin nicht (sagt
"druecken startet, druecken stoppt") — Push-to-Talk macht UX nur
unklarer ohne Mehrwert.
isLongPress-Ref entfernt (war nur fuer Push-to-Talk-Discrimination).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Max-Aufnahme:
Default rauf von 2 auf 5 Minuten, in den App-Settings konfigurierbar
zwischen 1 und 30 Minuten (loadMaxRecordingMs aus AsyncStorage,
Storage-Key aria_max_recording_sec). Notbremse-Verhalten bleibt:
nach Ablauf wird die Aufnahme automatisch beendet und gesendet.
Barge-In Kontext:
Wenn der User waehrend ARIA noch redet/arbeitet eine neue Sprach-
oder Text-Nachricht sendet, geht jetzt ein 'interrupted: true' Flag
mit. Bridge praefixed den Text fuer aria-core dann mit:
"[Hinweis: Stefan hat dich gerade unterbrochen waehrend du noch
gesprochen oder gearbeitet hast. Folgendes ist eine Korrektur,
Ergaenzung oder ein Themenwechsel zu deiner letzten Antwort.]"
So weiss ARIA dass die neue Message KEINE eigenstaendige Folgefrage
ist sondern auf den abgebrochenen Run bezogen. Der User sieht in
seinem Chat nur den reinen Text — der Hint geht nur an aria-core.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug 1 — Textauswahl in Bubbles ging nicht mehr:
MessageText hatte verschachtelte <Text onPress={...}> fuer Custom-Link-
Styling. Das fing die Long-Press-Geste ab, daher kein Markieren+Kopieren
mehr. Jetzt nur noch ein einzelnes <Text selectable dataDetectorType="all">,
Android macht URLs/Telefonnummern/Emails per System-Detection klickbar.
Bug 2 — VAD erkannte Stille nicht zuverlaessig (Aufnahme lief endlos):
Festwerte (-45dB Stille / -28dB Sprache) passten nicht zu jeder Umgebung.
In lauteren Raeumen lag der Hintergrundpegel ueber der Stille-Schwelle,
lastSpeechTime wurde dauerhaft aktualisiert → VAD feuerte nie, Aufnahme
lief bis 120s Max-Duration.
Jetzt adaptiv: erste 5 Mic-Samples (~500ms) bilden die Baseline; Stille-
Schwelle = baseline+6dB, Sprache-Schwelle = baseline+12dB. Toast zeigt
die kalibrierten Werte beim Aufnahmestart. Fallback auf -38dB/-22dB falls
das Mikro keine Metering-Updates liefert.
Bug 3 — Barge-In ("ach vergiss es"):
Wenn waehrend ARIAs Antwort eine neue Sprachnachricht aufgenommen wird,
wird ARIAs aktuelle Aktivitaet (TTS + thinking/tool) sofort abgebrochen
bevor die neue Message gesendet wird — wie in einem echten Gespraech wo
man den anderen unterbrechen darf.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Da kein adb-Zugriff: visuelle Debug-Pfade direkt in der App + im
Diagnostic-Bridge-Tab.
App: zwei Toasts beim Empfang eines stt-events
- "STT empfangen: ..." sobald das chat-event mit sender=stt reinkommt
- "Bubble #X ersetzt" oder "keine Placeholder → neue Bubble"
Bridge: explizites Info-Log "STT-Text an RVS broadcastet (sender=stt)"
nach erfolgreichem _send_to_rvs, "NICHT broadcastet" wenn die Methode
False lieferte (Ping fehlgeschlagen / Verbindung tot).
Naechster Test:
- Sprachnachricht aufnehmen
- Toast erscheint? → STT-Event kommt in App an, Bug ist im findIndex
- Toast erscheint nicht? → Diagnostic Bridge-Tab pruefen ob das Log
"STT-Text an RVS broadcastet" steht
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
docker-compose interpretiert $( als Variable-Interpolation-Pattern und
warf "Invalid interpolation format". Die anderen $$DIST-Stellen waren
schon korrekt escaped, nur das command-substitution fehlte.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Diagnostic-UI:
- chat-msg ist jetzt eine richtige Bubble (border-radius 14px, Schatten,
flex-Layout statt margin-Hack, Tail-Radius zur Sender-Seite hin).
- Eingabefelder (haupt + Vollbild) jetzt textarea mit Auto-Resize.
Enter sendet, Shift+Enter macht neue Zeile.
- white-space: pre-wrap behaelt Zeilenumbrueche aus dem Text bei.
Diagnostic-Server:
- sendToRVS_raw nutzt jetzt die persistente rvsWs statt fuer jedes Send
eine frische Verbindung aufzubauen. Der frische-WS-Pfad hatte Race-
Probleme (WS schloss bevor RVS broadcasten konnte → User-Nachrichten
von Diagnostic kamen nicht in der App an). Frische WS bleibt als
Fallback wenn die persistente gerade tot ist.
App:
- console.log am Anfang des chat-handlers + im STT-Result-Handler mit
findIndex-Result und Placeholder-Count. Bei nicht-erkanntem STT-Text
liefert `adb logcat -s ReactNativeJS:V` jetzt direkt den Befund:
kommt das Event ueberhaupt an, findet er die Placeholder?
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug 1a — Anruf-Pause:
Neues PhoneCallModule.kt nutzt TelephonyCallback (API 31+) bzw.
PhoneStateListener (Pre-12) um auf RINGING/OFFHOOK/IDLE zu reagieren.
Bei Klingeln/Gespraech ruft phoneCall.ts → audioService.haltAllPlayback,
ARIA verstummt sofort. READ_PHONE_STATE Permission wird beim ersten
Start angefragt; ohne Permission failt der Listener leise.
Bug 1b — Spotify-Resume:
AudioFocus wird jetzt an den Conversation-Lifecycle gekoppelt statt an
einzelne Streams. Solange wakeWordState 'conversing' ist, blockt
acquireConversationFocus() jeden per-Stream-Release. Erst beim Wechsel
auf 'armed'/'off' darf der Focus tatsaechlich freigegeben werden.
Verhindert das "Spotify kommt nach 10s wieder hoch"-Phaenomen auch
ueber Render-Pausen + zwischen mehreren ARIA-Antworten hinweg.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug 2: STT-Result schreibt jetzt eine neue User-Bubble wenn keine
Placeholder im State gefunden wird (statt das Update zu verwerfen).
Schuetzt vor Race-Conditions zwischen audio-send und State-Updates,
damit der gesprochene Text immer im Chat erscheint.
Bug 3: Bild + Text wurden als zwei getrennte Events ('file' + 'chat')
gesendet, jeder triggerte einen eigenen send_to_core. ARIA antwortete
zweimal — einmal "warte auf Anweisung" beim Bild, dann nochmal auf
den Text. Bridge buffert jetzt eingehende file-Events 800ms; kommt in
dem Fenster ein chat, werden alle Files + Text zu einer einzigen
aria-core-Nachricht gemerged. Kein chat → Files alleine wie bisher.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug: Voice-Override wurde nach der ersten ARIA-Antwort konsumiert.
Eine ARIA-Antwort triggert aber oft mehrere TTS-Calls (Tool-Use →
Zwischenmeldung → finale Antwort). Der erste nutzte die neue Stimme,
alle folgenden fielen auf self.xtts_voice (= alte Voice aus
voice_config.json) zurueck. Die App schickt nie ein config-Update,
daher blieb voice_config.json fuer immer auf der alten Stimme.
Neue Semantik:
- chat-/audio-Event mit voice="X" → Override="X", gilt fuer alle
folgenden TTS-Calls bis zum naechsten chat-Event
- chat-Event mit voice="" → Override geloescht, fallback auf
Default-Voice (voice_config.json / Diagnostic)
- chat-Event ohne voice-Field → Override unveraendert
Audio-Send in ChatScreen.tsx (Push-to-Talk-Pfad) gab voice/speed
gar nicht mit; jetzt konsistent mit dem Tap-to-Talk-Pfad.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Hauptursache warum kein Wake-Word je triggerte: das Google-Speech-
Embedding-Modell liefert (1,1,1,96), nicht (1,96). Der Cast
`as Array<FloatArray>` warf eine ClassCastException, die vom try/catch
geschluckt wurde — Pipeline lief still ins Leere.
Zusaetzlich:
- WW-Input-Frame-Count wird jetzt aus den Modell-Metadaten gelesen
(variiert pro Keyword; hey_jarvis=16, computer_v2evtl. anders)
- "Computer" als Wake-Word erweitert (Community-Modell aus
fwartner/home-assistant-wakewords-collection)
"ARIA" als Wake-Word: gibt's nicht fertig trainiert. Muesste ueber
das openWakeWord Colab-Notebook trainiert werden (~1h auf gratis-GPU).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wenn die Bridge zwischen zwei Saetzen rendert (1-2s pro Satz auf der
Gamebox-RTX 3060), kommen keine neuen PCM-Chunks rein und der AudioTrack-
Buffer laeuft leer. Spotify hat eine eigene Heuristik die nach ~10s
"stummer Lücke" eigenmaechtig die Wiedergabe wiederaufnimmt — auch wenn
wir den AudioFocus formal noch halten.
Fix: Writer-Thread fuettert Stille rein wenn der Puffer unter ~100ms
faellt (~50ms pro Refill-Tick alle 50ms). AudioTrack bleibt damit
durchgehend aktiv, andere Apps respektieren weiterhin den Fokus.
Bonus: 30s-Idle-Cutoff falls die Bridge crashed und kein final-Marker
mehr kommt — sonst wuerde der Writer-Thread ewig Stille fuettern.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mit ONNX Runtime fuer das Wake-Word kommen Native-Libs fuer alle 4
Architekturen rein (arm64-v8a, armeabi-v7a, x86, x86_64). Das
sprengt sowohl den Gitea-Upload (nginx-Limit) als auch unnoetig die
Auto-Update-Downloads aufs Phone. Per ABI-Split jetzt nur noch
arm64-v8a — deckt jedes Android-Phone seit 2017 ab.
build.sh greift den neuen APK-Pfad (app-arm64-v8a-release.apk),
faellt auf app-release.apk zurueck falls die Splits in build.gradle
deaktiviert werden.
versionCode 606 / versionName 0.0.6.6 (vom Linter mitgehoben).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AudioFocus wird jetzt mit 800ms Verzoegerung freigegeben — wenn ARIA
direkt eine zweite Antwort hinterherschickt oder das Recording ins TTS
uebergeht, wird das Release abgebrochen. Spotify/YouTube haben damit
keine Mikro-Sekunden-Luecke mehr zum Hochkommen waehrend ARIA spricht.
README: neue Sektion zur Wake-Word-Einrichtung mit Picovoice
(7-Tage-Trial, Console-Link, Anleitung fuer eigene Keywords) und
veraltete Wake-Word-Limitation entfernt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Damit man am Logfile schwarz auf weiss sieht ob der Wert wirklich an
die Library geht — falls bei Stefan speed=0.30 ankommt aber Maia
trotzdem schnell, ist's F5-TTS-Verhalten, nicht Pipeline.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Android-Eigenheit: bei nested Text-Komponenten muss selectable=true
auch an die Kinder; der Wert auf dem Parent erbt sich nicht zuverlaessig.
Plus: dataDetectorType="all" als Fallback fuer System-Linkifizierung,
falls unsere Regex einen Match verpasst.
suppressHighlighting=false damit Long-Press auf den Link-Texten den
Selection-Mode nicht blockt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stefan's Verwirrung: Ohr-Button + KEIN Porcupine = Direkt-Aufnahme,
nicht passives Lauschen. Wenn er lange wartet, schnappt das Mikro
Hintergrundgeraeusche/Sprache auf, sendet ab, Ohr aus. Sah aus wie
"Wake-Word triggerte" — war aber stinknormales Recording.
Fixes fuer klares Feedback:
- Toast bei jedem State-Wechsel:
* Direkt-Aufnahme (kein Porcupine): "Wake-Word nicht aktiv —
direkte Aufnahme startet (Mikro hoert mit)"
* armed: "Lausche auf X..."
* Wake erkannt: "Wake-Word X erkannt — sprich jetzt"
* endConversation: "Lausche wieder auf X" oder "Mikro aus"
- Ohr-Button-Icon zeigt drei States:
🔇 off
👂 armed (Porcupine lauscht passiv)
🎙️ conversing (aktive Aufnahme laeuft)
- ChatScreen subscribed wakeWordService.onStateChange fuer Live-
Updates des Icons.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug 2: STT-Result ueberschrieb beide noch unaufgeloeste Audio-Bubbles
mit gleichem Text. Fix: nur die ERSTE matchende Bubble aktualisieren
(findIndex + index-Update statt map). Reihenfolge ist FIFO weil Whisper
sequenziell verarbeitet.
Bug 3: Speed-Param wird nun in jedem Hop geloggt:
- ChatScreen: "[Chat] sende mit voice=X speed=Y"
- aria-bridge: "XTTS-Request gesendet (voice=X, speed=Y.YYx)"
- f5tts-bridge: "F5-TTS: N Satz(e), voice=X, speed=Y.YYx"
Damit kann man im logcat/docker-logs eindeutig sehen wo speed evtl.
verloren geht oder ob die Stimme einfach von Natur aus schnell ist.
Bug 4: VAD-Trigger-Reason mit Schwelle: "VAD NNN ms Stille (Schwelle=NNN ms)".
Plus startRecording loggt jetzt VAD-Stille + MAX-Recording.
Bug 1 (Porcupine): mehr Debug + Toast-Meldungen.
- init failure: err.name/code/stack ins Log
- start() ohne Porcupine: Toast "Access Key in Settings setzen"
- start() Fehler: Toast mit Fehlermeldung
- configure(): Toast wenn init scheitert
- Erfolgreiches arming: Toast "Lausche auf X"
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bei kurzen Saetzen (nur ein paar Chunks + sofort final) konnten die
async handlePcmChunk-Calls parallel laufen. Der final-Chunk konnte
native end() aufrufen BEVOR der vorherige Chunk seinen native start()
abgeschlossen hatte. Der Writer-Thread startete dann mit endRequested
bereits true, verarbeitete keine Chunks sauber → Audio ging verloren.
Fix: Wrapper chaint alle Chunk-Calls an eine Promise-Queue:
_pcmChunkQueue = Promise.resolve()
handlePcmChunk → _pcmChunkQueue.then(() => _handlePcmChunkImpl(p))
So werden start/writeChunk/end garantiert in der richtigen Reihenfolge
verarbeitet. Der API-Contract bleibt (gleiches return-Promise).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Die heruntergeladenen Update-APKs (~20-30MB pro Release) landeten in
CachesDirectoryPath und wurden nie geloescht. Bei regelmaessigen
Updates sammelt sich das auf mehrere 100MB an.
Fix: cleanupOldApks() wird gerufen
- einmal beim App-Start (Constructor) — alte APKs sind sowieso nicht
mehr relevant, die aktuelle Version laeuft ja aus dem System
- vor jedem neuen Download — falls jemand zwei Updates in einer
Session zieht
Loescht alle *.apk Dateien im CachesDirectoryPath und loggt die
freigemachte Groesse pro Datei.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Zwei Bugs die zusammen dafuer sorgen dass Worte "verschluckt" werden:
1) play() wurde bei preroll=0 erst beim ersten echten Chunk aufgerufen
— nicht schon nach der Leading-Silence. Dadurch musste AudioTrack
gleichzeitig Startup UND Audio abspielen, die Hardware-Anfahr-Latenz
schluckt die ersten Samples.
Fix: Bei prerollBytes==0 direkt nach dem silence-write play() rufen.
AudioTrack haelt den Play-State und wartet auf mehr Samples — die
naechsten Chunks kommen in den bereits laufenden Stream rein.
2) Nach letztem Chunk ging der Writer via return@Thread in den finally-
Block. Der wartete zwar auf playbackHeadPosition >= totalFrames, aber
Android's Hardware-Pipeline puffert oft noch ein paar Samples nach —
stop() kam, Samples futsch.
Fix: 300ms TRAILING_SILENCE am Ende schreiben. playbackHeadPosition
erreicht echt bis zum Ende der echten Samples bevor die Stille abspielt.
Loop umgeschrieben auf mainLoop-Label (break statt return@Thread) damit
Trailing-Silence garantiert laeuft.
LEADING_SILENCE auf 300ms erhoeht fuer bessere AudioTrack-Warmup-Toleranz.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
F5-TTS ist schnell genug dass der Puffer bei kurzen Saetzen eher
schadet als nuetzt — er verzoegert den play()-Start fuer Sekunden die
dann als Wartezeit auffallen.
Aenderungen:
- audio.ts: TTS_PREROLL_MIN_SEC 1.0 → 0 (Einstellbar in Settings)
- PcmStreamPlayerModule.kt: MIN_PREROLL_SECONDS auf 0.0, Fallback-
Logic respektiert jetzt 0 als gueltigen Wert (vorher hat der
.let { if (it > 0) it else DEFAULT } 0 zu 3.5s umgebogen).
Bei preroll=0 greift der Leading-Silence von 200ms immer noch, d.h.
AudioTrack-Startup bleibt sauber. play() wird dann beim allerersten
echten PCM-Chunk aufgerufen.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Neue −0.1 / +0.1 Buttons im Preview-Modal mit aktuellem Wert-Label.
Bei jedem Oeffnen wird der Speed auf 1.0 zurueckgesetzt (bewusst kein
persist — nur zum Experimentieren waehrend das Modal offen ist).
- Range 0.1-5.0, gleiche wie in App-Settings
- Wird beim Play an f5tts-bridge als speed-Param mitgegeben
- Server clampt auf 0.1-5.0, Fallback 1.0
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
TTS_SPEED_MIN 0.5 → 0.1, TTS_SPEED_MAX 2.0 → 5.0.
Bridge-seitige Validierungen (aria_bridge.py + f5tts/bridge.py) mit-
gezogen auf den gleichen Bereich.
Hinweis: Extremwerte (unter 0.5 oder ueber 2.0) koennen bei F5-TTS
verzerrte Ausgaben produzieren — Stefan bekommt die Freiheit zum
Experimentieren.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Drei zusammenhaengende Bugs:
1. VAD-Timer feuerte im 200ms setInterval WEITER nachdem die Stille-
Schwelle erreicht war — listeners wurden pro Aufnahme bis zu 5x
getriggert. Parallel laufende stopRecording()-Calls lieferten
audio-recorder-player's nativen Layer OOM / Crash.
Fix: silenceFired-Latch + Timer-Clear SOFORT beim ersten Feuer
(fireSilenceOnce-Helper). Gleiche Logik fuer Max-Dauer + Conv-Window.
2. VoiceButton silence-listener re-registrierte bei jedem isRecording-
Flip (deps [isRecording, onRecordingComplete]). Closure-State war
stale, und bei schnellen flips gabs register/unregister-Races.
Fix: empty deps, state direkt vom audioService via getRecordingState()
lesen. onRecordingComplete via Ref (damit der Callback aktuell bleibt
ohne re-register).
3. handleTap las den Button-State aus React (isRecording), der bei
schnellen Taps stale sein konnte — "erst zweiter Tap geht" Symptom.
Fix: audioService.getRecordingState() als Source-of-Truth, plus
tapBusy-Ref als Anti-Doppel-Tap-Guard waehrend asyncer start/stop.
'processing'-State wird korrekt ignoriert.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stefan hat aufgeklaert: Auto-Playback geht nur bei LANGEN Saetzen, bei
kurzen nicht. Das passt zur Pre-Roll-Logik: wenn weniger als pre-roll
Bytes gepuffert werden, soll eigentlich der Fallback in end() greifen,
der nach queue-Timeout play() aufruft.
Neuer Log-Eintrag zeigt ob der Fallback ausgeloest wurde:
"Playback gestartet VOR Pre-Roll (kurzer Text, NNNNB gepuffert)"
Beim naechsten Test mit adb logcat sehen wir direkt:
* Fallback-Log kommt → play() wurde aufgerufen, Problem liegt woanders
* Fallback-Log kommt NICHT → endRequested wird nicht rechtzeitig
erkannt oder Race mit concurrent handlePcmChunk-Calls
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stefan berichtet dass Auto-Playback trotz Closure-Fix nicht greift.
Zwei neue Log-Zeilen die beim naechsten Test direkt zeigen was schief
laeuft:
- ChatScreen: "[Chat] audio-msg canPlay=X (enabled=Y muted=Z)"
- audio.ts: "[Audio] PCM-Stream start: silent=X messageId=Y ..."
Ausreichend um zu unterscheiden:
* canPlay=false trotz Mund-an → ttsMuted bleibt im State haengen
* canPlay=true aber silent=true in audio.ts → Ref-Bug oder race
* silent=false aber nichts hoerbar → native-module oder audio-routing
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
War doppelt gelistet: einmal als erledigter Filter und einmal als
offener "wird als NO angezeigt"-Bug. Der Filter in aria-bridge verwirft
NO_REPLY-Antworten heute still, der Anzeige-Bug ist damit praktisch weg.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Offene Bugs auf 3 reduziert (NO_REPLY-Anzeige, Porcupine-Jarvis,
Porcupine-Crash — die zwei letzten abhaengig vom ADB-Logcat-Test).
App-Features-Backlog auf 2 (History-Race, Background-Audio) weil
Text-Auswahl/Autolink/Speed-Setting/Voice-Preview jetzt fertig sind.
Diagnostic Features-Abschnitt leer → geloescht.
Erledigt-Liste um ~18 Punkte ergaenzt (F5-TTS Pre-processing, deutsches
Fine-Tune, maxPayload-Fix, service_status, config_request, Conversation-
Window, Porcupine, HF-Cache Bind-Mount, cleanup-windows, Mute-Bug,
Zombie-Recording, Autolink, Speed-Setting, Preview-Modal).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Audio-Normalisierung: nie aufgefallen, bei Bedarf zurueck
- F5-TTS Streaming-Inferenz: Upstream-Feature, nicht unseres
- Deepspeed: premature optimization, Render ist durch Pre-Roll
kaschiert schnell genug
- BigVGAN-Support: obsolet seit Vocos + aihpi German Fine-Tune laeuft
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bugs:
- App Mute-/Auto-Playback: onMessage-Closure hielt stale ttsDeviceEnabled/
ttsMuted → Mute wurde ignoriert + AsyncStorage-Load kam nicht durch.
Fix via ttsCanPlayRef (live gespiegelt) statt Closure-Variablen.
- App Zombie-Recording: toggleWakeWord hat die laufende Aufnahme nicht
gestoppt → audioService.recordingState blieb 'recording' → normaler
Aufnahme-Button wirkungslos. Fix: await stopRecording() vor stop().
- Porcupine robuster: BuiltInKeywords-Enum Mapping mit String-Fallback,
errorCallback fuer Runtime-Crashes (state zurueck auf off statt
App-Crash), mehr Logging damit man beim naechsten Issue debuggen kann.
App-Features:
- MessageText Komponente: Text ist durchgehend selektierbar, erkennt
URLs (http/https), E-Mails, Telefonnummern und macht sie anklickbar
(oeffnet Browser / Mail-App / Android-Dialer via Linking).
- TTS-Wiedergabegeschwindigkeit pro Geraet einstellbar (Settings ->
"Sprechgeschwindigkeit", 0.5-2.0 in 0.1-Schritten, Default 1.0).
Wird als speed-Param an die F5-TTS-Bridge durchgereicht.
Bridge-Durchreichen:
- ChatScreen: speed aus AsyncStorage via ttsSpeedRef, an chat/audio/
tts_request mitgeschickt
- aria-bridge: _next_speed_override wie voice_override, an xtts_request
weitergereicht
- f5tts-bridge: speed-Param an F5TTS.infer() durchgereicht
Diagnostic-Feature:
- Voice-Preview-Button (Play-Icon) vor dem Delete-X in der Stimmen-Liste
- Modal mit Textfeld (Default-Beispieltext wird bei jedem Oeffnen neu
gesetzt) und Play-Button
- Server sammelt audio_pcm Frames der Preview-Anfrage, baut WAV,
schickt base64 zurueck, Browser spielt im <audio>-Tag ab
- 60s Timeout-Safety-Net
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug: User leert "Custom Checkpoint" in Diagnostic, klickt Anwenden, aber
die Bridge behielt den alten Wert weiter (z.B. BigVGAN-Pfad). Ursache:
- Server loeschte den Key bei leerem String aus voice_config.json
- Bridge's update_config sah key absent → "keep current" Semantik
- Resultat: kein Reset, alter Pfad blieb aktiv, NaN-Output blieb
Fix auf beiden Seiten:
- diagnostic/server.js: Keys werden immer mit dem Wert gesetzt (auch "")
statt geloescht. "" landet jetzt explizit in der config.json.
- f5tts/bridge.py: update_config unterscheidet jetzt:
* key fehlt in payload → current behalten (unveraendert)
* key da + leer → RESET auf DEFAULT_F5TTS_* (User-Wunsch)
* key da + Wert → neuen Wert nehmen
Damit kann der User in Diagnostic ein Feld leeren + Anwenden und die
Bridge schaltet wirklich auf Hard-Default zurueck.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
f5tts/bridge.py: das hardcoded model="small" in request_transcription war
ein Fehler — whisper-bridge hat dadurch stumm zwischen Modellen geswappt.
Wenn User large-v3 in Diagnostic eingestellt hatte:
- f5tts Voice-Transkribierung triggerte Swap zu "small" (+~500MB Laden)
- Danach aria-bridge schickte naechsten stt_request mit large-v3
(+~3GB Laden weil small jetzt im RAM war)
Doppelter Load, unnoetiger Traffic.
Fix:
- f5tts: kein model mehr im payload, whisper-bridge entscheidet
- whisper: wenn kein payload.model UND bereits ein Modell geladen →
das behalten. Nur wenn gar nichts da ist fallback auf WHISPER_MODEL
env default.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Die BigVGAN-Variante des aihpi F5-TTS Checkpoints ist nicht einfach ein
"optional besser" Fallback — sie ist mit dem Default-Vocos-Vocoder den die
f5-tts Library laedt inkompatibel. Output wird NaN, App bleibt stumm.
Stefan hat das probiert, App stumm, 10 Minuten Debugging. README war zu
locker formuliert ("Meist hoehere Quali") — jetzt klar als "funktioniert
AKTUELL NICHT" gekennzeichnet.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
F5-TTS generiert gelegentlich NaN/Inf samples — ohne sanitize lief der
int16-Cast in undefined behavior (RuntimeWarning + kaputter Sound in den
entsprechenden Stellen). Jetzt: nan_to_num vor clip, plus Warnung wie
viele samples betroffen waren.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Konfig-Tabelle mit den konkreten Diagnostic-Werten fuer das deutsche
Fine-Tune von aihpi/F5-TTS-German — Modell-Architektur, hf:// Pfade,
empfohlene cfg_strength / nfe_step. Plus Hinweis auf die BigVGAN-
Variante als Alternative.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
_resolve_hf_path wandelt hf://user/repo/path → lokaler Download via
huggingface_hub.hf_hub_download. So kann man in Diagnostic einfach die
HF-Pfade fuer custom Modelle reinschreiben, ohne erst manuell zu
downloaden + zu mounten.
Format: hf://aihpi/F5-TTS-German/F5TTS_Base/model_365000.safetensors
hf://aihpi/F5-TTS-German/vocab.txt
Diagnostic UI: Placeholders + Labels angepasst mit Beispiel-HF-Pfaden
und Hinweis dass fuer Fine-Tunes "F5TTS_Base" statt "F5TTS_v1_Base"
als Architektur-Name gesetzt werden muss.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
F5-TTS reagiert empfindlich auf leise / verrauschte / zerhackte
Referenzen — wir haben bisher nur auf 24kHz mono + 10s geclipped.
Jetzt zusaetzlich:
- silenceremove am Anfang (bis Speech einsetzt, <-50dB)
- silenceremove am Ende (0.5s Stille nach letzter Speech = Cutoff)
- loudnorm -16 LUFS (EBU R128) fuer konsistente Amplitude
Damit sieht das Modell saubere, konstant laute Referenz-Audios statt
kaputter Clips mit Ausklang oder leiser Aufnahme. Besonders bei Deutsch
(wo F5TTS_v1_Base schwach ist) hilft jede Input-Konsistenz der Quali.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
F5-TTS hat ein Hard-Limit von 12s fuer das Referenz-Audio — laengere
WAVs werden intern abgeschnitten, aber unser ref_text war das komplette
Transkript. Text und Audio wurden dadurch unaligned, Render-Qualitaet
leidet und der initial Warmup-Render dauerte 57s statt 5s.
Fix:
- normalize_ref_wav(max_seconds=10): ffmpeg schneidet auf 10s + 24kHz
mono, gibt was_modified zurueck damit Caller den txt invalidieren kann
- handle_voice_upload: clippt VOR der Transkription, Whisper sieht also
nur die 10s → txt passt garantiert zum Audio
- _do_tts: checkt vor jedem Render die WAV-Dauer. WAVs > 10.5s werden
geclippt, .txt geloescht → on-the-fly Neu-Transkription beim Render
Bestehende kaputte Voices (wie MAIA mit 600+ Worten txt zu einem 20s
Audio) werden beim naechsten Render automatisch gefixt.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Beim user kommt nach 'RVS verbunden' nichts mehr — Modell-Download
startet nicht, banner aktualisiert sich nicht. Vermutung: alter Code
laeuft noch (kein neu gebauter Container) ODER der Initial-Handshake
crashed silent (asyncio.create_task ohne await schluckt Exceptions).
- whisper + f5tts: Initial-Handshake mit logger.info Zeilen, damit
man sieht ob er ueberhaupt ausgefuehrt wird
- f5tts: zusaetzlich exception-Catch + fehler-broadcast falls der
Modell-Load crashed
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Vier Bugs in einem Aufwasch:
1. HF-Cache als Bind-Mount zurueck
xtts/hf-cache:/root/.cache/huggingface fuer beide Bridges. War vorher
raus, dadurch jedes Container-Restart = ~3GB Whisper-Download +
~1GB F5-TTS-Download. User dachte 5min ist einmalig — ist aber bei
jedem Restart. Jetzt: einmal pro Maschine geladen, fertig.
2. Banner zeigte stale "ready"
whisper-bridge sendete beim Connect nur dann Status wenn Modell schon
geladen war. Sonst blieb der App/Diagnostic Banner auf dem alten
"ready" State von vor dem Restart haengen — User sah "bereit" obwohl
gerade gar nichts geladen war. Jetzt wird IMMER ein Status broadcast:
ready oder loading.
3. config_request Pattern
aria-bridge wusste nicht wann Gamebox-Bridges sich (re)connecten.
Wenn die nach aria-bridge kamen, verpassten sie den Config-Broadcast
und blieben mit Hard-Defaults stehen.
Jetzt: whisper- und f5tts-bridge senden beim Connect ein
config_request, aria-bridge antwortet mit der persistierten Config
(whisperModel, xttsVoice, f5tts*-Felder).
4. RVS ALLOWED_TYPES um config_request erweitert.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
aria-bridge horcht jetzt auf service_status fuer den Service 'whisper'.
Solange whisper-bridge im 'loading' steckt (Erst-Download large-v3 kann
1-2 Min dauern), gilt fuer stt_request ein Timeout von 300s statt 45s.
Sobald 'ready', zurueck auf 45s — reicht selbst fuer lange Audios.
Symptom vorher: Beim ersten Sprechen nach Container-Restart hat aria-
bridge nach 45s aufgegeben und lokal gefallback waehrend whisper-bridge
noch fleissig den Download laufen hatte. Damit wurde der Sinn der
Auslagerung kaputt gemacht.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Symptom: aria-whisper-bridge bekam beim ersten internen stt_request
(via voice_upload mit WAV als base64, ~2.4MB) den Frame zu Gesicht,
default ws-max ist 1MB → mit Close-Code 1009 abgewiesen → Verbindung
tot → naechster stt_request lief in Timeout → lokales Fallback.
Fixes:
- whisper-bridge: max_size=50*1024*1024 in websockets.connect()
(gleicher Wert wie f5tts-bridge schon hat)
- RVS-Server: maxPayload=50*1024*1024 in WebSocketServer-Optionen,
damit der Server die Frames nicht selbst auf 1MB cappt bevor er
sie an die Bridge weiterleitet.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Vorher: Container-Start lud erst 'small' (env default), dann nochmal
das in Diagnostic konfigurierte Modell (z.B. large-v3) wenn die
config-Broadcast vom aria-bridge ankam. Doppelter Download, doppelte
Wartezeit, doppelter VRAM-Peak.
Jetzt:
- Initial wird NICHTS geladen
- aria-bridge sendet die persistierte voice_config.json kurz nach
RVS-Connect → whisper-bridge sieht den richtigen Modellnamen
- config-Handler erkennt: noch nichts geladen ODER Wechsel
→ loading-Broadcast → ensure_loaded → ready-Broadcast
- stt_request-Handler: gleicher Status-Broadcast falls Race-Condition
(Spracheingabe in den ersten 1-2s nach Container-Start)
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
App-Pendant zum Diagnostic-Banner. Wenn die Gamebox-Bridges (F5-TTS /
Whisper) ihren Lade-Status broadcasten, zeigt die App oben unter der
Verbindungs-Statusleiste ein farbiges Banner:
Gelb = irgendwas laedt (NICHT wegtippbar)
Gruen = alles bereit (tippbar zum Schliessen)
Rot = Fehler
Banner aggregiert beide Services in einer Kachel. Dismiss-State wird
zurueckgesetzt sobald irgendein Service wieder in 'loading' geht
(z.B. Modell-Wechsel via Diagnostic).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stefan akzeptiert die ~5min Modell-Download-Zeit nach jedem Container-
Start, dafuer keine 50GB Cache-Bloat mehr und kein Bind-Mount-Verzeichnis
zu pflegen.
- xtts/docker-compose.yml: hf-cache Bind-Mount entfernt fuer beide
Bridges. Modelle werden im writable Container-Layer abgelegt und mit
jedem `docker compose down` automatisch weggeraeumt.
- xtts/.gitignore: hf-cache/ Eintrag raus
- RVS ALLOWED_TYPES: service_status hinzu
Bridges broadcasten Lade-Status:
- f5tts-bridge: bei Connect 'loading' -> ensure_loaded -> 'ready'.
Auch bei config-getriggertem Modell-Wechsel: erst 'loading' Broadcast,
dann reload, dann 'ready'.
- whisper-bridge: gleiches Pattern. Modell wird jetzt erst nach
RVS-Connect geladen damit der loading-Broadcast tatsaechlich rausgeht.
Diagnostic:
- server.js: service_status wird an Browser durchgereicht
- index.html: neues Banner unten rechts (fixed position) zeigt Status
fuer beide Services. Aggregiert: Icon ist Lupe waehrend Loading,
Check wenn alles ready, X bei Error.
- Wenn alles ready: X-Button erscheint (manuell schliessen) +
nach 8s automatisches Fade-Out.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@picovoice/porcupine-react-native deklariert minSdkVersion 24, dadurch
schlug der Manifest-Merger fehl wenn die App weiter auf 23 stand.
Android 7.0 ist eh das pragmatische Minimum (Geraete <7.0 sind <1% Markt).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3.0.6 war geraten und gibt's nicht im npm Registry. Aktuelle stabile 3.x
ist 3.0.5; 4.0.0 hat Breaking Changes. Beide Picovoice-Packages auf
exakte Version gepinnt damit keine Auto-Bumps fies werden.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
cleanup-windows.ps1:
- Defensive Set-ExecutionPolicy Bypass am Anfang
- Self-Elevation: wenn nicht als Admin gestartet, relauncht das Script
sich selbst als Admin mit -ExecutionPolicy Bypass + Original-Args.
User muss nur einmal UAC bestaetigen, kein extra Befehl mehr noetig.
cleanup-windows.bat:
- Wrapper der powershell.exe mit -ExecutionPolicy Bypass aufruft.
- Funktioniert auch wenn Windows die .ps1 direkt blockt (z.B. unsignierte
Scripts global gesperrt).
- Aufruf: cleanup-windows.bat stefan [-SkipPrune] [-PruneOnly]
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Ein Script das auf der Gamebox (Windows + Docker Desktop + WSL2) alle
.vhdx Files findet und via diskpart compactet. Gibt den Speicherplatz
zurueck den man IN den Distros/Containern geloescht hat aber von der
VHDX bisher nicht freigegeben wurde.
Nutzung (PowerShell als ADMIN):
.\cleanup-windows.ps1 stefan
.\cleanup-windows.ps1 -User stefan -SkipPrune # nur compacten
.\cleanup-windows.ps1 -User stefan -PruneOnly # nur prune
Default-Flow:
1. docker system prune -a --volumes -f + builder prune
2. wsl --shutdown
3. Alle gefundenen ext4.vhdx (Docker Desktop + WSL-Distros) compacten
via diskpart 'compact vdisk' (kein Hyper-V noetig)
Zeigt fuer jedes File "vor → nach (gespart X GB)" und am Ende eine
Gesamt-Summary.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Beide Bridges teilen sich jetzt einen Bind-Mount ./hf-cache:/root/.cache/
huggingface. Vorher waren das zwei getrennte Named Volumes
(f5tts-models + whisper-models), die unter Docker Desktop / Windows
in der docker-desktop-data.vhdx gelandet sind und die VHDX nie wieder
freigegeben haben — auch nach docker volume rm bleibt der belegte Platz
in der VHDX bis zum Factory Reset.
Bind-Mount loest beides:
- Files direkt im xtts/hf-cache/ sichtbar, einfach im Explorer zu loeschen
- Kein VHDX-Bloat mehr
- Beide Container teilen sich den Cache (HF-Struktur identisch, keine
Konflikte da andere Modelle)
Cleanup von vorhandenen 50GB:
docker compose down
docker volume rm xtts_f5tts-models xtts_whisper-models (oder via
Docker Desktop UI)
Anschliessend in Docker Desktop: Settings -> Resources -> Disk image
location -> Disk usage -> "Clean up" / Reset wenn die VHDX nicht
schrumpft.
xtts/.gitignore: hf-cache/ + voices/ + .env
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Folgt der "keine neuen Settings in .env" Regel.
f5tts/bridge.py:
- F5TTS_MODEL/CKPT_FILE/VOCAB_FILE/CFG_STRENGTH/NFE_STEP ENV-Vars raus
- Hard-coded Defaults im Code (DEFAULT_F5TTS_*)
- F5Runner besitzt Live-Settings als Instance-Vars + update_config()
- config-Broadcast triggert Modell-Reload nur wenn Modell-relevantes
sich aendert (cfg_strength/nfe_step ohne Reload)
- F5TTS_DEVICE bleibt ENV (Hardware-Bootstrap)
xtts/docker-compose.yml: F5TTS_* ENV-Vars rausgenommen, Kommentar
verweist auf Diagnostic-Config.
aria-bridge: nimmt f5tts*-Felder im config-Handler entgegen, persistiert
sie in voice_config.json. Beim RVS-Connect broadcastet die Bridge die
persistierte Config einmalig — damit die f5tts-bridge nach Container-
Restart automatisch die zuletzt gewaehlten Settings bekommt, ohne dass
der User in Diagnostic was klicken muss.
Diagnostic UI:
- Neuer aufklappbarer "F5-TTS Modell-Tuning (advanced)" Bereich
- Felder: Modell-ID, Custom-Checkpoint, Vocab, cfg_strength, nfe_step
- voice_config beim Laden: Felder werden zurueck in die UI gesetzt
- sendVoiceConfig schickt die neuen Felder mit
- Server: send_voice_config persistiert die Felder, leere Strings
werden geloescht damit die Hard-Defaults greifen
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Bug-Root: voice_upload schrieb "Das ist ein Referenz Audio." als Platzhalter
wenn die whisper-bridge nicht erreichbar war. F5-TTS bekam dann diesen Text
als Sprach-Anker, sah aber im WAV ganz andere Worte → verwirrtes Modell,
halluziniert in beliebiger Sprache (z.B. Spanisch).
Fixes:
- handle_voice_upload: schreibt KEINE Platzhalter-.txt mehr. Bei Failure
bleibt die .txt weg → naechste TTS-Nutzung zieht via on-the-fly retry
nach.
- _do_tts: Legacy-Platzhalter wird beim Render erkannt und geloescht,
Transkription on-the-fly neu angezogen. Bestehende kaputte voices
reparieren sich automatisch beim ersten Render.
UI-Aufraeumung: F5-TTS hat keine "Standard"-Stimme — der Eintrag ist raus
in App SettingsScreen + Diagnostic. Diagnostic-Dropdown hat jetzt einen
disabled-Hinweis "(keine Stimme gewaehlt)".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
F5TTS_v1_Base ist hauptsaechlich auf Englisch+Chinesisch trainiert; bei
Deutsch (oder anderen Romance/Germanic-Sprachen) schwimmt der Generator
ohne starkes Conditioning gerne in eine andere Sprache.
- cfg_strength 2.0 → 2.5 (per ENV F5TTS_CFG_STRENGTH ueberschreibbar)
- nfe_step bleibt 32 (per ENV ueberschreibbar)
- F5TTS_CKPT_FILE / F5TTS_VOCAB_FILE als ENV — damit man eine Community-
German-Checkpoint einhaengen kann ohne Code-Aenderung
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Der Gespraechsmodus war bisher ein Endless-Loop: Mikro hat sich nach
jeder ARIA-Antwort wieder geoeffnet bis MAX_RECORDING_MS, danach Speech-
Gate verworfen und neu starten. Das Ohr blieb ewig an.
Neue Logik:
audio.ts: startRecording(autoStop, noSpeechTimeoutMs?) — wenn der User
innerhalb des Timeouts nicht anfaengt zu sprechen, wird Stille
gemeldet → stopRecording → Speech-Gate verwirft → result=null.
wakeword.ts: drei States off/armed/conversing. start() geht direkt in
'conversing' (kein Wake-Word verfuegbar; Stub fuer spaetere Porcupine-
Integration). endConversation() bei No-Speech.
ChatScreen: Aufnahme bekommt das Window aus AsyncStorage durchgereicht.
Bei null-Result → endConversation, UI-State synchron.
Settings: neuer +/- Block "Konversations-Fenster" 3-20s (Default 8).
Mit dem Stub ist die Architektur bereit fuer Porcupine: dann geht
endConversation auf 'armed' statt 'off' und der Wake-Word-Detector
laeuft passiv weiter.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Neuer +/- Block in SettingsScreen → Spracheingabe → "Stille-Toleranz",
1.0-8.0s, Default 2.8s. Wert in AsyncStorage (aria_vad_silence_sec).
audio.ts liest den Wert beim Aufnahme-Start und nutzt ihn fuer den
VAD-Auto-Stop-Schwellwert.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>