10 sekunden warten nach neuer chat, instruktionen verbessert.

This commit is contained in:
2025-12-27 02:59:34 +01:00
parent 90791b9ff6
commit 38e653361e
3 changed files with 116 additions and 16 deletions
+89 -15
View File
@@ -120,11 +120,19 @@ class ClaudesEyesAudioBridge:
self._sending = threading.Event()
self._sending.set() # Anfangs nicht am Senden (set = frei)
# Recording-Flag: Wenn gesetzt, wird gerade aufgenommen
# Heartbeat pausiert während Aufnahme aktiv ist
self._recording = threading.Event()
self._recording.clear() # Anfangs nicht am Aufnehmen
# Mute-Flag: Wenn True, ignoriert STT alle Eingaben
# Startet gemutet um ungewollte Aufnahmen zu vermeiden
self._muted = True
self._mute_lock = threading.Lock()
# Silence-Timeout: Wie lange Stille bevor Aufnahme als fertig gilt
self._silence_timeout = 5.0 # Sekunden
def _load_config(self, config_path: str) -> dict:
"""Lädt die Konfiguration"""
path = Path(config_path)
@@ -428,7 +436,8 @@ Die Befehle werden aus der TTS-Ausgabe rausgefiltert.
- Du musst nicht bei jedem TICK fahren - manchmal reicht auch schauen und kommentieren
## WICHTIG: Bestätige mit [READY]
Wenn du diese Instruktionen verstanden hast, antworte mit **[READY]** am Ende deiner Nachricht.
Wenn du diese Instruktionen verstanden hast, antworte mit dem Tag `[READY]` (exakt so, in eckigen Klammern!) am Ende deiner Nachricht.
**Das Format muss EXAKT `[READY]` sein** - nicht fett, nicht anders formatiert, sondern genau so: [READY]
Erst dann starten die automatischen TICKs mit Bildern!"""
console.print("[cyan]→ Sende Instruktionen an Claude...[/cyan]")
@@ -500,6 +509,16 @@ Erst dann starten die automatischen TICKs mit Bildern!"""
if not self.running:
break
# Warte bis Recording fertig ist (5s Stille)
if self._recording.is_set():
logger.debug("Stefan spricht noch, warte auf Stille...")
while self.running and self._recording.is_set():
time.sleep(0.5)
logger.debug("Stefan fertig, fahre fort")
if not self.running:
break
# Zufällige Pause nach Claudes Antwort (natürlicheres Tempo)
pause = random.uniform(min_pause, max_pause)
time.sleep(pause)
@@ -511,7 +530,7 @@ Erst dann starten die automatischen TICKs mit Bildern!"""
stefan_text = self._get_and_clear_stefan_buffer()
# Warte bis vorheriges Senden fertig ist
self._sending.wait()
self._sending.wait(timeout=30) # Max 30s warten
# Nächsten TICK senden (mit oder ohne Bild)
with self._lock:
@@ -622,40 +641,67 @@ Erst dann starten die automatischen TICKs mit Bildern!"""
"""
Hört auf Stefan und sammelt seine Worte im Buffer.
Wenn Claude tippt → Buffer sammeln
Wenn Claude fertig → Buffer wird mit nächstem TICK gesendet
Wenn gemutet → Ignoriert alle Eingaben
Ablauf:
1. Warte auf erste Spracheingabe
2. Signalisiere Recording aktiv → Heartbeat pausiert
3. Sammle weitere Eingaben bis 5 Sekunden Stille
4. Recording fertig → Buffer wird mit nächstem TICK gesendet
So wird Claude nicht unterbrochen und bekommt alles gesammelt.
Wenn gemutet → Ignoriert alle Eingaben
"""
if not self.stt:
logger.warning("STT nicht verfügbar")
return
logger.info("STT-Loop gestartet (mit Buffer)")
logger.info(f"STT-Loop gestartet (5s Stille = fertig)")
# Temporärer Buffer für aktuelle Aufnahme-Session
current_session_texts = []
last_speech_time = 0
while self.running:
try:
# Wenn gemutet, kurz warten und überspringen
if self.is_muted():
# Falls wir mitten in einer Aufnahme waren, diese beenden
if self._recording.is_set():
self._finalize_recording(current_session_texts)
current_session_texts = []
time.sleep(0.5)
continue
# Warte auf Sprache (mit Timeout)
result = self.stt.listen_once(timeout=2)
# Warte auf Sprache (kurzer Timeout für schnelle Reaktion)
result = self.stt.listen_once(timeout=1)
# Nochmal prüfen nach dem Hören (falls zwischendurch gemutet wurde)
if self.is_muted():
continue
if result and result.text and len(result.text) > 2:
# In Buffer speichern (thread-safe)
with self._stefan_buffer_lock:
self._stefan_buffer.append(result.text)
self.stats.stefan_inputs += 1
# Sprache erkannt!
current_session_texts.append(result.text)
last_speech_time = time.time()
self.stats.stefan_inputs += 1
console.print(f"\n[bold green]Stefan (gebuffert):[/bold green] {result.text}")
logger.debug(f"Stefan-Buffer: {len(self._stefan_buffer)} Einträge")
# Signalisiere dass Recording aktiv ist
if not self._recording.is_set():
self._recording.set()
console.print(f"\n[bold green]🎤 Stefan spricht...[/bold green]")
logger.debug("Recording gestartet")
console.print(f"[green] → {result.text}[/green]")
logger.debug(f"Stefan-Session: {len(current_session_texts)} Teile")
else:
# Keine Sprache erkannt - prüfe auf Stille-Timeout
if self._recording.is_set() and last_speech_time > 0:
silence_duration = time.time() - last_speech_time
if silence_duration >= self._silence_timeout:
# 5 Sekunden Stille - Aufnahme beenden
self._finalize_recording(current_session_texts)
current_session_texts = []
last_speech_time = 0
except Exception as e:
# Timeout ist normal
@@ -663,6 +709,30 @@ Erst dann starten die automatischen TICKs mit Bildern!"""
logger.error(f"STT-Loop-Fehler: {e}")
self.stats.errors += 1
def _finalize_recording(self, texts: list):
"""
Beendet eine Aufnahme-Session und speichert im Buffer.
Args:
texts: Liste der erkannten Texte in dieser Session
"""
if not texts:
self._recording.clear()
return
# Alle Texte zusammenfügen
full_text = " ".join(texts)
# In Haupt-Buffer speichern
with self._stefan_buffer_lock:
self._stefan_buffer.append(full_text)
console.print(f"\n[bold green]✓ Stefan (komplett):[/bold green] {full_text}")
logger.info(f"Recording beendet: {len(texts)} Teile → {len(full_text)} Zeichen")
# Recording-Flag zurücksetzen → Heartbeat kann weitermachen
self._recording.clear()
def _keyboard_loop(self):
"""
Hört auf Tastatureingaben für Mute-Toggle und andere Befehle.
@@ -730,6 +800,10 @@ Erst dann starten die automatischen TICKs mit Bildern!"""
# Neue URL in config.yaml speichern
self._save_chat_url_to_config(new_url)
# Warte bis der neue Chat vollständig geladen ist
console.print("[dim]Warte 10s bis Chat geladen...[/dim]")
time.sleep(10)
console.print("[cyan]Sende Instruktionen mit Referenz zum alten Chat...[/cyan]")
# Instruktionen erneut senden (mit Referenz zum alten Chat)