fixed chat textjson format, selected session for all, fixed android echo

This commit is contained in:
duffyduck 2026-03-29 03:18:02 +02:00
parent f2aebcbad9
commit 1972c4d1b4
3 changed files with 50 additions and 12 deletions

View File

@ -96,14 +96,23 @@ const ChatScreen: React.FC = () => {
const sender = (message.payload.sender as string) || '';
if (sender === 'user' || sender === 'diagnostic') return;
const ariaMsg: ChatMessage = {
id: nextId(),
sender: 'aria',
text: (message.payload.text as string) || '',
timestamp: message.timestamp,
attachments: message.payload.attachments as Attachment[] | undefined,
};
setMessages(prev => [...prev, ariaMsg]);
const text = (message.payload.text as string) || '';
const ts = message.timestamp;
// Duplikat-Schutz: gleicher Text innerhalb 5s ignorieren
setMessages(prev => {
const isDuplicate = prev.some(m =>
m.sender === 'aria' && m.text === text && Math.abs(m.timestamp - ts) < 5000
);
if (isDuplicate) return prev;
const ariaMsg: ChatMessage = {
id: nextId(),
sender: 'aria',
text,
timestamp: ts,
attachments: message.payload.attachments as Attachment[] | undefined,
};
return [...prev, ariaMsg];
});
}
// TTS-Audio abspielen wenn vorhanden

View File

@ -30,6 +30,7 @@ import wave
from pathlib import Path
from typing import Optional
import urllib.request
import numpy as np
import sounddevice as sd
import websockets
@ -59,6 +60,7 @@ RVS_PORT = os.getenv("RVS_PORT", "443") # Port des RVS
RVS_TLS = os.getenv("RVS_TLS", "true") # true = wss://, false = ws://
RVS_TLS_FALLBACK = os.getenv("RVS_TLS_FALLBACK", "true") # Bei TLS-Fehler ws:// versuchen
RVS_TOKEN = os.getenv("RVS_TOKEN", "") # Pairing-Token (gleich wie in der App)
DIAGNOSTIC_URL = os.getenv("DIAGNOSTIC_URL", "http://127.0.0.1:3001") # Diagnostic API
WHISPER_MODEL = os.getenv("WHISPER_MODEL", "small")
WHISPER_LANGUAGE = os.getenv("WHISPER_LANGUAGE", "de")
@ -409,7 +411,8 @@ class ARIABridge:
self.ws_url = self.config.get("ARIA_CORE_WS", CORE_WS_URL)
self.core_auth_token = self.config.get("ARIA_AUTH_TOKEN", CORE_AUTH_TOKEN)
self._req_id_counter = 0
self._session_key = "aria-bridge" # Feste Session fuer die Bridge
self._session_key = "main" # Fallback, wird per Diagnostic API aktualisiert
self._diagnostic_url = self.config.get("DIAGNOSTIC_URL", DIAGNOSTIC_URL)
# RVS-Verbindungsinfo aus Config oder Env
rvs_host = self.config.get("RVS_HOST", RVS_HOST)
rvs_port = self.config.get("RVS_PORT", RVS_PORT)
@ -790,12 +793,28 @@ class ARIABridge:
else:
logger.info("[core] TTS unterdrueckt (Modus: %s)", self.current_mode.config.name)
def _fetch_active_session(self) -> None:
"""Holt die aktive Session vom Diagnostic-Endpoint."""
try:
req = urllib.request.Request(f"{self._diagnostic_url}/api/session", method="GET")
with urllib.request.urlopen(req, timeout=2) as resp:
data = json.loads(resp.read().decode())
new_key = data.get("sessionKey", "")
if new_key and new_key != self._session_key:
logger.info("[session] Aktive Session gewechselt: %s -> %s", self._session_key, new_key)
self._session_key = new_key
except Exception as e:
logger.debug("[session] Diagnostic nicht erreichbar (%s) — nutze '%s'", e, self._session_key)
async def send_to_core(self, text: str, source: str = "bridge") -> None:
"""Sendet Text an aria-core (OpenClaw chat.send Protokoll)."""
if self.ws_core is None:
logger.error("[core] Nicht verbunden — Nachricht verworfen: '%s'", text[:60])
return
# Aktive Session vom Diagnostic holen
self._fetch_active_session()
req_id = self._next_req_id()
message = json.dumps({
"type": "req",

View File

@ -35,7 +35,10 @@ const state = {
rvs: { status: "disconnected", lastError: null },
proxy: { status: "unknown", lastError: null },
};
let activeSessionKey = "aria-diag-v3";
const SESSION_KEY_FILE = "/tmp/aria-active-session";
let activeSessionKey = (() => {
try { return fs.readFileSync(SESSION_KEY_FILE, "utf-8").trim(); } catch { return "main"; }
})();
const logs = [];
let gatewayWs = null;
let rvsWs = null;
@ -924,6 +927,9 @@ const server = http.createServer((req, res) => {
} else if (req.url === "/api/state") {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ state, logs: logs.slice(-100) }));
} else if (req.url === "/api/session") {
res.writeHead(200, { "Content-Type": "application/json" });
res.end(JSON.stringify({ sessionKey: activeSessionKey }));
} else {
res.writeHead(404);
res.end("Not Found");
@ -1375,8 +1381,10 @@ async function handleLoadChatHistory(clientWs) {
if (!text) continue;
if (role === "user") {
// Metadata-Prefix entfernen: "Sender (untrusted metadata):\n```json\n{...}\n```\n\n[timestamp] "
text = text.replace(/^Sender \(untrusted metadata\):[\s\S]*?```\s*\n*(?:\[.*?\]\s*)?/m, "").trim();
// Metadata-Prefix entfernen: "Sender (untrusted metadata):\n```json\n{...}\n```\n\n[timestamp] Text"
text = text.replace(/^Sender \(untrusted metadata\):[\s\S]*?```[\s\S]*?```\s*\n*/m, "").trim();
// Timestamp-Prefix entfernen: "[Sat 2026-03-28 14:51 UTC] "
text = text.replace(/^\[.*?\]\s*/, "").trim();
chatMessages.push({ type: "sent", text, meta: "Gateway direkt", ts: msg.timestamp || obj.timestamp || 0 });
} else if (role === "assistant") {
// Reply-Prefix entfernen: "[[reply_to_current]] "
@ -1401,6 +1409,7 @@ function handleSetActiveSession(clientWs, sessionKey) {
return;
}
activeSessionKey = sessionKey;
try { fs.writeFileSync(SESSION_KEY_FILE, activeSessionKey); } catch {}
log("info", "server", `Aktive Session: ${activeSessionKey}`);
// Allen Clients mitteilen
for (const c of browserClients) {
@ -1417,6 +1426,7 @@ async function handleCreateSession(clientWs, sessionName) {
try {
// Session wird automatisch erstellt wenn man die erste Nachricht sendet
activeSessionKey = sessionName;
try { fs.writeFileSync(SESSION_KEY_FILE, activeSessionKey); } catch {}
log("info", "server", `Neue Session erstellt und aktiviert: ${sessionName}`);
// Allen Clients mitteilen
for (const c of browserClients) {