From 3d3c8ce973b250963df69eb0064facf6ae231148 Mon Sep 17 00:00:00 2001 From: duffyduck Date: Sun, 29 Mar 2026 17:27:43 +0200 Subject: [PATCH] fixed tts format, added trigger words settings --- bridge/aria_bridge.py | 25 ++++++++++++++++++++----- diagnostic/index.html | 42 ++++++++++++++++++++++++++++++++++++++++++ diagnostic/server.js | 42 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+), 5 deletions(-) diff --git a/bridge/aria_bridge.py b/bridge/aria_bridge.py index 7163876..1c19a14 100644 --- a/bridge/aria_bridge.py +++ b/bridge/aria_bridge.py @@ -72,7 +72,7 @@ BLOCK_SIZE = 1280 # 80ms bei 16kHz — gut fuer Wake-Word-Erkennung RECORD_SECONDS = 8 # Max. Aufnahmedauer nach Wake-Word # Epische Trigger — bei diesen Woertern spricht Thorsten -EPIC_TRIGGERS = [ +EPIC_TRIGGERS_DEFAULT = [ "deploy", "erfolgreich", "alarm", @@ -84,6 +84,24 @@ EPIC_TRIGGERS = [ "aufgabe abgeschlossen", ] +# Trigger aus Shared-Config laden (von Diagnostic gespeichert) +TRIGGERS_FILE = "/shared/config/highlight_triggers.json" + +def load_epic_triggers(): + """Laedt Highlight-Trigger aus Shared-Config oder nutzt Defaults.""" + try: + if os.path.exists(TRIGGERS_FILE): + with open(TRIGGERS_FILE) as f: + triggers = json.load(f) + if isinstance(triggers, list) and len(triggers) > 0: + logger.info("Highlight-Trigger geladen: %d aus %s", len(triggers), TRIGGERS_FILE) + return triggers + except Exception as e: + logger.warning("Highlight-Trigger laden fehlgeschlagen: %s — nutze Defaults", e) + return EPIC_TRIGGERS_DEFAULT + +EPIC_TRIGGERS = load_epic_triggers() + def load_config() -> dict[str, str]: """Laedt Konfiguration aus /config/aria.env.""" @@ -184,10 +202,7 @@ class VoiceEngine: tmp_path = tmp.name with wave.open(tmp_path, "wb") as wav_file: - wav_file.setnchannels(1) - wav_file.setsampwidth(2) # 16-bit - wav_file.setframerate(voice.config.sample_rate) - voice.synthesize(text, wav_file) + voice.synthesize_wav(text, wav_file) audio_data = Path(tmp_path).read_bytes() Path(tmp_path).unlink(missing_ok=True) diff --git a/diagnostic/index.html b/diagnostic/index.html index 2f430b3..832b5c4 100644 --- a/diagnostic/index.html +++ b/diagnostic/index.html @@ -396,6 +396,24 @@ + +
+

Highlight-Trigger

+
+ Woerter die automatisch die Highlight-Stimme (Thorsten) ausloesen. + Eines pro Zeile. Aenderungen werden in der Bridge gespeichert. +
+
+ +
+ + +
+
+
+
+

Tool-Berechtigungen

