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'); });