feat(v0.2.4): blog generation UX overhaul — live progress bar
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
This commit is contained in:
parent
896c338c8e
commit
7719155e8e
@ -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",
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -2287,7 +2287,16 @@ function copyBlogContent(id) {
|
||||
|
||||
// BLOG
|
||||
function generateBlog(topic, speed) {
|
||||
el('blog-list').innerHTML = '<div class="loading pulse" id="blog-gen-status">Generating template... LLM 10-step pipeline starts in background (~10 min)</div>';
|
||||
// Show prominent progress overlay instead of just adding to list
|
||||
el('blog-list').innerHTML = '<div style="background:linear-gradient(135deg,#1a1a1a,#2a2a2a);color:white;padding:2rem;border-radius:12px;text-align:center">' +
|
||||
'<div style="font-size:1.5rem;font-weight:700;margin-bottom:1rem">🔄 Generating Blog with AI...</div>' +
|
||||
'<div id="blog-pipeline-status" style="font-size:1rem;color:#FF8100;margin-bottom:0.5rem">Starting 10-step Flexoptix Style pipeline...</div>' +
|
||||
'<div id="blog-pipeline-step" style="font-size:0.85rem;color:#888">Connecting to LLM (qwen2.5:14b on Mac Studio)</div>' +
|
||||
'<div style="margin-top:1.5rem;background:#333;border-radius:8px;height:8px;overflow:hidden">' +
|
||||
'<div id="blog-pipeline-bar" style="width:0%;height:100%;background:#FF8100;transition:width 0.5s ease"></div></div>' +
|
||||
'<div id="blog-pipeline-pct" style="font-size:0.8rem;color:#666;margin-top:0.5rem">0%</div>' +
|
||||
'</div>';
|
||||
|
||||
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'); });
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user