From 7719155e8e1d6c98157017aee903e1e7445d2607 Mon Sep 17 00:00:00 2001 From: Rene Fichtmueller Date: Tue, 31 Mar 2026 09:44:29 +0200 Subject: [PATCH] =?UTF-8?q?feat(v0.2.4):=20blog=20generation=20UX=20overha?= =?UTF-8?q?ul=20=E2=80=94=20live=20progress=20bar?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When you click Generate: - Dark overlay with orange progress bar shows pipeline status - Live step counter: 'Step 3/10: Outline Generation — decision-driven structure' - Percentage updates every 15 seconds via API polling - When done: shows word count + QA score, auto-opens the article - No more silent template dump — user sees the entire pipeline working --- packages/api/src/index.ts | 2 +- packages/api/src/routes/health.ts | 2 +- packages/dashboard/index.html | 87 +++++++++++++++++++++++++------ 3 files changed, 72 insertions(+), 19 deletions(-) diff --git a/packages/api/src/index.ts b/packages/api/src/index.ts index 66f86dc..abbe8bb 100644 --- a/packages/api/src/index.ts +++ b/packages/api/src/index.ts @@ -67,7 +67,7 @@ app.get("/", (_req, res) => { app.get("/api", (_req, res) => { res.json({ name: "Transceiver Intelligence Platform", - version: "0.2.3", + version: "0.2.4", endpoints: [ "GET /api/transceivers?q=&form_factor=&speed=&category=&fiber_type=&wdm_type=&coherent=", "GET /api/transceivers/:id", diff --git a/packages/api/src/routes/health.ts b/packages/api/src/routes/health.ts index 797c6d2..0e56a0c 100644 --- a/packages/api/src/routes/health.ts +++ b/packages/api/src/routes/health.ts @@ -14,7 +14,7 @@ healthRouter.get("/", async (_req: Request, res: Response) => { res.json({ success: true, status: "healthy", - version: "0.2.3", + version: "0.2.4", uptime: process.uptime(), database: { connected: true, diff --git a/packages/dashboard/index.html b/packages/dashboard/index.html index d2a2a92..c420862 100644 --- a/packages/dashboard/index.html +++ b/packages/dashboard/index.html @@ -2287,7 +2287,16 @@ function copyBlogContent(id) { // BLOG function generateBlog(topic, speed) { - el('blog-list').innerHTML = '
Generating template... LLM 10-step pipeline starts in background (~10 min)
'; + // Show prominent progress overlay instead of just adding to list + el('blog-list').innerHTML = '
' + + '
🔄 Generating Blog with AI...
' + + '
Starting 10-step Flexoptix Style pipeline...
' + + '
Connecting to LLM (qwen2.5:14b on Mac Studio)
' + + '
' + + '
' + + '
0%
' + + '
'; + var body = { topic: topic }; if (speed) body.speed = speed; fetch(API + '/api/blog/generate', { @@ -2296,29 +2305,73 @@ function generateBlog(topic, speed) { body: JSON.stringify(body) }).then(function(r) { return r.json(); }).then(function(data) { if (data.success) { - var msg = data.draft.title + ' — ' + data.draft.word_count + ' words'; - if (data.draft.llm_enhancing) msg += ' (LLM enhancing in background...)'; - showToast('Draft generated', msg); - if (data.draft.llm_enhancing) { - pollBlogLlm(data.draft.id, 0); - } - } else showToast('Failed', data.error || 'Unknown error', true); - loadBlogDrafts(); - }).catch(function(err) { showToast('Network error', err.message, true); }); + var statusEl = document.getElementById('blog-pipeline-status'); + if (statusEl) statusEl.textContent = 'Template created. LLM pipeline running...'; + var stepEl = document.getElementById('blog-pipeline-step'); + if (stepEl) stepEl.textContent = 'Step 1/10: Topic Expansion — analyzing real-world scenarios...'; + var barEl = document.getElementById('blog-pipeline-bar'); + if (barEl) barEl.style.width = '5%'; + pollBlogLlm(data.draft.id, 0); + } else { + showToast('Failed', data.error || 'Unknown error', true); + loadBlogDrafts(); + } + }).catch(function(err) { showToast('Network error', err.message, true); loadBlogDrafts(); }); } +var STEP_NAMES = [ + 'Topic Expansion — analyzing real-world scenarios', + 'Angle Selection — picking the strongest angle', + 'Outline Generation — decision-driven structure', + 'Master Draft — writing 2500+ word article', + 'Reality Injection — adding production failures', + 'Technical Deepening — specific optics + numbers', + 'Opinion Layer — removing neutrality', + 'Kill AI Tone — making it sound human', + 'QA Check — fixing weak sections', + 'Quality Score — rating 1-10' +]; + function pollBlogLlm(id, attempt) { - if (attempt > 60) { showToast("Timeout", "LLM pipeline took too long. Check logs."); return; } + if (attempt > 60) { + showToast('Timeout', 'LLM pipeline took too long. Refresh to check.'); + loadBlogDrafts(); + return; + } setTimeout(function() { api('/api/blog/' + id).then(function(data) { - if (data.draft && data.draft.generated_by && data.draft.generated_by && data.draft.generated_by !== 'tip-blog-engine-template' && data.draft.generated_by !== null) { - showToast('LLM Enhanced', data.draft.title + ' — ' + data.draft.word_count + ' words'); - loadBlogDrafts(); + var d = data.draft || data; + var done = d.generated_by && d.generated_by !== 'tip-blog-engine-template' && d.generated_by !== null; + var steps = d.pipeline_steps_completed || 0; + + if (done) { + // Pipeline finished! Show the result + var pct = document.getElementById('blog-pipeline-pct'); + var bar = document.getElementById('blog-pipeline-bar'); + var status = document.getElementById('blog-pipeline-status'); + if (bar) bar.style.width = '100%'; + if (pct) pct.textContent = '100%'; + if (status) { + status.textContent = '✅ Blog generated! ' + (d.word_count || '?') + ' words, QA Score: ' + (d.auto_qa_score ? JSON.parse(typeof d.auto_qa_score === 'string' ? d.auto_qa_score : JSON.stringify(d.auto_qa_score)).overall || '?' : '?') + '/10'; + status.style.color = '#2d6a4f'; + } + showToast('Blog Ready!', d.title + ' — ' + d.word_count + ' words (LLM-generated)'); + setTimeout(function() { loadBlogDrafts(); viewBlogDraft(id); }, 2000); } else { - var steps = data.draft.pipeline_steps_completed || 0; showToast("LLM Step " + steps + "/10", "Pipeline running..."); pollBlogLlm(id, attempt + 1); + // Still processing — update progress + var pctVal = Math.min(95, steps * 10 + 5); + var bar = document.getElementById('blog-pipeline-bar'); + var pct = document.getElementById('blog-pipeline-pct'); + var stepEl = document.getElementById('blog-pipeline-step'); + var status = document.getElementById('blog-pipeline-status'); + if (bar) bar.style.width = pctVal + '%'; + if (pct) pct.textContent = pctVal + '%'; + if (stepEl && steps > 0 && steps <= 10) stepEl.textContent = 'Step ' + steps + '/10: ' + (STEP_NAMES[steps-1] || 'Processing...'); + if (status) status.textContent = 'LLM Pipeline: Step ' + steps + '/10'; + pollBlogLlm(id, attempt + 1); } - }).catch(function() {}); - }, 20000); + }).catch(function() { pollBlogLlm(id, attempt + 1); }); + }, 15000); } el('gen-hype').addEventListener('click', function() { generateBlog('hype_cycle', '800G'); });