ui: redesign LLM panel for light theme readability

Replace hard-coded purple/green colors with theme CSS variables.
Dark code blocks (#1e1e1e bg), orange accent for active borders/badges,
dark green for status text, amber for warnings — all readable on white.
This commit is contained in:
Rene Fichtmueller 2026-04-09 21:20:43 +02:00
parent bf626f9de6
commit 7af5b32b3f

View File

@ -1208,94 +1208,99 @@
<div id="tab-blog" class="hidden"> <div id="tab-blog" class="hidden">
<!-- LLM ENGINE PANEL --> <!-- LLM ENGINE PANEL -->
<div class="card" style="margin-bottom:1.25rem;border:1px solid rgba(124,92,252,0.3);background:var(--surface2)"> <div class="card" style="margin-bottom:1.25rem;border-left:3px solid var(--accent)">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:0.85rem"> <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:0.85rem">
<div> <div style="display:flex;align-items:center;gap:0.6rem">
<span style="font-size:0.85rem;font-weight:700;color:#a78bfa">🤖 Blog Generation LLM</span> <span style="font-size:0.9rem;font-weight:700;color:var(--text-bright)">🤖 Blog Generation LLM</span>
<span id="blog-llm-status-badge" style="margin-left:0.5rem;font-size:0.68rem;padding:2px 7px;border-radius:10px;background:rgba(100,100,100,0.25);color:var(--text-dim)">loading…</span> <span id="blog-llm-status-badge" style="font-size:0.68rem;padding:2px 8px;border-radius:10px;background:var(--surface3);color:var(--text-dim);font-weight:600">loading…</span>
</div> </div>
<button onclick="loadBlogLLMStatus()" style="background:transparent;color:var(--text-dim);border:1px solid var(--border);padding:3px 10px;border-radius:6px;cursor:pointer;font-size:0.72rem"></button> <button onclick="loadBlogLLMStatus()" style="background:transparent;color:var(--text-dim);border:1px solid var(--border);padding:3px 10px;border-radius:6px;cursor:pointer;font-size:0.72rem"></button>
</div> </div>
<!-- Active model info bar --> <!-- Active model bar -->
<div id="blog-llm-active-bar" style="background:rgba(124,92,252,0.08);border:1px solid rgba(124,92,252,0.2);border-radius:8px;padding:0.6rem 0.85rem;margin-bottom:0.9rem;display:flex;align-items:center;gap:0.75rem"> <div style="background:var(--accent-glow);border:1px solid rgba(255,129,0,0.25);border-radius:8px;padding:0.55rem 0.85rem;margin-bottom:1rem;display:flex;align-items:center;gap:0.75rem">
<span style="font-size:0.8rem;color:var(--text-dim)">Active model:</span> <span style="font-size:0.78rem;color:var(--text-dim);font-weight:600">AKTIV:</span>
<span id="blog-llm-active-model" style="font-family:monospace;font-size:0.8rem;color:#a78bfa;font-weight:600"></span> <code id="blog-llm-active-model" style="font-size:0.82rem;color:var(--text-bright);font-weight:700"></code>
<span id="blog-llm-active-provider" style="font-size:0.7rem;padding:2px 6px;border-radius:4px;background:rgba(124,92,252,0.15);color:#a78bfa"></span> <span id="blog-llm-active-provider" style="font-size:0.68rem;padding:2px 7px;border-radius:4px;background:var(--accent);color:#fff;font-weight:700"></span>
<span id="blog-llm-queue" style="margin-left:auto;font-size:0.72rem;color:var(--text-dim)"></span> <span id="blog-llm-queue" style="margin-left:auto;font-size:0.72rem;color:var(--text-dim)"></span>
</div> </div>
<!-- Model cards --> <!-- Model cards -->
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:0.75rem"> <div style="display:grid;grid-template-columns:repeat(3,1fr);gap:0.85rem">
<!-- Claude (recommended) --> <!-- Claude (recommended) -->
<div id="blog-model-card-claude" style="border-radius:8px;padding:0.75rem;border:1px solid rgba(124,92,252,0.25);background:rgba(124,92,252,0.06);position:relative"> <div id="blog-model-card-claude" style="border-radius:8px;padding:0.85rem;border:2px solid var(--border);background:var(--surface)">
<div style="display:flex;align-items:center;gap:0.5rem;margin-bottom:0.4rem"> <div style="display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:0.6rem">
<span style="font-size:0.85rem">🧠</span> <div>
<span style="font-size:0.78rem;font-weight:700;color:#a78bfa">claude-sonnet-4-6</span> <div style="font-size:0.8rem;font-weight:700;color:var(--text-bright)">🧠 claude-sonnet-4-6</div>
<span style="margin-left:auto;font-size:0.65rem;padding:1px 5px;border-radius:3px;background:rgba(124,92,252,0.25);color:#a78bfa;font-weight:700">RECOMMENDED</span> <div style="font-size:0.68rem;color:var(--text-dim);margin-top:2px">Anthropic API</div>
</div> </div>
<div style="font-size:0.7rem;color:var(--text-dim);line-height:1.5"> <span style="font-size:0.62rem;padding:2px 6px;border-radius:3px;background:var(--accent);color:#fff;font-weight:700;white-space:nowrap">★ EMPFOHLEN</span>
<div>★★★★★ Blog quality</div>
<div>★★★★☆ Speed (API latency)</div>
<div style="margin-top:0.3rem;color:#86efac">✓ Multi-constraint prompts</div>
<div style="color:#86efac">✓ No mode collapse</div>
<div style="color:#86efac">✓ 4096 token output</div>
<div style="margin-top:0.3rem;color:var(--text-dim)">Provider: Anthropic API</div>
</div> </div>
<div style="margin-top:0.6rem;padding-top:0.5rem;border-top:1px solid var(--border)"> <div style="font-size:0.72rem;color:var(--text);line-height:1.8;margin-bottom:0.6rem">
<code style="font-size:0.65rem;color:#a78bfa;word-break:break-all">BLOG_LLM_PROVIDER=anthropic<br>ANTHROPIC_MODEL=claude-sonnet-4-6</code> <div><span style="color:var(--accent)">★★★★★</span> Blog-Qualität</div>
<div><span style="color:var(--accent)">★★★★</span><span style="color:var(--text-dim)"></span> Geschwindigkeit</div>
<div style="margin-top:0.35rem;color:#1a7a3a;font-weight:500">✓ Komplexe Multi-Constraint Prompts</div>
<div style="color:#1a7a3a;font-weight:500">✓ Kein Mode Collapse</div>
<div style="color:#1a7a3a;font-weight:500">✓ 4096 Token Output</div>
</div> </div>
<div id="blog-model-claude-status" style="margin-top:0.5rem;font-size:0.68rem;color:var(--text-dim)">checking…</div> <div style="background:#1e1e1e;border-radius:5px;padding:0.5rem 0.65rem;margin-bottom:0.5rem">
<code style="font-size:0.65rem;color:#f8f8f2;line-height:1.6;word-break:break-all;display:block">BLOG_LLM_PROVIDER=anthropic<br>ANTHROPIC_MODEL=claude-sonnet-4-6</code>
</div>
<div id="blog-model-claude-status" style="font-size:0.7rem;color:var(--text-dim)">checking…</div>
</div> </div>
<!-- Fine-tuned local (current default) --> <!-- Fine-tuned local -->
<div id="blog-model-card-fo" style="border-radius:8px;padding:0.75rem;border:1px solid rgba(34,197,94,0.25);background:rgba(34,197,94,0.04)"> <div id="blog-model-card-fo" style="border-radius:8px;padding:0.85rem;border:2px solid var(--border);background:var(--surface)">
<div style="display:flex;align-items:center;gap:0.5rem;margin-bottom:0.4rem"> <div style="display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:0.6rem">
<span style="font-size:0.85rem">🎯</span> <div>
<span style="font-size:0.78rem;font-weight:700;color:#86efac">fo-blog-v3-qwen7b</span> <div style="font-size:0.8rem;font-weight:700;color:var(--text-bright)">🎯 fo-blog-v3-qwen7b</div>
<span id="blog-model-fo-active" style="display:none;margin-left:auto;font-size:0.65rem;padding:1px 5px;border-radius:3px;background:rgba(34,197,94,0.25);color:#86efac;font-weight:700">ACTIVE</span> <div style="font-size:0.68rem;color:var(--text-dim);margin-top:2px">Ollama / Mac Studio</div>
</div> </div>
<div style="font-size:0.7rem;color:var(--text-dim);line-height:1.5"> <span id="blog-model-fo-active" style="display:none;font-size:0.62rem;padding:2px 6px;border-radius:3px;background:#1a7a3a;color:#fff;font-weight:700">● AKTIV</span>
<div>★★★★☆ Blog quality</div>
<div>★★★★★ Speed (local GPU)</div>
<div style="margin-top:0.3rem;color:#86efac">✓ Fine-tuned on TIP style</div>
<div style="color:#86efac">✓ Privacy (runs locally)</div>
<div style="color:#fbbf24">⚠ Occasional mode collapse</div>
<div style="margin-top:0.3rem;color:var(--text-dim)">Provider: Ollama / Mac Studio</div>
</div> </div>
<div style="margin-top:0.6rem;padding-top:0.5rem;border-top:1px solid var(--border)"> <div style="font-size:0.72rem;color:var(--text);line-height:1.8;margin-bottom:0.6rem">
<code style="font-size:0.65rem;color:#86efac;word-break:break-all">BLOG_LLM_PROVIDER=ollama<br>OLLAMA_LLM_MODEL=fo-blog-v3-qwen7b</code> <div><span style="color:var(--accent)">★★★★</span><span style="color:var(--text-dim)"></span> Blog-Qualität</div>
<div><span style="color:var(--accent)">★★★★★</span> Geschwindigkeit</div>
<div style="margin-top:0.35rem;color:#1a7a3a;font-weight:500">✓ Fine-tuned auf TIP-Stil</div>
<div style="color:#1a7a3a;font-weight:500">✓ Lokal / kein API-Kosten</div>
<div style="color:#b45309;font-weight:500">⚠ Gelegentlicher Mode Collapse</div>
</div> </div>
<div id="blog-model-fo-status" style="margin-top:0.5rem;font-size:0.68rem;color:var(--text-dim)">checking…</div> <div style="background:#1e1e1e;border-radius:5px;padding:0.5rem 0.65rem;margin-bottom:0.5rem">
<code style="font-size:0.65rem;color:#f8f8f2;line-height:1.6;word-break:break-all;display:block">BLOG_LLM_PROVIDER=ollama<br>OLLAMA_LLM_MODEL=fo-blog-v3-qwen7b</code>
</div>
<div id="blog-model-fo-status" style="font-size:0.7rem;color:var(--text-dim)">checking…</div>
</div> </div>
<!-- Standard Qwen --> <!-- Standard Qwen -->
<div id="blog-model-card-qwen" style="border-radius:8px;padding:0.75rem;border:1px solid rgba(100,100,100,0.2);background:rgba(100,100,100,0.04)"> <div id="blog-model-card-qwen" style="border-radius:8px;padding:0.85rem;border:2px solid var(--border);background:var(--surface)">
<div style="display:flex;align-items:center;gap:0.5rem;margin-bottom:0.4rem"> <div style="display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:0.6rem">
<span style="font-size:0.85rem"></span> <div>
<span style="font-size:0.78rem;font-weight:700;color:var(--text)">qwen2.5:14b</span> <div style="font-size:0.8rem;font-weight:700;color:var(--text-bright)">⚡ qwen2.5:14b</div>
<div style="font-size:0.68rem;color:var(--text-dim);margin-top:2px">Ollama / Mac Studio</div>
</div> </div>
<div style="font-size:0.7rem;color:var(--text-dim);line-height:1.5">
<div>★★★☆☆ Blog quality</div>
<div>★★★★☆ Speed (local GPU)</div>
<div style="margin-top:0.3rem;color:#86efac">✓ General purpose</div>
<div style="color:#86efac">✓ No API cost</div>
<div style="color:#fbbf24">⚠ Mode collapse on complex prompts</div>
<div style="margin-top:0.3rem;color:var(--text-dim)">Provider: Ollama / Mac Studio</div>
</div> </div>
<div style="margin-top:0.6rem;padding-top:0.5rem;border-top:1px solid var(--border)"> <div style="font-size:0.72rem;color:var(--text);line-height:1.8;margin-bottom:0.6rem">
<code style="font-size:0.65rem;color:var(--text-dim);word-break:break-all">BLOG_LLM_PROVIDER=ollama<br>OLLAMA_LLM_MODEL=qwen2.5:14b</code> <div><span style="color:var(--accent)">★★★</span><span style="color:var(--text-dim)">★★</span> Blog-Qualität</div>
<div><span style="color:var(--accent)">★★★★</span><span style="color:var(--text-dim)"></span> Geschwindigkeit</div>
<div style="margin-top:0.35rem;color:#1a7a3a;font-weight:500">✓ Allzweck-Modell</div>
<div style="color:#1a7a3a;font-weight:500">✓ Keine API-Kosten</div>
<div style="color:#b45309;font-weight:500">⚠ Mode Collapse bei komplexen Prompts</div>
</div> </div>
<div id="blog-model-qwen-status" style="margin-top:0.5rem;font-size:0.68rem;color:var(--text-dim)">local model</div> <div style="background:#1e1e1e;border-radius:5px;padding:0.5rem 0.65rem;margin-bottom:0.5rem">
<code style="font-size:0.65rem;color:#f8f8f2;line-height:1.6;word-break:break-all;display:block">BLOG_LLM_PROVIDER=ollama<br>OLLAMA_LLM_MODEL=qwen2.5:14b</code>
</div>
<div id="blog-model-qwen-status" style="font-size:0.7rem;color:var(--text-dim)">local model</div>
</div> </div>
</div><!-- end model grid --> </div><!-- end model grid -->
<!-- Config note --> <!-- Config note -->
<div style="margin-top:0.75rem;padding:0.6rem 0.85rem;background:rgba(0,0,0,0.15);border-radius:6px;font-size:0.7rem;color:var(--text-dim)"> <div style="margin-top:0.85rem;padding:0.6rem 0.85rem;background:var(--surface2);border-radius:6px;font-size:0.72rem;color:var(--text)">
<strong style="color:var(--text)">Modell wechseln:</strong> <strong>Modell wechseln:</strong> SSH → Erik →
SSH → Erik → <code style="color:#a78bfa">nano /opt/tip/ecosystem.config.js</code> → BLOG_LLM_PROVIDER + ANTHROPIC_API_KEY setzen → <code style="color:#a78bfa">pm2 restart tip-api --update-env</code> <code style="background:#1e1e1e;color:#f8f8f2;padding:1px 5px;border-radius:3px">nano /opt/tip/ecosystem.config.js</code>
→ BLOG_LLM_PROVIDER + ANTHROPIC_API_KEY →
<code style="background:#1e1e1e;color:#f8f8f2;padding:1px 5px;border-radius:3px">pm2 restart tip-api --update-env</code>
</div> </div>
</div><!-- end LLM panel --> </div><!-- end LLM panel -->
@ -4410,50 +4415,48 @@ async function loadBlogLLMStatus() {
} }
if (activeModel) activeModel.textContent = llm.model || '—'; if (activeModel) activeModel.textContent = llm.model || '—';
if (activeProvider) { if (activeProvider) {
activeProvider.textContent = llm.provider || '—'; activeProvider.textContent = llm.provider === 'anthropic' ? 'anthropic' : 'ollama';
activeProvider.style.background = llm.provider === 'anthropic' ? 'rgba(124,92,252,0.2)' : 'rgba(34,197,94,0.15)'; activeProvider.style.background = 'var(--accent)';
activeProvider.style.color = llm.provider === 'anthropic' ? '#a78bfa' : '#86efac'; activeProvider.style.color = '#fff';
} }
if (queueEl) { if (queueEl) {
var q = data.queue_depth || 0; var q = data.queue_depth || 0;
queueEl.textContent = q > 0 ? 'Queue: ' + q + ' jobs' : 'Queue: idle'; queueEl.textContent = q > 0 ? 'Queue: ' + q + ' Jobs' : 'Queue: idle';
} }
// Mark active model card // Mark active model card with accent border
var foActive = document.getElementById('blog-model-fo-active'); var foActive = document.getElementById('blog-model-fo-active');
var foCard = document.getElementById('blog-model-card-fo'); var foCard = document.getElementById('blog-model-card-fo');
var claudeCard = document.getElementById('blog-model-card-claude'); var claudeCard = document.getElementById('blog-model-card-claude');
if (llm.provider === 'anthropic') { if (llm.provider === 'anthropic') {
if (claudeCard) claudeCard.style.border = '1px solid rgba(124,92,252,0.6)'; if (claudeCard) claudeCard.style.border = '2px solid var(--accent)';
claudeCard.style.background = 'rgba(124,92,252,0.1)';
var claudeStatusEl = document.getElementById('blog-model-claude-status'); var claudeStatusEl = document.getElementById('blog-model-claude-status');
if (claudeStatusEl) { if (claudeStatusEl) {
claudeStatusEl.textContent = '● ACTIVE — API key configured'; claudeStatusEl.textContent = '● Aktiv — API-Key konfiguriert';
claudeStatusEl.style.color = '#a78bfa'; claudeStatusEl.style.color = '#1a7a3a';
claudeStatusEl.style.fontWeight = '600';
} }
document.getElementById('blog-model-fo-status').textContent = 'available (not active)'; var foSt = document.getElementById('blog-model-fo-status');
if (foSt) { foSt.textContent = 'bereit (nicht aktiv)'; foSt.style.color = 'var(--text-dim)'; }
} else { } else {
// Ollama active
if (foActive) foActive.style.display = 'inline'; if (foActive) foActive.style.display = 'inline';
if (foCard) { if (foCard) foCard.style.border = '2px solid var(--accent)';
foCard.style.border = '1px solid rgba(34,197,94,0.5)';
foCard.style.background = 'rgba(34,197,94,0.08)';
}
var foStatusEl = document.getElementById('blog-model-fo-status'); var foStatusEl = document.getElementById('blog-model-fo-status');
if (foStatusEl) { if (foStatusEl) {
foStatusEl.textContent = llm.ok ? '● ACTIVE — Ollama reachable' : '⚠ Ollama unreachable: ' + (llm.error || 'check connection'); foStatusEl.textContent = llm.ok ? '● Aktiv — Ollama erreichbar' : '⚠ Ollama nicht erreichbar: ' + (llm.error || '').slice(0, 60);
foStatusEl.style.color = llm.ok ? '#86efac' : '#fbbf24'; foStatusEl.style.color = llm.ok ? '#1a7a3a' : '#b45309';
foStatusEl.style.fontWeight = '600';
} }
var claudeStatusEl2 = document.getElementById('blog-model-claude-status'); var clSt = document.getElementById('blog-model-claude-status');
if (claudeStatusEl2) { if (clSt) {
claudeStatusEl2.textContent = 'available — set BLOG_LLM_PROVIDER=anthropic + ANTHROPIC_API_KEY'; clSt.textContent = 'bereit — BLOG_LLM_PROVIDER=anthropic + ANTHROPIC_API_KEY setzen';
claudeStatusEl2.style.color = 'var(--text-dim)'; clSt.style.color = 'var(--text-dim)';
} }
} }
} catch(e) { } catch(e) {
var b = document.getElementById('blog-llm-status-badge'); var b = document.getElementById('blog-llm-status-badge');
if (b) { b.textContent = 'error'; b.style.color = '#f87171'; } if (b) { b.textContent = 'Fehler'; b.style.background = '#fee2e2'; b.style.color = '#b91c1c'; }
} }
} }