Files
helix-engage/docs/generate-pptx.js
saridsa2 48ed300094 feat: unified context panel, remove tabs, context-aware layout
- Merged AI Assistant + Lead 360 tabs into single context-aware panel
- Context section shows: lead profile, AI insight (live from event bus), appointments, activity
- "On call with" banner only shows during active calls (isInCall prop)
- AI Chat always available at bottom of panel
- Phase 1 only — AI Chat panel needs full redesign with Vercel AI SDK tool calling (Phase 2)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 14:44:48 +05:30

681 lines
24 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Helix Engage — Weekly Update (Mar 1825, 2026)
* Light Mode PowerPoint Generator via PptxGenJS
*/
const PptxGenJS = require("pptxgenjs");
// ── Design Tokens (Light Mode) ─────────────────────────────────────────
const C = {
bg: "FFFFFF",
bgSubtle: "F8FAFC",
bgCard: "F1F5F9",
bgCardAlt: "E2E8F0",
text: "1E293B",
textSec: "475569",
textMuted: "94A3B8",
accent1: "0EA5E9", // Sky blue (telephony)
accent2: "8B5CF6", // Violet (server/backend)
accent3: "10B981", // Emerald (UX)
accent4: "F59E0B", // Amber (features)
accent5: "EF4444", // Rose (ops)
accent6: "6366F1", // Indigo (timeline)
white: "FFFFFF",
border: "CBD5E1",
};
const FONT = {
heading: "Arial",
body: "Arial",
};
// ── Helpers ──────────────────────────────────────────────────────────────
function addSlideNumber(slide, num, total) {
slide.addText(`${num} / ${total}`, {
x: 8.8, y: 5.2, w: 1.2, h: 0.3,
fontSize: 8, color: C.textMuted,
fontFace: FONT.body,
align: "right",
});
}
function addAccentBar(slide, color) {
slide.addShape("rect", {
x: 0, y: 0, w: 10, h: 0.06,
fill: { color },
});
}
function addLabel(slide, text, color, x, y) {
slide.addShape("roundRect", {
x, y, w: text.length * 0.09 + 0.4, h: 0.3,
fill: { color, transparency: 88 },
rectRadius: 0.15,
});
slide.addText(text.toUpperCase(), {
x, y, w: text.length * 0.09 + 0.4, h: 0.3,
fontSize: 7, fontFace: FONT.heading, bold: true,
color, align: "center", valign: "middle",
letterSpacing: 2,
});
}
function addCard(slide, opts) {
const { x, y, w, h, title, titleColor, items, badge } = opts;
// Card background
slide.addShape("roundRect", {
x, y, w, h,
fill: { color: C.bgCard },
line: { color: C.border, width: 0.5 },
rectRadius: 0.1,
});
// Title
const titleText = badge
? [{ text: title + " ", options: { bold: true, color: titleColor, fontSize: 11 } },
{ text: badge, options: { bold: true, color: C.white, fontSize: 7, highlight: titleColor } }]
: title;
slide.addText(titleText, {
x: x + 0.2, y: y + 0.08, w: w - 0.4, h: 0.35,
fontSize: 11, fontFace: FONT.heading, bold: true,
color: titleColor,
});
// Items as bullet list
if (items && items.length > 0) {
slide.addText(
items.map(item => ({
text: item,
options: {
fontSize: 8.5, fontFace: FONT.body, color: C.textSec,
bullet: { type: "bullet", style: "arabicPeriod" },
paraSpaceAfter: 2,
breakLine: true,
},
})),
{
x: x + 0.2, y: y + 0.4, w: w - 0.4, h: h - 0.5,
valign: "top",
bullet: { type: "bullet" },
lineSpacingMultiple: 1.1,
}
);
}
}
// ── Build Presentation ──────────────────────────────────────────────────
async function build() {
const pptx = new PptxGenJS();
pptx.layout = "LAYOUT_16x9";
pptx.author = "Satya Suman Sari";
pptx.company = "FortyTwo Platform";
pptx.title = "Helix Engage — Weekly Update (Mar 1825, 2026)";
pptx.subject = "Engineering Progress Report";
const TOTAL = 9;
// ═══════════════════════════════════════════════════════════════════════
// SLIDE 1 — Title
// ═══════════════════════════════════════════════════════════════════════
{
const slide = pptx.addSlide();
slide.background = { color: C.bg };
// Accent bar top
addAccentBar(slide, C.accent1);
// Decorative side stripe
slide.addShape("rect", {
x: 0, y: 0, w: 0.12, h: 5.63,
fill: { color: C.accent1 },
});
// Label
addLabel(slide, "Weekly Engineering Update", C.accent1, 3.0, 1.2);
// Title
slide.addText("Helix Engage", {
x: 1.0, y: 1.8, w: 8, h: 1.2,
fontSize: 44, fontFace: FONT.heading, bold: true,
color: C.accent1, align: "center",
});
// Subtitle
slide.addText("Contact Center CRM · Real-time Telephony · AI Copilot", {
x: 1.5, y: 2.9, w: 7, h: 0.5,
fontSize: 14, fontFace: FONT.body,
color: C.textSec, align: "center",
});
// Date
slide.addText("March 18 25, 2026", {
x: 3, y: 3.6, w: 4, h: 0.4,
fontSize: 12, fontFace: FONT.heading, bold: true,
color: C.textMuted, align: "center",
letterSpacing: 3,
});
// Bottom decoration
slide.addShape("rect", {
x: 3.5, y: 4.2, w: 3, h: 0.04,
fill: { color: C.accent2 },
});
// Author
slide.addText("Satya Suman Sari · FortyTwo Platform", {
x: 2, y: 4.5, w: 6, h: 0.35,
fontSize: 9, fontFace: FONT.body,
color: C.textMuted, align: "center",
});
addSlideNumber(slide, 1, TOTAL);
}
// ═══════════════════════════════════════════════════════════════════════
// SLIDE 2 — At a Glance
// ═══════════════════════════════════════════════════════════════════════
{
const slide = pptx.addSlide();
slide.background = { color: C.bg };
addAccentBar(slide, C.accent2);
addLabel(slide, "At a Glance", C.accent2, 0.5, 0.3);
slide.addText("Week in Numbers", {
x: 0.5, y: 0.65, w: 5, h: 0.5,
fontSize: 24, fontFace: FONT.heading, bold: true,
color: C.text,
});
// Stat cards
const stats = [
{ value: "78", label: "Total Commits", color: C.accent1 },
{ value: "3", label: "Repositories", color: C.accent2 },
{ value: "8", label: "Days Active", color: C.accent3 },
{ value: "50", label: "Frontend Commits", color: C.accent4 },
];
stats.forEach((s, i) => {
const x = 0.5 + i * 2.35;
// Card bg
slide.addShape("roundRect", {
x, y: 1.3, w: 2.1, h: 1.7,
fill: { color: C.bgCard },
line: { color: C.border, width: 0.5 },
rectRadius: 0.12,
});
// Accent top line
slide.addShape("rect", {
x: x + 0.2, y: 1.35, w: 1.7, h: 0.035,
fill: { color: s.color },
});
// Number
slide.addText(s.value, {
x, y: 1.5, w: 2.1, h: 0.9,
fontSize: 36, fontFace: FONT.heading, bold: true,
color: s.color, align: "center", valign: "middle",
});
// Label
slide.addText(s.label, {
x, y: 2.4, w: 2.1, h: 0.4,
fontSize: 9, fontFace: FONT.body,
color: C.textSec, align: "center",
});
});
// Repo breakdown pills
const repos = [
{ name: "helix-engage", count: "50", clr: C.accent1 },
{ name: "helix-engage-server", count: "27", clr: C.accent2 },
{ name: "FortyTwoApps/SDK", count: "1", clr: C.accent3 },
];
repos.forEach((r, i) => {
const x = 1.5 + i * 2.8;
slide.addShape("roundRect", {
x, y: 3.4, w: 2.5, h: 0.4,
fill: { color: C.bgCard },
line: { color: r.clr, width: 1 },
rectRadius: 0.2,
});
slide.addText(`${r.name} ${r.count}`, {
x, y: 3.4, w: 2.5, h: 0.4,
fontSize: 9, fontFace: FONT.heading, bold: true,
color: r.clr, align: "center", valign: "middle",
});
});
// Summary text
slide.addText("3 repos · 7 working days · 78 commits shipped to production", {
x: 1, y: 4.2, w: 8, h: 0.35,
fontSize: 10, fontFace: FONT.body, italic: true,
color: C.textMuted, align: "center",
});
addSlideNumber(slide, 2, TOTAL);
}
// ═══════════════════════════════════════════════════════════════════════
// SLIDE 3 — Telephony & SIP
// ═══════════════════════════════════════════════════════════════════════
{
const slide = pptx.addSlide();
slide.background = { color: C.bg };
addAccentBar(slide, C.accent1);
addLabel(slide, "Core Infrastructure", C.accent1, 0.5, 0.3);
slide.addText([
{ text: "☎ ", options: { fontSize: 22 } },
{ text: "Telephony & SIP Overhaul", options: { fontSize: 22, bold: true, color: C.text } },
], { x: 0.5, y: 0.65, w: 9, h: 0.5, fontFace: FONT.heading });
addCard(slide, {
x: 0.3, y: 1.35, w: 4.5, h: 2.0,
title: "Outbound Calling", titleColor: C.accent1, badge: "Frontend",
items: [
"Direct SIP call from browser — no Kookoo bridge",
"Immediate call card UI with auto-answer SIP bridge",
"End Call label fix, force active state after auto-answer",
"Reset outboundPending on call end",
],
});
addCard(slide, {
x: 5.2, y: 1.35, w: 4.5, h: 2.0,
title: "Ozonetel Integration", titleColor: C.accent2, badge: "Server",
items: [
"Ozonetel V3 dial endpoint + webhook handler",
"Set Disposition API for ACW release",
"Force Ready endpoint for agent state mgmt",
"Token: 10-min cache, 401 invalidation, refresh on login",
],
});
addCard(slide, {
x: 0.3, y: 3.55, w: 4.5, h: 1.8,
title: "SIP & Agent State", titleColor: C.accent1, badge: "Frontend",
items: [
"SIP driven by Agent entity with token refresh",
"Centralised outbound dial into useSip().dialOutbound()",
"UCID tracking from SIP headers for disposition",
"Network indicator for connection health",
],
});
addCard(slide, {
x: 5.2, y: 3.55, w: 4.5, h: 1.8,
title: "Multi-Agent & Sessions", titleColor: C.accent2, badge: "Server",
items: [
"Multi-agent SIP with Redis session lockout",
"Strict duplicate login — one device per agent",
"Session lock stores IP + timestamp for debugging",
"SSE agent state broadcast for supervisor view",
],
});
addSlideNumber(slide, 3, TOTAL);
}
// ═══════════════════════════════════════════════════════════════════════
// SLIDE 4 — Call Desk & Agent UX
// ═══════════════════════════════════════════════════════════════════════
{
const slide = pptx.addSlide();
slide.background = { color: C.bg };
addAccentBar(slide, C.accent3);
addLabel(slide, "User Experience", C.accent3, 0.5, 0.3);
slide.addText([
{ text: "🖥 ", options: { fontSize: 22 } },
{ text: "Call Desk & Agent UX", options: { fontSize: 22, bold: true, color: C.text } },
], { x: 0.5, y: 0.65, w: 9, h: 0.5, fontFace: FONT.heading });
addCard(slide, {
x: 0.3, y: 1.35, w: 3.05, h: 2.6,
title: "Call Desk Redesign", titleColor: C.accent3,
items: [
"2-panel layout with collapsible sidebar & inline AI",
"Collapsible context panel, worklist/calls tabs",
"Pinned header & chat input, numpad dialler",
"Ringtone support for incoming calls",
],
});
addCard(slide, {
x: 3.55, y: 1.35, w: 3.05, h: 2.6,
title: "Post-Call Workflow", titleColor: C.accent3,
items: [
"Disposition → appointment booking → follow-up",
"Disposition returns straight to worklist",
"Send disposition to sidecar with UCID for ACW",
"Enquiry in post-call, appointment skip button",
],
});
addCard(slide, {
x: 6.8, y: 1.35, w: 2.9, h: 2.6,
title: "UI Polish", titleColor: C.accent3,
items: [
"FontAwesome Pro Duotone icon migration",
"Tooltips, sticky headers, roles, search",
"Fix React error #520 in prod tables",
"AI scroll containment, brand tokens refresh",
],
});
addSlideNumber(slide, 4, TOTAL);
}
// ═══════════════════════════════════════════════════════════════════════
// SLIDE 5 — Features Shipped
// ═══════════════════════════════════════════════════════════════════════
{
const slide = pptx.addSlide();
slide.background = { color: C.bg };
addAccentBar(slide, C.accent4);
addLabel(slide, "Features Shipped", C.accent4, 0.5, 0.3);
slide.addText([
{ text: "🚀 ", options: { fontSize: 22 } },
{ text: "Major Features", options: { fontSize: 22, bold: true, color: C.text } },
], { x: 0.5, y: 0.65, w: 9, h: 0.5, fontFace: FONT.heading });
addCard(slide, {
x: 0.3, y: 1.35, w: 4.5, h: 2.0,
title: "Supervisor Module", titleColor: C.accent4,
items: [
"Team performance analytics page",
"Live monitor with active calls visibility",
"Master data management pages",
"Server: team perf + active calls endpoints",
],
});
addCard(slide, {
x: 5.2, y: 1.35, w: 4.5, h: 2.0,
title: "Missed Call Queue (Phase 2)", titleColor: C.accent4,
items: [
"Missed call queue ingestion & worklist",
"Auto-assignment engine for agents",
"Login redesign with role-based routing",
"Lead lookup for missed callers",
],
});
addCard(slide, {
x: 0.3, y: 3.55, w: 4.5, h: 1.8,
title: "Agent Features (Phase 1)", titleColor: C.accent4,
items: [
"Agent status toggle (Ready / Not Ready / Break)",
"Global search across patients, leads, calls",
"Enquiry form for new patient intake",
"My Performance page + logout modal",
],
});
addCard(slide, {
x: 5.2, y: 3.55, w: 4.5, h: 1.8,
title: "Recording Analysis", titleColor: C.accent4,
items: [
"Deepgram diarization + AI insights",
"Redis caching layer for analysis results",
"Full-stack: frontend player + server module",
],
});
addSlideNumber(slide, 5, TOTAL);
}
// ═══════════════════════════════════════════════════════════════════════
// SLIDE 6 — Backend & Data
// ═══════════════════════════════════════════════════════════════════════
{
const slide = pptx.addSlide();
slide.background = { color: C.bg };
addAccentBar(slide, C.accent2);
addLabel(slide, "Backend & Data", C.accent2, 0.5, 0.3);
slide.addText([
{ text: "⚙ ", options: { fontSize: 22 } },
{ text: "Backend & Data Layer", options: { fontSize: 22, bold: true, color: C.text } },
], { x: 0.5, y: 0.65, w: 9, h: 0.5, fontFace: FONT.heading });
addCard(slide, {
x: 0.3, y: 1.35, w: 4.5, h: 2.0,
title: "Platform Data Wiring", titleColor: C.accent2,
items: [
"Migrated frontend to Jotai + Vercel AI SDK",
"Corrected all 7 GraphQL queries (fields, LINKS/PHONES)",
"Webhook handler for Ozonetel call records",
"Complete seeder: 5 doctors, appointments linked",
],
});
addCard(slide, {
x: 5.2, y: 1.35, w: 4.5, h: 2.0,
title: "Server Endpoints", titleColor: C.accent2,
items: [
"Call control, recording, CDR, missed calls, live assist",
"Agent summary, AHT, performance aggregation",
"Token refresh endpoint for auto-renewal",
"Search module with full-text capabilities",
],
});
addCard(slide, {
x: 0.3, y: 3.55, w: 4.5, h: 1.8,
title: "Data Pages Built", titleColor: C.accent2,
items: [
"Worklist table, call history, patients, dashboard",
"Reports, team dashboard, campaigns, settings",
"Agent detail page, campaign edit slideout",
"Appointments page with data refresh on login",
],
});
addCard(slide, {
x: 5.2, y: 3.55, w: 4.5, h: 1.8,
title: "SDK App", titleColor: C.accent3, badge: "FortyTwoApps",
items: [
"Helix Engage SDK app entity definitions",
"Call center CRM object model for platform",
"Foundation for platform-native data integration",
],
});
addSlideNumber(slide, 6, TOTAL);
}
// ═══════════════════════════════════════════════════════════════════════
// SLIDE 7 — Deployment & Ops
// ═══════════════════════════════════════════════════════════════════════
{
const slide = pptx.addSlide();
slide.background = { color: C.bg };
addAccentBar(slide, C.accent5);
addLabel(slide, "Operations", C.accent5, 0.5, 0.3);
slide.addText([
{ text: "🛠 ", options: { fontSize: 22 } },
{ text: "Deployment & DevOps", options: { fontSize: 22, bold: true, color: C.text } },
], { x: 0.5, y: 0.65, w: 9, h: 0.5, fontFace: FONT.heading });
addCard(slide, {
x: 0.3, y: 1.35, w: 3.05, h: 2.2,
title: "Deployment", titleColor: C.accent5,
items: [
"Deployed to Hostinger VPS with Docker",
"Switched to global_healthx Ozonetel account",
"Dockerfile for server-side containerization",
],
});
addCard(slide, {
x: 3.55, y: 1.35, w: 3.05, h: 2.2,
title: "AI & Testing", titleColor: C.accent5,
items: [
"Migrated AI to Vercel AI SDK + OpenAI provider",
"AI flow test script — validates full pipeline",
"Live call assist integration",
],
});
addCard(slide, {
x: 6.8, y: 1.35, w: 2.9, h: 2.2,
title: "Documentation", titleColor: C.accent5,
items: [
"Team onboarding README with arch guide",
"Supervisor module spec + plan",
"Multi-agent spec + plan",
"Next session plans in commits",
],
});
addSlideNumber(slide, 7, TOTAL);
}
// ═══════════════════════════════════════════════════════════════════════
// SLIDE 8 — Timeline
// ═══════════════════════════════════════════════════════════════════════
{
const slide = pptx.addSlide();
slide.background = { color: C.bg };
addAccentBar(slide, C.accent6);
addLabel(slide, "Day by Day", C.accent6, 0.5, 0.3);
slide.addText([
{ text: "📅 ", options: { fontSize: 22 } },
{ text: "Development Timeline", options: { fontSize: 22, bold: true, color: C.text } },
], { x: 0.5, y: 0.65, w: 9, h: 0.5, fontFace: FONT.heading });
const timeline = [
{ date: "MAR 18 (Tue)", title: "Foundation Day", desc: "Call desk redesign, Jotai + AI SDK migration, seeder, AI flow test, VPS deploy" },
{ date: "MAR 19 (Wed)", title: "Data Layer Sprint", desc: "All data pages, post-call workflow, GraphQL fixes, Kookoo IVR, outbound UI" },
{ date: "MAR 20 (Thu)", title: "Telephony Breakthrough", desc: "Direct SIP replacing Kookoo, UCID tracking, Force Ready, Set Disposition" },
{ date: "MAR 21 (Fri)", title: "Agent Experience", desc: "Phase 1: status toggle, search, enquiry form, My Performance, FA icons, AHT" },
{ date: "MAR 23 (Sun)", title: "Scale & Reliability", desc: "Phase 2: missed call queue, auto-assign, Redis lockout, Patient 360, SDK defs" },
{ date: "MAR 24 (Mon)", title: "Supervisor Module", desc: "Team perf, live monitor, master data, SSE, UUID fix, maintenance, QA sweep" },
{ date: "MAR 25 (Tue)", title: "Intelligence Layer", desc: "Deepgram diarization, AI insights, SIP via Agent entity, token refresh, network" },
];
// Vertical line
slide.addShape("rect", {
x: 1.4, y: 1.3, w: 0.025, h: 4.0,
fill: { color: C.accent6, transparency: 60 },
});
timeline.forEach((entry, i) => {
const y = 1.3 + i * 0.56;
// Dot
slide.addShape("ellipse", {
x: 1.32, y: y + 0.08, w: 0.18, h: 0.18,
fill: { color: C.accent6 },
line: { color: C.bg, width: 2 },
});
// Date
slide.addText(entry.date, {
x: 1.7, y: y, w: 1.6, h: 0.22,
fontSize: 7, fontFace: FONT.heading, bold: true,
color: C.accent6,
});
// Title
slide.addText(entry.title, {
x: 3.3, y: y, w: 2.0, h: 0.22,
fontSize: 9, fontFace: FONT.heading, bold: true,
color: C.text,
});
// Description
slide.addText(entry.desc, {
x: 5.3, y: y, w: 4.2, h: 0.45,
fontSize: 8, fontFace: FONT.body,
color: C.textSec,
valign: "top",
});
});
addSlideNumber(slide, 8, TOTAL);
}
// ═══════════════════════════════════════════════════════════════════════
// SLIDE 9 — Closing
// ═══════════════════════════════════════════════════════════════════════
{
const slide = pptx.addSlide();
slide.background = { color: C.bg };
addAccentBar(slide, C.accent3);
// Big headline
slide.addText("78 commits. 8 days. Ship mode.", {
x: 0.5, y: 1.4, w: 9, h: 0.8,
fontSize: 32, fontFace: FONT.heading, bold: true,
color: C.accent3, align: "center",
});
// Ship emoji
slide.addText("🚢", {
x: 4.2, y: 2.3, w: 1.6, h: 0.6,
fontSize: 28, align: "center",
});
// Description
slide.addText(
"From browser-native SIP calling to AI-powered recording analysis — Helix Engage is becoming a production contact center platform.",
{
x: 1.5, y: 3.0, w: 7, h: 0.6,
fontSize: 11, fontFace: FONT.body,
color: C.textSec, align: "center",
lineSpacingMultiple: 1.3,
}
);
// Achievement pills
const achievements = [
{ text: "SIP Calling ✓", color: C.accent1 },
{ text: "Multi-Agent ✓", color: C.accent2 },
{ text: "Supervisor ✓", color: C.accent3 },
{ text: "AI Copilot ✓", color: C.accent4 },
{ text: "Recording Analysis ✓", color: C.accent5 },
];
achievements.forEach((a, i) => {
const x = 0.8 + i * 1.8;
slide.addShape("roundRect", {
x, y: 3.9, w: 1.6, h: 0.35,
fill: { color: C.bgCard },
line: { color: a.color, width: 1 },
rectRadius: 0.17,
});
slide.addText(a.text, {
x, y: 3.9, w: 1.6, h: 0.35,
fontSize: 8, fontFace: FONT.heading, bold: true,
color: a.color, align: "center", valign: "middle",
});
});
// Author
slide.addText("Satya Suman Sari · FortyTwo Platform", {
x: 2, y: 4.7, w: 6, h: 0.3,
fontSize: 9, fontFace: FONT.body,
color: C.textMuted, align: "center",
});
addSlideNumber(slide, 9, TOTAL);
}
// ── Save ──────────────────────────────────────────────────────────────
const outPath = "weekly-update-mar18-25.pptx";
await pptx.writeFile({ fileName: outPath });
console.log(`✅ Presentation saved: ${outPath}`);
}
build().catch(err => {
console.error("❌ Failed:", err.message);
process.exit(1);
});