10 sekunden warten nach neuer chat, instruktionen verbessert.
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user