claude-presentation-master 5.0.0 → 6.0.0
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 +2 -2
- package/dist/index.d.mts +307 -158
- package/dist/index.d.ts +307 -158
- package/dist/index.js +829 -615
- package/dist/index.mjs +826 -612
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -26,8 +26,280 @@ var TemplateNotFoundError = class extends Error {
|
|
|
26
26
|
}
|
|
27
27
|
};
|
|
28
28
|
|
|
29
|
+
// src/kb/KnowledgeGateway.ts
|
|
30
|
+
import { readFileSync } from "fs";
|
|
31
|
+
import { join, dirname } from "path";
|
|
32
|
+
import { fileURLToPath } from "url";
|
|
33
|
+
import * as yaml from "yaml";
|
|
34
|
+
function getModuleDir() {
|
|
35
|
+
if (typeof import.meta !== "undefined" && import.meta.url) {
|
|
36
|
+
return dirname(fileURLToPath(import.meta.url));
|
|
37
|
+
}
|
|
38
|
+
if (typeof __dirname !== "undefined") {
|
|
39
|
+
return __dirname;
|
|
40
|
+
}
|
|
41
|
+
return process.cwd();
|
|
42
|
+
}
|
|
43
|
+
var KnowledgeGateway = class {
|
|
44
|
+
kb;
|
|
45
|
+
loaded = false;
|
|
46
|
+
constructor() {
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Load the knowledge base from YAML file
|
|
50
|
+
*/
|
|
51
|
+
async load() {
|
|
52
|
+
if (this.loaded) return;
|
|
53
|
+
const moduleDir = getModuleDir();
|
|
54
|
+
const possiblePaths = [
|
|
55
|
+
join(moduleDir, "../../assets/presentation-knowledge.yaml"),
|
|
56
|
+
join(moduleDir, "../assets/presentation-knowledge.yaml"),
|
|
57
|
+
join(moduleDir, "../../../assets/presentation-knowledge.yaml"),
|
|
58
|
+
join(moduleDir, "assets/presentation-knowledge.yaml"),
|
|
59
|
+
join(process.cwd(), "assets/presentation-knowledge.yaml"),
|
|
60
|
+
join(process.cwd(), "node_modules/claude-presentation-master/assets/presentation-knowledge.yaml")
|
|
61
|
+
];
|
|
62
|
+
for (const path of possiblePaths) {
|
|
63
|
+
try {
|
|
64
|
+
const content = readFileSync(path, "utf-8");
|
|
65
|
+
this.kb = yaml.parse(content);
|
|
66
|
+
this.loaded = true;
|
|
67
|
+
console.log(` \u2713 Knowledge base loaded from ${path}`);
|
|
68
|
+
return;
|
|
69
|
+
} catch {
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
throw new Error(`Knowledge base not found. Tried: ${possiblePaths.join(", ")}`);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Get presentation mode configuration (keynote or business)
|
|
76
|
+
*/
|
|
77
|
+
getMode(mode) {
|
|
78
|
+
this.ensureLoaded();
|
|
79
|
+
return this.kb.presentation_modes[mode];
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Determine which mode is best for a given presentation type
|
|
83
|
+
*/
|
|
84
|
+
getModeForType(type) {
|
|
85
|
+
const keynoteTypes = ["ted_keynote", "sales_pitch", "all_hands"];
|
|
86
|
+
const businessTypes = ["consulting_deck", "investment_banking", "investor_pitch", "technical_presentation"];
|
|
87
|
+
if (keynoteTypes.includes(type)) return "keynote";
|
|
88
|
+
if (businessTypes.includes(type)) return "business";
|
|
89
|
+
return "keynote";
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Get word limits for the specified mode
|
|
93
|
+
*/
|
|
94
|
+
getWordLimits(mode) {
|
|
95
|
+
const modeConfig = this.getMode(mode);
|
|
96
|
+
const range = modeConfig.characteristics.words_per_slide;
|
|
97
|
+
if (mode === "keynote") {
|
|
98
|
+
return { min: 6, max: 15, ideal: 10 };
|
|
99
|
+
} else {
|
|
100
|
+
return { min: 40, max: 80, ideal: 60 };
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get bullet point limits
|
|
105
|
+
*/
|
|
106
|
+
getBulletLimits(mode) {
|
|
107
|
+
if (mode === "keynote") {
|
|
108
|
+
return { maxBullets: 3, maxWordsPerBullet: 8 };
|
|
109
|
+
} else {
|
|
110
|
+
return { maxBullets: 5, maxWordsPerBullet: 20 };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Get whitespace percentage requirement
|
|
115
|
+
*/
|
|
116
|
+
getWhitespaceRequirement(mode) {
|
|
117
|
+
if (mode === "keynote") return 0.4;
|
|
118
|
+
return 0.25;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Get slide templates for the specified mode
|
|
122
|
+
*/
|
|
123
|
+
getSlideTemplates(mode) {
|
|
124
|
+
this.ensureLoaded();
|
|
125
|
+
const key = mode === "keynote" ? "keynote_mode" : "business_mode";
|
|
126
|
+
return this.kb.slide_templates[key] || [];
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Get a specific slide template by name
|
|
130
|
+
*/
|
|
131
|
+
getSlideTemplate(mode, templateName) {
|
|
132
|
+
const templates = this.getSlideTemplates(mode);
|
|
133
|
+
return templates.find((t) => t.name.toLowerCase().includes(templateName.toLowerCase()));
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Get quality metrics for grading
|
|
137
|
+
*/
|
|
138
|
+
getQualityMetrics() {
|
|
139
|
+
this.ensureLoaded();
|
|
140
|
+
return this.kb.quality_metrics;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Get anti-patterns to avoid
|
|
144
|
+
*/
|
|
145
|
+
getAntiPatterns(mode) {
|
|
146
|
+
this.ensureLoaded();
|
|
147
|
+
const key = mode === "keynote" ? "keynote_mode" : "business_mode";
|
|
148
|
+
return this.kb.anti_patterns[key] || [];
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Get data visualization anti-patterns
|
|
152
|
+
*/
|
|
153
|
+
getDataVizAntiPatterns() {
|
|
154
|
+
this.ensureLoaded();
|
|
155
|
+
return this.kb.anti_patterns.data_visualization || [];
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Get accessibility anti-patterns
|
|
159
|
+
*/
|
|
160
|
+
getAccessibilityAntiPatterns() {
|
|
161
|
+
this.ensureLoaded();
|
|
162
|
+
return this.kb.anti_patterns.accessibility || [];
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Get color palette by name
|
|
166
|
+
*/
|
|
167
|
+
getColorPalette(name) {
|
|
168
|
+
this.ensureLoaded();
|
|
169
|
+
const palettes = this.kb.design_system.color_palettes;
|
|
170
|
+
return palettes[name];
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Get recommended color palette for presentation type
|
|
174
|
+
*/
|
|
175
|
+
getRecommendedPalette(type) {
|
|
176
|
+
this.ensureLoaded();
|
|
177
|
+
const palettes = this.kb.design_system.color_palettes;
|
|
178
|
+
switch (type) {
|
|
179
|
+
case "consulting_deck":
|
|
180
|
+
return palettes.consulting_classic;
|
|
181
|
+
case "investment_banking":
|
|
182
|
+
case "investor_pitch":
|
|
183
|
+
return palettes.executive_professional;
|
|
184
|
+
case "ted_keynote":
|
|
185
|
+
return palettes.dark_executive;
|
|
186
|
+
case "sales_pitch":
|
|
187
|
+
return palettes.modern_business;
|
|
188
|
+
case "technical_presentation":
|
|
189
|
+
return palettes.modern_business;
|
|
190
|
+
case "all_hands":
|
|
191
|
+
return palettes.strategy_growth;
|
|
192
|
+
default:
|
|
193
|
+
return palettes.consulting_classic;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Get typography guidelines for mode
|
|
198
|
+
*/
|
|
199
|
+
getTypography(mode) {
|
|
200
|
+
this.ensureLoaded();
|
|
201
|
+
const key = mode === "keynote" ? "keynote_mode" : "business_mode";
|
|
202
|
+
return this.kb.design_system.typography[key];
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Get story framework by name
|
|
206
|
+
*/
|
|
207
|
+
getStoryFramework(name) {
|
|
208
|
+
this.ensureLoaded();
|
|
209
|
+
return this.kb.story_frameworks[name];
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Get expert principles by name
|
|
213
|
+
*/
|
|
214
|
+
getExpertPrinciples(expertName) {
|
|
215
|
+
this.ensureLoaded();
|
|
216
|
+
if (this.kb.experts[expertName]) {
|
|
217
|
+
return this.kb.experts[expertName];
|
|
218
|
+
}
|
|
219
|
+
if (this.kb.data_visualization_experts) {
|
|
220
|
+
for (const key of Object.keys(this.kb.data_visualization_experts)) {
|
|
221
|
+
if (key.includes(expertName.toLowerCase())) {
|
|
222
|
+
return this.kb.data_visualization_experts[key];
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Get Duarte's glance test requirements
|
|
230
|
+
*/
|
|
231
|
+
getDuarteGlanceTest() {
|
|
232
|
+
this.ensureLoaded();
|
|
233
|
+
const duarte = this.kb.experts.nancy_duarte;
|
|
234
|
+
return {
|
|
235
|
+
wordLimit: duarte.core_principles.glance_test.word_limit || 25,
|
|
236
|
+
timeSeconds: 3
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Get Miller's Law constraints
|
|
241
|
+
*/
|
|
242
|
+
getMillersLaw() {
|
|
243
|
+
this.ensureLoaded();
|
|
244
|
+
return { minItems: 5, maxItems: 9 };
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Get cognitive load constraints
|
|
248
|
+
*/
|
|
249
|
+
getCognitiveLoadLimits() {
|
|
250
|
+
this.ensureLoaded();
|
|
251
|
+
return { maxItemsPerChunk: 7 };
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Get chart selection guidance
|
|
255
|
+
*/
|
|
256
|
+
getChartGuidance(purpose) {
|
|
257
|
+
this.ensureLoaded();
|
|
258
|
+
return this.kb.chart_selection_guide.by_purpose[purpose];
|
|
259
|
+
}
|
|
260
|
+
/**
|
|
261
|
+
* Get charts to avoid
|
|
262
|
+
*/
|
|
263
|
+
getChartsToAvoid() {
|
|
264
|
+
this.ensureLoaded();
|
|
265
|
+
const knaflic = this.kb.data_visualization_experts.cole_nussbaumer_knaflic;
|
|
266
|
+
return knaflic.chart_guidance.avoid_these || [];
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Get investment banking pitch book structure
|
|
270
|
+
*/
|
|
271
|
+
getIBPitchBookStructure(type) {
|
|
272
|
+
this.ensureLoaded();
|
|
273
|
+
return this.kb.investment_banking?.pitch_book_types[type];
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Check if knowledge base is loaded
|
|
277
|
+
*/
|
|
278
|
+
ensureLoaded() {
|
|
279
|
+
if (!this.loaded) {
|
|
280
|
+
throw new Error("Knowledge base not loaded. Call load() first.");
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Get the full knowledge base (for advanced queries)
|
|
285
|
+
*/
|
|
286
|
+
getRawKB() {
|
|
287
|
+
this.ensureLoaded();
|
|
288
|
+
return this.kb;
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
var gatewayInstance = null;
|
|
292
|
+
async function getKnowledgeGateway() {
|
|
293
|
+
if (!gatewayInstance) {
|
|
294
|
+
gatewayInstance = new KnowledgeGateway();
|
|
295
|
+
await gatewayInstance.load();
|
|
296
|
+
}
|
|
297
|
+
return gatewayInstance;
|
|
298
|
+
}
|
|
299
|
+
|
|
29
300
|
// src/core/ContentAnalyzer.ts
|
|
30
301
|
var ContentAnalyzer = class {
|
|
302
|
+
kb;
|
|
31
303
|
// Signal words for SCQA detection
|
|
32
304
|
situationSignals = [
|
|
33
305
|
"currently",
|
|
@@ -39,7 +311,8 @@ var ContentAnalyzer = class {
|
|
|
39
311
|
"our",
|
|
40
312
|
"the market",
|
|
41
313
|
"industry",
|
|
42
|
-
"context"
|
|
314
|
+
"context",
|
|
315
|
+
"background"
|
|
43
316
|
];
|
|
44
317
|
complicationSignals = [
|
|
45
318
|
"however",
|
|
@@ -57,20 +330,10 @@ var ContentAnalyzer = class {
|
|
|
57
330
|
"yet",
|
|
58
331
|
"although",
|
|
59
332
|
"despite",
|
|
60
|
-
"while"
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
"
|
|
64
|
-
"what",
|
|
65
|
-
"why",
|
|
66
|
-
"when",
|
|
67
|
-
"where",
|
|
68
|
-
"which",
|
|
69
|
-
"should",
|
|
70
|
-
"could",
|
|
71
|
-
"can we",
|
|
72
|
-
"is it possible",
|
|
73
|
-
"?"
|
|
333
|
+
"while",
|
|
334
|
+
"crisis",
|
|
335
|
+
"gap",
|
|
336
|
+
"broken"
|
|
74
337
|
];
|
|
75
338
|
answerSignals = [
|
|
76
339
|
"therefore",
|
|
@@ -86,429 +349,439 @@ var ContentAnalyzer = class {
|
|
|
86
349
|
"we should",
|
|
87
350
|
"must",
|
|
88
351
|
"need to",
|
|
89
|
-
"the answer"
|
|
352
|
+
"the answer",
|
|
353
|
+
"introducing",
|
|
354
|
+
"presenting",
|
|
355
|
+
"platform"
|
|
90
356
|
];
|
|
91
|
-
//
|
|
92
|
-
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
"
|
|
101
|
-
"
|
|
102
|
-
"
|
|
103
|
-
|
|
104
|
-
whatCouldBeSignals = [
|
|
105
|
-
"imagine",
|
|
106
|
-
"vision",
|
|
107
|
-
"future",
|
|
108
|
-
"could be",
|
|
109
|
-
"what if",
|
|
110
|
-
"possibility",
|
|
111
|
-
"potential",
|
|
112
|
-
"opportunity",
|
|
113
|
-
"transform",
|
|
114
|
-
"envision",
|
|
115
|
-
"ideal",
|
|
116
|
-
"dream",
|
|
117
|
-
"goal",
|
|
118
|
-
"aspiration"
|
|
357
|
+
// CTA signals - used to filter these OUT of answer detection
|
|
358
|
+
ctaSignals = [
|
|
359
|
+
"contact",
|
|
360
|
+
"call us",
|
|
361
|
+
"email",
|
|
362
|
+
"schedule",
|
|
363
|
+
"sign up",
|
|
364
|
+
"register",
|
|
365
|
+
"next steps",
|
|
366
|
+
"get started",
|
|
367
|
+
"reach out",
|
|
368
|
+
"visit",
|
|
369
|
+
"follow"
|
|
119
370
|
];
|
|
371
|
+
// Type detection signals
|
|
372
|
+
typeSignals = {
|
|
373
|
+
ted_keynote: ["inspire", "vision", "imagine", "dream", "transform", "story", "journey"],
|
|
374
|
+
sales_pitch: ["buy", "purchase", "pricing", "offer", "deal", "discount", "roi", "value"],
|
|
375
|
+
consulting_deck: ["recommend", "analysis", "assessment", "strategy", "findings", "options", "mece"],
|
|
376
|
+
investment_banking: ["valuation", "dcf", "multiple", "enterprise value", "ebitda", "ipo", "m&a"],
|
|
377
|
+
investor_pitch: ["investment", "funding", "series", "traction", "market size", "tam", "runway"],
|
|
378
|
+
technical_presentation: ["architecture", "api", "system", "implementation", "code", "database", "deploy"],
|
|
379
|
+
all_hands: ["team", "quarter", "update", "progress", "celebrate", "recognize", "company"]
|
|
380
|
+
};
|
|
381
|
+
async initialize() {
|
|
382
|
+
this.kb = await getKnowledgeGateway();
|
|
383
|
+
}
|
|
120
384
|
/**
|
|
121
385
|
* Analyze content and extract structural elements.
|
|
122
386
|
*/
|
|
123
387
|
async analyze(content, contentType) {
|
|
388
|
+
await this.initialize();
|
|
124
389
|
const text = this.parseContent(content, contentType);
|
|
125
|
-
const
|
|
126
|
-
const
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
const
|
|
131
|
-
const
|
|
132
|
-
const
|
|
390
|
+
const title = this.extractTitle(text);
|
|
391
|
+
const detectedType = this.detectPresentationType(text);
|
|
392
|
+
console.log(` \u2713 Detected type: ${detectedType}`);
|
|
393
|
+
const sections = this.extractSections(text);
|
|
394
|
+
console.log(` \u2713 Found ${sections.length} sections`);
|
|
395
|
+
const scqa = this.extractSCQA(text);
|
|
396
|
+
const sparkline = this.extractSparkline(text);
|
|
397
|
+
const keyMessages = this.extractKeyMessages(text);
|
|
398
|
+
const dataPoints = this.extractDataPoints(text);
|
|
399
|
+
console.log(` \u2713 Found ${dataPoints.length} data points`);
|
|
400
|
+
const titles = sections.map((s) => s.header).filter((h) => h.length > 0);
|
|
401
|
+
const starMoments = this.extractStarMoments(text);
|
|
402
|
+
const estimatedSlideCount = Math.max(5, sections.length + 3);
|
|
133
403
|
return {
|
|
134
|
-
|
|
135
|
-
|
|
404
|
+
detectedType,
|
|
405
|
+
title,
|
|
406
|
+
sections,
|
|
136
407
|
keyMessages,
|
|
408
|
+
dataPoints,
|
|
409
|
+
scqa: {
|
|
410
|
+
situation: scqa.situation || "",
|
|
411
|
+
complication: scqa.complication || "",
|
|
412
|
+
question: scqa.question || "",
|
|
413
|
+
answer: scqa.answer || ""
|
|
414
|
+
},
|
|
415
|
+
sparkline: {
|
|
416
|
+
whatIs: sparkline.callToAction ? [sparkline.callToAction] : [],
|
|
417
|
+
whatCouldBe: keyMessages,
|
|
418
|
+
callToAdventure: sparkline.callToAction || ""
|
|
419
|
+
},
|
|
137
420
|
titles,
|
|
138
421
|
starMoments,
|
|
139
422
|
estimatedSlideCount
|
|
140
423
|
};
|
|
141
424
|
}
|
|
142
425
|
/**
|
|
143
|
-
* Parse content based on
|
|
426
|
+
* Parse content based on type
|
|
144
427
|
*/
|
|
145
428
|
parseContent(content, contentType) {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
return this.parseMarkdown(content);
|
|
149
|
-
case "json":
|
|
150
|
-
return this.parseJSON(content);
|
|
151
|
-
case "yaml":
|
|
152
|
-
return this.parseYAML(content);
|
|
153
|
-
case "text":
|
|
154
|
-
default:
|
|
155
|
-
return content;
|
|
429
|
+
if (contentType === "markdown" || content.includes("#") || content.includes("- ")) {
|
|
430
|
+
return content;
|
|
156
431
|
}
|
|
432
|
+
return content;
|
|
157
433
|
}
|
|
158
434
|
/**
|
|
159
|
-
*
|
|
160
|
-
*/
|
|
161
|
-
parseMarkdown(content) {
|
|
162
|
-
let text = content;
|
|
163
|
-
text = text.replace(/^#{1,6}\s+(.+)$/gm, "\n[HEADER] $1\n");
|
|
164
|
-
text = text.replace(/^[-*+]\s+(.+)$/gm, "[BULLET] $1");
|
|
165
|
-
text = text.replace(/^\d+\.\s+(.+)$/gm, "[NUMBERED] $1");
|
|
166
|
-
text = text.replace(/\*\*(.+?)\*\*/g, "[EMPHASIS] $1 [/EMPHASIS]");
|
|
167
|
-
text = text.replace(/\*(.+?)\*/g, "$1");
|
|
168
|
-
text = text.replace(/```[\s\S]*?```/g, "[CODE BLOCK]");
|
|
169
|
-
text = text.replace(/`(.+?)`/g, "$1");
|
|
170
|
-
text = text.replace(/\[(.+?)\]\(.+?\)/g, "$1");
|
|
171
|
-
text = text.replace(/!\[.*?\]\(.+?\)/g, "[IMAGE]");
|
|
172
|
-
return text.trim();
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* Parse JSON content.
|
|
435
|
+
* Extract the main title from content
|
|
176
436
|
*/
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
return
|
|
181
|
-
}
|
|
182
|
-
|
|
437
|
+
extractTitle(text) {
|
|
438
|
+
const h1Match = text.match(/^#\s+(.+)$/m);
|
|
439
|
+
if (h1Match && h1Match[1]) {
|
|
440
|
+
return h1Match[1].replace(/\*\*/g, "").trim();
|
|
441
|
+
}
|
|
442
|
+
const lines = text.split("\n").filter((l) => l.trim().length > 0);
|
|
443
|
+
if (lines.length > 0 && lines[0]) {
|
|
444
|
+
return lines[0].replace(/^#+\s*/, "").replace(/\*\*/g, "").trim().slice(0, 80);
|
|
183
445
|
}
|
|
446
|
+
return "Presentation";
|
|
184
447
|
}
|
|
185
448
|
/**
|
|
186
|
-
*
|
|
449
|
+
* Detect presentation type from content signals
|
|
187
450
|
*/
|
|
188
|
-
|
|
189
|
-
const
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
451
|
+
detectPresentationType(text) {
|
|
452
|
+
const lowerText = text.toLowerCase();
|
|
453
|
+
const scores = {
|
|
454
|
+
ted_keynote: 0,
|
|
455
|
+
sales_pitch: 0,
|
|
456
|
+
consulting_deck: 0,
|
|
457
|
+
investment_banking: 0,
|
|
458
|
+
investor_pitch: 0,
|
|
459
|
+
technical_presentation: 0,
|
|
460
|
+
all_hands: 0
|
|
461
|
+
};
|
|
462
|
+
for (const [type, signals] of Object.entries(this.typeSignals)) {
|
|
463
|
+
for (const signal of signals) {
|
|
464
|
+
if (lowerText.includes(signal)) {
|
|
465
|
+
scores[type]++;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
let maxScore = 0;
|
|
470
|
+
let detectedType = "consulting_deck";
|
|
471
|
+
for (const [type, score] of Object.entries(scores)) {
|
|
472
|
+
if (score > maxScore) {
|
|
473
|
+
maxScore = score;
|
|
474
|
+
detectedType = type;
|
|
195
475
|
}
|
|
196
476
|
}
|
|
197
|
-
return
|
|
477
|
+
return detectedType;
|
|
198
478
|
}
|
|
199
479
|
/**
|
|
200
|
-
*
|
|
480
|
+
* Extract sections from content (headers, bullets, content)
|
|
201
481
|
*/
|
|
202
|
-
|
|
203
|
-
const
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
482
|
+
extractSections(text) {
|
|
483
|
+
const sections = [];
|
|
484
|
+
const lines = text.split("\n");
|
|
485
|
+
let currentSection = null;
|
|
486
|
+
let contentLines = [];
|
|
487
|
+
for (const line of lines) {
|
|
488
|
+
const trimmedLine = line.trim();
|
|
489
|
+
const headerMatch = trimmedLine.match(/^(#{1,6})\s+(.+)$/);
|
|
490
|
+
if (headerMatch) {
|
|
491
|
+
if (currentSection) {
|
|
492
|
+
currentSection.content = contentLines.join("\n").trim();
|
|
493
|
+
if (currentSection.header || currentSection.content || currentSection.bullets.length > 0) {
|
|
494
|
+
sections.push(currentSection);
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
currentSection = {
|
|
498
|
+
header: (headerMatch[2] || "").replace(/\*\*/g, "").trim(),
|
|
499
|
+
level: (headerMatch[1] || "").length,
|
|
500
|
+
content: "",
|
|
501
|
+
bullets: [],
|
|
502
|
+
metrics: []
|
|
503
|
+
};
|
|
504
|
+
contentLines = [];
|
|
505
|
+
continue;
|
|
506
|
+
}
|
|
507
|
+
const bulletMatch = trimmedLine.match(/^[-*+]\s+(.+)$/);
|
|
508
|
+
if (bulletMatch && bulletMatch[1] && currentSection) {
|
|
509
|
+
currentSection.bullets.push(bulletMatch[1]);
|
|
510
|
+
continue;
|
|
511
|
+
}
|
|
512
|
+
const numberedMatch = trimmedLine.match(/^\d+\.\s+(.+)$/);
|
|
513
|
+
if (numberedMatch && numberedMatch[1] && currentSection) {
|
|
514
|
+
currentSection.bullets.push(numberedMatch[1]);
|
|
515
|
+
continue;
|
|
516
|
+
}
|
|
517
|
+
const metricMatch = trimmedLine.match(/\$?([\d,]+\.?\d*)[%]?\s*[-–—:]\s*(.+)/);
|
|
518
|
+
if (metricMatch && metricMatch[1] && metricMatch[2] && currentSection) {
|
|
519
|
+
currentSection.metrics.push({
|
|
520
|
+
value: metricMatch[1],
|
|
521
|
+
label: metricMatch[2].slice(0, 50)
|
|
522
|
+
});
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
if (trimmedLine.includes("|") && currentSection) {
|
|
526
|
+
const cells = trimmedLine.split("|").map((c) => c.trim()).filter((c) => c && !c.match(/^-+$/));
|
|
527
|
+
if (cells.length >= 2) {
|
|
528
|
+
const value = cells.find((c) => c.match(/^\$?[\d,]+\.?\d*[%]?$/));
|
|
529
|
+
const label = cells.find((c) => !c.match(/^\$?[\d,]+\.?\d*[%]?$/) && c.length > 2);
|
|
530
|
+
if (value && label) {
|
|
531
|
+
currentSection.metrics.push({ value, label: label.slice(0, 50) });
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
continue;
|
|
210
535
|
}
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
const newPrefix = prefix ? `${prefix}.${key}` : key;
|
|
214
|
-
parts.push(this.flattenObject(value, newPrefix));
|
|
536
|
+
if (trimmedLine && currentSection) {
|
|
537
|
+
contentLines.push(trimmedLine);
|
|
215
538
|
}
|
|
216
|
-
} else if (obj !== null && obj !== void 0) {
|
|
217
|
-
parts.push(String(obj));
|
|
218
539
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
return
|
|
226
|
-
}
|
|
227
|
-
/**
|
|
228
|
-
* Split text into sentences.
|
|
229
|
-
*/
|
|
230
|
-
splitIntoSentences(text) {
|
|
231
|
-
const cleaned = text.replace(/Mr\./g, "Mr").replace(/Mrs\./g, "Mrs").replace(/Dr\./g, "Dr").replace(/vs\./g, "vs").replace(/etc\./g, "etc").replace(/e\.g\./g, "eg").replace(/i\.e\./g, "ie");
|
|
232
|
-
return cleaned.split(/[.!?]+/).map((s) => s.trim()).filter((s) => s.length > 10);
|
|
540
|
+
if (currentSection) {
|
|
541
|
+
currentSection.content = contentLines.join("\n").trim();
|
|
542
|
+
if (currentSection.header || currentSection.content || currentSection.bullets.length > 0) {
|
|
543
|
+
sections.push(currentSection);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
return sections;
|
|
233
547
|
}
|
|
234
548
|
/**
|
|
235
|
-
* Extract SCQA structure (Barbara Minto
|
|
549
|
+
* Extract SCQA structure (Barbara Minto)
|
|
236
550
|
*/
|
|
237
|
-
extractSCQA(
|
|
551
|
+
extractSCQA(text) {
|
|
552
|
+
const paragraphs = text.split(/\n\n+/).filter((p) => p.trim());
|
|
238
553
|
let situation = "";
|
|
239
554
|
let complication = "";
|
|
240
555
|
let question = "";
|
|
241
556
|
let answer = "";
|
|
242
557
|
for (const para of paragraphs.slice(0, 3)) {
|
|
243
|
-
if (this.containsSignals(para, this.situationSignals)) {
|
|
244
|
-
situation = this.
|
|
558
|
+
if (this.containsSignals(para.toLowerCase(), this.situationSignals)) {
|
|
559
|
+
situation = this.extractFirstSentence(para);
|
|
245
560
|
break;
|
|
246
561
|
}
|
|
247
562
|
}
|
|
248
563
|
for (const para of paragraphs) {
|
|
249
|
-
if (this.containsSignals(para, this.complicationSignals)) {
|
|
250
|
-
complication = this.
|
|
564
|
+
if (this.containsSignals(para.toLowerCase(), this.complicationSignals)) {
|
|
565
|
+
complication = this.extractFirstSentence(para);
|
|
251
566
|
break;
|
|
252
567
|
}
|
|
253
568
|
}
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
569
|
+
const middleStart = Math.floor(paragraphs.length * 0.2);
|
|
570
|
+
const middleEnd = Math.floor(paragraphs.length * 0.8);
|
|
571
|
+
for (const para of paragraphs.slice(middleStart, middleEnd)) {
|
|
572
|
+
const lowerPara = para.toLowerCase();
|
|
573
|
+
if (this.containsSignals(lowerPara, this.answerSignals) && !this.containsSignals(lowerPara, this.ctaSignals)) {
|
|
574
|
+
answer = this.extractFirstSentence(para);
|
|
257
575
|
break;
|
|
258
576
|
}
|
|
259
577
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
answer = this.extractRelevantSentence(para, this.answerSignals);
|
|
263
|
-
break;
|
|
264
|
-
}
|
|
578
|
+
if (!situation && paragraphs.length > 0 && paragraphs[0]) {
|
|
579
|
+
situation = this.extractFirstSentence(paragraphs[0]);
|
|
265
580
|
}
|
|
266
|
-
if (!
|
|
267
|
-
|
|
581
|
+
if (!answer && paragraphs.length > 2) {
|
|
582
|
+
for (const para of paragraphs.slice(1, Math.floor(paragraphs.length * 0.5))) {
|
|
583
|
+
const lowerPara = para.toLowerCase();
|
|
584
|
+
if (lowerPara.includes("recommend") || lowerPara.includes("strategy") || lowerPara.includes("solution") || lowerPara.includes("approach")) {
|
|
585
|
+
answer = this.extractFirstSentence(para);
|
|
586
|
+
break;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
268
589
|
}
|
|
269
|
-
if (
|
|
270
|
-
|
|
271
|
-
answer = lastPara ? this.truncateToSentence(lastPara, 150) : "";
|
|
590
|
+
if (complication && !question) {
|
|
591
|
+
question = `How do we address: ${complication.slice(0, 80)}?`;
|
|
272
592
|
}
|
|
273
593
|
return { situation, complication, question, answer };
|
|
274
594
|
}
|
|
275
595
|
/**
|
|
276
|
-
* Extract
|
|
596
|
+
* Extract STAR moments (Something They'll Always Remember)
|
|
597
|
+
* Per Nancy Duarte - these are emotional peaks in the presentation
|
|
277
598
|
*/
|
|
278
|
-
|
|
279
|
-
const
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
599
|
+
extractStarMoments(text) {
|
|
600
|
+
const starMoments = [];
|
|
601
|
+
const boldMatches = text.match(/\*\*(.+?)\*\*/g);
|
|
602
|
+
if (boldMatches) {
|
|
603
|
+
for (const match of boldMatches.slice(0, 5)) {
|
|
604
|
+
const cleaned = match.replace(/\*\*/g, "").trim();
|
|
605
|
+
const lowerCleaned = cleaned.toLowerCase();
|
|
606
|
+
if (cleaned.length > 15 && cleaned.length < 100 && !this.containsSignals(lowerCleaned, this.ctaSignals) && !/^\d+[%x]?\s*$/.test(cleaned)) {
|
|
607
|
+
starMoments.push(cleaned);
|
|
608
|
+
}
|
|
286
609
|
}
|
|
287
|
-
|
|
288
|
-
|
|
610
|
+
}
|
|
611
|
+
const exclamations = text.match(/[^.!?]*![^.!?]*/g);
|
|
612
|
+
if (exclamations) {
|
|
613
|
+
for (const ex of exclamations.slice(0, 2)) {
|
|
614
|
+
const cleaned = ex.trim();
|
|
615
|
+
const lowerCleaned = cleaned.toLowerCase();
|
|
616
|
+
if (cleaned.length > 10 && cleaned.length < 100 && !starMoments.includes(cleaned) && !this.containsSignals(lowerCleaned, this.ctaSignals)) {
|
|
617
|
+
starMoments.push(cleaned);
|
|
618
|
+
}
|
|
289
619
|
}
|
|
290
620
|
}
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
621
|
+
return starMoments.slice(0, 3);
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Extract Sparkline elements (Nancy Duarte)
|
|
625
|
+
*/
|
|
626
|
+
extractSparkline(text) {
|
|
627
|
+
const paragraphs = text.split(/\n\n+/).filter((p) => p.trim());
|
|
628
|
+
let callToAction = "";
|
|
629
|
+
const ctaSignals = ["next steps", "call to action", "take action", "start now", "join us", "contact"];
|
|
630
|
+
for (const para of paragraphs.slice(-3)) {
|
|
631
|
+
if (this.containsSignals(para.toLowerCase(), ctaSignals)) {
|
|
632
|
+
callToAction = this.extractFirstSentence(para);
|
|
294
633
|
break;
|
|
295
634
|
}
|
|
296
635
|
}
|
|
297
|
-
return {
|
|
636
|
+
return { callToAction };
|
|
298
637
|
}
|
|
299
638
|
/**
|
|
300
|
-
* Extract key messages (max 3 - Rule of Three)
|
|
639
|
+
* Extract key messages (max 3 - Rule of Three)
|
|
301
640
|
*/
|
|
302
|
-
extractKeyMessages(text
|
|
641
|
+
extractKeyMessages(text) {
|
|
303
642
|
const messages = [];
|
|
304
|
-
const
|
|
305
|
-
if (
|
|
306
|
-
for (const match of
|
|
307
|
-
const
|
|
308
|
-
if (
|
|
309
|
-
messages.push(
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
const headerMatches = text.match(/\[HEADER\](.+)/g);
|
|
314
|
-
if (headerMatches && messages.length < 3) {
|
|
315
|
-
for (const match of headerMatches.slice(0, 3 - messages.length)) {
|
|
316
|
-
const content = match.replace("[HEADER]", "").trim();
|
|
317
|
-
if (content.length > 5 && content.length < 80) {
|
|
318
|
-
messages.push(content);
|
|
643
|
+
const h2Matches = text.match(/^##\s+(.+)$/gm);
|
|
644
|
+
if (h2Matches) {
|
|
645
|
+
for (const match of h2Matches.slice(0, 3)) {
|
|
646
|
+
const msg = match.replace(/^##\s+/, "").replace(/\*\*/g, "").trim();
|
|
647
|
+
if (msg.length > 5 && msg.length < 80) {
|
|
648
|
+
messages.push(msg);
|
|
319
649
|
}
|
|
320
650
|
}
|
|
321
651
|
}
|
|
322
652
|
if (messages.length < 3) {
|
|
323
|
-
const
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
messages.push(sentence);
|
|
332
|
-
if (messages.length >= 3) break;
|
|
653
|
+
const boldMatches = text.match(/\*\*(.+?)\*\*/g);
|
|
654
|
+
if (boldMatches) {
|
|
655
|
+
for (const match of boldMatches) {
|
|
656
|
+
const msg = match.replace(/\*\*/g, "").trim();
|
|
657
|
+
if (msg.length > 10 && msg.length < 80 && !messages.includes(msg)) {
|
|
658
|
+
messages.push(msg);
|
|
659
|
+
if (messages.length >= 3) break;
|
|
660
|
+
}
|
|
333
661
|
}
|
|
334
662
|
}
|
|
335
663
|
}
|
|
336
664
|
return messages.slice(0, 3);
|
|
337
665
|
}
|
|
338
666
|
/**
|
|
339
|
-
*
|
|
667
|
+
* Extract data points (metrics with values)
|
|
340
668
|
*/
|
|
341
|
-
|
|
342
|
-
const
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
669
|
+
extractDataPoints(text) {
|
|
670
|
+
const dataPoints = [];
|
|
671
|
+
const dollarMatches = text.match(/\$[\d,]+(?:\.\d+)?[MBK]?(?:\s*(?:million|billion|thousand))?/gi);
|
|
672
|
+
if (dollarMatches) {
|
|
673
|
+
for (const match of dollarMatches.slice(0, 4)) {
|
|
674
|
+
const context = this.getContextAroundMatch(text, match);
|
|
675
|
+
dataPoints.push({
|
|
676
|
+
value: match,
|
|
677
|
+
label: this.extractLabelFromContext(context)
|
|
678
|
+
});
|
|
347
679
|
}
|
|
348
680
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
const
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
681
|
+
const percentMatches = text.match(/\d+(?:\.\d+)?%/g);
|
|
682
|
+
if (percentMatches) {
|
|
683
|
+
for (const match of percentMatches.slice(0, 4)) {
|
|
684
|
+
if (!dataPoints.some((d) => d.value === match)) {
|
|
685
|
+
const context = this.getContextAroundMatch(text, match);
|
|
686
|
+
dataPoints.push({
|
|
687
|
+
value: match,
|
|
688
|
+
label: this.extractLabelFromContext(context)
|
|
689
|
+
});
|
|
356
690
|
}
|
|
357
691
|
}
|
|
358
692
|
}
|
|
359
|
-
return
|
|
693
|
+
return dataPoints.slice(0, 6);
|
|
360
694
|
}
|
|
361
695
|
/**
|
|
362
|
-
*
|
|
696
|
+
* Get context around a match
|
|
363
697
|
*/
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
const
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
}
|
|
371
|
-
if (title.toLowerCase().includes("should")) {
|
|
372
|
-
title = title.replace(/we should|you should|should/gi, "").trim();
|
|
373
|
-
return this.capitalizeFirst(title);
|
|
374
|
-
}
|
|
375
|
-
if (title.toLowerCase().includes("need to")) {
|
|
376
|
-
title = title.replace(/we need to|you need to|need to/gi, "").trim();
|
|
377
|
-
return this.capitalizeFirst(title);
|
|
378
|
-
}
|
|
379
|
-
if (title.length < 50) {
|
|
380
|
-
return title;
|
|
381
|
-
}
|
|
382
|
-
return this.truncateToWords(title, 8);
|
|
698
|
+
getContextAroundMatch(text, match) {
|
|
699
|
+
const index = text.indexOf(match);
|
|
700
|
+
if (index === -1) return "";
|
|
701
|
+
const start = Math.max(0, index - 50);
|
|
702
|
+
const end = Math.min(text.length, index + match.length + 50);
|
|
703
|
+
return text.slice(start, end);
|
|
383
704
|
}
|
|
384
705
|
/**
|
|
385
|
-
*
|
|
706
|
+
* Extract a label from surrounding context
|
|
707
|
+
* Fixes the "Century Interactive |" garbage issue by stripping table syntax
|
|
386
708
|
*/
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
const
|
|
390
|
-
|
|
391
|
-
"amazing",
|
|
392
|
-
"incredible",
|
|
393
|
-
"remarkable",
|
|
394
|
-
"stunning",
|
|
395
|
-
"imagine",
|
|
396
|
-
"what if",
|
|
397
|
-
"breakthrough",
|
|
398
|
-
"revolutionary",
|
|
399
|
-
"never before",
|
|
400
|
-
"first time",
|
|
401
|
-
"unprecedented",
|
|
402
|
-
"game-changing",
|
|
403
|
-
"dramatic"
|
|
404
|
-
];
|
|
405
|
-
for (const para of paragraphs) {
|
|
406
|
-
if (this.containsSignals(para.toLowerCase(), starSignals)) {
|
|
407
|
-
const moment = this.truncateToSentence(para, 120);
|
|
408
|
-
if (moment.length > 20) {
|
|
409
|
-
starMoments.push(moment);
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
const statPattern = /\d+[%xX]|\$[\d,]+(?:\s*(?:million|billion|trillion))?|\d+(?:\s*(?:million|billion|trillion))/g;
|
|
414
|
-
for (const para of paragraphs) {
|
|
415
|
-
if (statPattern.test(para) && starMoments.length < 5) {
|
|
416
|
-
const moment = this.truncateToSentence(para, 100);
|
|
417
|
-
if (!starMoments.includes(moment)) {
|
|
418
|
-
starMoments.push(moment);
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
return starMoments.slice(0, 5);
|
|
709
|
+
extractLabelFromContext(context) {
|
|
710
|
+
let cleaned = context.replace(/\|/g, " ").replace(/-{3,}/g, "").replace(/\s{2,}/g, " ").replace(/\*\*/g, "").replace(/#+\s*/g, "").trim();
|
|
711
|
+
const words = cleaned.split(/\s+/).filter((w) => w.length > 2 && !w.match(/^\d/));
|
|
712
|
+
return words.slice(0, 4).join(" ") || "Value";
|
|
423
713
|
}
|
|
424
714
|
/**
|
|
425
|
-
*
|
|
715
|
+
* Check if text contains any of the signals
|
|
426
716
|
*/
|
|
427
|
-
estimateSlideCount(text, paragraphs) {
|
|
428
|
-
const wordCount = text.split(/\s+/).length;
|
|
429
|
-
const headerCount = (text.match(/\[HEADER\]/g) ?? []).length;
|
|
430
|
-
const bulletGroups = (text.match(/\[BULLET\]/g) ?? []).length / 4;
|
|
431
|
-
const wordBasedEstimate = Math.ceil(wordCount / 35);
|
|
432
|
-
const estimate = Math.max(
|
|
433
|
-
5,
|
|
434
|
-
// Minimum 5 slides
|
|
435
|
-
Math.ceil((wordBasedEstimate + headerCount + bulletGroups) / 2)
|
|
436
|
-
);
|
|
437
|
-
return Math.min(estimate, 30);
|
|
438
|
-
}
|
|
439
|
-
// === Helper Methods ===
|
|
440
717
|
containsSignals(text, signals) {
|
|
441
|
-
|
|
442
|
-
return signals.some((signal) => lowerText.includes(signal));
|
|
443
|
-
}
|
|
444
|
-
extractRelevantSentence(paragraph, signals) {
|
|
445
|
-
const sentences = paragraph.split(/[.!?]+/);
|
|
446
|
-
for (const sentence of sentences) {
|
|
447
|
-
if (this.containsSignals(sentence.toLowerCase(), signals)) {
|
|
448
|
-
return sentence.trim();
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
return this.truncateToSentence(paragraph, 150);
|
|
718
|
+
return signals.some((signal) => text.includes(signal));
|
|
452
719
|
}
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
const
|
|
458
|
-
const
|
|
459
|
-
const
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
if (lastBoundary > maxLength * 0.5) {
|
|
463
|
-
return text.slice(0, lastBoundary + 1).trim();
|
|
464
|
-
}
|
|
465
|
-
return truncated.trim() + "...";
|
|
466
|
-
}
|
|
467
|
-
truncateToWords(text, maxWords) {
|
|
468
|
-
const words = text.split(/\s+/);
|
|
469
|
-
if (words.length <= maxWords) {
|
|
470
|
-
return text;
|
|
720
|
+
/**
|
|
721
|
+
* Extract first meaningful sentence from text
|
|
722
|
+
*/
|
|
723
|
+
extractFirstSentence(text) {
|
|
724
|
+
const cleaned = text.replace(/^#+\s*/gm, "").replace(/\*\*/g, "").replace(/\|/g, " ").trim();
|
|
725
|
+
const sentences = cleaned.split(/[.!?]+/);
|
|
726
|
+
const first = sentences[0]?.trim();
|
|
727
|
+
if (first && first.length > 10) {
|
|
728
|
+
return first.slice(0, 150);
|
|
471
729
|
}
|
|
472
|
-
return
|
|
473
|
-
}
|
|
474
|
-
capitalizeFirst(text) {
|
|
475
|
-
if (!text) return "";
|
|
476
|
-
return text.charAt(0).toUpperCase() + text.slice(1);
|
|
730
|
+
return cleaned.slice(0, 150);
|
|
477
731
|
}
|
|
478
732
|
};
|
|
479
733
|
|
|
480
734
|
// src/core/SlideFactory.ts
|
|
481
735
|
var SlideFactory = class {
|
|
482
736
|
templates;
|
|
737
|
+
usedContent = /* @__PURE__ */ new Set();
|
|
483
738
|
constructor() {
|
|
484
739
|
this.templates = this.initializeTemplates();
|
|
485
740
|
}
|
|
741
|
+
/**
|
|
742
|
+
* Check if content has already been used (deduplication)
|
|
743
|
+
*/
|
|
744
|
+
isContentUsed(content) {
|
|
745
|
+
if (!content) return true;
|
|
746
|
+
const normalized = content.toLowerCase().replace(/[^a-z0-9]/g, "").slice(0, 50);
|
|
747
|
+
if (this.usedContent.has(normalized)) {
|
|
748
|
+
return true;
|
|
749
|
+
}
|
|
750
|
+
this.usedContent.add(normalized);
|
|
751
|
+
return false;
|
|
752
|
+
}
|
|
486
753
|
/**
|
|
487
754
|
* Create slides from analyzed content.
|
|
488
755
|
*/
|
|
489
756
|
async createSlides(analysis, mode) {
|
|
490
757
|
const slides = [];
|
|
491
758
|
let slideIndex = 0;
|
|
759
|
+
this.usedContent.clear();
|
|
492
760
|
slides.push(this.createTitleSlide(slideIndex++, analysis));
|
|
761
|
+
this.isContentUsed(analysis.titles[0] ?? "");
|
|
493
762
|
if (mode === "business" && analysis.keyMessages.length >= 2) {
|
|
494
763
|
slides.push(this.createAgendaSlide(slideIndex++, analysis));
|
|
495
764
|
}
|
|
496
|
-
if (analysis.scqa.situation) {
|
|
765
|
+
if (analysis.scqa.situation && !this.isContentUsed(analysis.scqa.situation)) {
|
|
497
766
|
slides.push(this.createContextSlide(slideIndex++, analysis, mode));
|
|
498
767
|
}
|
|
499
|
-
if (analysis.scqa.complication) {
|
|
768
|
+
if (analysis.scqa.complication && !this.isContentUsed(analysis.scqa.complication)) {
|
|
500
769
|
slides.push(this.createProblemSlide(slideIndex++, analysis, mode));
|
|
501
770
|
}
|
|
502
771
|
for (const message of analysis.keyMessages) {
|
|
503
|
-
|
|
772
|
+
if (!this.isContentUsed(message)) {
|
|
773
|
+
slides.push(this.createMessageSlide(slideIndex++, message, mode));
|
|
774
|
+
}
|
|
504
775
|
}
|
|
505
776
|
for (const starMoment of analysis.starMoments.slice(0, 2)) {
|
|
506
|
-
|
|
777
|
+
if (!this.isContentUsed(starMoment)) {
|
|
778
|
+
slides.push(this.createStarMomentSlide(slideIndex++, starMoment, mode));
|
|
779
|
+
}
|
|
507
780
|
}
|
|
508
|
-
if (analysis.scqa.answer) {
|
|
781
|
+
if (analysis.scqa.answer && !this.isContentUsed(analysis.scqa.answer)) {
|
|
509
782
|
slides.push(this.createSolutionSlide(slideIndex++, analysis, mode));
|
|
510
783
|
}
|
|
511
|
-
if (analysis.sparkline.callToAdventure) {
|
|
784
|
+
if (analysis.sparkline.callToAdventure && !this.isContentUsed(analysis.sparkline.callToAdventure)) {
|
|
512
785
|
slides.push(this.createCTASlide(slideIndex++, analysis, mode));
|
|
513
786
|
}
|
|
514
787
|
slides.push(this.createThankYouSlide(slideIndex++));
|
|
@@ -518,13 +791,18 @@ var SlideFactory = class {
|
|
|
518
791
|
* Create a title slide.
|
|
519
792
|
*/
|
|
520
793
|
createTitleSlide(index, analysis) {
|
|
521
|
-
|
|
794
|
+
let subtitle = "";
|
|
795
|
+
if (analysis.scqa.answer && analysis.scqa.answer.length > 10) {
|
|
796
|
+
subtitle = analysis.scqa.answer;
|
|
797
|
+
} else if (analysis.starMoments.length > 0 && analysis.starMoments[0]) {
|
|
798
|
+
subtitle = analysis.starMoments[0];
|
|
799
|
+
}
|
|
522
800
|
return {
|
|
523
801
|
index,
|
|
524
802
|
type: "title",
|
|
525
803
|
data: {
|
|
526
804
|
title: analysis.titles[0] ?? "Presentation",
|
|
527
|
-
subtitle: this.truncate(subtitle,
|
|
805
|
+
subtitle: this.truncate(subtitle, 80),
|
|
528
806
|
keyMessage: analysis.scqa.answer
|
|
529
807
|
},
|
|
530
808
|
classes: ["slide-title"]
|
|
@@ -1755,19 +2033,28 @@ var ScoreCalculator = class {
|
|
|
1755
2033
|
import { chromium } from "playwright";
|
|
1756
2034
|
var QAEngine = class {
|
|
1757
2035
|
browser = null;
|
|
2036
|
+
kb;
|
|
2037
|
+
/**
|
|
2038
|
+
* Initialize KnowledgeGateway
|
|
2039
|
+
*/
|
|
2040
|
+
async initialize() {
|
|
2041
|
+
this.kb = await getKnowledgeGateway();
|
|
2042
|
+
}
|
|
1758
2043
|
/**
|
|
1759
|
-
* Validate a presentation
|
|
2044
|
+
* Validate a presentation using KB-driven quality metrics
|
|
1760
2045
|
*/
|
|
1761
2046
|
async validate(presentation, options) {
|
|
2047
|
+
await this.initialize();
|
|
1762
2048
|
const html = typeof presentation === "string" ? presentation : presentation.toString("utf-8");
|
|
1763
2049
|
const mode = options?.mode ?? "keynote";
|
|
2050
|
+
const qualityMetrics = this.kb.getQualityMetrics();
|
|
1764
2051
|
await this.initBrowser();
|
|
1765
2052
|
try {
|
|
1766
2053
|
const [visualResults, contentResults, expertResults, accessibilityResults] = await Promise.all([
|
|
1767
|
-
this.runVisualTests(html, mode),
|
|
1768
|
-
this.runContentTests(html, mode),
|
|
2054
|
+
this.runVisualTests(html, mode, qualityMetrics),
|
|
2055
|
+
this.runContentTests(html, mode, qualityMetrics),
|
|
1769
2056
|
this.runExpertTests(html, mode),
|
|
1770
|
-
this.runAccessibilityTests(html)
|
|
2057
|
+
this.runAccessibilityTests(html, qualityMetrics)
|
|
1771
2058
|
]);
|
|
1772
2059
|
const issues = this.collectIssues(visualResults, contentResults, expertResults, accessibilityResults);
|
|
1773
2060
|
const errorCount = issues.filter((i) => i.severity === "error").length;
|
|
@@ -1785,18 +2072,18 @@ var QAEngine = class {
|
|
|
1785
2072
|
}
|
|
1786
2073
|
}
|
|
1787
2074
|
/**
|
|
1788
|
-
* Calculate overall QA score
|
|
2075
|
+
* Calculate overall QA score using KB-driven weights
|
|
1789
2076
|
*/
|
|
1790
2077
|
calculateScore(results) {
|
|
1791
2078
|
const weights = {
|
|
1792
2079
|
visual: 0.35,
|
|
1793
|
-
// 35%
|
|
2080
|
+
// 35% - Design quality
|
|
1794
2081
|
content: 0.3,
|
|
1795
|
-
// 30%
|
|
2082
|
+
// 30% - Content quality
|
|
1796
2083
|
expert: 0.25,
|
|
1797
|
-
// 25%
|
|
2084
|
+
// 25% - Expert methodology
|
|
1798
2085
|
accessibility: 0.1
|
|
1799
|
-
// 10%
|
|
2086
|
+
// 10% - Accessibility
|
|
1800
2087
|
};
|
|
1801
2088
|
const visualScore = this.calculateVisualScore(results.visual);
|
|
1802
2089
|
const contentScore = this.calculateContentScore(results.content);
|
|
@@ -1843,13 +2130,15 @@ var QAEngine = class {
|
|
|
1843
2130
|
};
|
|
1844
2131
|
}
|
|
1845
2132
|
// ===========================================================================
|
|
1846
|
-
// VISUAL TESTS
|
|
2133
|
+
// VISUAL TESTS - KB-DRIVEN
|
|
1847
2134
|
// ===========================================================================
|
|
1848
|
-
async runVisualTests(html, mode) {
|
|
2135
|
+
async runVisualTests(html, mode, qualityMetrics) {
|
|
1849
2136
|
const page = await this.browser.newPage();
|
|
1850
2137
|
await page.setViewportSize({ width: 1280, height: 720 });
|
|
1851
2138
|
await page.setContent(html);
|
|
1852
2139
|
await page.waitForTimeout(1e3);
|
|
2140
|
+
const modeMetrics = mode === "keynote" ? qualityMetrics.keynote_mode : qualityMetrics.business_mode;
|
|
2141
|
+
const minWhitespace = this.kb.getWhitespaceRequirement(mode) * 100;
|
|
1853
2142
|
const slideCount = await page.evaluate(() => {
|
|
1854
2143
|
return window.Reveal?.getTotalSlides?.() ?? document.querySelectorAll(".slides > section").length;
|
|
1855
2144
|
});
|
|
@@ -1915,9 +2204,8 @@ var QAEngine = class {
|
|
|
1915
2204
|
}, { slideIndex: i });
|
|
1916
2205
|
if (slideAnalysis) {
|
|
1917
2206
|
const issues = [];
|
|
1918
|
-
const minWhitespace = mode === "keynote" ? 40 : 25;
|
|
1919
2207
|
if (slideAnalysis.whitespace < minWhitespace) {
|
|
1920
|
-
issues.push(`Whitespace ${slideAnalysis.whitespace}% below ${minWhitespace}% minimum`);
|
|
2208
|
+
issues.push(`Whitespace ${slideAnalysis.whitespace}% below ${minWhitespace}% minimum (KB-defined)`);
|
|
1921
2209
|
}
|
|
1922
2210
|
if (slideAnalysis.whitespace > 80) {
|
|
1923
2211
|
issues.push(`Whitespace ${slideAnalysis.whitespace}% - slide appears sparse`);
|
|
@@ -1972,34 +2260,35 @@ var QAEngine = class {
|
|
|
1972
2260
|
};
|
|
1973
2261
|
}
|
|
1974
2262
|
// ===========================================================================
|
|
1975
|
-
// CONTENT TESTS
|
|
2263
|
+
// CONTENT TESTS - KB-DRIVEN
|
|
1976
2264
|
// ===========================================================================
|
|
1977
|
-
async runContentTests(html, mode) {
|
|
2265
|
+
async runContentTests(html, mode, qualityMetrics) {
|
|
1978
2266
|
const page = await this.browser.newPage();
|
|
1979
2267
|
await page.setContent(html);
|
|
1980
2268
|
await page.waitForTimeout(500);
|
|
1981
|
-
const
|
|
2269
|
+
const wordLimits = this.kb.getWordLimits(mode);
|
|
2270
|
+
const glanceTest = this.kb.getDuarteGlanceTest();
|
|
2271
|
+
const results = await page.evaluate((params) => {
|
|
2272
|
+
const { targetMode, maxWords, minWords, glanceWordLimit } = params;
|
|
1982
2273
|
const slides = document.querySelectorAll(".slides > section");
|
|
1983
2274
|
const perSlide = [];
|
|
1984
|
-
const
|
|
2275
|
+
const glanceTestResults = [];
|
|
1985
2276
|
const signalNoise = [];
|
|
1986
2277
|
const oneIdea = [];
|
|
1987
2278
|
slides.forEach((slide, index) => {
|
|
1988
2279
|
const text = slide.innerText || "";
|
|
1989
2280
|
const words = text.split(/\s+/).filter((w) => w.length > 0);
|
|
1990
2281
|
const wordCount = words.length;
|
|
1991
|
-
const maxWords = targetMode === "keynote" ? 25 : 80;
|
|
1992
|
-
const minWords = targetMode === "business" ? 20 : 0;
|
|
1993
2282
|
const withinLimit = wordCount <= maxWords && wordCount >= minWords;
|
|
1994
2283
|
const title = slide.querySelector("h2")?.textContent || "";
|
|
1995
2284
|
const hasVerb = /\b(is|are|was|were|has|have|had|will|can|could|should|would|may|might|must|exceeded|increased|decreased|grew|fell|drove|caused|enabled|prevented|achieved|failed|creates?|generates?|delivers?|provides?|shows?|demonstrates?)\b/i.test(title);
|
|
1996
2285
|
const hasInsight = title.length > 30 && hasVerb;
|
|
1997
2286
|
const issues = [];
|
|
1998
2287
|
if (!withinLimit) {
|
|
1999
|
-
issues.push(`Word count ${wordCount} outside ${minWords}-${maxWords} range`);
|
|
2288
|
+
issues.push(`Word count ${wordCount} outside ${minWords}-${maxWords} range (KB-defined)`);
|
|
2000
2289
|
}
|
|
2001
2290
|
if (targetMode === "business" && !hasInsight && index > 0) {
|
|
2002
|
-
issues.push("Title is not action-oriented (missing insight)");
|
|
2291
|
+
issues.push("Title is not action-oriented (missing insight per Minto)");
|
|
2003
2292
|
}
|
|
2004
2293
|
perSlide.push({
|
|
2005
2294
|
slideIndex: index,
|
|
@@ -2012,12 +2301,12 @@ var QAEngine = class {
|
|
|
2012
2301
|
const keyMessage = prominentElement?.textContent?.trim() || "";
|
|
2013
2302
|
const keyWordCount = keyMessage.split(/\s+/).filter((w) => w.length > 0).length;
|
|
2014
2303
|
const readingTime = keyWordCount / 4.2;
|
|
2015
|
-
|
|
2304
|
+
glanceTestResults.push({
|
|
2016
2305
|
slideIndex: index,
|
|
2017
2306
|
keyMessage,
|
|
2018
2307
|
wordCount: keyWordCount,
|
|
2019
2308
|
readingTime: Math.round(readingTime * 10) / 10,
|
|
2020
|
-
passed: readingTime <= 3 && keyWordCount <=
|
|
2309
|
+
passed: readingTime <= 3 && keyWordCount <= glanceWordLimit,
|
|
2021
2310
|
recommendation: readingTime > 3 ? `Shorten to ${Math.floor(3 * 4.2)} words or less` : void 0
|
|
2022
2311
|
});
|
|
2023
2312
|
const elements = slide.querySelectorAll("h1, h2, h3, p, li, img");
|
|
@@ -2044,35 +2333,143 @@ var QAEngine = class {
|
|
|
2044
2333
|
conflictingIdeas: ideaCount > 2 ? ["Multiple competing ideas detected"] : void 0
|
|
2045
2334
|
});
|
|
2046
2335
|
});
|
|
2047
|
-
return { perSlide, glanceTest, signalNoise, oneIdea };
|
|
2048
|
-
},
|
|
2336
|
+
return { perSlide, glanceTest: glanceTestResults, signalNoise, oneIdea };
|
|
2337
|
+
}, {
|
|
2338
|
+
targetMode: mode,
|
|
2339
|
+
maxWords: wordLimits.max,
|
|
2340
|
+
minWords: mode === "business" ? 20 : 0,
|
|
2341
|
+
glanceWordLimit: glanceTest.wordLimit
|
|
2342
|
+
});
|
|
2049
2343
|
await page.close();
|
|
2050
2344
|
return results;
|
|
2051
2345
|
}
|
|
2052
2346
|
// ===========================================================================
|
|
2053
|
-
// EXPERT TESTS
|
|
2347
|
+
// EXPERT TESTS - KB-DRIVEN
|
|
2054
2348
|
// ===========================================================================
|
|
2055
2349
|
async runExpertTests(html, mode) {
|
|
2350
|
+
const duartePrinciples = this.kb.getExpertPrinciples("nancy_duarte");
|
|
2351
|
+
const reynoldsPrinciples = this.kb.getExpertPrinciples("garr_reynolds");
|
|
2352
|
+
const galloPrinciples = this.kb.getExpertPrinciples("carmine_gallo");
|
|
2353
|
+
const andersonPrinciples = this.kb.getExpertPrinciples("chris_anderson");
|
|
2056
2354
|
return {
|
|
2057
|
-
duarte: this.
|
|
2058
|
-
reynolds: this.
|
|
2059
|
-
gallo: this.
|
|
2060
|
-
anderson: this.
|
|
2355
|
+
duarte: this.validateDuartePrinciples(html, duartePrinciples),
|
|
2356
|
+
reynolds: this.validateReynoldsPrinciples(html, reynoldsPrinciples),
|
|
2357
|
+
gallo: this.validateGalloPrinciples(html, galloPrinciples),
|
|
2358
|
+
anderson: this.validateAndersonPrinciples(html, andersonPrinciples)
|
|
2061
2359
|
};
|
|
2062
2360
|
}
|
|
2063
|
-
|
|
2361
|
+
validateDuartePrinciples(html, principles) {
|
|
2362
|
+
const violations = [];
|
|
2363
|
+
let score = 100;
|
|
2364
|
+
const slideMatches = html.match(/<section[^>]*>[\s\S]*?<\/section>/gi) || [];
|
|
2365
|
+
slideMatches.forEach((slide, index) => {
|
|
2366
|
+
const h1Match = slide.match(/<h1[^>]*>([\s\S]*?)<\/h1>/i);
|
|
2367
|
+
const h2Match = slide.match(/<h2[^>]*>([\s\S]*?)<\/h2>/i);
|
|
2368
|
+
const keyMessage = (h1Match?.[1] || h2Match?.[1] || "").replace(/<[^>]+>/g, "").trim();
|
|
2369
|
+
const wordCount = keyMessage.split(/\s+/).filter((w) => w.length > 0).length;
|
|
2370
|
+
if (wordCount > 25) {
|
|
2371
|
+
violations.push(`Slide ${index + 1}: Key message exceeds 25 words (Duarte Glance Test)`);
|
|
2372
|
+
score -= 5;
|
|
2373
|
+
}
|
|
2374
|
+
});
|
|
2375
|
+
const hasStarMoment = html.includes("callout") || html.includes("highlight") || html.includes("big-idea");
|
|
2376
|
+
if (!hasStarMoment && slideMatches.length > 5) {
|
|
2377
|
+
violations.push("Missing STAR moment (Something They'll Always Remember)");
|
|
2378
|
+
score -= 10;
|
|
2379
|
+
}
|
|
2064
2380
|
return {
|
|
2065
|
-
expertName:
|
|
2066
|
-
principlesChecked:
|
|
2381
|
+
expertName: "Nancy Duarte",
|
|
2382
|
+
principlesChecked: ["Glance Test", "STAR Moment", "Sparkline Structure"],
|
|
2067
2383
|
passed: score >= 80,
|
|
2068
|
-
score,
|
|
2069
|
-
violations
|
|
2384
|
+
score: Math.max(0, score),
|
|
2385
|
+
violations
|
|
2386
|
+
};
|
|
2387
|
+
}
|
|
2388
|
+
validateReynoldsPrinciples(html, principles) {
|
|
2389
|
+
const violations = [];
|
|
2390
|
+
let score = 100;
|
|
2391
|
+
const decorativeElements = (html.match(/class="[^"]*decorative[^"]*"/gi) || []).length;
|
|
2392
|
+
const randomImages = (html.match(/picsum\.photos/gi) || []).length;
|
|
2393
|
+
if (randomImages > 0) {
|
|
2394
|
+
violations.push(`Found ${randomImages} random stock images (Reynolds: only use purposeful images)`);
|
|
2395
|
+
score -= randomImages * 10;
|
|
2396
|
+
}
|
|
2397
|
+
if (decorativeElements > 3) {
|
|
2398
|
+
violations.push(`Too many decorative elements (${decorativeElements}) - reduces signal-to-noise ratio`);
|
|
2399
|
+
score -= 10;
|
|
2400
|
+
}
|
|
2401
|
+
const columnLayouts = (html.match(/class="[^"]*columns[^"]*"/gi) || []).length;
|
|
2402
|
+
const slideCount = (html.match(/<section/gi) || []).length;
|
|
2403
|
+
if (columnLayouts > slideCount * 0.5) {
|
|
2404
|
+
violations.push("Overuse of column layouts - simplify per Reynolds");
|
|
2405
|
+
score -= 10;
|
|
2406
|
+
}
|
|
2407
|
+
return {
|
|
2408
|
+
expertName: "Garr Reynolds",
|
|
2409
|
+
principlesChecked: ["Signal-to-Noise", "Simplicity", "Picture Superiority"],
|
|
2410
|
+
passed: score >= 80,
|
|
2411
|
+
score: Math.max(0, score),
|
|
2412
|
+
violations
|
|
2413
|
+
};
|
|
2414
|
+
}
|
|
2415
|
+
validateGalloPrinciples(html, principles) {
|
|
2416
|
+
const violations = [];
|
|
2417
|
+
let score = 100;
|
|
2418
|
+
const bulletLists = html.match(/<ul[^>]*>[\s\S]*?<\/ul>/gi) || [];
|
|
2419
|
+
bulletLists.forEach((list, index) => {
|
|
2420
|
+
const bullets = (list.match(/<li/gi) || []).length;
|
|
2421
|
+
if (bullets > 5) {
|
|
2422
|
+
violations.push(`Bullet list ${index + 1} has ${bullets} items (Gallo: max 3-5)`);
|
|
2423
|
+
score -= 5;
|
|
2424
|
+
}
|
|
2425
|
+
});
|
|
2426
|
+
const hasQuote = html.includes("blockquote") || html.includes("quote");
|
|
2427
|
+
const hasStory = html.toLowerCase().includes("story") || html.toLowerCase().includes("journey");
|
|
2428
|
+
if (!hasQuote && !hasStory) {
|
|
2429
|
+
violations.push("Missing emotional connection elements (quotes, stories)");
|
|
2430
|
+
score -= 10;
|
|
2431
|
+
}
|
|
2432
|
+
return {
|
|
2433
|
+
expertName: "Carmine Gallo",
|
|
2434
|
+
principlesChecked: ["Rule of Three", "Emotional Connection", "Headline Power"],
|
|
2435
|
+
passed: score >= 80,
|
|
2436
|
+
score: Math.max(0, score),
|
|
2437
|
+
violations
|
|
2438
|
+
};
|
|
2439
|
+
}
|
|
2440
|
+
validateAndersonPrinciples(html, principles) {
|
|
2441
|
+
const violations = [];
|
|
2442
|
+
let score = 100;
|
|
2443
|
+
const slideMatches = html.match(/<section[^>]*>[\s\S]*?<\/section>/gi) || [];
|
|
2444
|
+
slideMatches.forEach((slide, index) => {
|
|
2445
|
+
const headings = (slide.match(/<h[12][^>]*>/gi) || []).length;
|
|
2446
|
+
if (headings > 2) {
|
|
2447
|
+
violations.push(`Slide ${index + 1}: Multiple ideas detected (Anderson: one idea per slide)`);
|
|
2448
|
+
score -= 5;
|
|
2449
|
+
}
|
|
2450
|
+
});
|
|
2451
|
+
const jargonPatterns = ["synergy", "leverage", "paradigm", "holistic", "streamline"];
|
|
2452
|
+
let jargonCount = 0;
|
|
2453
|
+
jargonPatterns.forEach((pattern) => {
|
|
2454
|
+
const matches = html.toLowerCase().match(new RegExp(pattern, "gi")) || [];
|
|
2455
|
+
jargonCount += matches.length;
|
|
2456
|
+
});
|
|
2457
|
+
if (jargonCount > 5) {
|
|
2458
|
+
violations.push(`Excessive jargon detected (${jargonCount} instances) - simplify language`);
|
|
2459
|
+
score -= 10;
|
|
2460
|
+
}
|
|
2461
|
+
return {
|
|
2462
|
+
expertName: "Chris Anderson",
|
|
2463
|
+
principlesChecked: ["One Idea", "Clarity", "Throughline"],
|
|
2464
|
+
passed: score >= 80,
|
|
2465
|
+
score: Math.max(0, score),
|
|
2466
|
+
violations
|
|
2070
2467
|
};
|
|
2071
2468
|
}
|
|
2072
2469
|
// ===========================================================================
|
|
2073
|
-
// ACCESSIBILITY TESTS
|
|
2470
|
+
// ACCESSIBILITY TESTS - KB-DRIVEN
|
|
2074
2471
|
// ===========================================================================
|
|
2075
|
-
async runAccessibilityTests(html) {
|
|
2472
|
+
async runAccessibilityTests(html, qualityMetrics) {
|
|
2076
2473
|
const page = await this.browser.newPage();
|
|
2077
2474
|
await page.setContent(html);
|
|
2078
2475
|
await page.waitForTimeout(500);
|
|
@@ -2122,7 +2519,7 @@ var QAEngine = class {
|
|
|
2122
2519
|
};
|
|
2123
2520
|
}
|
|
2124
2521
|
// ===========================================================================
|
|
2125
|
-
// SCORING
|
|
2522
|
+
// SCORING - KB-DRIVEN
|
|
2126
2523
|
// ===========================================================================
|
|
2127
2524
|
calculateVisualScore(results) {
|
|
2128
2525
|
let score = 100;
|
|
@@ -2246,6 +2643,7 @@ var QAEngine = class {
|
|
|
2246
2643
|
// src/generators/html/RevealJsGenerator.ts
|
|
2247
2644
|
var RevealJsGenerator = class {
|
|
2248
2645
|
templateEngine;
|
|
2646
|
+
kb;
|
|
2249
2647
|
defaultRevealConfig = {
|
|
2250
2648
|
revealVersion: "5.0.4",
|
|
2251
2649
|
hash: true,
|
|
@@ -2264,20 +2662,32 @@ var RevealJsGenerator = class {
|
|
|
2264
2662
|
constructor() {
|
|
2265
2663
|
this.templateEngine = new TemplateEngine();
|
|
2266
2664
|
}
|
|
2665
|
+
/**
|
|
2666
|
+
* Initialize KnowledgeGateway
|
|
2667
|
+
*/
|
|
2668
|
+
async initialize() {
|
|
2669
|
+
this.kb = await getKnowledgeGateway();
|
|
2670
|
+
}
|
|
2267
2671
|
/**
|
|
2268
2672
|
* Generate complete Reveal.js HTML presentation.
|
|
2269
2673
|
*/
|
|
2270
2674
|
async generate(slides, config) {
|
|
2675
|
+
await this.initialize();
|
|
2271
2676
|
const templateConfig = {};
|
|
2272
2677
|
if (config.theme) templateConfig.theme = config.theme;
|
|
2273
2678
|
if (config.customTemplates) templateConfig.customTemplates = config.customTemplates;
|
|
2274
2679
|
const slideHtml = this.templateEngine.renderAll(slides, templateConfig);
|
|
2680
|
+
const presentationType = this.detectPresentationType(config);
|
|
2681
|
+
const palette = this.kb.getRecommendedPalette(presentationType);
|
|
2682
|
+
const typography = this.kb.getTypography(config.mode);
|
|
2275
2683
|
const docConfig = {
|
|
2276
2684
|
title: config.title,
|
|
2277
2685
|
slides: slideHtml.join("\n"),
|
|
2278
2686
|
theme: config.theme ?? "default",
|
|
2279
2687
|
revealConfig: this.defaultRevealConfig,
|
|
2280
|
-
mode: config.mode
|
|
2688
|
+
mode: config.mode,
|
|
2689
|
+
palette,
|
|
2690
|
+
typography
|
|
2281
2691
|
};
|
|
2282
2692
|
if (config.author) docConfig.author = config.author;
|
|
2283
2693
|
if (config.subject) docConfig.subject = config.subject;
|
|
@@ -2288,11 +2698,23 @@ var RevealJsGenerator = class {
|
|
|
2288
2698
|
}
|
|
2289
2699
|
return html;
|
|
2290
2700
|
}
|
|
2701
|
+
/**
|
|
2702
|
+
* Detect presentation type from config
|
|
2703
|
+
*/
|
|
2704
|
+
detectPresentationType(config) {
|
|
2705
|
+
if (config.presentationType) {
|
|
2706
|
+
return config.presentationType;
|
|
2707
|
+
}
|
|
2708
|
+
if (config.mode === "keynote") {
|
|
2709
|
+
return "ted_keynote";
|
|
2710
|
+
}
|
|
2711
|
+
return "consulting_deck";
|
|
2712
|
+
}
|
|
2291
2713
|
/**
|
|
2292
2714
|
* Build the complete HTML document.
|
|
2293
2715
|
*/
|
|
2294
2716
|
buildDocument(options) {
|
|
2295
|
-
const { title, author, subject, slides, theme, customCSS, revealConfig, mode } = options;
|
|
2717
|
+
const { title, author, subject, slides, theme, customCSS, revealConfig, mode, palette, typography } = options;
|
|
2296
2718
|
return `<!DOCTYPE html>
|
|
2297
2719
|
<html lang="en">
|
|
2298
2720
|
<head>
|
|
@@ -2300,7 +2722,7 @@ var RevealJsGenerator = class {
|
|
|
2300
2722
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
2301
2723
|
<meta name="author" content="${this.escapeHtml(author ?? "Claude Presentation Master")}">
|
|
2302
2724
|
<meta name="description" content="${this.escapeHtml(subject ?? "")}">
|
|
2303
|
-
<meta name="generator" content="Claude Presentation Master
|
|
2725
|
+
<meta name="generator" content="Claude Presentation Master v6.0.0">
|
|
2304
2726
|
<title>${this.escapeHtml(title)}</title>
|
|
2305
2727
|
|
|
2306
2728
|
<!-- Reveal.js CSS -->
|
|
@@ -2314,10 +2736,10 @@ var RevealJsGenerator = class {
|
|
|
2314
2736
|
<!-- Mermaid for diagrams -->
|
|
2315
2737
|
<script src="https://cdn.jsdelivr.net/npm/mermaid@10.6.1/dist/mermaid.min.js"></script>
|
|
2316
2738
|
|
|
2317
|
-
<!-- Presentation Engine CSS -->
|
|
2739
|
+
<!-- Presentation Engine CSS - KB-Driven Design System -->
|
|
2318
2740
|
<style>
|
|
2319
|
-
${this.getBaseStyles(mode)}
|
|
2320
|
-
${this.getThemeStyles(theme)}
|
|
2741
|
+
${this.getBaseStyles(mode, palette, typography)}
|
|
2742
|
+
${this.getThemeStyles(theme, palette)}
|
|
2321
2743
|
${this.getAnimationStyles()}
|
|
2322
2744
|
${customCSS ?? ""}
|
|
2323
2745
|
</style>
|
|
@@ -2369,26 +2791,35 @@ ${slides}
|
|
|
2369
2791
|
</html>`;
|
|
2370
2792
|
}
|
|
2371
2793
|
/**
|
|
2372
|
-
* Get base styles for slides
|
|
2794
|
+
* Get base styles for slides - KB-DRIVEN
|
|
2373
2795
|
*/
|
|
2374
|
-
getBaseStyles(mode) {
|
|
2796
|
+
getBaseStyles(mode, palette, typography) {
|
|
2375
2797
|
const fontSize = mode === "keynote" ? "2.5em" : "1.8em";
|
|
2376
2798
|
const lineHeight = mode === "keynote" ? "1.4" : "1.5";
|
|
2799
|
+
const primary = palette.primary || "#1a1a2e";
|
|
2800
|
+
const secondary = palette.secondary || "#16213e";
|
|
2801
|
+
const accent = palette.accent || "#0f3460";
|
|
2802
|
+
const highlight = palette.accent || "#e94560";
|
|
2803
|
+
const text = palette.text || "#1a1a2e";
|
|
2804
|
+
const background = palette.background || "#ffffff";
|
|
2377
2805
|
return `
|
|
2378
|
-
/* Base Styles */
|
|
2806
|
+
/* Base Styles - KB-Driven Design System */
|
|
2379
2807
|
:root {
|
|
2808
|
+
/* Typography from KB */
|
|
2380
2809
|
--font-heading: 'Source Sans Pro', 'Helvetica Neue', -apple-system, BlinkMacSystemFont, sans-serif;
|
|
2381
2810
|
--font-body: 'Source Sans Pro', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
2382
2811
|
--font-mono: 'SF Mono', 'Fira Code', 'JetBrains Mono', monospace;
|
|
2383
2812
|
|
|
2384
|
-
|
|
2385
|
-
--color-
|
|
2386
|
-
--color-
|
|
2387
|
-
--color-
|
|
2388
|
-
--color-
|
|
2389
|
-
--color-text
|
|
2390
|
-
--color-
|
|
2813
|
+
/* Colors from KB Palette: ${palette.name} */
|
|
2814
|
+
--color-primary: ${primary};
|
|
2815
|
+
--color-secondary: ${secondary};
|
|
2816
|
+
--color-accent: ${accent};
|
|
2817
|
+
--color-highlight: ${highlight};
|
|
2818
|
+
--color-text: ${text};
|
|
2819
|
+
--color-text-light: ${this.lightenColor(text, 30)};
|
|
2820
|
+
--color-background: ${background};
|
|
2391
2821
|
|
|
2822
|
+
/* Layout */
|
|
2392
2823
|
--slide-padding: 60px;
|
|
2393
2824
|
--content-max-width: 1200px;
|
|
2394
2825
|
}
|
|
@@ -2504,7 +2935,7 @@ ${slides}
|
|
|
2504
2935
|
font-size: 0.8em;
|
|
2505
2936
|
}
|
|
2506
2937
|
|
|
2507
|
-
/* Images */
|
|
2938
|
+
/* Images - NO RANDOM PICSUM - Only user-provided or none */
|
|
2508
2939
|
.reveal img {
|
|
2509
2940
|
max-width: 100%;
|
|
2510
2941
|
height: auto;
|
|
@@ -2610,9 +3041,25 @@ ${slides}
|
|
|
2610
3041
|
`;
|
|
2611
3042
|
}
|
|
2612
3043
|
/**
|
|
2613
|
-
*
|
|
3044
|
+
* Lighten a hex color
|
|
3045
|
+
*/
|
|
3046
|
+
lightenColor(hex, percent) {
|
|
3047
|
+
hex = hex.replace("#", "");
|
|
3048
|
+
let r = parseInt(hex.substring(0, 2), 16);
|
|
3049
|
+
let g = parseInt(hex.substring(2, 4), 16);
|
|
3050
|
+
let b = parseInt(hex.substring(4, 6), 16);
|
|
3051
|
+
r = Math.min(255, Math.floor(r + (255 - r) * (percent / 100)));
|
|
3052
|
+
g = Math.min(255, Math.floor(g + (255 - g) * (percent / 100)));
|
|
3053
|
+
b = Math.min(255, Math.floor(b + (255 - b) * (percent / 100)));
|
|
3054
|
+
return `#${r.toString(16).padStart(2, "0")}${g.toString(16).padStart(2, "0")}${b.toString(16).padStart(2, "0")}`;
|
|
3055
|
+
}
|
|
3056
|
+
/**
|
|
3057
|
+
* Get theme-specific styles - KB-DRIVEN
|
|
2614
3058
|
*/
|
|
2615
|
-
getThemeStyles(theme) {
|
|
3059
|
+
getThemeStyles(theme, palette) {
|
|
3060
|
+
if (theme === "default") {
|
|
3061
|
+
return "";
|
|
3062
|
+
}
|
|
2616
3063
|
const themes = {
|
|
2617
3064
|
"default": "",
|
|
2618
3065
|
"light-corporate": `
|
|
@@ -2626,10 +3073,10 @@ ${slides}
|
|
|
2626
3073
|
`,
|
|
2627
3074
|
"modern-tech": `
|
|
2628
3075
|
:root {
|
|
2629
|
-
--color-primary: #1a1a2e;
|
|
2630
|
-
--color-secondary: #16213e;
|
|
2631
|
-
--color-accent: #0f3460;
|
|
2632
|
-
--color-highlight: #e94560;
|
|
3076
|
+
--color-primary: ${palette.primary || "#1a1a2e"};
|
|
3077
|
+
--color-secondary: ${palette.secondary || "#16213e"};
|
|
3078
|
+
--color-accent: ${palette.accent || "#0f3460"};
|
|
3079
|
+
--color-highlight: ${palette.accent || "#e94560"};
|
|
2633
3080
|
--color-background: #f8f9fa;
|
|
2634
3081
|
}
|
|
2635
3082
|
`,
|
|
@@ -3875,239 +4322,6 @@ function createDefaultImageProvider(options) {
|
|
|
3875
4322
|
return new CompositeImageProvider(providers);
|
|
3876
4323
|
}
|
|
3877
4324
|
|
|
3878
|
-
// src/knowledge/KnowledgeBase.ts
|
|
3879
|
-
import { readFileSync } from "fs";
|
|
3880
|
-
import { join, dirname } from "path";
|
|
3881
|
-
import { fileURLToPath } from "url";
|
|
3882
|
-
import * as yaml from "yaml";
|
|
3883
|
-
function getModuleDir() {
|
|
3884
|
-
if (typeof import.meta !== "undefined" && import.meta.url) {
|
|
3885
|
-
return dirname(fileURLToPath(import.meta.url));
|
|
3886
|
-
}
|
|
3887
|
-
if (typeof __dirname !== "undefined") {
|
|
3888
|
-
return __dirname;
|
|
3889
|
-
}
|
|
3890
|
-
return process.cwd();
|
|
3891
|
-
}
|
|
3892
|
-
var moduleDir = getModuleDir();
|
|
3893
|
-
var KnowledgeBase = class {
|
|
3894
|
-
data = null;
|
|
3895
|
-
loaded = false;
|
|
3896
|
-
/**
|
|
3897
|
-
* Load the knowledge base from the bundled YAML file.
|
|
3898
|
-
*/
|
|
3899
|
-
async load() {
|
|
3900
|
-
if (this.loaded) return;
|
|
3901
|
-
try {
|
|
3902
|
-
const possiblePaths = [
|
|
3903
|
-
// From dist/: go up to package root
|
|
3904
|
-
join(moduleDir, "../../assets/presentation-knowledge.yaml"),
|
|
3905
|
-
join(moduleDir, "../assets/presentation-knowledge.yaml"),
|
|
3906
|
-
join(moduleDir, "../../../assets/presentation-knowledge.yaml"),
|
|
3907
|
-
// From bundle in dist/index.js: go up one level
|
|
3908
|
-
join(moduleDir, "assets/presentation-knowledge.yaml"),
|
|
3909
|
-
// CWD-based paths for development or local installs
|
|
3910
|
-
join(process.cwd(), "assets/presentation-knowledge.yaml"),
|
|
3911
|
-
join(process.cwd(), "node_modules/claude-presentation-master/assets/presentation-knowledge.yaml")
|
|
3912
|
-
];
|
|
3913
|
-
let assetPath = "";
|
|
3914
|
-
for (const p of possiblePaths) {
|
|
3915
|
-
try {
|
|
3916
|
-
readFileSync(p);
|
|
3917
|
-
assetPath = p;
|
|
3918
|
-
break;
|
|
3919
|
-
} catch {
|
|
3920
|
-
continue;
|
|
3921
|
-
}
|
|
3922
|
-
}
|
|
3923
|
-
if (!assetPath) {
|
|
3924
|
-
throw new Error("Could not locate knowledge base file");
|
|
3925
|
-
}
|
|
3926
|
-
const content = readFileSync(assetPath, "utf-8");
|
|
3927
|
-
this.data = yaml.parse(content);
|
|
3928
|
-
this.loaded = true;
|
|
3929
|
-
console.log(`\u{1F4DA} Knowledge base loaded: v${this.data.version}`);
|
|
3930
|
-
} catch (error) {
|
|
3931
|
-
console.warn("\u26A0\uFE0F Could not load knowledge base, using defaults");
|
|
3932
|
-
this.data = this.getDefaultData();
|
|
3933
|
-
this.loaded = true;
|
|
3934
|
-
}
|
|
3935
|
-
}
|
|
3936
|
-
/**
|
|
3937
|
-
* Get expert methodology by name.
|
|
3938
|
-
*/
|
|
3939
|
-
getExpert(name) {
|
|
3940
|
-
this.ensureLoaded();
|
|
3941
|
-
return this.data?.experts?.[name];
|
|
3942
|
-
}
|
|
3943
|
-
/**
|
|
3944
|
-
* Get all expert names.
|
|
3945
|
-
*/
|
|
3946
|
-
getExpertNames() {
|
|
3947
|
-
this.ensureLoaded();
|
|
3948
|
-
return Object.keys(this.data?.experts ?? {});
|
|
3949
|
-
}
|
|
3950
|
-
/**
|
|
3951
|
-
* Get framework recommendation for audience.
|
|
3952
|
-
*/
|
|
3953
|
-
getFrameworkForAudience(audience) {
|
|
3954
|
-
this.ensureLoaded();
|
|
3955
|
-
return this.data?.frameworkSelector?.byAudience?.[audience];
|
|
3956
|
-
}
|
|
3957
|
-
/**
|
|
3958
|
-
* Get framework recommendation for goal.
|
|
3959
|
-
*/
|
|
3960
|
-
getFrameworkForGoal(goal) {
|
|
3961
|
-
this.ensureLoaded();
|
|
3962
|
-
return this.data?.frameworkSelector?.byGoal?.[goal];
|
|
3963
|
-
}
|
|
3964
|
-
/**
|
|
3965
|
-
* Get QA scoring rubric.
|
|
3966
|
-
*/
|
|
3967
|
-
getScoringRubric() {
|
|
3968
|
-
this.ensureLoaded();
|
|
3969
|
-
return this.data?.automatedQA?.scoringRubric;
|
|
3970
|
-
}
|
|
3971
|
-
/**
|
|
3972
|
-
* Get mode configuration (keynote or business).
|
|
3973
|
-
*/
|
|
3974
|
-
getModeConfig(mode) {
|
|
3975
|
-
this.ensureLoaded();
|
|
3976
|
-
return this.data?.modes?.[mode];
|
|
3977
|
-
}
|
|
3978
|
-
/**
|
|
3979
|
-
* Get slide type configuration.
|
|
3980
|
-
*/
|
|
3981
|
-
getSlideType(type) {
|
|
3982
|
-
this.ensureLoaded();
|
|
3983
|
-
return this.data?.slideTypes?.[type];
|
|
3984
|
-
}
|
|
3985
|
-
/**
|
|
3986
|
-
* Get the knowledge base version.
|
|
3987
|
-
*/
|
|
3988
|
-
getVersion() {
|
|
3989
|
-
this.ensureLoaded();
|
|
3990
|
-
return this.data?.version ?? "unknown";
|
|
3991
|
-
}
|
|
3992
|
-
/**
|
|
3993
|
-
* Validate a slide against expert principles.
|
|
3994
|
-
*/
|
|
3995
|
-
validateAgainstExpert(expertName, slideData) {
|
|
3996
|
-
const expert = this.getExpert(expertName);
|
|
3997
|
-
if (!expert) {
|
|
3998
|
-
return { passed: true, violations: [] };
|
|
3999
|
-
}
|
|
4000
|
-
const violations = [];
|
|
4001
|
-
if (expert.wordLimits) {
|
|
4002
|
-
if (expert.wordLimits.max && slideData.wordCount > expert.wordLimits.max) {
|
|
4003
|
-
violations.push(`Exceeds ${expertName} word limit of ${expert.wordLimits.max}`);
|
|
4004
|
-
}
|
|
4005
|
-
if (expert.wordLimits.min && slideData.wordCount < expert.wordLimits.min) {
|
|
4006
|
-
violations.push(`Below ${expertName} minimum of ${expert.wordLimits.min} words`);
|
|
4007
|
-
}
|
|
4008
|
-
}
|
|
4009
|
-
return {
|
|
4010
|
-
passed: violations.length === 0,
|
|
4011
|
-
violations
|
|
4012
|
-
};
|
|
4013
|
-
}
|
|
4014
|
-
/**
|
|
4015
|
-
* Ensure knowledge base is loaded.
|
|
4016
|
-
*/
|
|
4017
|
-
ensureLoaded() {
|
|
4018
|
-
if (!this.loaded) {
|
|
4019
|
-
this.data = this.getDefaultData();
|
|
4020
|
-
this.loaded = true;
|
|
4021
|
-
}
|
|
4022
|
-
}
|
|
4023
|
-
/**
|
|
4024
|
-
* Get default data if YAML can't be loaded.
|
|
4025
|
-
*/
|
|
4026
|
-
getDefaultData() {
|
|
4027
|
-
return {
|
|
4028
|
-
version: "1.0.0-fallback",
|
|
4029
|
-
lastUpdated: (/* @__PURE__ */ new Date()).toISOString(),
|
|
4030
|
-
experts: {
|
|
4031
|
-
"Nancy Duarte": {
|
|
4032
|
-
name: "Nancy Duarte",
|
|
4033
|
-
principles: [
|
|
4034
|
-
{ name: "Glance Test", description: "Message clear in 3 seconds" },
|
|
4035
|
-
{ name: "STAR Moment", description: "Something They'll Always Remember" },
|
|
4036
|
-
{ name: "Sparkline", description: "Contrast What Is vs What Could Be" }
|
|
4037
|
-
]
|
|
4038
|
-
},
|
|
4039
|
-
"Garr Reynolds": {
|
|
4040
|
-
name: "Garr Reynolds",
|
|
4041
|
-
principles: [
|
|
4042
|
-
{ name: "Signal-to-Noise", description: "Maximize signal, minimize noise" },
|
|
4043
|
-
{ name: "Simplicity", description: "Amplify through simplification" }
|
|
4044
|
-
]
|
|
4045
|
-
},
|
|
4046
|
-
"Carmine Gallo": {
|
|
4047
|
-
name: "Carmine Gallo",
|
|
4048
|
-
principles: [
|
|
4049
|
-
{ name: "Rule of Three", description: "Maximum 3 key messages" },
|
|
4050
|
-
{ name: "Emotional Connection", description: "Connect emotionally first" }
|
|
4051
|
-
]
|
|
4052
|
-
},
|
|
4053
|
-
"Chris Anderson": {
|
|
4054
|
-
name: "Chris Anderson",
|
|
4055
|
-
principles: [
|
|
4056
|
-
{ name: "One Idea", description: "One powerful idea per talk" },
|
|
4057
|
-
{ name: "Dead Laptop Test", description: "Present without slides" }
|
|
4058
|
-
]
|
|
4059
|
-
}
|
|
4060
|
-
},
|
|
4061
|
-
frameworkSelector: {
|
|
4062
|
-
byAudience: {
|
|
4063
|
-
"board": {
|
|
4064
|
-
primaryFramework: "Barbara Minto",
|
|
4065
|
-
slideTypes: ["executive_summary", "data_insight"]
|
|
4066
|
-
},
|
|
4067
|
-
"sales": {
|
|
4068
|
-
primaryFramework: "Nancy Duarte",
|
|
4069
|
-
slideTypes: ["big_idea", "social_proof"]
|
|
4070
|
-
}
|
|
4071
|
-
},
|
|
4072
|
-
byGoal: {
|
|
4073
|
-
"persuade": {
|
|
4074
|
-
primaryFramework: "Nancy Duarte",
|
|
4075
|
-
slideTypes: ["big_idea", "star_moment"]
|
|
4076
|
-
},
|
|
4077
|
-
"inform": {
|
|
4078
|
-
primaryFramework: "Barbara Minto",
|
|
4079
|
-
slideTypes: ["bullet_points", "data_insight"]
|
|
4080
|
-
}
|
|
4081
|
-
}
|
|
4082
|
-
},
|
|
4083
|
-
automatedQA: {
|
|
4084
|
-
scoringRubric: {
|
|
4085
|
-
totalPoints: 100,
|
|
4086
|
-
passingThreshold: 95,
|
|
4087
|
-
categories: {
|
|
4088
|
-
visual: { weight: 35, checks: {} },
|
|
4089
|
-
content: { weight: 30, checks: {} },
|
|
4090
|
-
expert: { weight: 25, checks: {} },
|
|
4091
|
-
accessibility: { weight: 10, checks: {} }
|
|
4092
|
-
}
|
|
4093
|
-
}
|
|
4094
|
-
},
|
|
4095
|
-
slideTypes: {},
|
|
4096
|
-
modes: {
|
|
4097
|
-
keynote: { maxWords: 25, minWhitespace: 35 },
|
|
4098
|
-
business: { maxWords: 80, minWhitespace: 25 }
|
|
4099
|
-
}
|
|
4100
|
-
};
|
|
4101
|
-
}
|
|
4102
|
-
};
|
|
4103
|
-
var knowledgeBaseInstance = null;
|
|
4104
|
-
function getKnowledgeBase() {
|
|
4105
|
-
if (!knowledgeBaseInstance) {
|
|
4106
|
-
knowledgeBaseInstance = new KnowledgeBase();
|
|
4107
|
-
}
|
|
4108
|
-
return knowledgeBaseInstance;
|
|
4109
|
-
}
|
|
4110
|
-
|
|
4111
4325
|
// src/index.ts
|
|
4112
4326
|
async function generate(config) {
|
|
4113
4327
|
const engine = new PresentationEngine();
|
|
@@ -4122,7 +4336,7 @@ async function validate(presentation, options) {
|
|
|
4122
4336
|
score
|
|
4123
4337
|
};
|
|
4124
4338
|
}
|
|
4125
|
-
var VERSION = "
|
|
4339
|
+
var VERSION = "6.0.0";
|
|
4126
4340
|
var index_default = {
|
|
4127
4341
|
generate,
|
|
4128
4342
|
validate,
|
|
@@ -4135,7 +4349,7 @@ export {
|
|
|
4135
4349
|
CompositeChartProvider,
|
|
4136
4350
|
CompositeImageProvider,
|
|
4137
4351
|
ContentAnalyzer,
|
|
4138
|
-
|
|
4352
|
+
KnowledgeGateway,
|
|
4139
4353
|
LocalImageProvider,
|
|
4140
4354
|
MermaidProvider,
|
|
4141
4355
|
PlaceholderImageProvider,
|
|
@@ -4156,7 +4370,7 @@ export {
|
|
|
4156
4370
|
createDefaultImageProvider,
|
|
4157
4371
|
index_default as default,
|
|
4158
4372
|
generate,
|
|
4159
|
-
|
|
4373
|
+
getKnowledgeGateway,
|
|
4160
4374
|
validate
|
|
4161
4375
|
};
|
|
4162
4376
|
/**
|