fix(voice): klarer Befehl = STOP, Gespraech = 30s passiv (kein zweiter Gong)

Nach dem Re-Arm-Fix rief die App resume() → das spielte einen zweiten Gong
und oeffnete ein neues Aufnahme-Fenster, obwohl Stefan nur einen Steuerbefehl
gab. Sein gewuenschtes Verhalten:
- Klarer Befehl (Fast-Path, speak=false, z.B. Liedersteuerung) = KEINE
  Konversation → STOP: direkt zurueck aufs Wake-Word (kein Gong, keine
  Aufnahme, kein 30s-Fenster).
- Gespraech (gesprochene Antwort) = kein neuer Gong, direkt 30s passives
  Lauschen (weiterreden wie mit einem Menschen), 30s still → Wake-Word.

endConversation(skipPassive) neu: true springt direkt zu armed statt in
passives Lauschen. onPlaybackFinished (Gespraech) → passiv (Vordergrund) bzw.
direkt armed (Hintergrund); stille Fast-Path-Antwort → skipPassive; manueller
Stop-Button → skipPassive. resume() bleibt nur noch Mic-Fail-Retry.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-11 20:52:04 +02:00
co-authored by Claude Opus 4.8
parent a0494e90ee
commit 9fb29aa517
2 changed files with 15 additions and 14 deletions
+10 -12
View File
@@ -1212,11 +1212,10 @@ const ChatScreen: React.FC = () => {
const _isSilent = (message.payload as any).speak === false
|| ((message.payload as any).answeredBy === 'fast-path');
if (_isSilent && wakeWordService.isConversing()) {
if (AppState.currentState === 'active') {
wakeWordService.resume();
} else {
wakeWordService.endConversation().catch(() => {});
}
// Klarer Steuerbefehl (Liedersteuerung etc.) = KEINE Konversation →
// STOP: direkt zurueck aufs Wake-Word. Kein Gong, keine Aufnahme,
// kein 30s-Fenster (skipPassive=true).
wakeWordService.endConversation(true).catch(() => {});
}
}
@@ -1446,12 +1445,11 @@ const ChatScreen: React.FC = () => {
useEffect(() => {
const unsubPlayback = audioService.onPlaybackFinished(() => {
if (!wakeWordService.isActive()) return;
if (AppState.currentState === 'active') {
wakeWordService.resume();
} else {
console.log('[Chat] TTS fertig im Background → endConversation (kein Multi-Turn)');
wakeWordService.endConversation().catch(() => {});
}
// Gespraech (gesprochene Antwort): KEIN neuer Gong / kein Aufnahme-Fenster,
// sondern direkt passives Lauschen (30s weiterreden wie mit einem Menschen).
// Im Hintergrund gibt's kein Multi-Turn → direkt re-armen (skipPassive).
const bg = AppState.currentState !== 'active';
wakeWordService.endConversation(bg).catch(() => {});
});
return () => unsubPlayback();
}, []);
@@ -2072,7 +2070,7 @@ const ChatScreen: React.FC = () => {
await audioService.stopStreamingRecording('user');
if (wakeWordService.isConversing()) {
console.log('[Chat] Manueller Stop in Konversation → endConversation, zurueck zu armed');
await wakeWordService.endConversation();
await wakeWordService.endConversation(true); // explizit gestoppt → STOP (kein 30s-Passiv)
}
}, []);