fix(voice): verlorene Sprachnachrichten — Allow-List, Kaltstart, Dedup, Voice-Router
Vier unabhaengige Ursachen fuer 'erst beim zweiten Aufnehmen' bzw. 'wird gar
nicht verarbeitet' (server-/box-seitig, ohne App-Update wirksam):
1) rvs/server.js: stt_lease, stt_lease_request, stt_transcribe_blob,
stt_transcribe_result und chat_ack fehlten in ALLOWED_TYPES und wurden STILL
verworfen (dieselbe Falle wie bei worker_*/host_*). Folgen: das Lease lief
immer in den 250ms-Timeout -> jede Aufnahme startete verspaetet und OHNE
targetInstance nahmen alle STT-Worker dieselbe Session an (doppelte
stt_endpoint); chat_ack kam nie an -> getippte Nachrichten galten in der App
nach 3 Versuchen als fehlgeschlagen, obwohl sie verarbeitet waren.
2) xtts/whisper/bridge.py: Beim Kaltstart wurde die Session erst NACH dem
Modell-Load angelegt — alle Chunks der ersten Aufnahme liefen ins Leere und
der Take war weg (die zweite klappte, weil das Modell dann warm war). Session
wird jetzt sofort angelegt, der Endpointer wartet solange (runner.model None).
3) bridge/aria_bridge.py: Text-Dedup-Fenster 5s -> 1.5s. Es soll nur den
Zwilling zweier Worker abfangen; mit 5s fielen echte Wiederholungen weg —
also genau das Nachsprechen nach einem verschluckten Take, und kurze
Kommandos ('lauter', 'nächstes').
4) bridge/aria_bridge.py Voice-Router: Komma als Prefix-Trenner entfernt (nur
noch ':' und '-'), Fuzzy-Schwelle 0.6 -> 0.82, Sticky wird nicht mehr bei
jeder Nachricht verlaengert. Vorher matchten normale Saetze wie 'In Ordnung,
mach mal ...' als Projekt-Prefix: die Nachricht landete still in einem
Projekt und war im Hauptchat unsichtbar — verifiziert mit Beispielsaetzen.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
+23
-7
@@ -3407,11 +3407,18 @@ class ARIABridge:
|
||||
# weiter auseinander (man hoert den Wechsel erst).
|
||||
_norm_txt = " ".join(text.lower().split())
|
||||
_now_t = asyncio.get_event_loop().time()
|
||||
# Fenster bewusst KURZ (1.5s): es soll nur den Zwilling abfangen, den
|
||||
# zwei STT-Worker fuer DIESELBE Aufnahme liefern. Mit den frueheren 5s
|
||||
# fielen echte Wiederholungen weg — also genau der Fall "ARIA hat mich
|
||||
# nicht gehoert, ich sag's nochmal" und kurze Kommandos wie "lauter",
|
||||
# "nächstes", "stopp". Die eigentliche Absicherung ist ohnehin die
|
||||
# Idempotenz ueber audioRequestId weiter oben.
|
||||
_DUPE_WINDOW_SEC = 1.5
|
||||
if (_norm_txt
|
||||
and _norm_txt == getattr(self, "_last_endpoint_norm", "")
|
||||
and (_now_t - getattr(self, "_last_endpoint_at", 0.0)) < 5.0):
|
||||
logger.info("[rvs] stt_endpoint Dupe verworfen (gleicher Text <5s): %r",
|
||||
text[:60])
|
||||
and (_now_t - getattr(self, "_last_endpoint_at", 0.0)) < _DUPE_WINDOW_SEC):
|
||||
logger.info("[rvs] stt_endpoint Dupe verworfen (gleicher Text <%.1fs): %r",
|
||||
_DUPE_WINDOW_SEC, text[:60])
|
||||
return
|
||||
self._last_endpoint_norm = _norm_txt
|
||||
self._last_endpoint_at = _now_t
|
||||
@@ -3777,8 +3784,12 @@ class ARIABridge:
|
||||
r")\s*[.!?]?\s*$",
|
||||
re.IGNORECASE,
|
||||
)
|
||||
# Trenner bewusst nur ':' und '-' — NICHT das Komma. Whisper setzt gern
|
||||
# Kommata, und damit matchten normale Saetze wie "In Ordnung, mach mal ..."
|
||||
# als Projekt-Prefix: die Nachricht wanderte still in ein Projekt und war im
|
||||
# Hauptchat unsichtbar ("wird gar nicht verarbeitet").
|
||||
_VOICE_META_PROJECT_PREFIX = re.compile(
|
||||
r"^\s*(?:aria[,.]?\s+)?(?:f(?:ü|ue)r|ins?)\s+([\w\-äöüßÄÖÜ]{2,40})[:\-,]\s*(.+?)\s*$",
|
||||
r"^\s*(?:aria[,.]?\s+)?(?:f(?:ü|ue)r|ins?)\s+([\w\-äöüßÄÖÜ]{2,40})\s*[:\-]\s*(.+?)\s*$",
|
||||
re.IGNORECASE | re.DOTALL,
|
||||
)
|
||||
|
||||
@@ -3833,7 +3844,10 @@ class ARIABridge:
|
||||
s = SequenceMatcher(None, q, pname).ratio()
|
||||
if s > best_score:
|
||||
best, best_score = p, s
|
||||
if best and best_score >= 0.6:
|
||||
# Schwelle bewusst hoch (0.82): bei 0.6 reichte schon eine vage
|
||||
# Aehnlichkeit, und die Nachricht verschwand still in einem
|
||||
# fremden Projekt. Lieber im Hauptchat lassen als falsch routen.
|
||||
if best and best_score >= 0.82:
|
||||
pid = best["id"]
|
||||
self._voice_sticky_project_id = pid
|
||||
self._voice_sticky_expires_at = now + self._VOICE_STICKY_TIMEOUT_SEC
|
||||
@@ -3845,8 +3859,10 @@ class ARIABridge:
|
||||
# Kein Match → als normale Nachricht weiter (Sticky wenn aktiv)
|
||||
# 3) Kein Meta / Prefix → Sticky oder Default
|
||||
if self._voice_sticky_project_id and now < self._voice_sticky_expires_at:
|
||||
# Sticky refreshen
|
||||
self._voice_sticky_expires_at = now + self._VOICE_STICKY_TIMEOUT_SEC
|
||||
# Sticky NICHT verlaengern: frueher hat jede Folgenachricht die Frist
|
||||
# erneuert — ein einziger Fehl-Match und danach landete dauerhaft
|
||||
# alles in diesem Projekt. Jetzt laeuft er nach der urspruenglichen
|
||||
# Zeit aus und der Hauptchat uebernimmt wieder.
|
||||
return (True, stripped, self._voice_sticky_project_id, "sticky")
|
||||
# Sticky abgelaufen — zurücksetzen
|
||||
self._voice_sticky_project_id = ""
|
||||
|
||||
Reference in New Issue
Block a user