added brain and session viewer
This commit is contained in:
@@ -160,6 +160,43 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Session + Brain Viewer -->
|
||||
<div class="grid" style="grid-template-columns: 1fr 1fr;">
|
||||
<div class="card">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;">
|
||||
<h2>Sessions</h2>
|
||||
<button class="btn secondary" onclick="loadSessions()" style="padding:4px 10px;font-size:11px;">Laden</button>
|
||||
</div>
|
||||
<div id="sessions-list" style="max-height:300px;overflow-y:auto;font-size:12px;"></div>
|
||||
<div id="session-detail" style="display:none;margin-top:8px;background:#080810;border:1px solid #1E1E2E;border-radius:4px;padding:8px;max-height:300px;overflow-y:auto;">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;">
|
||||
<span style="font-size:11px;color:#0096FF;font-weight:bold;" id="session-detail-title"></span>
|
||||
<button class="btn secondary" onclick="closeSessionDetail()" style="padding:2px 8px;font-size:10px;">Schliessen</button>
|
||||
</div>
|
||||
<div id="session-detail-content" style="font-size:11px;line-height:1.5;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;">
|
||||
<h2>Brain / Memory</h2>
|
||||
<button class="btn secondary" onclick="loadBrain()" style="padding:4px 10px;font-size:11px;">Laden</button>
|
||||
</div>
|
||||
<div id="brain-list" style="max-height:200px;overflow-y:auto;font-size:12px;"></div>
|
||||
<div id="brain-content" style="display:none;margin-top:8px;background:#080810;border:1px solid #1E1E2E;border-radius:4px;padding:8px;max-height:300px;overflow-y:auto;">
|
||||
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;">
|
||||
<span style="font-size:11px;color:#0096FF;font-weight:bold;" id="brain-content-title"></span>
|
||||
<button class="btn secondary" onclick="closeBrainContent()" style="padding:2px 8px;font-size:10px;">Schliessen</button>
|
||||
</div>
|
||||
<pre id="brain-content-text" style="font-size:11px;line-height:1.5;white-space:pre-wrap;color:#E0E0F0;margin:0;"></pre>
|
||||
</div>
|
||||
<div id="brain-empty" style="display:none;text-align:center;padding:20px;color:#555570;">
|
||||
<div style="font-size:24px;margin-bottom:8px;">🧠</div>
|
||||
<div style="font-size:12px;">Gehirn ist leer</div>
|
||||
<div style="font-size:10px;margin-top:4px;">ARIA speichert Erinnerungen wenn sie etwas Wichtiges lernt</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Logs mit Tabs -->
|
||||
<div class="card" style="margin-top:12px; padding: 8px 0 0 0;">
|
||||
<div style="padding: 0 12px;">
|
||||
@@ -420,6 +457,16 @@
|
||||
showDockerLogs(msg);
|
||||
return;
|
||||
}
|
||||
// Session + Brain Viewer
|
||||
if (msg.type === 'sessions_list') { renderSessions(msg); return; }
|
||||
if (msg.type === 'session_detail') { renderSessionDetail(msg); return; }
|
||||
if (msg.type === 'session_deleted') {
|
||||
if (msg.ok) loadSessions(); // Liste neu laden
|
||||
else alert('Loeschen fehlgeschlagen: ' + (msg.error || '?'));
|
||||
return;
|
||||
}
|
||||
if (msg.type === 'brain_list') { renderBrainList(msg); return; }
|
||||
if (msg.type === 'brain_content') { renderBrainContent(msg); return; }
|
||||
if (msg.type === 'response') { return; }
|
||||
};
|
||||
}
|
||||
@@ -794,6 +841,171 @@
|
||||
}
|
||||
}
|
||||
|
||||
// ── Session Viewer ────────────────────────────────────────
|
||||
|
||||
function loadSessions() {
|
||||
document.getElementById('sessions-list').innerHTML = '<div style="color:#8888AA;padding:8px;">Lade...</div>';
|
||||
send({ action: 'list_sessions' });
|
||||
}
|
||||
|
||||
function renderSessions(data) {
|
||||
const container = document.getElementById('sessions-list');
|
||||
if (data.error) {
|
||||
container.innerHTML = `<div style="color:#FF6B6B;padding:8px;">Fehler: ${escapeHtml(data.error)}</div>`;
|
||||
return;
|
||||
}
|
||||
if (!data.sessions || data.sessions.length === 0) {
|
||||
container.innerHTML = data.raw
|
||||
? `<pre style="color:#555570;font-size:10px;white-space:pre-wrap;padding:8px;">${escapeHtml(data.raw)}</pre>`
|
||||
: '<div style="color:#555570;padding:8px;text-align:center;">Keine Sessions gefunden</div>';
|
||||
return;
|
||||
}
|
||||
let html = '<table style="width:100%;border-collapse:collapse;">';
|
||||
html += '<tr style="color:#8888AA;font-size:10px;text-align:left;border-bottom:1px solid #1E1E2E;">'
|
||||
+ '<th style="padding:4px 6px;">Session</th>'
|
||||
+ '<th style="padding:4px 6px;">Zeilen</th>'
|
||||
+ '<th style="padding:4px 6px;">Groesse</th>'
|
||||
+ '<th style="padding:4px 6px;">Zuletzt</th>'
|
||||
+ '<th style="padding:4px 6px;"></th></tr>';
|
||||
for (const s of data.sessions) {
|
||||
const date = s.modified ? new Date(s.modified * 1000).toLocaleString('de-DE') : '?';
|
||||
const key = escapeHtml(s.sessionKey || s.path.split('/').pop());
|
||||
html += `<tr style="border-bottom:1px solid #0D0D1A;cursor:pointer;" onmouseover="this.style.background='#1E1E2E'" onmouseout="this.style.background=''">`
|
||||
+ `<td style="padding:4px 6px;color:#E0E0F0;" onclick="viewSession('${escapeHtml(s.path)}')">${key}</td>`
|
||||
+ `<td style="padding:4px 6px;color:#8888AA;">${s.lines}</td>`
|
||||
+ `<td style="padding:4px 6px;color:#8888AA;">${escapeHtml(s.size)}</td>`
|
||||
+ `<td style="padding:4px 6px;color:#8888AA;font-size:10px;">${date}</td>`
|
||||
+ `<td style="padding:4px 6px;"><button class="btn secondary" onclick="event.stopPropagation();deleteSession('${escapeHtml(s.path)}')" style="padding:2px 6px;font-size:10px;color:#FF6B6B;">X</button></td>`
|
||||
+ '</tr>';
|
||||
}
|
||||
html += '</table>';
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
function viewSession(path) {
|
||||
const detail = document.getElementById('session-detail');
|
||||
const title = document.getElementById('session-detail-title');
|
||||
const content = document.getElementById('session-detail-content');
|
||||
detail.style.display = 'block';
|
||||
title.textContent = path.split('/').pop();
|
||||
content.innerHTML = '<div style="color:#8888AA;">Lade...</div>';
|
||||
send({ action: 'read_session', sessionPath: path });
|
||||
}
|
||||
|
||||
function renderSessionDetail(data) {
|
||||
const content = document.getElementById('session-detail-content');
|
||||
if (data.error) {
|
||||
content.innerHTML = `<div style="color:#FF6B6B;">${escapeHtml(data.error)}</div>`;
|
||||
return;
|
||||
}
|
||||
if (data.raw) {
|
||||
content.innerHTML = `<pre style="color:#555570;font-size:10px;white-space:pre-wrap;">${escapeHtml(data.raw)}</pre>`;
|
||||
return;
|
||||
}
|
||||
if (!data.messages || data.messages.length === 0) {
|
||||
content.innerHTML = '<div style="color:#555570;">Keine Nachrichten</div>';
|
||||
return;
|
||||
}
|
||||
let html = '';
|
||||
for (const msg of data.messages) {
|
||||
const role = msg.role || msg.type || '?';
|
||||
const text = extractMessageText(msg);
|
||||
const roleColor = role === 'user' ? '#0096FF' : role === 'assistant' ? '#34C759' : '#8888AA';
|
||||
html += `<div style="margin-bottom:4px;padding:4px 6px;border-left:2px solid ${roleColor};background:#0D0D1A;border-radius:0 4px 4px 0;">`
|
||||
+ `<span style="color:${roleColor};font-size:10px;font-weight:bold;">${escapeHtml(role)}</span> `
|
||||
+ `<span style="color:#E0E0F0;">${escapeHtml(text.slice(0, 500))}${text.length > 500 ? '...' : ''}</span>`
|
||||
+ '</div>';
|
||||
}
|
||||
content.innerHTML = html;
|
||||
}
|
||||
|
||||
function extractMessageText(msg) {
|
||||
if (typeof msg.content === 'string') return msg.content;
|
||||
if (Array.isArray(msg.content)) {
|
||||
return msg.content.filter(c => c.type === 'text').map(c => c.text || '').join('');
|
||||
}
|
||||
if (msg.text) return msg.text;
|
||||
if (msg.message) return typeof msg.message === 'string' ? msg.message : JSON.stringify(msg.message);
|
||||
return JSON.stringify(msg).slice(0, 200);
|
||||
}
|
||||
|
||||
function closeSessionDetail() {
|
||||
document.getElementById('session-detail').style.display = 'none';
|
||||
}
|
||||
|
||||
function deleteSession(path) {
|
||||
const name = path.split('/').pop();
|
||||
if (!confirm(`Session "${name}" wirklich loeschen?`)) return;
|
||||
send({ action: 'delete_session', sessionPath: path });
|
||||
}
|
||||
|
||||
// ── Brain Viewer ────────────────────────────────────────
|
||||
|
||||
function loadBrain() {
|
||||
document.getElementById('brain-list').innerHTML = '<div style="color:#8888AA;padding:8px;">Lade...</div>';
|
||||
document.getElementById('brain-empty').style.display = 'none';
|
||||
send({ action: 'list_brain' });
|
||||
}
|
||||
|
||||
function renderBrainList(data) {
|
||||
const container = document.getElementById('brain-list');
|
||||
const emptyEl = document.getElementById('brain-empty');
|
||||
|
||||
if (data.error) {
|
||||
container.innerHTML = `<div style="color:#FF6B6B;padding:8px;">Fehler: ${escapeHtml(data.error)}</div>`;
|
||||
emptyEl.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
if (!data.files || data.files.length === 0) {
|
||||
container.innerHTML = '';
|
||||
emptyEl.style.display = 'block';
|
||||
return;
|
||||
}
|
||||
emptyEl.style.display = 'none';
|
||||
|
||||
const TYPE_COLORS = { user: '#0096FF', feedback: '#FFD60A', project: '#34C759', reference: '#FF9500' };
|
||||
let html = '';
|
||||
for (const f of data.files) {
|
||||
if (f.name === '.gitkeep') continue;
|
||||
const color = TYPE_COLORS[f.memType] || '#8888AA';
|
||||
const date = f.modified ? new Date(f.modified * 1000).toLocaleString('de-DE') : '?';
|
||||
html += `<div style="padding:6px 8px;border-bottom:1px solid #0D0D1A;cursor:pointer;display:flex;align-items:center;gap:8px;" onmouseover="this.style.background='#1E1E2E'" onmouseout="this.style.background=''" onclick="viewBrainFile('${escapeHtml(f.name)}')">`
|
||||
+ `<span style="background:${color};width:8px;height:8px;border-radius:50%;flex-shrink:0;" title="${escapeHtml(f.memType || 'unbekannt')}"></span>`
|
||||
+ `<div style="flex:1;min-width:0;">`
|
||||
+ `<div style="color:#E0E0F0;font-size:12px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">${escapeHtml(f.name)}</div>`
|
||||
+ (f.description ? `<div style="color:#8888AA;font-size:10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;">${escapeHtml(f.description)}</div>` : '')
|
||||
+ `</div>`
|
||||
+ `<div style="color:#555570;font-size:10px;white-space:nowrap;">${escapeHtml(f.size)}</div>`
|
||||
+ '</div>';
|
||||
}
|
||||
container.innerHTML = html || '<div style="color:#555570;padding:8px;text-align:center;">Nur .gitkeep gefunden</div>';
|
||||
}
|
||||
|
||||
function viewBrainFile(name) {
|
||||
const panel = document.getElementById('brain-content');
|
||||
const title = document.getElementById('brain-content-title');
|
||||
const text = document.getElementById('brain-content-text');
|
||||
panel.style.display = 'block';
|
||||
title.textContent = name;
|
||||
text.textContent = 'Lade...';
|
||||
send({ action: 'read_brain_file', filename: name });
|
||||
}
|
||||
|
||||
function renderBrainContent(data) {
|
||||
const text = document.getElementById('brain-content-text');
|
||||
if (data.error) {
|
||||
text.textContent = `Fehler: ${data.error}`;
|
||||
text.style.color = '#FF6B6B';
|
||||
return;
|
||||
}
|
||||
text.style.color = '#E0E0F0';
|
||||
text.textContent = data.content || '(leer)';
|
||||
}
|
||||
|
||||
function closeBrainContent() {
|
||||
document.getElementById('brain-content').style.display = 'none';
|
||||
}
|
||||
|
||||
connectWS();
|
||||
</script>
|
||||
</body>
|
||||
|
||||
Reference in New Issue
Block a user