@@ -599,6 +617,14 @@ return; } + if (msg.type === 'trigger_list') { + const textarea = document.getElementById('highlight-triggers'); + textarea.value = (msg.triggers || []).join('\n'); + document.getElementById('trigger-status').textContent = msg.triggers.length + ' Trigger geladen'; + document.getElementById('trigger-status').style.color = '#8888AA'; + return; + } + if (msg.type === 'watchdog') { const colors = { warning: '#FFD60A', fixing: '#FF9500', fixed: '#34C759', error: '#FF3B30' }; const color = colors[msg.status] || '#FFD60A'; @@ -1080,6 +1106,20 @@ }, 120000); } + // ── Highlight-Trigger ──────────────────────── + function loadHighlightTriggers() { + send({ action: 'get_triggers' }); + } + function saveHighlightTriggers() { + const text = document.getElementById('highlight-triggers').value; + const triggers = text.split('\n').map(t => t.trim()).filter(t => t.length > 0); + send({ action: 'save_triggers', triggers }); + document.getElementById('trigger-status').textContent = 'Gespeichert (' + triggers.length + ' Trigger)'; + document.getElementById('trigger-status').style.color = '#34C759'; + } + // Beim Tab-Wechsel zu Einstellungen: Trigger laden + const origSwitchMainTab = typeof switchMainTab === 'function' ? switchMainTab : null; + // ── Modus-Wechsel ──────────────────────────── let currentMode = 'normal'; const MODE_LABELS = { normal: 'Normal', dnd: 'Nicht stoeren', whisper: 'Fluestern', hangar: 'Hangar', gaming: 'Gaming' }; @@ -1514,6 +1554,8 @@ document.querySelectorAll('.main-nav-btn').forEach(b => { if (b.textContent.trim().toLowerCase().includes(tab === 'main' ? 'main' : 'einstellung')) b.classList.add('active'); }); + // Einstellungen: Trigger laden + if (tab === 'settings') loadHighlightTriggers(); } // ── Einstellungen: Tool-Berechtigungen ────────────────── diff --git a/diagnostic/server.js b/diagnostic/server.js index f3aab37..1441d2d 100644 --- a/diagnostic/server.js +++ b/diagnostic/server.js @@ -1147,6 +1147,10 @@ wss.on("connection", (ws) => { if (ws._sshSock) ws._sshSock.write(msg.data); } else if (msg.action === "live_ssh_close") { if (ws._sshSock) { ws._sshSock.end(); ws._sshSock = null; } + } else if (msg.action === "get_triggers") { + handleGetTriggers(ws); + } else if (msg.action === "save_triggers") { + handleSaveTriggers(ws, msg.triggers || []); } else if (msg.action === "test_tts") { handleTestTTS(ws, msg.voice || "ramona", msg.text || "Test"); } else if (msg.action === "check_tts") { @@ -1277,6 +1281,44 @@ function startLiveSSH(clientWs) { createReq.end(createBody); } +// ── Highlight-Trigger ───────────────────────────────── + +const TRIGGERS_FILE = "/shared/config/highlight_triggers.json"; + +async function handleGetTriggers(clientWs) { + try { + // Zuerst aus Shared Volume lesen, dann Fallback auf Bridge-Defaults + let triggers; + if (fs.existsSync(TRIGGERS_FILE)) { + triggers = JSON.parse(fs.readFileSync(TRIGGERS_FILE, "utf-8")); + } else { + // Defaults aus der Bridge lesen + const result = await dockerExec("aria-bridge", `python3 -c " +import sys; sys.path.insert(0,'/app') +from aria_bridge import EPIC_TRIGGERS +print('\\n'.join(EPIC_TRIGGERS)) +"`); + triggers = result.trim().split("\n").filter(t => t); + } + clientWs.send(JSON.stringify({ type: "trigger_list", triggers })); + } catch (err) { + clientWs.send(JSON.stringify({ type: "trigger_list", triggers: [], error: err.message })); + } +} + +async function handleSaveTriggers(clientWs, triggers) { + try { + // In Shared Volume speichern (fuer Bridge lesbar) + fs.mkdirSync("/shared/config", { recursive: true }); + fs.writeFileSync(TRIGGERS_FILE, JSON.stringify(triggers, null, 2)); + log("info", "server", `${triggers.length} Highlight-Trigger gespeichert`); + // Bridge informieren (wird beim naechsten Start geladen) + clientWs.send(JSON.stringify({ type: "trigger_list", triggers })); + } catch (err) { + log("error", "server", `Trigger speichern fehlgeschlagen: ${err.message}`); + } +} + // ── TTS Diagnose ────────────────────────────────────── async function handleTestTTS(clientWs, voice, text) { try {