claude-presentation-master 7.2.0 → 7.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/cli.js +6 -0
- package/dist/index.d.mts +96 -10
- package/dist/index.d.ts +96 -10
- package/dist/index.js +539 -54
- package/dist/index.mjs +539 -54
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -102,6 +102,75 @@ var import_fs = require("fs");
|
|
|
102
102
|
var import_path = require("path");
|
|
103
103
|
var import_url = require("url");
|
|
104
104
|
var yaml = __toESM(require("yaml"));
|
|
105
|
+
|
|
106
|
+
// src/utils/Logger.ts
|
|
107
|
+
var Logger = class {
|
|
108
|
+
level;
|
|
109
|
+
prefix;
|
|
110
|
+
timestamps;
|
|
111
|
+
constructor(options = {}) {
|
|
112
|
+
this.level = options.level ?? 1 /* INFO */;
|
|
113
|
+
this.prefix = options.prefix ?? "";
|
|
114
|
+
this.timestamps = options.timestamps ?? false;
|
|
115
|
+
}
|
|
116
|
+
setLevel(level) {
|
|
117
|
+
this.level = level;
|
|
118
|
+
}
|
|
119
|
+
formatMessage(message) {
|
|
120
|
+
const parts = [];
|
|
121
|
+
if (this.timestamps) {
|
|
122
|
+
parts.push(`[${(/* @__PURE__ */ new Date()).toISOString()}]`);
|
|
123
|
+
}
|
|
124
|
+
if (this.prefix) {
|
|
125
|
+
parts.push(`[${this.prefix}]`);
|
|
126
|
+
}
|
|
127
|
+
parts.push(message);
|
|
128
|
+
return parts.join(" ");
|
|
129
|
+
}
|
|
130
|
+
debug(message, ...args) {
|
|
131
|
+
if (this.level <= 0 /* DEBUG */) {
|
|
132
|
+
console.debug(this.formatMessage(message), ...args);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
info(message, ...args) {
|
|
136
|
+
if (this.level <= 1 /* INFO */) {
|
|
137
|
+
console.info(this.formatMessage(message), ...args);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
warn(message, ...args) {
|
|
141
|
+
if (this.level <= 2 /* WARN */) {
|
|
142
|
+
console.warn(this.formatMessage(message), ...args);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
error(message, ...args) {
|
|
146
|
+
if (this.level <= 3 /* ERROR */) {
|
|
147
|
+
console.error(this.formatMessage(message), ...args);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
// Progress messages (always shown unless silent)
|
|
151
|
+
progress(message) {
|
|
152
|
+
if (this.level < 4 /* SILENT */) {
|
|
153
|
+
console.info(message);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// Success messages
|
|
157
|
+
success(message) {
|
|
158
|
+
if (this.level < 4 /* SILENT */) {
|
|
159
|
+
console.info(`\u2705 ${message}`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Step messages for workflow progress
|
|
163
|
+
step(message) {
|
|
164
|
+
if (this.level <= 1 /* INFO */) {
|
|
165
|
+
console.info(` \u2713 ${message}`);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
var logger = new Logger({
|
|
170
|
+
level: process.env.LOG_LEVEL ? parseInt(process.env.LOG_LEVEL) : 1 /* INFO */
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// src/kb/KnowledgeGateway.ts
|
|
105
174
|
var import_meta = {};
|
|
106
175
|
function getModuleDir() {
|
|
107
176
|
if (typeof import_meta !== "undefined" && import_meta.url) {
|
|
@@ -113,7 +182,7 @@ function getModuleDir() {
|
|
|
113
182
|
return process.cwd();
|
|
114
183
|
}
|
|
115
184
|
var KnowledgeGateway = class {
|
|
116
|
-
kb;
|
|
185
|
+
kb = {};
|
|
117
186
|
loaded = false;
|
|
118
187
|
constructor() {
|
|
119
188
|
}
|
|
@@ -136,7 +205,7 @@ var KnowledgeGateway = class {
|
|
|
136
205
|
const content = (0, import_fs.readFileSync)(path, "utf-8");
|
|
137
206
|
this.kb = yaml.parse(content);
|
|
138
207
|
this.loaded = true;
|
|
139
|
-
|
|
208
|
+
logger.step(`Knowledge base loaded from ${path}`);
|
|
140
209
|
return;
|
|
141
210
|
} catch {
|
|
142
211
|
}
|
|
@@ -327,7 +396,7 @@ var KnowledgeGateway = class {
|
|
|
327
396
|
*/
|
|
328
397
|
getChartGuidance(purpose) {
|
|
329
398
|
this.ensureLoaded();
|
|
330
|
-
return this.kb.chart_selection_guide.by_purpose[purpose];
|
|
399
|
+
return this.kb.chart_selection_guide.by_purpose?.[purpose];
|
|
331
400
|
}
|
|
332
401
|
/**
|
|
333
402
|
* Get charts to avoid
|
|
@@ -342,7 +411,7 @@ var KnowledgeGateway = class {
|
|
|
342
411
|
*/
|
|
343
412
|
getIBPitchBookStructure(type) {
|
|
344
413
|
this.ensureLoaded();
|
|
345
|
-
return this.kb.investment_banking?.pitch_book_types[type];
|
|
414
|
+
return this.kb.investment_banking?.pitch_book_types?.[type];
|
|
346
415
|
}
|
|
347
416
|
/**
|
|
348
417
|
* Check if knowledge base is loaded
|
|
@@ -894,14 +963,14 @@ var ContentAnalyzer = class {
|
|
|
894
963
|
const text = this.parseContent(content, contentType);
|
|
895
964
|
const title = this.extractTitle(text);
|
|
896
965
|
const detectedType = this.detectPresentationType(text);
|
|
897
|
-
|
|
966
|
+
logger.step(`Detected type: ${detectedType}`);
|
|
898
967
|
const sections = this.extractSections(text);
|
|
899
|
-
|
|
968
|
+
logger.step(`Found ${sections.length} sections`);
|
|
900
969
|
const scqa = this.extractSCQA(text);
|
|
901
970
|
const sparkline = this.extractSparkline(text);
|
|
902
971
|
const keyMessages = this.extractKeyMessages(text);
|
|
903
972
|
const dataPoints = this.extractDataPoints(text);
|
|
904
|
-
|
|
973
|
+
logger.step(`Found ${dataPoints.length} data points`);
|
|
905
974
|
const titles = sections.map((s) => s.header).filter((h) => h.length > 0);
|
|
906
975
|
const starMoments = this.extractStarMoments(text);
|
|
907
976
|
const estimatedSlideCount = Math.max(5, sections.length + 3);
|
|
@@ -1021,12 +1090,16 @@ var ContentAnalyzer = class {
|
|
|
1021
1090
|
}
|
|
1022
1091
|
const bulletMatch = trimmedLine.match(/^[-*+]\s+(.+)$/);
|
|
1023
1092
|
if (bulletMatch && bulletMatch[1] && currentSection) {
|
|
1024
|
-
|
|
1093
|
+
const bulletText = bulletMatch[1];
|
|
1094
|
+
currentSection.bullets.push(bulletText);
|
|
1095
|
+
this.extractMetricsFromText(bulletText, currentSection.metrics);
|
|
1025
1096
|
continue;
|
|
1026
1097
|
}
|
|
1027
1098
|
const numberedMatch = trimmedLine.match(/^\d+\.\s+(.+)$/);
|
|
1028
1099
|
if (numberedMatch && numberedMatch[1] && currentSection) {
|
|
1029
|
-
|
|
1100
|
+
const itemText = numberedMatch[1];
|
|
1101
|
+
currentSection.bullets.push(itemText);
|
|
1102
|
+
this.extractMetricsFromText(itemText, currentSection.metrics);
|
|
1030
1103
|
continue;
|
|
1031
1104
|
}
|
|
1032
1105
|
const metricMatch = trimmedLine.match(/\$?([\d,]+\.?\d*)[%]?\s*[-–—:]\s*(.+)/);
|
|
@@ -1037,6 +1110,9 @@ var ContentAnalyzer = class {
|
|
|
1037
1110
|
});
|
|
1038
1111
|
continue;
|
|
1039
1112
|
}
|
|
1113
|
+
if (currentSection && trimmedLine) {
|
|
1114
|
+
this.extractMetricsFromText(trimmedLine, currentSection.metrics);
|
|
1115
|
+
}
|
|
1040
1116
|
if (trimmedLine.includes("|") && currentSection) {
|
|
1041
1117
|
const cells = trimmedLine.split("|").map((c) => c.trim()).filter((c) => c && !c.match(/^-+$/));
|
|
1042
1118
|
if (cells.length >= 2) {
|
|
@@ -1408,6 +1484,49 @@ var ContentAnalyzer = class {
|
|
|
1408
1484
|
const fallback = cleaned.slice(0, 150);
|
|
1409
1485
|
return fallback.length >= 20 ? fallback : "";
|
|
1410
1486
|
}
|
|
1487
|
+
/**
|
|
1488
|
+
* Extract metrics from natural language text
|
|
1489
|
+
* Handles formats like "40% productivity loss", "$2.5M investment"
|
|
1490
|
+
*/
|
|
1491
|
+
extractMetricsFromText(text, metrics) {
|
|
1492
|
+
const usedValues = new Set(metrics.map((m) => m.value));
|
|
1493
|
+
const moneyMatches = text.matchAll(/(\$[\d,.]+[MBK]?)\s+([a-zA-Z][a-zA-Z\s]{2,30})/g);
|
|
1494
|
+
for (const match of moneyMatches) {
|
|
1495
|
+
const value = match[1];
|
|
1496
|
+
const rawLabel = match[2]?.trim();
|
|
1497
|
+
if (value && rawLabel && !usedValues.has(value)) {
|
|
1498
|
+
usedValues.add(value);
|
|
1499
|
+
metrics.push({ value, label: this.cleanMetricLabel(rawLabel) });
|
|
1500
|
+
}
|
|
1501
|
+
}
|
|
1502
|
+
const percentMatches = text.matchAll(/(\d+(?:\.\d+)?%)\s+([a-zA-Z][a-zA-Z\s]{2,30})/g);
|
|
1503
|
+
for (const match of percentMatches) {
|
|
1504
|
+
const value = match[1];
|
|
1505
|
+
const rawLabel = match[2]?.trim();
|
|
1506
|
+
if (value && rawLabel && !usedValues.has(value)) {
|
|
1507
|
+
usedValues.add(value);
|
|
1508
|
+
metrics.push({ value, label: this.cleanMetricLabel(rawLabel) });
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
const multMatches = text.matchAll(/(\d+[xX])\s+([a-zA-Z][a-zA-Z\s]{2,20})/g);
|
|
1512
|
+
for (const match of multMatches) {
|
|
1513
|
+
const value = match[1];
|
|
1514
|
+
const rawLabel = match[2]?.trim();
|
|
1515
|
+
if (value && rawLabel && !usedValues.has(value)) {
|
|
1516
|
+
usedValues.add(value);
|
|
1517
|
+
metrics.push({ value, label: this.cleanMetricLabel(rawLabel) });
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
const numMatches = text.matchAll(/(\d{3,}\+?)\s+([a-zA-Z][a-zA-Z\s]{2,20})/g);
|
|
1521
|
+
for (const match of numMatches) {
|
|
1522
|
+
const value = match[1];
|
|
1523
|
+
const rawLabel = match[2]?.trim();
|
|
1524
|
+
if (value && rawLabel && !usedValues.has(value)) {
|
|
1525
|
+
usedValues.add(value);
|
|
1526
|
+
metrics.push({ value, label: this.cleanMetricLabel(rawLabel) });
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
}
|
|
1411
1530
|
};
|
|
1412
1531
|
|
|
1413
1532
|
// src/core/ContentPatternClassifier.ts
|
|
@@ -1592,8 +1711,8 @@ var SlideFactory = class {
|
|
|
1592
1711
|
this.usedContent = /* @__PURE__ */ new Set();
|
|
1593
1712
|
this.usedTitles = /* @__PURE__ */ new Set();
|
|
1594
1713
|
this.config = this.loadKBConfig(type);
|
|
1595
|
-
|
|
1596
|
-
|
|
1714
|
+
logger.step(`SlideFactory v7.1.0 initialized for ${type} (${this.config.mode} mode)`);
|
|
1715
|
+
logger.step(`KB Config loaded: ${this.config.allowedTypes.length} allowed types`);
|
|
1597
1716
|
}
|
|
1598
1717
|
/**
|
|
1599
1718
|
* Load ALL configuration from KB - ZERO hardcoded values after this.
|
|
@@ -1621,7 +1740,7 @@ var SlideFactory = class {
|
|
|
1621
1740
|
async createSlides(analysis) {
|
|
1622
1741
|
const slides = [];
|
|
1623
1742
|
const storyStructure = this.kb.getStoryStructure(this.presentationType);
|
|
1624
|
-
|
|
1743
|
+
logger.step(`Using ${storyStructure.framework} story framework`);
|
|
1625
1744
|
slides.push(this.createTitleSlide(0, analysis));
|
|
1626
1745
|
const minSectionsForAgenda = Math.max(3, this.config.rules.bulletsPerSlide.max - 2);
|
|
1627
1746
|
if (this.config.mode === "business" && analysis.sections.length >= minSectionsForAgenda) {
|
|
@@ -1659,7 +1778,7 @@ var SlideFactory = class {
|
|
|
1659
1778
|
const validatedSlides = this.validateAndFixSlides(slides);
|
|
1660
1779
|
this.checkRequiredElements(validatedSlides);
|
|
1661
1780
|
this.checkAntiPatterns(validatedSlides);
|
|
1662
|
-
|
|
1781
|
+
logger.step(`Created ${validatedSlides.length} validated slides`);
|
|
1663
1782
|
return validatedSlides;
|
|
1664
1783
|
}
|
|
1665
1784
|
// ===========================================================================
|
|
@@ -1700,7 +1819,7 @@ var SlideFactory = class {
|
|
|
1700
1819
|
case "technical":
|
|
1701
1820
|
return this.createCodeSlide(index, section);
|
|
1702
1821
|
default:
|
|
1703
|
-
|
|
1822
|
+
logger.warn(`Unknown slide type '${type}', using bullet-points`);
|
|
1704
1823
|
return this.createBulletSlide(index, section);
|
|
1705
1824
|
}
|
|
1706
1825
|
}
|
|
@@ -1833,15 +1952,19 @@ var SlideFactory = class {
|
|
|
1833
1952
|
// CONTENT SLIDES - ALL values from KB
|
|
1834
1953
|
// ===========================================================================
|
|
1835
1954
|
createBigNumberSlide(index, section, pattern) {
|
|
1836
|
-
const
|
|
1837
|
-
|
|
1838
|
-
|
|
1955
|
+
const fullContent = `${section.header} ${section.content} ${section.bullets.join(" ")}`;
|
|
1956
|
+
const bigNumber = this.classifier.extractBigNumber(fullContent);
|
|
1957
|
+
const actualValue = bigNumber?.value || pattern.bigNumberValue;
|
|
1958
|
+
if (!actualValue) {
|
|
1959
|
+
logger.warn(`No number found for big-number slide, falling back to single-statement`);
|
|
1960
|
+
return this.createSingleStatementSlide(index, section);
|
|
1961
|
+
}
|
|
1839
1962
|
return {
|
|
1840
1963
|
index,
|
|
1841
1964
|
type: "big-number",
|
|
1842
1965
|
data: {
|
|
1843
1966
|
title: this.createTitle(section.header, section),
|
|
1844
|
-
keyMessage:
|
|
1967
|
+
keyMessage: actualValue,
|
|
1845
1968
|
body: bigNumber?.context || this.truncateText(
|
|
1846
1969
|
section.content,
|
|
1847
1970
|
this.config.defaults.context.maxWords
|
|
@@ -2110,7 +2233,7 @@ var SlideFactory = class {
|
|
|
2110
2233
|
slide.data.bullets = slide.data.bullets.slice(0, validation.fixes.bulletCount);
|
|
2111
2234
|
}
|
|
2112
2235
|
if (validation.violations.length > 0) {
|
|
2113
|
-
|
|
2236
|
+
logger.warn(`Slide ${slide.index} (${slide.type}): Fixed ${Object.keys(validation.fixes).length} issues, ${validation.violations.length} remaining`);
|
|
2114
2237
|
}
|
|
2115
2238
|
if (validation.warnings.length > 0) {
|
|
2116
2239
|
slide.notes = (slide.notes || "") + "\nWarnings: " + validation.warnings.join(", ");
|
|
@@ -2150,7 +2273,7 @@ var SlideFactory = class {
|
|
|
2150
2273
|
}
|
|
2151
2274
|
}
|
|
2152
2275
|
if (missingElements.length > 0) {
|
|
2153
|
-
|
|
2276
|
+
logger.warn(`Missing required elements: ${missingElements.join(", ")}`);
|
|
2154
2277
|
}
|
|
2155
2278
|
}
|
|
2156
2279
|
/**
|
|
@@ -2181,7 +2304,7 @@ var SlideFactory = class {
|
|
|
2181
2304
|
}
|
|
2182
2305
|
}
|
|
2183
2306
|
if (violations.length > 0) {
|
|
2184
|
-
|
|
2307
|
+
logger.warn(`Anti-pattern violations: ${violations.join(", ")}`);
|
|
2185
2308
|
}
|
|
2186
2309
|
}
|
|
2187
2310
|
// ===========================================================================
|
|
@@ -2526,9 +2649,12 @@ var TemplateEngine = class {
|
|
|
2526
2649
|
this.templates.set("big-number", this.handlebars.compile(`
|
|
2527
2650
|
<section class="{{classes}}" data-slide-index="{{slideIndex}}" style="{{styles}}">
|
|
2528
2651
|
<div class="slide-content big-number-content">
|
|
2529
|
-
|
|
2530
|
-
{{
|
|
2531
|
-
|
|
2652
|
+
{{#if title}}
|
|
2653
|
+
<h2 class="title animate-fadeIn">{{title}}</h2>
|
|
2654
|
+
{{/if}}
|
|
2655
|
+
<div class="number animate-zoomIn">{{keyMessage}}</div>
|
|
2656
|
+
{{#if body}}
|
|
2657
|
+
<p class="number-context animate-fadeIn delay-300">{{body}}</p>
|
|
2532
2658
|
{{/if}}
|
|
2533
2659
|
{{> source}}
|
|
2534
2660
|
</div>
|
|
@@ -4912,6 +5038,12 @@ ${slides}
|
|
|
4912
5038
|
const highlight = palette.accent || "#e94560";
|
|
4913
5039
|
const text = palette.text || "#1a1a2e";
|
|
4914
5040
|
const background = palette.background || "#ffffff";
|
|
5041
|
+
const isDark = this.isDarkPalette(palette);
|
|
5042
|
+
const defaultBg = isDark ? background : "#ffffff";
|
|
5043
|
+
const defaultText = isDark ? text : "#1a1a2e";
|
|
5044
|
+
const headingColor = isDark ? primary : primary;
|
|
5045
|
+
const titleBg = isDark ? background : primary;
|
|
5046
|
+
const titleBgEnd = isDark ? this.lightenColor(background, 10) : this.darkenColor(primary, 15);
|
|
4915
5047
|
return `
|
|
4916
5048
|
/* Base Styles - KB-Driven Design System */
|
|
4917
5049
|
:root {
|
|
@@ -4938,7 +5070,13 @@ ${slides}
|
|
|
4938
5070
|
font-family: var(--font-body);
|
|
4939
5071
|
font-size: ${fontSize};
|
|
4940
5072
|
line-height: ${lineHeight};
|
|
4941
|
-
color:
|
|
5073
|
+
color: ${defaultText};
|
|
5074
|
+
background: ${defaultBg};
|
|
5075
|
+
}
|
|
5076
|
+
|
|
5077
|
+
/* Override reveal.js default backgrounds for dark mode */
|
|
5078
|
+
.reveal .slides section {
|
|
5079
|
+
background: ${defaultBg};
|
|
4942
5080
|
}
|
|
4943
5081
|
|
|
4944
5082
|
.reveal .slides {
|
|
@@ -4967,10 +5105,17 @@ ${slides}
|
|
|
4967
5105
|
font-family: var(--font-heading);
|
|
4968
5106
|
font-weight: 700;
|
|
4969
5107
|
letter-spacing: -0.02em;
|
|
4970
|
-
color:
|
|
5108
|
+
color: ${isDark ? primary : primary};
|
|
4971
5109
|
margin-bottom: 0.5em;
|
|
4972
5110
|
}
|
|
4973
5111
|
|
|
5112
|
+
/* Dark mode text visibility */
|
|
5113
|
+
${isDark ? `
|
|
5114
|
+
.reveal, .reveal p, .reveal li, .reveal span {
|
|
5115
|
+
color: ${text};
|
|
5116
|
+
}
|
|
5117
|
+
` : ""}
|
|
5118
|
+
|
|
4974
5119
|
.reveal h1 { font-size: 2.5em; }
|
|
4975
5120
|
.reveal h2 { font-size: 1.8em; }
|
|
4976
5121
|
.reveal h3 { font-size: 1.3em; }
|
|
@@ -5148,6 +5293,124 @@ ${slides}
|
|
|
5148
5293
|
font-weight: 600;
|
|
5149
5294
|
margin-top: 1em;
|
|
5150
5295
|
}
|
|
5296
|
+
|
|
5297
|
+
/* ================================================================
|
|
5298
|
+
SLIDE TYPE BACKGROUNDS - KB-Driven Visual Design
|
|
5299
|
+
Creates visual hierarchy and differentiation between slide types
|
|
5300
|
+
================================================================ */
|
|
5301
|
+
|
|
5302
|
+
/* Title slide: Bold background - makes strong first impression */
|
|
5303
|
+
.reveal .slide-title {
|
|
5304
|
+
background: linear-gradient(135deg, ${titleBg} 0%, ${titleBgEnd} 100%);
|
|
5305
|
+
}
|
|
5306
|
+
.reveal .slide-title h1,
|
|
5307
|
+
.reveal .slide-title h2,
|
|
5308
|
+
.reveal .slide-title p,
|
|
5309
|
+
.reveal .slide-title .subtitle {
|
|
5310
|
+
color: ${isDark ? primary : "#ffffff"};
|
|
5311
|
+
}
|
|
5312
|
+
|
|
5313
|
+
/* Section dividers: Subtle visual breaks */
|
|
5314
|
+
.reveal .slide-section-divider {
|
|
5315
|
+
background: ${isDark ? this.lightenColor(background, 8) : `linear-gradient(180deg, ${this.lightenColor(primary, 85)} 0%, ${this.lightenColor(primary, 92)} 100%)`};
|
|
5316
|
+
}
|
|
5317
|
+
|
|
5318
|
+
/* Big number slides: Clean with accent highlight - emphasizes the data */
|
|
5319
|
+
.reveal .slide-big-number {
|
|
5320
|
+
background: var(--color-background);
|
|
5321
|
+
border-left: 8px solid var(--color-highlight);
|
|
5322
|
+
}
|
|
5323
|
+
.reveal .slide-big-number .number {
|
|
5324
|
+
font-size: 5em;
|
|
5325
|
+
background: linear-gradient(135deg, var(--color-highlight) 0%, var(--color-accent) 100%);
|
|
5326
|
+
-webkit-background-clip: text;
|
|
5327
|
+
-webkit-text-fill-color: transparent;
|
|
5328
|
+
background-clip: text;
|
|
5329
|
+
}
|
|
5330
|
+
|
|
5331
|
+
/* Metrics grid: Light accent background - data-focused */
|
|
5332
|
+
.reveal .slide-metrics-grid {
|
|
5333
|
+
background: ${isDark ? this.lightenColor(background, 8) : this.lightenColor(accent, 90)};
|
|
5334
|
+
}
|
|
5335
|
+
${isDark ? `.reveal .slide-metrics-grid { color: ${text}; }` : ""}
|
|
5336
|
+
|
|
5337
|
+
/* CTA slide: Highlight color - drives action */
|
|
5338
|
+
.reveal .slide-cta {
|
|
5339
|
+
background: linear-gradient(135deg, var(--color-highlight) 0%, var(--color-accent) 100%);
|
|
5340
|
+
}
|
|
5341
|
+
.reveal .slide-cta h2,
|
|
5342
|
+
.reveal .slide-cta p {
|
|
5343
|
+
color: #ffffff;
|
|
5344
|
+
}
|
|
5345
|
+
.reveal .slide-cta .cta-button {
|
|
5346
|
+
background: #ffffff;
|
|
5347
|
+
color: var(--color-highlight);
|
|
5348
|
+
}
|
|
5349
|
+
|
|
5350
|
+
/* Thank you slide: Matches title for bookend effect */
|
|
5351
|
+
.reveal .slide-thank-you {
|
|
5352
|
+
background: linear-gradient(135deg, ${titleBg} 0%, ${titleBgEnd} 100%);
|
|
5353
|
+
}
|
|
5354
|
+
.reveal .slide-thank-you h2,
|
|
5355
|
+
.reveal .slide-thank-you p,
|
|
5356
|
+
.reveal .slide-thank-you .subtitle {
|
|
5357
|
+
color: ${isDark ? primary : "#ffffff"};
|
|
5358
|
+
}
|
|
5359
|
+
|
|
5360
|
+
/* Quote slides: Elegant subtle background */
|
|
5361
|
+
.reveal .slide-quote {
|
|
5362
|
+
background: ${isDark ? this.lightenColor(background, 5) : this.lightenColor(secondary, 92)};
|
|
5363
|
+
}
|
|
5364
|
+
.reveal .slide-quote blockquote {
|
|
5365
|
+
border-left-color: var(--color-accent);
|
|
5366
|
+
font-size: 1.3em;
|
|
5367
|
+
}
|
|
5368
|
+
${isDark ? `.reveal .slide-quote { color: ${text}; }` : ""}
|
|
5369
|
+
|
|
5370
|
+
/* Single statement: Clean, centered, impactful */
|
|
5371
|
+
.reveal .slide-single-statement {
|
|
5372
|
+
background: var(--color-background);
|
|
5373
|
+
}
|
|
5374
|
+
.reveal .slide-single-statement .statement,
|
|
5375
|
+
.reveal .slide-single-statement .big-idea-text {
|
|
5376
|
+
font-size: 2.2em;
|
|
5377
|
+
max-width: 80%;
|
|
5378
|
+
margin: 0 auto;
|
|
5379
|
+
}
|
|
5380
|
+
|
|
5381
|
+
/* Comparison slides: Split visual */
|
|
5382
|
+
.reveal .slide-comparison .columns {
|
|
5383
|
+
gap: 60px;
|
|
5384
|
+
}
|
|
5385
|
+
.reveal .slide-comparison .column:first-child {
|
|
5386
|
+
border-right: 2px solid ${this.lightenColor(secondary, 70)};
|
|
5387
|
+
padding-right: 30px;
|
|
5388
|
+
}
|
|
5389
|
+
|
|
5390
|
+
/* Timeline/Process: Visual flow */
|
|
5391
|
+
.reveal .slide-timeline .steps,
|
|
5392
|
+
.reveal .slide-process .steps {
|
|
5393
|
+
display: flex;
|
|
5394
|
+
gap: 20px;
|
|
5395
|
+
}
|
|
5396
|
+
.reveal .slide-timeline .step,
|
|
5397
|
+
.reveal .slide-process .step {
|
|
5398
|
+
flex: 1;
|
|
5399
|
+
padding: 20px;
|
|
5400
|
+
background: ${isDark ? this.lightenColor(background, 10) : this.lightenColor(secondary, 92)};
|
|
5401
|
+
border-radius: 8px;
|
|
5402
|
+
border-top: 4px solid var(--color-accent);
|
|
5403
|
+
${isDark ? `color: ${text};` : ""}
|
|
5404
|
+
}
|
|
5405
|
+
|
|
5406
|
+
/* Progress bar enhancement */
|
|
5407
|
+
.reveal .progress {
|
|
5408
|
+
background: ${this.lightenColor(primary, 80)};
|
|
5409
|
+
height: 4px;
|
|
5410
|
+
}
|
|
5411
|
+
.reveal .progress span {
|
|
5412
|
+
background: var(--color-highlight);
|
|
5413
|
+
}
|
|
5151
5414
|
`;
|
|
5152
5415
|
}
|
|
5153
5416
|
/**
|
|
@@ -5163,6 +5426,37 @@ ${slides}
|
|
|
5163
5426
|
b = Math.min(255, Math.floor(b + (255 - b) * (percent / 100)));
|
|
5164
5427
|
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
5165
5428
|
}
|
|
5429
|
+
/**
|
|
5430
|
+
* Check if a palette is "dark mode" (dark background, light text)
|
|
5431
|
+
*/
|
|
5432
|
+
isDarkPalette(palette) {
|
|
5433
|
+
const bgLuminance = this.getLuminance(palette.background || "#ffffff");
|
|
5434
|
+
const textLuminance = this.getLuminance(palette.text || "#000000");
|
|
5435
|
+
return bgLuminance < textLuminance;
|
|
5436
|
+
}
|
|
5437
|
+
/**
|
|
5438
|
+
* Get relative luminance of a hex color (0-1, 0=black, 1=white)
|
|
5439
|
+
*/
|
|
5440
|
+
getLuminance(hex) {
|
|
5441
|
+
hex = hex.replace("#", "");
|
|
5442
|
+
const r = parseInt(hex.substring(0, 2), 16) / 255;
|
|
5443
|
+
const g = parseInt(hex.substring(2, 4), 16) / 255;
|
|
5444
|
+
const b = parseInt(hex.substring(4, 6), 16) / 255;
|
|
5445
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
5446
|
+
}
|
|
5447
|
+
/**
|
|
5448
|
+
* Darken a hex color
|
|
5449
|
+
*/
|
|
5450
|
+
darkenColor(hex, percent) {
|
|
5451
|
+
hex = hex.replace("#", "");
|
|
5452
|
+
let r = parseInt(hex.substring(0, 2), 16);
|
|
5453
|
+
let g = parseInt(hex.substring(2, 4), 16);
|
|
5454
|
+
let b = parseInt(hex.substring(4, 6), 16);
|
|
5455
|
+
r = Math.max(0, Math.floor(r * (1 - percent / 100)));
|
|
5456
|
+
g = Math.max(0, Math.floor(g * (1 - percent / 100)));
|
|
5457
|
+
b = Math.max(0, Math.floor(b * (1 - percent / 100)));
|
|
5458
|
+
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
5459
|
+
}
|
|
5166
5460
|
/**
|
|
5167
5461
|
* Get theme-specific styles - KB-DRIVEN
|
|
5168
5462
|
*/
|
|
@@ -5379,15 +5673,15 @@ var IterativeQAEngine = class {
|
|
|
5379
5673
|
let autoFixSummary = "";
|
|
5380
5674
|
let totalFixesApplied = 0;
|
|
5381
5675
|
if (opts.verbose) {
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5676
|
+
logger.progress("\n\u{1F504} Starting Iterative QA Process");
|
|
5677
|
+
logger.info(` Target Score: ${opts.minScore}/100`);
|
|
5678
|
+
logger.info(` Max Iterations: ${opts.maxIterations}`);
|
|
5679
|
+
logger.progress("");
|
|
5386
5680
|
}
|
|
5387
5681
|
for (let i = 0; i < opts.maxIterations; i++) {
|
|
5388
5682
|
const iterationNum = i + 1;
|
|
5389
5683
|
if (opts.verbose) {
|
|
5390
|
-
|
|
5684
|
+
logger.progress(`\u{1F4CA} Iteration ${iterationNum}/${opts.maxIterations}...`);
|
|
5391
5685
|
}
|
|
5392
5686
|
scoringResult = await this.scorer.score(currentSlides, currentHtml, opts.minScore);
|
|
5393
5687
|
iterations.push({
|
|
@@ -5406,17 +5700,17 @@ var IterativeQAEngine = class {
|
|
|
5406
5700
|
timestamp: /* @__PURE__ */ new Date()
|
|
5407
5701
|
});
|
|
5408
5702
|
if (opts.verbose) {
|
|
5409
|
-
|
|
5703
|
+
logger.info(` Score: ${scoringResult.overallScore}/100`);
|
|
5410
5704
|
}
|
|
5411
5705
|
if (scoringResult.passed) {
|
|
5412
5706
|
if (opts.verbose) {
|
|
5413
|
-
|
|
5707
|
+
logger.success(`PASSED - Score meets threshold (${opts.minScore})`);
|
|
5414
5708
|
}
|
|
5415
5709
|
break;
|
|
5416
5710
|
}
|
|
5417
5711
|
if (i < opts.maxIterations - 1) {
|
|
5418
5712
|
if (opts.verbose) {
|
|
5419
|
-
|
|
5713
|
+
logger.warn("Below threshold, applying auto-fixes...");
|
|
5420
5714
|
}
|
|
5421
5715
|
const fixResult = await this.fixer.fix(currentSlides, scoringResult);
|
|
5422
5716
|
if (fixResult.fixesApplied.length > 0) {
|
|
@@ -5428,12 +5722,12 @@ var IterativeQAEngine = class {
|
|
|
5428
5722
|
}
|
|
5429
5723
|
totalFixesApplied += fixResult.fixesApplied.length;
|
|
5430
5724
|
if (opts.verbose) {
|
|
5431
|
-
|
|
5725
|
+
logger.info(` \u{1F527} Applied ${fixResult.fixesApplied.length} fixes`);
|
|
5432
5726
|
}
|
|
5433
5727
|
autoFixSummary += fixResult.summary + "\n";
|
|
5434
5728
|
} else {
|
|
5435
5729
|
if (opts.verbose) {
|
|
5436
|
-
|
|
5730
|
+
logger.warn("No auto-fixes available, manual review needed");
|
|
5437
5731
|
}
|
|
5438
5732
|
break;
|
|
5439
5733
|
}
|
|
@@ -5449,7 +5743,7 @@ var IterativeQAEngine = class {
|
|
|
5449
5743
|
totalFixesApplied
|
|
5450
5744
|
);
|
|
5451
5745
|
if (opts.verbose) {
|
|
5452
|
-
|
|
5746
|
+
logger.info(report);
|
|
5453
5747
|
}
|
|
5454
5748
|
return {
|
|
5455
5749
|
finalScore: scoringResult.overallScore,
|
|
@@ -6251,6 +6545,172 @@ var PowerPointGenerator = class {
|
|
|
6251
6545
|
}
|
|
6252
6546
|
};
|
|
6253
6547
|
|
|
6548
|
+
// src/generators/PDFGenerator.ts
|
|
6549
|
+
var import_puppeteer = __toESM(require("puppeteer"));
|
|
6550
|
+
var PDFGenerator = class {
|
|
6551
|
+
defaultOptions = {
|
|
6552
|
+
orientation: "landscape",
|
|
6553
|
+
printBackground: true,
|
|
6554
|
+
format: "Slide",
|
|
6555
|
+
scale: 1
|
|
6556
|
+
};
|
|
6557
|
+
/**
|
|
6558
|
+
* Generate PDF from HTML presentation
|
|
6559
|
+
* @param html - The HTML content of the presentation
|
|
6560
|
+
* @param options - PDF generation options
|
|
6561
|
+
* @returns Buffer containing the PDF file
|
|
6562
|
+
*/
|
|
6563
|
+
async generate(html, options = {}) {
|
|
6564
|
+
const opts = { ...this.defaultOptions, ...options };
|
|
6565
|
+
logger.progress("\u{1F4C4} Generating PDF...");
|
|
6566
|
+
let browser;
|
|
6567
|
+
try {
|
|
6568
|
+
browser = await import_puppeteer.default.launch({
|
|
6569
|
+
headless: true,
|
|
6570
|
+
args: [
|
|
6571
|
+
"--no-sandbox",
|
|
6572
|
+
"--disable-setuid-sandbox",
|
|
6573
|
+
"--disable-dev-shm-usage"
|
|
6574
|
+
]
|
|
6575
|
+
});
|
|
6576
|
+
const page = await browser.newPage();
|
|
6577
|
+
const printHtml = this.preparePrintHtml(html);
|
|
6578
|
+
await page.setViewport({
|
|
6579
|
+
width: 1920,
|
|
6580
|
+
height: 1080
|
|
6581
|
+
});
|
|
6582
|
+
await page.setContent(printHtml, {
|
|
6583
|
+
waitUntil: ["networkidle0", "domcontentloaded"]
|
|
6584
|
+
});
|
|
6585
|
+
await page.evaluate(() => {
|
|
6586
|
+
return new Promise((resolve) => {
|
|
6587
|
+
if (document.fonts && document.fonts.ready) {
|
|
6588
|
+
document.fonts.ready.then(() => resolve());
|
|
6589
|
+
} else {
|
|
6590
|
+
setTimeout(resolve, 1e3);
|
|
6591
|
+
}
|
|
6592
|
+
});
|
|
6593
|
+
});
|
|
6594
|
+
const pdfBuffer = await page.pdf({
|
|
6595
|
+
width: "1920px",
|
|
6596
|
+
height: "1080px",
|
|
6597
|
+
printBackground: opts.printBackground,
|
|
6598
|
+
scale: opts.scale,
|
|
6599
|
+
landscape: opts.orientation === "landscape",
|
|
6600
|
+
margin: {
|
|
6601
|
+
top: "0px",
|
|
6602
|
+
right: "0px",
|
|
6603
|
+
bottom: "0px",
|
|
6604
|
+
left: "0px"
|
|
6605
|
+
}
|
|
6606
|
+
});
|
|
6607
|
+
logger.step("PDF generated successfully");
|
|
6608
|
+
return Buffer.from(pdfBuffer);
|
|
6609
|
+
} catch (error) {
|
|
6610
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6611
|
+
logger.error(`PDF generation failed: ${errorMessage}`);
|
|
6612
|
+
throw new Error(`PDF generation failed: ${errorMessage}`);
|
|
6613
|
+
} finally {
|
|
6614
|
+
if (browser) {
|
|
6615
|
+
await browser.close();
|
|
6616
|
+
}
|
|
6617
|
+
}
|
|
6618
|
+
}
|
|
6619
|
+
/**
|
|
6620
|
+
* Prepare HTML for print/PDF output
|
|
6621
|
+
* Modifies the HTML to work better as a printed document
|
|
6622
|
+
*/
|
|
6623
|
+
preparePrintHtml(html) {
|
|
6624
|
+
const printCss = `
|
|
6625
|
+
<style id="pdf-print-styles">
|
|
6626
|
+
/* Print-specific overrides */
|
|
6627
|
+
@page {
|
|
6628
|
+
size: 1920px 1080px;
|
|
6629
|
+
margin: 0;
|
|
6630
|
+
}
|
|
6631
|
+
|
|
6632
|
+
@media print {
|
|
6633
|
+
html, body {
|
|
6634
|
+
margin: 0;
|
|
6635
|
+
padding: 0;
|
|
6636
|
+
width: 1920px;
|
|
6637
|
+
height: 1080px;
|
|
6638
|
+
}
|
|
6639
|
+
|
|
6640
|
+
.reveal .slides {
|
|
6641
|
+
width: 100% !important;
|
|
6642
|
+
height: 100% !important;
|
|
6643
|
+
margin: 0 !important;
|
|
6644
|
+
padding: 0 !important;
|
|
6645
|
+
transform: none !important;
|
|
6646
|
+
}
|
|
6647
|
+
|
|
6648
|
+
.reveal .slides section {
|
|
6649
|
+
page-break-after: always;
|
|
6650
|
+
page-break-inside: avoid;
|
|
6651
|
+
width: 1920px !important;
|
|
6652
|
+
height: 1080px !important;
|
|
6653
|
+
margin: 0 !important;
|
|
6654
|
+
padding: 60px !important;
|
|
6655
|
+
box-sizing: border-box;
|
|
6656
|
+
position: relative !important;
|
|
6657
|
+
top: auto !important;
|
|
6658
|
+
left: auto !important;
|
|
6659
|
+
transform: none !important;
|
|
6660
|
+
display: flex !important;
|
|
6661
|
+
opacity: 1 !important;
|
|
6662
|
+
visibility: visible !important;
|
|
6663
|
+
}
|
|
6664
|
+
|
|
6665
|
+
.reveal .slides section:last-child {
|
|
6666
|
+
page-break-after: auto;
|
|
6667
|
+
}
|
|
6668
|
+
|
|
6669
|
+
/* Make all slides visible for printing */
|
|
6670
|
+
.reveal .slides section.future,
|
|
6671
|
+
.reveal .slides section.past {
|
|
6672
|
+
display: flex !important;
|
|
6673
|
+
opacity: 1 !important;
|
|
6674
|
+
visibility: visible !important;
|
|
6675
|
+
}
|
|
6676
|
+
|
|
6677
|
+
/* Disable animations for print */
|
|
6678
|
+
* {
|
|
6679
|
+
animation: none !important;
|
|
6680
|
+
transition: none !important;
|
|
6681
|
+
}
|
|
6682
|
+
|
|
6683
|
+
/* Hide Reveal.js controls */
|
|
6684
|
+
.reveal .controls,
|
|
6685
|
+
.reveal .progress,
|
|
6686
|
+
.reveal .slide-number,
|
|
6687
|
+
.reveal .speaker-notes,
|
|
6688
|
+
.reveal .navigate-left,
|
|
6689
|
+
.reveal .navigate-right,
|
|
6690
|
+
.reveal .navigate-up,
|
|
6691
|
+
.reveal .navigate-down {
|
|
6692
|
+
display: none !important;
|
|
6693
|
+
}
|
|
6694
|
+
}
|
|
6695
|
+
|
|
6696
|
+
/* Force print mode in Puppeteer */
|
|
6697
|
+
.reveal .slides section {
|
|
6698
|
+
page-break-after: always;
|
|
6699
|
+
page-break-inside: avoid;
|
|
6700
|
+
}
|
|
6701
|
+
</style>
|
|
6702
|
+
`;
|
|
6703
|
+
if (html.includes("</head>")) {
|
|
6704
|
+
return html.replace("</head>", `${printCss}</head>`);
|
|
6705
|
+
} else {
|
|
6706
|
+
return printCss + html;
|
|
6707
|
+
}
|
|
6708
|
+
}
|
|
6709
|
+
};
|
|
6710
|
+
function createPDFGenerator() {
|
|
6711
|
+
return new PDFGenerator();
|
|
6712
|
+
}
|
|
6713
|
+
|
|
6254
6714
|
// src/core/PresentationEngine.ts
|
|
6255
6715
|
var PresentationEngine = class {
|
|
6256
6716
|
contentAnalyzer;
|
|
@@ -6259,6 +6719,7 @@ var PresentationEngine = class {
|
|
|
6259
6719
|
qaEngine;
|
|
6260
6720
|
htmlGenerator;
|
|
6261
6721
|
pptxGenerator;
|
|
6722
|
+
pdfGenerator;
|
|
6262
6723
|
kb;
|
|
6263
6724
|
constructor() {
|
|
6264
6725
|
this.contentAnalyzer = new ContentAnalyzer();
|
|
@@ -6267,6 +6728,7 @@ var PresentationEngine = class {
|
|
|
6267
6728
|
this.qaEngine = new QAEngine();
|
|
6268
6729
|
this.htmlGenerator = new RevealJsGenerator();
|
|
6269
6730
|
this.pptxGenerator = new PowerPointGenerator();
|
|
6731
|
+
this.pdfGenerator = createPDFGenerator();
|
|
6270
6732
|
}
|
|
6271
6733
|
/**
|
|
6272
6734
|
* Generate a presentation from content.
|
|
@@ -6276,26 +6738,26 @@ var PresentationEngine = class {
|
|
|
6276
6738
|
*/
|
|
6277
6739
|
async generate(config) {
|
|
6278
6740
|
this.validateConfig(config);
|
|
6279
|
-
|
|
6741
|
+
logger.progress("\u{1F4DA} Loading knowledge base...");
|
|
6280
6742
|
this.kb = await getKnowledgeGateway();
|
|
6281
|
-
|
|
6743
|
+
logger.progress("\u{1F4DD} Analyzing content...");
|
|
6282
6744
|
const analysis = await this.contentAnalyzer.analyze(config.content, config.contentType);
|
|
6283
6745
|
const presentationType = config.presentationType || analysis.detectedType;
|
|
6284
|
-
|
|
6746
|
+
logger.step(`Presentation type: ${presentationType}`);
|
|
6285
6747
|
const slideFactory = createSlideFactory(this.kb, presentationType);
|
|
6286
|
-
|
|
6748
|
+
logger.progress("\u{1F3A8} Creating slides...");
|
|
6287
6749
|
const slides = await slideFactory.createSlides(analysis);
|
|
6288
|
-
|
|
6750
|
+
logger.progress("\u2705 Validating structure...");
|
|
6289
6751
|
const structureErrors = this.validateStructure(slides, config.mode);
|
|
6290
6752
|
if (structureErrors.length > 0) {
|
|
6291
6753
|
if (config.skipQA) {
|
|
6292
|
-
|
|
6293
|
-
structureErrors.forEach((e) =>
|
|
6754
|
+
logger.warn("Structure warnings (bypassed):");
|
|
6755
|
+
structureErrors.forEach((e) => logger.warn(` \u2022 ${e}`));
|
|
6294
6756
|
} else {
|
|
6295
6757
|
throw new ValidationError(structureErrors, "Slide structure validation failed");
|
|
6296
6758
|
}
|
|
6297
6759
|
}
|
|
6298
|
-
|
|
6760
|
+
logger.progress("\u{1F528} Generating outputs...");
|
|
6299
6761
|
const outputs = {};
|
|
6300
6762
|
if (config.format.includes("html")) {
|
|
6301
6763
|
outputs.html = await this.htmlGenerator.generate(slides, config);
|
|
@@ -6313,7 +6775,7 @@ var PresentationEngine = class {
|
|
|
6313
6775
|
const maxIterations = config.maxIterations ?? 5;
|
|
6314
6776
|
const useIterativeQA = config.useIterativeQA !== false;
|
|
6315
6777
|
if (useIterativeQA) {
|
|
6316
|
-
|
|
6778
|
+
logger.progress("\u{1F50D} Running Iterative QA (7-Dimension Scoring)...");
|
|
6317
6779
|
const iterativeEngine = createIterativeQAEngine(
|
|
6318
6780
|
config.mode,
|
|
6319
6781
|
presentationType,
|
|
@@ -6335,20 +6797,30 @@ var PresentationEngine = class {
|
|
|
6335
6797
|
throw new QAFailureError(score, threshold, qaResults);
|
|
6336
6798
|
}
|
|
6337
6799
|
} else {
|
|
6338
|
-
|
|
6800
|
+
logger.progress("\u{1F50D} Running QA validation (legacy mode)...");
|
|
6339
6801
|
qaResults = await this.qaEngine.validate(outputs.html, {
|
|
6340
6802
|
mode: config.mode,
|
|
6341
6803
|
strictMode: true
|
|
6342
6804
|
});
|
|
6343
6805
|
score = this.scoreCalculator.calculate(qaResults);
|
|
6344
|
-
|
|
6806
|
+
logger.info(`\u{1F4CA} QA Score: ${score}/100`);
|
|
6345
6807
|
if (score < threshold) {
|
|
6346
6808
|
throw new QAFailureError(score, threshold, qaResults);
|
|
6347
6809
|
}
|
|
6348
6810
|
}
|
|
6349
6811
|
} else {
|
|
6350
6812
|
qaResults = this.qaEngine.createEmptyResults();
|
|
6351
|
-
|
|
6813
|
+
logger.warn("QA validation skipped (NOT RECOMMENDED)");
|
|
6814
|
+
}
|
|
6815
|
+
if (outputs.html && (config.format.includes("pdf") || config.generatePdf !== false)) {
|
|
6816
|
+
try {
|
|
6817
|
+
logger.progress("\u{1F4C4} Generating PDF from validated HTML...");
|
|
6818
|
+
outputs.pdf = await this.pdfGenerator.generate(outputs.html);
|
|
6819
|
+
logger.step("PDF generated successfully");
|
|
6820
|
+
} catch (pdfError) {
|
|
6821
|
+
const errorMsg = pdfError instanceof Error ? pdfError.message : String(pdfError);
|
|
6822
|
+
logger.warn(`PDF generation failed (non-critical): ${errorMsg}`);
|
|
6823
|
+
}
|
|
6352
6824
|
}
|
|
6353
6825
|
const metadata = this.buildMetadata(config, analysis, finalSlides, iterativeResult);
|
|
6354
6826
|
return {
|
|
@@ -6436,15 +6908,28 @@ var PresentationEngine = class {
|
|
|
6436
6908
|
if (slides.length < 3) {
|
|
6437
6909
|
errors.push("Presentation must have at least 3 slides");
|
|
6438
6910
|
}
|
|
6911
|
+
const sparseByDesignTypes = [
|
|
6912
|
+
"title",
|
|
6913
|
+
"section-divider",
|
|
6914
|
+
"thank-you",
|
|
6915
|
+
"big-number",
|
|
6916
|
+
"single-statement",
|
|
6917
|
+
"cta",
|
|
6918
|
+
"agenda",
|
|
6919
|
+
"metrics-grid",
|
|
6920
|
+
"quote",
|
|
6921
|
+
"image-focus"
|
|
6922
|
+
];
|
|
6439
6923
|
slides.forEach((slide, index) => {
|
|
6440
6924
|
const wordCount = this.countWords(slide);
|
|
6441
6925
|
if (mode === "keynote") {
|
|
6442
|
-
if (wordCount > 25) {
|
|
6926
|
+
if (wordCount > 25 && !sparseByDesignTypes.includes(slide.type)) {
|
|
6443
6927
|
errors.push(`Slide ${index + 1}: ${wordCount} words exceeds keynote limit of 25`);
|
|
6444
6928
|
}
|
|
6445
6929
|
} else {
|
|
6446
|
-
|
|
6447
|
-
|
|
6930
|
+
const requiresMinWords = ["bullet-points", "two-column", "process-flow"];
|
|
6931
|
+
if (wordCount < 20 && requiresMinWords.includes(slide.type)) {
|
|
6932
|
+
logger.warn(`Slide ${index + 1}: ${wordCount} words is sparse for ${slide.type} slide`);
|
|
6448
6933
|
}
|
|
6449
6934
|
if (wordCount > 100) {
|
|
6450
6935
|
errors.push(`Slide ${index + 1}: ${wordCount} words exceeds business limit of 100`);
|
|
@@ -6538,11 +7023,11 @@ var SlideGenerator = class {
|
|
|
6538
7023
|
await this.initialize();
|
|
6539
7024
|
this.presentationType = type || analysis.detectedType;
|
|
6540
7025
|
this.mode = this.kb.getModeForType(this.presentationType);
|
|
6541
|
-
|
|
7026
|
+
logger.step(`Using ${this.mode} mode for ${this.presentationType}`);
|
|
6542
7027
|
this.factory = createSlideFactory(this.kb, this.presentationType);
|
|
6543
7028
|
const slides = await this.factory.createSlides(analysis);
|
|
6544
7029
|
const legacySlides = this.convertToLegacyFormat(slides);
|
|
6545
|
-
|
|
7030
|
+
logger.step(`Generated ${legacySlides.length} KB-validated slides`);
|
|
6546
7031
|
return legacySlides;
|
|
6547
7032
|
}
|
|
6548
7033
|
/**
|