diff --git a/app/web/app.js b/app/web/app.js index a1ca26a..8d6d5dd 100644 --- a/app/web/app.js +++ b/app/web/app.js @@ -1,6 +1,5 @@ "use strict"; -const SESSION_ID = "web-main"; const $ = (sel) => document.querySelector(sel); const messagesEl = $("#messages"); @@ -10,28 +9,46 @@ const formEl = $("#prompt-form"); const micBtn = $("#mic"); let busy = false; +// Session-ID pro Nutzer (sonst "gehoert einem anderen Nutzer"-Konflikt). Wird aus +// /api/me abgeleitet; bis dahin null -> ensureSession() wartet auf loadMe(). +let sessionId = null; +let mePromise = null; // ---------- Identitaet / Menue ---------- -async function loadMe() { - try { - const res = await fetch("/api/me", { headers: { Accept: "application/json" } }); - if (!res.ok) { - $("#identity").textContent = "Nicht angemeldet"; - return; +function loadMe() { + mePromise = (async () => { + try { + const res = await fetch("/api/me", { headers: { Accept: "application/json" } }); + if (!res.ok) { + $("#identity").textContent = "Nicht angemeldet"; + return null; + } + const me = await res.json(); + sessionId = "web-" + me.user_id; + $("#identity").textContent = "Angemeldet als " + (me.display_name || me.external_id || "Gast"); + if (me.sso_logout_url) { + const logout = $("#logout"); + logout.href = me.sso_logout_url; + logout.classList.remove("hidden"); + } + if (me.is_admin) { + $("#admin").classList.remove("hidden"); + } + return me; + } catch (e) { + $("#identity").textContent = "Verbindung fehlgeschlagen"; + return null; } - const me = await res.json(); - $("#identity").textContent = "Angemeldet als " + (me.display_name || me.external_id || "Gast"); - if (me.sso_logout_url) { - const logout = $("#logout"); - logout.href = me.sso_logout_url; - logout.classList.remove("hidden"); - } - if (me.is_admin) { - $("#admin").classList.remove("hidden"); - } - } catch (e) { - $("#identity").textContent = "Verbindung fehlgeschlagen"; + })(); + return mePromise; +} + +// Stellt sicher, dass eine nutzerspezifische Session-ID feststeht, bevor ein Turn startet. +async function ensureSession() { + if (!sessionId && mePromise) { + try { await mePromise; } catch (e) { /* ignore */ } } + if (!sessionId) sessionId = "web-anon"; } async function loadUsers() { @@ -91,7 +108,7 @@ function playPcm(chunks, sampleRate) { // ---------- WS-Turn (Text und Sprache teilen die Event-Logik) ---------- function wsUrl(path) { const proto = location.protocol === "https:" ? "wss" : "ws"; - return `${proto}://${location.host}${path}?session_id=${encodeURIComponent(SESSION_ID)}`; + return `${proto}://${location.host}${path}?session_id=${encodeURIComponent(sessionId)}`; } // onopen: (ws) => sendet die Eingabe. Liefert ein Promise, das beim done-Event endet. @@ -148,6 +165,7 @@ function runTurn(path, onopen) { async function sendText(text) { if (busy || !text.trim()) return; busy = true; + await ensureSession(); addMessage("user", text); statusEl.textContent = "denkt …"; await runTurn("/ws/chat", (ws) => { @@ -198,6 +216,7 @@ function stopRecording() { async function sendVoice(bytes) { if (busy) return; busy = true; + await ensureSession(); statusEl.textContent = "verarbeite Sprache …"; await runTurn("/ws/voice", (ws) => { ws.send(JSON.stringify({ type: "start", format: "webm", stream: true, audio_stream: true })); diff --git a/app/web/index.html b/app/web/index.html index deafe81..bc210fa 100644 --- a/app/web/index.html +++ b/app/web/index.html @@ -4,7 +4,7 @@