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.mjs
CHANGED
|
@@ -31,6 +31,75 @@ import { readFileSync } from "fs";
|
|
|
31
31
|
import { join, dirname } from "path";
|
|
32
32
|
import { fileURLToPath } from "url";
|
|
33
33
|
import * as yaml from "yaml";
|
|
34
|
+
|
|
35
|
+
// src/utils/Logger.ts
|
|
36
|
+
var Logger = class {
|
|
37
|
+
level;
|
|
38
|
+
prefix;
|
|
39
|
+
timestamps;
|
|
40
|
+
constructor(options = {}) {
|
|
41
|
+
this.level = options.level ?? 1 /* INFO */;
|
|
42
|
+
this.prefix = options.prefix ?? "";
|
|
43
|
+
this.timestamps = options.timestamps ?? false;
|
|
44
|
+
}
|
|
45
|
+
setLevel(level) {
|
|
46
|
+
this.level = level;
|
|
47
|
+
}
|
|
48
|
+
formatMessage(message) {
|
|
49
|
+
const parts = [];
|
|
50
|
+
if (this.timestamps) {
|
|
51
|
+
parts.push(`[${(/* @__PURE__ */ new Date()).toISOString()}]`);
|
|
52
|
+
}
|
|
53
|
+
if (this.prefix) {
|
|
54
|
+
parts.push(`[${this.prefix}]`);
|
|
55
|
+
}
|
|
56
|
+
parts.push(message);
|
|
57
|
+
return parts.join(" ");
|
|
58
|
+
}
|
|
59
|
+
debug(message, ...args) {
|
|
60
|
+
if (this.level <= 0 /* DEBUG */) {
|
|
61
|
+
console.debug(this.formatMessage(message), ...args);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
info(message, ...args) {
|
|
65
|
+
if (this.level <= 1 /* INFO */) {
|
|
66
|
+
console.info(this.formatMessage(message), ...args);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
warn(message, ...args) {
|
|
70
|
+
if (this.level <= 2 /* WARN */) {
|
|
71
|
+
console.warn(this.formatMessage(message), ...args);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
error(message, ...args) {
|
|
75
|
+
if (this.level <= 3 /* ERROR */) {
|
|
76
|
+
console.error(this.formatMessage(message), ...args);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
// Progress messages (always shown unless silent)
|
|
80
|
+
progress(message) {
|
|
81
|
+
if (this.level < 4 /* SILENT */) {
|
|
82
|
+
console.info(message);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Success messages
|
|
86
|
+
success(message) {
|
|
87
|
+
if (this.level < 4 /* SILENT */) {
|
|
88
|
+
console.info(`\u2705 ${message}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// Step messages for workflow progress
|
|
92
|
+
step(message) {
|
|
93
|
+
if (this.level <= 1 /* INFO */) {
|
|
94
|
+
console.info(` \u2713 ${message}`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
var logger = new Logger({
|
|
99
|
+
level: process.env.LOG_LEVEL ? parseInt(process.env.LOG_LEVEL) : 1 /* INFO */
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// src/kb/KnowledgeGateway.ts
|
|
34
103
|
function getModuleDir() {
|
|
35
104
|
if (typeof import.meta !== "undefined" && import.meta.url) {
|
|
36
105
|
return dirname(fileURLToPath(import.meta.url));
|
|
@@ -41,7 +110,7 @@ function getModuleDir() {
|
|
|
41
110
|
return process.cwd();
|
|
42
111
|
}
|
|
43
112
|
var KnowledgeGateway = class {
|
|
44
|
-
kb;
|
|
113
|
+
kb = {};
|
|
45
114
|
loaded = false;
|
|
46
115
|
constructor() {
|
|
47
116
|
}
|
|
@@ -64,7 +133,7 @@ var KnowledgeGateway = class {
|
|
|
64
133
|
const content = readFileSync(path, "utf-8");
|
|
65
134
|
this.kb = yaml.parse(content);
|
|
66
135
|
this.loaded = true;
|
|
67
|
-
|
|
136
|
+
logger.step(`Knowledge base loaded from ${path}`);
|
|
68
137
|
return;
|
|
69
138
|
} catch {
|
|
70
139
|
}
|
|
@@ -255,7 +324,7 @@ var KnowledgeGateway = class {
|
|
|
255
324
|
*/
|
|
256
325
|
getChartGuidance(purpose) {
|
|
257
326
|
this.ensureLoaded();
|
|
258
|
-
return this.kb.chart_selection_guide.by_purpose[purpose];
|
|
327
|
+
return this.kb.chart_selection_guide.by_purpose?.[purpose];
|
|
259
328
|
}
|
|
260
329
|
/**
|
|
261
330
|
* Get charts to avoid
|
|
@@ -270,7 +339,7 @@ var KnowledgeGateway = class {
|
|
|
270
339
|
*/
|
|
271
340
|
getIBPitchBookStructure(type) {
|
|
272
341
|
this.ensureLoaded();
|
|
273
|
-
return this.kb.investment_banking?.pitch_book_types[type];
|
|
342
|
+
return this.kb.investment_banking?.pitch_book_types?.[type];
|
|
274
343
|
}
|
|
275
344
|
/**
|
|
276
345
|
* Check if knowledge base is loaded
|
|
@@ -822,14 +891,14 @@ var ContentAnalyzer = class {
|
|
|
822
891
|
const text = this.parseContent(content, contentType);
|
|
823
892
|
const title = this.extractTitle(text);
|
|
824
893
|
const detectedType = this.detectPresentationType(text);
|
|
825
|
-
|
|
894
|
+
logger.step(`Detected type: ${detectedType}`);
|
|
826
895
|
const sections = this.extractSections(text);
|
|
827
|
-
|
|
896
|
+
logger.step(`Found ${sections.length} sections`);
|
|
828
897
|
const scqa = this.extractSCQA(text);
|
|
829
898
|
const sparkline = this.extractSparkline(text);
|
|
830
899
|
const keyMessages = this.extractKeyMessages(text);
|
|
831
900
|
const dataPoints = this.extractDataPoints(text);
|
|
832
|
-
|
|
901
|
+
logger.step(`Found ${dataPoints.length} data points`);
|
|
833
902
|
const titles = sections.map((s) => s.header).filter((h) => h.length > 0);
|
|
834
903
|
const starMoments = this.extractStarMoments(text);
|
|
835
904
|
const estimatedSlideCount = Math.max(5, sections.length + 3);
|
|
@@ -949,12 +1018,16 @@ var ContentAnalyzer = class {
|
|
|
949
1018
|
}
|
|
950
1019
|
const bulletMatch = trimmedLine.match(/^[-*+]\s+(.+)$/);
|
|
951
1020
|
if (bulletMatch && bulletMatch[1] && currentSection) {
|
|
952
|
-
|
|
1021
|
+
const bulletText = bulletMatch[1];
|
|
1022
|
+
currentSection.bullets.push(bulletText);
|
|
1023
|
+
this.extractMetricsFromText(bulletText, currentSection.metrics);
|
|
953
1024
|
continue;
|
|
954
1025
|
}
|
|
955
1026
|
const numberedMatch = trimmedLine.match(/^\d+\.\s+(.+)$/);
|
|
956
1027
|
if (numberedMatch && numberedMatch[1] && currentSection) {
|
|
957
|
-
|
|
1028
|
+
const itemText = numberedMatch[1];
|
|
1029
|
+
currentSection.bullets.push(itemText);
|
|
1030
|
+
this.extractMetricsFromText(itemText, currentSection.metrics);
|
|
958
1031
|
continue;
|
|
959
1032
|
}
|
|
960
1033
|
const metricMatch = trimmedLine.match(/\$?([\d,]+\.?\d*)[%]?\s*[-–—:]\s*(.+)/);
|
|
@@ -965,6 +1038,9 @@ var ContentAnalyzer = class {
|
|
|
965
1038
|
});
|
|
966
1039
|
continue;
|
|
967
1040
|
}
|
|
1041
|
+
if (currentSection && trimmedLine) {
|
|
1042
|
+
this.extractMetricsFromText(trimmedLine, currentSection.metrics);
|
|
1043
|
+
}
|
|
968
1044
|
if (trimmedLine.includes("|") && currentSection) {
|
|
969
1045
|
const cells = trimmedLine.split("|").map((c) => c.trim()).filter((c) => c && !c.match(/^-+$/));
|
|
970
1046
|
if (cells.length >= 2) {
|
|
@@ -1336,6 +1412,49 @@ var ContentAnalyzer = class {
|
|
|
1336
1412
|
const fallback = cleaned.slice(0, 150);
|
|
1337
1413
|
return fallback.length >= 20 ? fallback : "";
|
|
1338
1414
|
}
|
|
1415
|
+
/**
|
|
1416
|
+
* Extract metrics from natural language text
|
|
1417
|
+
* Handles formats like "40% productivity loss", "$2.5M investment"
|
|
1418
|
+
*/
|
|
1419
|
+
extractMetricsFromText(text, metrics) {
|
|
1420
|
+
const usedValues = new Set(metrics.map((m) => m.value));
|
|
1421
|
+
const moneyMatches = text.matchAll(/(\$[\d,.]+[MBK]?)\s+([a-zA-Z][a-zA-Z\s]{2,30})/g);
|
|
1422
|
+
for (const match of moneyMatches) {
|
|
1423
|
+
const value = match[1];
|
|
1424
|
+
const rawLabel = match[2]?.trim();
|
|
1425
|
+
if (value && rawLabel && !usedValues.has(value)) {
|
|
1426
|
+
usedValues.add(value);
|
|
1427
|
+
metrics.push({ value, label: this.cleanMetricLabel(rawLabel) });
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
const percentMatches = text.matchAll(/(\d+(?:\.\d+)?%)\s+([a-zA-Z][a-zA-Z\s]{2,30})/g);
|
|
1431
|
+
for (const match of percentMatches) {
|
|
1432
|
+
const value = match[1];
|
|
1433
|
+
const rawLabel = match[2]?.trim();
|
|
1434
|
+
if (value && rawLabel && !usedValues.has(value)) {
|
|
1435
|
+
usedValues.add(value);
|
|
1436
|
+
metrics.push({ value, label: this.cleanMetricLabel(rawLabel) });
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
const multMatches = text.matchAll(/(\d+[xX])\s+([a-zA-Z][a-zA-Z\s]{2,20})/g);
|
|
1440
|
+
for (const match of multMatches) {
|
|
1441
|
+
const value = match[1];
|
|
1442
|
+
const rawLabel = match[2]?.trim();
|
|
1443
|
+
if (value && rawLabel && !usedValues.has(value)) {
|
|
1444
|
+
usedValues.add(value);
|
|
1445
|
+
metrics.push({ value, label: this.cleanMetricLabel(rawLabel) });
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
const numMatches = text.matchAll(/(\d{3,}\+?)\s+([a-zA-Z][a-zA-Z\s]{2,20})/g);
|
|
1449
|
+
for (const match of numMatches) {
|
|
1450
|
+
const value = match[1];
|
|
1451
|
+
const rawLabel = match[2]?.trim();
|
|
1452
|
+
if (value && rawLabel && !usedValues.has(value)) {
|
|
1453
|
+
usedValues.add(value);
|
|
1454
|
+
metrics.push({ value, label: this.cleanMetricLabel(rawLabel) });
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1339
1458
|
};
|
|
1340
1459
|
|
|
1341
1460
|
// src/core/ContentPatternClassifier.ts
|
|
@@ -1520,8 +1639,8 @@ var SlideFactory = class {
|
|
|
1520
1639
|
this.usedContent = /* @__PURE__ */ new Set();
|
|
1521
1640
|
this.usedTitles = /* @__PURE__ */ new Set();
|
|
1522
1641
|
this.config = this.loadKBConfig(type);
|
|
1523
|
-
|
|
1524
|
-
|
|
1642
|
+
logger.step(`SlideFactory v7.1.0 initialized for ${type} (${this.config.mode} mode)`);
|
|
1643
|
+
logger.step(`KB Config loaded: ${this.config.allowedTypes.length} allowed types`);
|
|
1525
1644
|
}
|
|
1526
1645
|
/**
|
|
1527
1646
|
* Load ALL configuration from KB - ZERO hardcoded values after this.
|
|
@@ -1549,7 +1668,7 @@ var SlideFactory = class {
|
|
|
1549
1668
|
async createSlides(analysis) {
|
|
1550
1669
|
const slides = [];
|
|
1551
1670
|
const storyStructure = this.kb.getStoryStructure(this.presentationType);
|
|
1552
|
-
|
|
1671
|
+
logger.step(`Using ${storyStructure.framework} story framework`);
|
|
1553
1672
|
slides.push(this.createTitleSlide(0, analysis));
|
|
1554
1673
|
const minSectionsForAgenda = Math.max(3, this.config.rules.bulletsPerSlide.max - 2);
|
|
1555
1674
|
if (this.config.mode === "business" && analysis.sections.length >= minSectionsForAgenda) {
|
|
@@ -1587,7 +1706,7 @@ var SlideFactory = class {
|
|
|
1587
1706
|
const validatedSlides = this.validateAndFixSlides(slides);
|
|
1588
1707
|
this.checkRequiredElements(validatedSlides);
|
|
1589
1708
|
this.checkAntiPatterns(validatedSlides);
|
|
1590
|
-
|
|
1709
|
+
logger.step(`Created ${validatedSlides.length} validated slides`);
|
|
1591
1710
|
return validatedSlides;
|
|
1592
1711
|
}
|
|
1593
1712
|
// ===========================================================================
|
|
@@ -1628,7 +1747,7 @@ var SlideFactory = class {
|
|
|
1628
1747
|
case "technical":
|
|
1629
1748
|
return this.createCodeSlide(index, section);
|
|
1630
1749
|
default:
|
|
1631
|
-
|
|
1750
|
+
logger.warn(`Unknown slide type '${type}', using bullet-points`);
|
|
1632
1751
|
return this.createBulletSlide(index, section);
|
|
1633
1752
|
}
|
|
1634
1753
|
}
|
|
@@ -1761,15 +1880,19 @@ var SlideFactory = class {
|
|
|
1761
1880
|
// CONTENT SLIDES - ALL values from KB
|
|
1762
1881
|
// ===========================================================================
|
|
1763
1882
|
createBigNumberSlide(index, section, pattern) {
|
|
1764
|
-
const
|
|
1765
|
-
|
|
1766
|
-
|
|
1883
|
+
const fullContent = `${section.header} ${section.content} ${section.bullets.join(" ")}`;
|
|
1884
|
+
const bigNumber = this.classifier.extractBigNumber(fullContent);
|
|
1885
|
+
const actualValue = bigNumber?.value || pattern.bigNumberValue;
|
|
1886
|
+
if (!actualValue) {
|
|
1887
|
+
logger.warn(`No number found for big-number slide, falling back to single-statement`);
|
|
1888
|
+
return this.createSingleStatementSlide(index, section);
|
|
1889
|
+
}
|
|
1767
1890
|
return {
|
|
1768
1891
|
index,
|
|
1769
1892
|
type: "big-number",
|
|
1770
1893
|
data: {
|
|
1771
1894
|
title: this.createTitle(section.header, section),
|
|
1772
|
-
keyMessage:
|
|
1895
|
+
keyMessage: actualValue,
|
|
1773
1896
|
body: bigNumber?.context || this.truncateText(
|
|
1774
1897
|
section.content,
|
|
1775
1898
|
this.config.defaults.context.maxWords
|
|
@@ -2038,7 +2161,7 @@ var SlideFactory = class {
|
|
|
2038
2161
|
slide.data.bullets = slide.data.bullets.slice(0, validation.fixes.bulletCount);
|
|
2039
2162
|
}
|
|
2040
2163
|
if (validation.violations.length > 0) {
|
|
2041
|
-
|
|
2164
|
+
logger.warn(`Slide ${slide.index} (${slide.type}): Fixed ${Object.keys(validation.fixes).length} issues, ${validation.violations.length} remaining`);
|
|
2042
2165
|
}
|
|
2043
2166
|
if (validation.warnings.length > 0) {
|
|
2044
2167
|
slide.notes = (slide.notes || "") + "\nWarnings: " + validation.warnings.join(", ");
|
|
@@ -2078,7 +2201,7 @@ var SlideFactory = class {
|
|
|
2078
2201
|
}
|
|
2079
2202
|
}
|
|
2080
2203
|
if (missingElements.length > 0) {
|
|
2081
|
-
|
|
2204
|
+
logger.warn(`Missing required elements: ${missingElements.join(", ")}`);
|
|
2082
2205
|
}
|
|
2083
2206
|
}
|
|
2084
2207
|
/**
|
|
@@ -2109,7 +2232,7 @@ var SlideFactory = class {
|
|
|
2109
2232
|
}
|
|
2110
2233
|
}
|
|
2111
2234
|
if (violations.length > 0) {
|
|
2112
|
-
|
|
2235
|
+
logger.warn(`Anti-pattern violations: ${violations.join(", ")}`);
|
|
2113
2236
|
}
|
|
2114
2237
|
}
|
|
2115
2238
|
// ===========================================================================
|
|
@@ -2454,9 +2577,12 @@ var TemplateEngine = class {
|
|
|
2454
2577
|
this.templates.set("big-number", this.handlebars.compile(`
|
|
2455
2578
|
<section class="{{classes}}" data-slide-index="{{slideIndex}}" style="{{styles}}">
|
|
2456
2579
|
<div class="slide-content big-number-content">
|
|
2457
|
-
|
|
2458
|
-
{{
|
|
2459
|
-
|
|
2580
|
+
{{#if title}}
|
|
2581
|
+
<h2 class="title animate-fadeIn">{{title}}</h2>
|
|
2582
|
+
{{/if}}
|
|
2583
|
+
<div class="number animate-zoomIn">{{keyMessage}}</div>
|
|
2584
|
+
{{#if body}}
|
|
2585
|
+
<p class="number-context animate-fadeIn delay-300">{{body}}</p>
|
|
2460
2586
|
{{/if}}
|
|
2461
2587
|
{{> source}}
|
|
2462
2588
|
</div>
|
|
@@ -4840,6 +4966,12 @@ ${slides}
|
|
|
4840
4966
|
const highlight = palette.accent || "#e94560";
|
|
4841
4967
|
const text = palette.text || "#1a1a2e";
|
|
4842
4968
|
const background = palette.background || "#ffffff";
|
|
4969
|
+
const isDark = this.isDarkPalette(palette);
|
|
4970
|
+
const defaultBg = isDark ? background : "#ffffff";
|
|
4971
|
+
const defaultText = isDark ? text : "#1a1a2e";
|
|
4972
|
+
const headingColor = isDark ? primary : primary;
|
|
4973
|
+
const titleBg = isDark ? background : primary;
|
|
4974
|
+
const titleBgEnd = isDark ? this.lightenColor(background, 10) : this.darkenColor(primary, 15);
|
|
4843
4975
|
return `
|
|
4844
4976
|
/* Base Styles - KB-Driven Design System */
|
|
4845
4977
|
:root {
|
|
@@ -4866,7 +4998,13 @@ ${slides}
|
|
|
4866
4998
|
font-family: var(--font-body);
|
|
4867
4999
|
font-size: ${fontSize};
|
|
4868
5000
|
line-height: ${lineHeight};
|
|
4869
|
-
color:
|
|
5001
|
+
color: ${defaultText};
|
|
5002
|
+
background: ${defaultBg};
|
|
5003
|
+
}
|
|
5004
|
+
|
|
5005
|
+
/* Override reveal.js default backgrounds for dark mode */
|
|
5006
|
+
.reveal .slides section {
|
|
5007
|
+
background: ${defaultBg};
|
|
4870
5008
|
}
|
|
4871
5009
|
|
|
4872
5010
|
.reveal .slides {
|
|
@@ -4895,10 +5033,17 @@ ${slides}
|
|
|
4895
5033
|
font-family: var(--font-heading);
|
|
4896
5034
|
font-weight: 700;
|
|
4897
5035
|
letter-spacing: -0.02em;
|
|
4898
|
-
color:
|
|
5036
|
+
color: ${isDark ? primary : primary};
|
|
4899
5037
|
margin-bottom: 0.5em;
|
|
4900
5038
|
}
|
|
4901
5039
|
|
|
5040
|
+
/* Dark mode text visibility */
|
|
5041
|
+
${isDark ? `
|
|
5042
|
+
.reveal, .reveal p, .reveal li, .reveal span {
|
|
5043
|
+
color: ${text};
|
|
5044
|
+
}
|
|
5045
|
+
` : ""}
|
|
5046
|
+
|
|
4902
5047
|
.reveal h1 { font-size: 2.5em; }
|
|
4903
5048
|
.reveal h2 { font-size: 1.8em; }
|
|
4904
5049
|
.reveal h3 { font-size: 1.3em; }
|
|
@@ -5076,6 +5221,124 @@ ${slides}
|
|
|
5076
5221
|
font-weight: 600;
|
|
5077
5222
|
margin-top: 1em;
|
|
5078
5223
|
}
|
|
5224
|
+
|
|
5225
|
+
/* ================================================================
|
|
5226
|
+
SLIDE TYPE BACKGROUNDS - KB-Driven Visual Design
|
|
5227
|
+
Creates visual hierarchy and differentiation between slide types
|
|
5228
|
+
================================================================ */
|
|
5229
|
+
|
|
5230
|
+
/* Title slide: Bold background - makes strong first impression */
|
|
5231
|
+
.reveal .slide-title {
|
|
5232
|
+
background: linear-gradient(135deg, ${titleBg} 0%, ${titleBgEnd} 100%);
|
|
5233
|
+
}
|
|
5234
|
+
.reveal .slide-title h1,
|
|
5235
|
+
.reveal .slide-title h2,
|
|
5236
|
+
.reveal .slide-title p,
|
|
5237
|
+
.reveal .slide-title .subtitle {
|
|
5238
|
+
color: ${isDark ? primary : "#ffffff"};
|
|
5239
|
+
}
|
|
5240
|
+
|
|
5241
|
+
/* Section dividers: Subtle visual breaks */
|
|
5242
|
+
.reveal .slide-section-divider {
|
|
5243
|
+
background: ${isDark ? this.lightenColor(background, 8) : `linear-gradient(180deg, ${this.lightenColor(primary, 85)} 0%, ${this.lightenColor(primary, 92)} 100%)`};
|
|
5244
|
+
}
|
|
5245
|
+
|
|
5246
|
+
/* Big number slides: Clean with accent highlight - emphasizes the data */
|
|
5247
|
+
.reveal .slide-big-number {
|
|
5248
|
+
background: var(--color-background);
|
|
5249
|
+
border-left: 8px solid var(--color-highlight);
|
|
5250
|
+
}
|
|
5251
|
+
.reveal .slide-big-number .number {
|
|
5252
|
+
font-size: 5em;
|
|
5253
|
+
background: linear-gradient(135deg, var(--color-highlight) 0%, var(--color-accent) 100%);
|
|
5254
|
+
-webkit-background-clip: text;
|
|
5255
|
+
-webkit-text-fill-color: transparent;
|
|
5256
|
+
background-clip: text;
|
|
5257
|
+
}
|
|
5258
|
+
|
|
5259
|
+
/* Metrics grid: Light accent background - data-focused */
|
|
5260
|
+
.reveal .slide-metrics-grid {
|
|
5261
|
+
background: ${isDark ? this.lightenColor(background, 8) : this.lightenColor(accent, 90)};
|
|
5262
|
+
}
|
|
5263
|
+
${isDark ? `.reveal .slide-metrics-grid { color: ${text}; }` : ""}
|
|
5264
|
+
|
|
5265
|
+
/* CTA slide: Highlight color - drives action */
|
|
5266
|
+
.reveal .slide-cta {
|
|
5267
|
+
background: linear-gradient(135deg, var(--color-highlight) 0%, var(--color-accent) 100%);
|
|
5268
|
+
}
|
|
5269
|
+
.reveal .slide-cta h2,
|
|
5270
|
+
.reveal .slide-cta p {
|
|
5271
|
+
color: #ffffff;
|
|
5272
|
+
}
|
|
5273
|
+
.reveal .slide-cta .cta-button {
|
|
5274
|
+
background: #ffffff;
|
|
5275
|
+
color: var(--color-highlight);
|
|
5276
|
+
}
|
|
5277
|
+
|
|
5278
|
+
/* Thank you slide: Matches title for bookend effect */
|
|
5279
|
+
.reveal .slide-thank-you {
|
|
5280
|
+
background: linear-gradient(135deg, ${titleBg} 0%, ${titleBgEnd} 100%);
|
|
5281
|
+
}
|
|
5282
|
+
.reveal .slide-thank-you h2,
|
|
5283
|
+
.reveal .slide-thank-you p,
|
|
5284
|
+
.reveal .slide-thank-you .subtitle {
|
|
5285
|
+
color: ${isDark ? primary : "#ffffff"};
|
|
5286
|
+
}
|
|
5287
|
+
|
|
5288
|
+
/* Quote slides: Elegant subtle background */
|
|
5289
|
+
.reveal .slide-quote {
|
|
5290
|
+
background: ${isDark ? this.lightenColor(background, 5) : this.lightenColor(secondary, 92)};
|
|
5291
|
+
}
|
|
5292
|
+
.reveal .slide-quote blockquote {
|
|
5293
|
+
border-left-color: var(--color-accent);
|
|
5294
|
+
font-size: 1.3em;
|
|
5295
|
+
}
|
|
5296
|
+
${isDark ? `.reveal .slide-quote { color: ${text}; }` : ""}
|
|
5297
|
+
|
|
5298
|
+
/* Single statement: Clean, centered, impactful */
|
|
5299
|
+
.reveal .slide-single-statement {
|
|
5300
|
+
background: var(--color-background);
|
|
5301
|
+
}
|
|
5302
|
+
.reveal .slide-single-statement .statement,
|
|
5303
|
+
.reveal .slide-single-statement .big-idea-text {
|
|
5304
|
+
font-size: 2.2em;
|
|
5305
|
+
max-width: 80%;
|
|
5306
|
+
margin: 0 auto;
|
|
5307
|
+
}
|
|
5308
|
+
|
|
5309
|
+
/* Comparison slides: Split visual */
|
|
5310
|
+
.reveal .slide-comparison .columns {
|
|
5311
|
+
gap: 60px;
|
|
5312
|
+
}
|
|
5313
|
+
.reveal .slide-comparison .column:first-child {
|
|
5314
|
+
border-right: 2px solid ${this.lightenColor(secondary, 70)};
|
|
5315
|
+
padding-right: 30px;
|
|
5316
|
+
}
|
|
5317
|
+
|
|
5318
|
+
/* Timeline/Process: Visual flow */
|
|
5319
|
+
.reveal .slide-timeline .steps,
|
|
5320
|
+
.reveal .slide-process .steps {
|
|
5321
|
+
display: flex;
|
|
5322
|
+
gap: 20px;
|
|
5323
|
+
}
|
|
5324
|
+
.reveal .slide-timeline .step,
|
|
5325
|
+
.reveal .slide-process .step {
|
|
5326
|
+
flex: 1;
|
|
5327
|
+
padding: 20px;
|
|
5328
|
+
background: ${isDark ? this.lightenColor(background, 10) : this.lightenColor(secondary, 92)};
|
|
5329
|
+
border-radius: 8px;
|
|
5330
|
+
border-top: 4px solid var(--color-accent);
|
|
5331
|
+
${isDark ? `color: ${text};` : ""}
|
|
5332
|
+
}
|
|
5333
|
+
|
|
5334
|
+
/* Progress bar enhancement */
|
|
5335
|
+
.reveal .progress {
|
|
5336
|
+
background: ${this.lightenColor(primary, 80)};
|
|
5337
|
+
height: 4px;
|
|
5338
|
+
}
|
|
5339
|
+
.reveal .progress span {
|
|
5340
|
+
background: var(--color-highlight);
|
|
5341
|
+
}
|
|
5079
5342
|
`;
|
|
5080
5343
|
}
|
|
5081
5344
|
/**
|
|
@@ -5091,6 +5354,37 @@ ${slides}
|
|
|
5091
5354
|
b = Math.min(255, Math.floor(b + (255 - b) * (percent / 100)));
|
|
5092
5355
|
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
5093
5356
|
}
|
|
5357
|
+
/**
|
|
5358
|
+
* Check if a palette is "dark mode" (dark background, light text)
|
|
5359
|
+
*/
|
|
5360
|
+
isDarkPalette(palette) {
|
|
5361
|
+
const bgLuminance = this.getLuminance(palette.background || "#ffffff");
|
|
5362
|
+
const textLuminance = this.getLuminance(palette.text || "#000000");
|
|
5363
|
+
return bgLuminance < textLuminance;
|
|
5364
|
+
}
|
|
5365
|
+
/**
|
|
5366
|
+
* Get relative luminance of a hex color (0-1, 0=black, 1=white)
|
|
5367
|
+
*/
|
|
5368
|
+
getLuminance(hex) {
|
|
5369
|
+
hex = hex.replace("#", "");
|
|
5370
|
+
const r = parseInt(hex.substring(0, 2), 16) / 255;
|
|
5371
|
+
const g = parseInt(hex.substring(2, 4), 16) / 255;
|
|
5372
|
+
const b = parseInt(hex.substring(4, 6), 16) / 255;
|
|
5373
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
5374
|
+
}
|
|
5375
|
+
/**
|
|
5376
|
+
* Darken a hex color
|
|
5377
|
+
*/
|
|
5378
|
+
darkenColor(hex, percent) {
|
|
5379
|
+
hex = hex.replace("#", "");
|
|
5380
|
+
let r = parseInt(hex.substring(0, 2), 16);
|
|
5381
|
+
let g = parseInt(hex.substring(2, 4), 16);
|
|
5382
|
+
let b = parseInt(hex.substring(4, 6), 16);
|
|
5383
|
+
r = Math.max(0, Math.floor(r * (1 - percent / 100)));
|
|
5384
|
+
g = Math.max(0, Math.floor(g * (1 - percent / 100)));
|
|
5385
|
+
b = Math.max(0, Math.floor(b * (1 - percent / 100)));
|
|
5386
|
+
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
5387
|
+
}
|
|
5094
5388
|
/**
|
|
5095
5389
|
* Get theme-specific styles - KB-DRIVEN
|
|
5096
5390
|
*/
|
|
@@ -5307,15 +5601,15 @@ var IterativeQAEngine = class {
|
|
|
5307
5601
|
let autoFixSummary = "";
|
|
5308
5602
|
let totalFixesApplied = 0;
|
|
5309
5603
|
if (opts.verbose) {
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5604
|
+
logger.progress("\n\u{1F504} Starting Iterative QA Process");
|
|
5605
|
+
logger.info(` Target Score: ${opts.minScore}/100`);
|
|
5606
|
+
logger.info(` Max Iterations: ${opts.maxIterations}`);
|
|
5607
|
+
logger.progress("");
|
|
5314
5608
|
}
|
|
5315
5609
|
for (let i = 0; i < opts.maxIterations; i++) {
|
|
5316
5610
|
const iterationNum = i + 1;
|
|
5317
5611
|
if (opts.verbose) {
|
|
5318
|
-
|
|
5612
|
+
logger.progress(`\u{1F4CA} Iteration ${iterationNum}/${opts.maxIterations}...`);
|
|
5319
5613
|
}
|
|
5320
5614
|
scoringResult = await this.scorer.score(currentSlides, currentHtml, opts.minScore);
|
|
5321
5615
|
iterations.push({
|
|
@@ -5334,17 +5628,17 @@ var IterativeQAEngine = class {
|
|
|
5334
5628
|
timestamp: /* @__PURE__ */ new Date()
|
|
5335
5629
|
});
|
|
5336
5630
|
if (opts.verbose) {
|
|
5337
|
-
|
|
5631
|
+
logger.info(` Score: ${scoringResult.overallScore}/100`);
|
|
5338
5632
|
}
|
|
5339
5633
|
if (scoringResult.passed) {
|
|
5340
5634
|
if (opts.verbose) {
|
|
5341
|
-
|
|
5635
|
+
logger.success(`PASSED - Score meets threshold (${opts.minScore})`);
|
|
5342
5636
|
}
|
|
5343
5637
|
break;
|
|
5344
5638
|
}
|
|
5345
5639
|
if (i < opts.maxIterations - 1) {
|
|
5346
5640
|
if (opts.verbose) {
|
|
5347
|
-
|
|
5641
|
+
logger.warn("Below threshold, applying auto-fixes...");
|
|
5348
5642
|
}
|
|
5349
5643
|
const fixResult = await this.fixer.fix(currentSlides, scoringResult);
|
|
5350
5644
|
if (fixResult.fixesApplied.length > 0) {
|
|
@@ -5356,12 +5650,12 @@ var IterativeQAEngine = class {
|
|
|
5356
5650
|
}
|
|
5357
5651
|
totalFixesApplied += fixResult.fixesApplied.length;
|
|
5358
5652
|
if (opts.verbose) {
|
|
5359
|
-
|
|
5653
|
+
logger.info(` \u{1F527} Applied ${fixResult.fixesApplied.length} fixes`);
|
|
5360
5654
|
}
|
|
5361
5655
|
autoFixSummary += fixResult.summary + "\n";
|
|
5362
5656
|
} else {
|
|
5363
5657
|
if (opts.verbose) {
|
|
5364
|
-
|
|
5658
|
+
logger.warn("No auto-fixes available, manual review needed");
|
|
5365
5659
|
}
|
|
5366
5660
|
break;
|
|
5367
5661
|
}
|
|
@@ -5377,7 +5671,7 @@ var IterativeQAEngine = class {
|
|
|
5377
5671
|
totalFixesApplied
|
|
5378
5672
|
);
|
|
5379
5673
|
if (opts.verbose) {
|
|
5380
|
-
|
|
5674
|
+
logger.info(report);
|
|
5381
5675
|
}
|
|
5382
5676
|
return {
|
|
5383
5677
|
finalScore: scoringResult.overallScore,
|
|
@@ -6179,6 +6473,172 @@ var PowerPointGenerator = class {
|
|
|
6179
6473
|
}
|
|
6180
6474
|
};
|
|
6181
6475
|
|
|
6476
|
+
// src/generators/PDFGenerator.ts
|
|
6477
|
+
import puppeteer from "puppeteer";
|
|
6478
|
+
var PDFGenerator = class {
|
|
6479
|
+
defaultOptions = {
|
|
6480
|
+
orientation: "landscape",
|
|
6481
|
+
printBackground: true,
|
|
6482
|
+
format: "Slide",
|
|
6483
|
+
scale: 1
|
|
6484
|
+
};
|
|
6485
|
+
/**
|
|
6486
|
+
* Generate PDF from HTML presentation
|
|
6487
|
+
* @param html - The HTML content of the presentation
|
|
6488
|
+
* @param options - PDF generation options
|
|
6489
|
+
* @returns Buffer containing the PDF file
|
|
6490
|
+
*/
|
|
6491
|
+
async generate(html, options = {}) {
|
|
6492
|
+
const opts = { ...this.defaultOptions, ...options };
|
|
6493
|
+
logger.progress("\u{1F4C4} Generating PDF...");
|
|
6494
|
+
let browser;
|
|
6495
|
+
try {
|
|
6496
|
+
browser = await puppeteer.launch({
|
|
6497
|
+
headless: true,
|
|
6498
|
+
args: [
|
|
6499
|
+
"--no-sandbox",
|
|
6500
|
+
"--disable-setuid-sandbox",
|
|
6501
|
+
"--disable-dev-shm-usage"
|
|
6502
|
+
]
|
|
6503
|
+
});
|
|
6504
|
+
const page = await browser.newPage();
|
|
6505
|
+
const printHtml = this.preparePrintHtml(html);
|
|
6506
|
+
await page.setViewport({
|
|
6507
|
+
width: 1920,
|
|
6508
|
+
height: 1080
|
|
6509
|
+
});
|
|
6510
|
+
await page.setContent(printHtml, {
|
|
6511
|
+
waitUntil: ["networkidle0", "domcontentloaded"]
|
|
6512
|
+
});
|
|
6513
|
+
await page.evaluate(() => {
|
|
6514
|
+
return new Promise((resolve) => {
|
|
6515
|
+
if (document.fonts && document.fonts.ready) {
|
|
6516
|
+
document.fonts.ready.then(() => resolve());
|
|
6517
|
+
} else {
|
|
6518
|
+
setTimeout(resolve, 1e3);
|
|
6519
|
+
}
|
|
6520
|
+
});
|
|
6521
|
+
});
|
|
6522
|
+
const pdfBuffer = await page.pdf({
|
|
6523
|
+
width: "1920px",
|
|
6524
|
+
height: "1080px",
|
|
6525
|
+
printBackground: opts.printBackground,
|
|
6526
|
+
scale: opts.scale,
|
|
6527
|
+
landscape: opts.orientation === "landscape",
|
|
6528
|
+
margin: {
|
|
6529
|
+
top: "0px",
|
|
6530
|
+
right: "0px",
|
|
6531
|
+
bottom: "0px",
|
|
6532
|
+
left: "0px"
|
|
6533
|
+
}
|
|
6534
|
+
});
|
|
6535
|
+
logger.step("PDF generated successfully");
|
|
6536
|
+
return Buffer.from(pdfBuffer);
|
|
6537
|
+
} catch (error) {
|
|
6538
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
6539
|
+
logger.error(`PDF generation failed: ${errorMessage}`);
|
|
6540
|
+
throw new Error(`PDF generation failed: ${errorMessage}`);
|
|
6541
|
+
} finally {
|
|
6542
|
+
if (browser) {
|
|
6543
|
+
await browser.close();
|
|
6544
|
+
}
|
|
6545
|
+
}
|
|
6546
|
+
}
|
|
6547
|
+
/**
|
|
6548
|
+
* Prepare HTML for print/PDF output
|
|
6549
|
+
* Modifies the HTML to work better as a printed document
|
|
6550
|
+
*/
|
|
6551
|
+
preparePrintHtml(html) {
|
|
6552
|
+
const printCss = `
|
|
6553
|
+
<style id="pdf-print-styles">
|
|
6554
|
+
/* Print-specific overrides */
|
|
6555
|
+
@page {
|
|
6556
|
+
size: 1920px 1080px;
|
|
6557
|
+
margin: 0;
|
|
6558
|
+
}
|
|
6559
|
+
|
|
6560
|
+
@media print {
|
|
6561
|
+
html, body {
|
|
6562
|
+
margin: 0;
|
|
6563
|
+
padding: 0;
|
|
6564
|
+
width: 1920px;
|
|
6565
|
+
height: 1080px;
|
|
6566
|
+
}
|
|
6567
|
+
|
|
6568
|
+
.reveal .slides {
|
|
6569
|
+
width: 100% !important;
|
|
6570
|
+
height: 100% !important;
|
|
6571
|
+
margin: 0 !important;
|
|
6572
|
+
padding: 0 !important;
|
|
6573
|
+
transform: none !important;
|
|
6574
|
+
}
|
|
6575
|
+
|
|
6576
|
+
.reveal .slides section {
|
|
6577
|
+
page-break-after: always;
|
|
6578
|
+
page-break-inside: avoid;
|
|
6579
|
+
width: 1920px !important;
|
|
6580
|
+
height: 1080px !important;
|
|
6581
|
+
margin: 0 !important;
|
|
6582
|
+
padding: 60px !important;
|
|
6583
|
+
box-sizing: border-box;
|
|
6584
|
+
position: relative !important;
|
|
6585
|
+
top: auto !important;
|
|
6586
|
+
left: auto !important;
|
|
6587
|
+
transform: none !important;
|
|
6588
|
+
display: flex !important;
|
|
6589
|
+
opacity: 1 !important;
|
|
6590
|
+
visibility: visible !important;
|
|
6591
|
+
}
|
|
6592
|
+
|
|
6593
|
+
.reveal .slides section:last-child {
|
|
6594
|
+
page-break-after: auto;
|
|
6595
|
+
}
|
|
6596
|
+
|
|
6597
|
+
/* Make all slides visible for printing */
|
|
6598
|
+
.reveal .slides section.future,
|
|
6599
|
+
.reveal .slides section.past {
|
|
6600
|
+
display: flex !important;
|
|
6601
|
+
opacity: 1 !important;
|
|
6602
|
+
visibility: visible !important;
|
|
6603
|
+
}
|
|
6604
|
+
|
|
6605
|
+
/* Disable animations for print */
|
|
6606
|
+
* {
|
|
6607
|
+
animation: none !important;
|
|
6608
|
+
transition: none !important;
|
|
6609
|
+
}
|
|
6610
|
+
|
|
6611
|
+
/* Hide Reveal.js controls */
|
|
6612
|
+
.reveal .controls,
|
|
6613
|
+
.reveal .progress,
|
|
6614
|
+
.reveal .slide-number,
|
|
6615
|
+
.reveal .speaker-notes,
|
|
6616
|
+
.reveal .navigate-left,
|
|
6617
|
+
.reveal .navigate-right,
|
|
6618
|
+
.reveal .navigate-up,
|
|
6619
|
+
.reveal .navigate-down {
|
|
6620
|
+
display: none !important;
|
|
6621
|
+
}
|
|
6622
|
+
}
|
|
6623
|
+
|
|
6624
|
+
/* Force print mode in Puppeteer */
|
|
6625
|
+
.reveal .slides section {
|
|
6626
|
+
page-break-after: always;
|
|
6627
|
+
page-break-inside: avoid;
|
|
6628
|
+
}
|
|
6629
|
+
</style>
|
|
6630
|
+
`;
|
|
6631
|
+
if (html.includes("</head>")) {
|
|
6632
|
+
return html.replace("</head>", `${printCss}</head>`);
|
|
6633
|
+
} else {
|
|
6634
|
+
return printCss + html;
|
|
6635
|
+
}
|
|
6636
|
+
}
|
|
6637
|
+
};
|
|
6638
|
+
function createPDFGenerator() {
|
|
6639
|
+
return new PDFGenerator();
|
|
6640
|
+
}
|
|
6641
|
+
|
|
6182
6642
|
// src/core/PresentationEngine.ts
|
|
6183
6643
|
var PresentationEngine = class {
|
|
6184
6644
|
contentAnalyzer;
|
|
@@ -6187,6 +6647,7 @@ var PresentationEngine = class {
|
|
|
6187
6647
|
qaEngine;
|
|
6188
6648
|
htmlGenerator;
|
|
6189
6649
|
pptxGenerator;
|
|
6650
|
+
pdfGenerator;
|
|
6190
6651
|
kb;
|
|
6191
6652
|
constructor() {
|
|
6192
6653
|
this.contentAnalyzer = new ContentAnalyzer();
|
|
@@ -6195,6 +6656,7 @@ var PresentationEngine = class {
|
|
|
6195
6656
|
this.qaEngine = new QAEngine();
|
|
6196
6657
|
this.htmlGenerator = new RevealJsGenerator();
|
|
6197
6658
|
this.pptxGenerator = new PowerPointGenerator();
|
|
6659
|
+
this.pdfGenerator = createPDFGenerator();
|
|
6198
6660
|
}
|
|
6199
6661
|
/**
|
|
6200
6662
|
* Generate a presentation from content.
|
|
@@ -6204,26 +6666,26 @@ var PresentationEngine = class {
|
|
|
6204
6666
|
*/
|
|
6205
6667
|
async generate(config) {
|
|
6206
6668
|
this.validateConfig(config);
|
|
6207
|
-
|
|
6669
|
+
logger.progress("\u{1F4DA} Loading knowledge base...");
|
|
6208
6670
|
this.kb = await getKnowledgeGateway();
|
|
6209
|
-
|
|
6671
|
+
logger.progress("\u{1F4DD} Analyzing content...");
|
|
6210
6672
|
const analysis = await this.contentAnalyzer.analyze(config.content, config.contentType);
|
|
6211
6673
|
const presentationType = config.presentationType || analysis.detectedType;
|
|
6212
|
-
|
|
6674
|
+
logger.step(`Presentation type: ${presentationType}`);
|
|
6213
6675
|
const slideFactory = createSlideFactory(this.kb, presentationType);
|
|
6214
|
-
|
|
6676
|
+
logger.progress("\u{1F3A8} Creating slides...");
|
|
6215
6677
|
const slides = await slideFactory.createSlides(analysis);
|
|
6216
|
-
|
|
6678
|
+
logger.progress("\u2705 Validating structure...");
|
|
6217
6679
|
const structureErrors = this.validateStructure(slides, config.mode);
|
|
6218
6680
|
if (structureErrors.length > 0) {
|
|
6219
6681
|
if (config.skipQA) {
|
|
6220
|
-
|
|
6221
|
-
structureErrors.forEach((e) =>
|
|
6682
|
+
logger.warn("Structure warnings (bypassed):");
|
|
6683
|
+
structureErrors.forEach((e) => logger.warn(` \u2022 ${e}`));
|
|
6222
6684
|
} else {
|
|
6223
6685
|
throw new ValidationError(structureErrors, "Slide structure validation failed");
|
|
6224
6686
|
}
|
|
6225
6687
|
}
|
|
6226
|
-
|
|
6688
|
+
logger.progress("\u{1F528} Generating outputs...");
|
|
6227
6689
|
const outputs = {};
|
|
6228
6690
|
if (config.format.includes("html")) {
|
|
6229
6691
|
outputs.html = await this.htmlGenerator.generate(slides, config);
|
|
@@ -6241,7 +6703,7 @@ var PresentationEngine = class {
|
|
|
6241
6703
|
const maxIterations = config.maxIterations ?? 5;
|
|
6242
6704
|
const useIterativeQA = config.useIterativeQA !== false;
|
|
6243
6705
|
if (useIterativeQA) {
|
|
6244
|
-
|
|
6706
|
+
logger.progress("\u{1F50D} Running Iterative QA (7-Dimension Scoring)...");
|
|
6245
6707
|
const iterativeEngine = createIterativeQAEngine(
|
|
6246
6708
|
config.mode,
|
|
6247
6709
|
presentationType,
|
|
@@ -6263,20 +6725,30 @@ var PresentationEngine = class {
|
|
|
6263
6725
|
throw new QAFailureError(score, threshold, qaResults);
|
|
6264
6726
|
}
|
|
6265
6727
|
} else {
|
|
6266
|
-
|
|
6728
|
+
logger.progress("\u{1F50D} Running QA validation (legacy mode)...");
|
|
6267
6729
|
qaResults = await this.qaEngine.validate(outputs.html, {
|
|
6268
6730
|
mode: config.mode,
|
|
6269
6731
|
strictMode: true
|
|
6270
6732
|
});
|
|
6271
6733
|
score = this.scoreCalculator.calculate(qaResults);
|
|
6272
|
-
|
|
6734
|
+
logger.info(`\u{1F4CA} QA Score: ${score}/100`);
|
|
6273
6735
|
if (score < threshold) {
|
|
6274
6736
|
throw new QAFailureError(score, threshold, qaResults);
|
|
6275
6737
|
}
|
|
6276
6738
|
}
|
|
6277
6739
|
} else {
|
|
6278
6740
|
qaResults = this.qaEngine.createEmptyResults();
|
|
6279
|
-
|
|
6741
|
+
logger.warn("QA validation skipped (NOT RECOMMENDED)");
|
|
6742
|
+
}
|
|
6743
|
+
if (outputs.html && (config.format.includes("pdf") || config.generatePdf !== false)) {
|
|
6744
|
+
try {
|
|
6745
|
+
logger.progress("\u{1F4C4} Generating PDF from validated HTML...");
|
|
6746
|
+
outputs.pdf = await this.pdfGenerator.generate(outputs.html);
|
|
6747
|
+
logger.step("PDF generated successfully");
|
|
6748
|
+
} catch (pdfError) {
|
|
6749
|
+
const errorMsg = pdfError instanceof Error ? pdfError.message : String(pdfError);
|
|
6750
|
+
logger.warn(`PDF generation failed (non-critical): ${errorMsg}`);
|
|
6751
|
+
}
|
|
6280
6752
|
}
|
|
6281
6753
|
const metadata = this.buildMetadata(config, analysis, finalSlides, iterativeResult);
|
|
6282
6754
|
return {
|
|
@@ -6364,15 +6836,28 @@ var PresentationEngine = class {
|
|
|
6364
6836
|
if (slides.length < 3) {
|
|
6365
6837
|
errors.push("Presentation must have at least 3 slides");
|
|
6366
6838
|
}
|
|
6839
|
+
const sparseByDesignTypes = [
|
|
6840
|
+
"title",
|
|
6841
|
+
"section-divider",
|
|
6842
|
+
"thank-you",
|
|
6843
|
+
"big-number",
|
|
6844
|
+
"single-statement",
|
|
6845
|
+
"cta",
|
|
6846
|
+
"agenda",
|
|
6847
|
+
"metrics-grid",
|
|
6848
|
+
"quote",
|
|
6849
|
+
"image-focus"
|
|
6850
|
+
];
|
|
6367
6851
|
slides.forEach((slide, index) => {
|
|
6368
6852
|
const wordCount = this.countWords(slide);
|
|
6369
6853
|
if (mode === "keynote") {
|
|
6370
|
-
if (wordCount > 25) {
|
|
6854
|
+
if (wordCount > 25 && !sparseByDesignTypes.includes(slide.type)) {
|
|
6371
6855
|
errors.push(`Slide ${index + 1}: ${wordCount} words exceeds keynote limit of 25`);
|
|
6372
6856
|
}
|
|
6373
6857
|
} else {
|
|
6374
|
-
|
|
6375
|
-
|
|
6858
|
+
const requiresMinWords = ["bullet-points", "two-column", "process-flow"];
|
|
6859
|
+
if (wordCount < 20 && requiresMinWords.includes(slide.type)) {
|
|
6860
|
+
logger.warn(`Slide ${index + 1}: ${wordCount} words is sparse for ${slide.type} slide`);
|
|
6376
6861
|
}
|
|
6377
6862
|
if (wordCount > 100) {
|
|
6378
6863
|
errors.push(`Slide ${index + 1}: ${wordCount} words exceeds business limit of 100`);
|
|
@@ -6466,11 +6951,11 @@ var SlideGenerator = class {
|
|
|
6466
6951
|
await this.initialize();
|
|
6467
6952
|
this.presentationType = type || analysis.detectedType;
|
|
6468
6953
|
this.mode = this.kb.getModeForType(this.presentationType);
|
|
6469
|
-
|
|
6954
|
+
logger.step(`Using ${this.mode} mode for ${this.presentationType}`);
|
|
6470
6955
|
this.factory = createSlideFactory(this.kb, this.presentationType);
|
|
6471
6956
|
const slides = await this.factory.createSlides(analysis);
|
|
6472
6957
|
const legacySlides = this.convertToLegacyFormat(slides);
|
|
6473
|
-
|
|
6958
|
+
logger.step(`Generated ${legacySlides.length} KB-validated slides`);
|
|
6474
6959
|
return legacySlides;
|
|
6475
6960
|
}
|
|
6476
6961
|
/**
|