feat: add LLM model selector panel to Blog Engine tab
Shows active model (fo-blog-v3-qwen7b / claude-sonnet-4-6 / qwen2.5:14b), live status from /api/blog/llm/status, ratings, config instructions, and highlights which model is currently active.
This commit is contained in:
parent
3d00a4a00a
commit
c898f52bbe
@ -1206,6 +1206,99 @@
|
|||||||
|
|
||||||
<!-- BLOG -->
|
<!-- BLOG -->
|
||||||
<div id="tab-blog" class="hidden">
|
<div id="tab-blog" class="hidden">
|
||||||
|
|
||||||
|
<!-- LLM ENGINE PANEL -->
|
||||||
|
<div class="card" style="margin-bottom:1.25rem;border:1px solid rgba(124,92,252,0.3);background:var(--surface2)">
|
||||||
|
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:0.85rem">
|
||||||
|
<div>
|
||||||
|
<span style="font-size:0.85rem;font-weight:700;color:#a78bfa">🤖 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>
|
||||||
|
</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>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Active model info 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">
|
||||||
|
<span style="font-size:0.8rem;color:var(--text-dim)">Active model:</span>
|
||||||
|
<span id="blog-llm-active-model" style="font-family:monospace;font-size:0.8rem;color:#a78bfa;font-weight:600">—</span>
|
||||||
|
<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-queue" style="margin-left:auto;font-size:0.72rem;color:var(--text-dim)"></span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Model cards -->
|
||||||
|
<div style="display:grid;grid-template-columns:repeat(3,1fr);gap:0.75rem">
|
||||||
|
|
||||||
|
<!-- 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 style="display:flex;align-items:center;gap:0.5rem;margin-bottom:0.4rem">
|
||||||
|
<span style="font-size:0.85rem">🧠</span>
|
||||||
|
<span style="font-size:0.78rem;font-weight:700;color:#a78bfa">claude-sonnet-4-6</span>
|
||||||
|
<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>
|
||||||
|
<div style="font-size:0.7rem;color:var(--text-dim);line-height:1.5">
|
||||||
|
<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 style="margin-top:0.6rem;padding-top:0.5rem;border-top:1px solid var(--border)">
|
||||||
|
<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>
|
||||||
|
<div id="blog-model-claude-status" style="margin-top:0.5rem;font-size:0.68rem;color:var(--text-dim)">checking…</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Fine-tuned local (current default) -->
|
||||||
|
<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 style="display:flex;align-items:center;gap:0.5rem;margin-bottom:0.4rem">
|
||||||
|
<span style="font-size:0.85rem">🎯</span>
|
||||||
|
<span style="font-size:0.78rem;font-weight:700;color:#86efac">fo-blog-v3-qwen7b</span>
|
||||||
|
<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>
|
||||||
|
<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">✓ 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 style="margin-top:0.6rem;padding-top:0.5rem;border-top:1px solid var(--border)">
|
||||||
|
<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>
|
||||||
|
<div id="blog-model-fo-status" style="margin-top:0.5rem;font-size:0.68rem;color:var(--text-dim)">checking…</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- 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 style="display:flex;align-items:center;gap:0.5rem;margin-bottom:0.4rem">
|
||||||
|
<span style="font-size:0.85rem">⚡</span>
|
||||||
|
<span style="font-size:0.78rem;font-weight:700;color:var(--text)">qwen2.5:14b</span>
|
||||||
|
</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 style="margin-top:0.6rem;padding-top:0.5rem;border-top:1px solid var(--border)">
|
||||||
|
<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>
|
||||||
|
<div id="blog-model-qwen-status" style="margin-top:0.5rem;font-size:0.68rem;color:var(--text-dim)">local model</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div><!-- end model grid -->
|
||||||
|
|
||||||
|
<!-- 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)">
|
||||||
|
<strong style="color:var(--text)">Modell wechseln:</strong>
|
||||||
|
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>
|
||||||
|
</div>
|
||||||
|
</div><!-- end LLM panel -->
|
||||||
|
|
||||||
<div style="margin-bottom:0.8rem;display:flex;justify-content:space-between;align-items:center">
|
<div style="margin-bottom:0.8rem;display:flex;justify-content:space-between;align-items:center">
|
||||||
<h3 style="font-size:1rem;font-weight:600">Hot Topics <span id="hot-topics-subtitle" style="font-size:0.7rem;color:var(--text-dim);font-weight:400">auto-discovered from market data + conferences</span></h3>
|
<h3 style="font-size:1rem;font-weight:600">Hot Topics <span id="hot-topics-subtitle" style="font-size:0.7rem;color:var(--text-dim);font-weight:400">auto-discovered from market data + conferences</span></h3>
|
||||||
<button onclick="loadHotTopics()" style="background:var(--accent);color:white;border:none;padding:5px 12px;border-radius:6px;cursor:pointer;font-size:0.75rem">Refresh</button>
|
<button onclick="loadHotTopics()" style="background:var(--accent);color:white;border:none;padding:5px 12px;border-radius:6px;cursor:pointer;font-size:0.75rem">Refresh</button>
|
||||||
@ -1874,7 +1967,7 @@ function goToTab(tabName) {
|
|||||||
if (tabName === 'news') loadNews(1);
|
if (tabName === 'news') loadNews(1);
|
||||||
if (tabName === 'vendors') loadVendors();
|
if (tabName === 'vendors') loadVendors();
|
||||||
if (tabName === 'standards') loadStandardsList();
|
if (tabName === 'standards') loadStandardsList();
|
||||||
if (tabName === 'blog') { loadBlogDrafts(); loadSLLInsights(); }
|
if (tabName === 'blog') { loadBlogDrafts(); loadSLLInsights(); loadBlogLLMStatus(); }
|
||||||
if (tabName === 'finder') document.getElementById('finder-switch-input').focus();
|
if (tabName === 'finder') document.getElementById('finder-switch-input').focus();
|
||||||
if (tabName === 'crawlers') loadCrawlerStatus();
|
if (tabName === 'crawlers') loadCrawlerStatus();
|
||||||
if (tabName === 'procurement') loadProcurement();
|
if (tabName === 'procurement') loadProcurement();
|
||||||
@ -4301,6 +4394,69 @@ async function runFinder() {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
async function loadBlogLLMStatus() {
|
||||||
|
try {
|
||||||
|
var data = await api('/api/blog/llm/status');
|
||||||
|
var llm = data.llm || {};
|
||||||
|
var badge = document.getElementById('blog-llm-status-badge');
|
||||||
|
var activeModel = document.getElementById('blog-llm-active-model');
|
||||||
|
var activeProvider = document.getElementById('blog-llm-active-provider');
|
||||||
|
var queueEl = document.getElementById('blog-llm-queue');
|
||||||
|
|
||||||
|
if (badge) {
|
||||||
|
badge.textContent = llm.ok ? 'online' : 'offline';
|
||||||
|
badge.style.background = llm.ok ? 'rgba(34,197,94,0.2)' : 'rgba(193,18,31,0.2)';
|
||||||
|
badge.style.color = llm.ok ? '#86efac' : '#f87171';
|
||||||
|
}
|
||||||
|
if (activeModel) activeModel.textContent = llm.model || '—';
|
||||||
|
if (activeProvider) {
|
||||||
|
activeProvider.textContent = llm.provider || '—';
|
||||||
|
activeProvider.style.background = llm.provider === 'anthropic' ? 'rgba(124,92,252,0.2)' : 'rgba(34,197,94,0.15)';
|
||||||
|
activeProvider.style.color = llm.provider === 'anthropic' ? '#a78bfa' : '#86efac';
|
||||||
|
}
|
||||||
|
if (queueEl) {
|
||||||
|
var q = data.queue_depth || 0;
|
||||||
|
queueEl.textContent = q > 0 ? 'Queue: ' + q + ' jobs' : 'Queue: idle';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mark active model card
|
||||||
|
var foActive = document.getElementById('blog-model-fo-active');
|
||||||
|
var foCard = document.getElementById('blog-model-card-fo');
|
||||||
|
var claudeCard = document.getElementById('blog-model-card-claude');
|
||||||
|
|
||||||
|
if (llm.provider === 'anthropic') {
|
||||||
|
if (claudeCard) claudeCard.style.border = '1px solid rgba(124,92,252,0.6)';
|
||||||
|
claudeCard.style.background = 'rgba(124,92,252,0.1)';
|
||||||
|
var claudeStatusEl = document.getElementById('blog-model-claude-status');
|
||||||
|
if (claudeStatusEl) {
|
||||||
|
claudeStatusEl.textContent = '● ACTIVE — API key configured';
|
||||||
|
claudeStatusEl.style.color = '#a78bfa';
|
||||||
|
}
|
||||||
|
document.getElementById('blog-model-fo-status').textContent = 'available (not active)';
|
||||||
|
} else {
|
||||||
|
// Ollama active
|
||||||
|
if (foActive) foActive.style.display = 'inline';
|
||||||
|
if (foCard) {
|
||||||
|
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');
|
||||||
|
if (foStatusEl) {
|
||||||
|
foStatusEl.textContent = llm.ok ? '● ACTIVE — Ollama reachable' : '⚠ Ollama unreachable: ' + (llm.error || 'check connection');
|
||||||
|
foStatusEl.style.color = llm.ok ? '#86efac' : '#fbbf24';
|
||||||
|
}
|
||||||
|
var claudeStatusEl2 = document.getElementById('blog-model-claude-status');
|
||||||
|
if (claudeStatusEl2) {
|
||||||
|
claudeStatusEl2.textContent = 'available — set BLOG_LLM_PROVIDER=anthropic + ANTHROPIC_API_KEY';
|
||||||
|
claudeStatusEl2.style.color = 'var(--text-dim)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch(e) {
|
||||||
|
var b = document.getElementById('blog-llm-status-badge');
|
||||||
|
if (b) { b.textContent = 'error'; b.style.color = '#f87171'; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
async function loadBlogDrafts() {
|
async function loadBlogDrafts() {
|
||||||
var data = await api('/api/blog');
|
var data = await api('/api/blog');
|
||||||
// Check which drafts are still generating (in-progress pipelines)
|
// Check which drafts are still generating (in-progress pipelines)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user