claude-presentation-master 3.8.8 → 4.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/README.md +32 -19
- package/dist/index.d.mts +36 -11
- package/dist/index.d.ts +36 -11
- package/dist/index.js +187 -132
- package/dist/index.mjs +187 -132
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,25 +20,38 @@
|
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
## What's New in
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
-
|
|
29
|
-
-
|
|
30
|
-
|
|
31
|
-
###
|
|
32
|
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
36
|
-
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
-
|
|
40
|
-
-
|
|
41
|
-
-
|
|
23
|
+
## What's New in v4.0.0 — True Knowledge-Driven Architecture
|
|
24
|
+
|
|
25
|
+
**The Knowledge Base now DRIVES everything at runtime — no more hardcoded specs.**
|
|
26
|
+
|
|
27
|
+
### Breaking Changes
|
|
28
|
+
- `PresentationEngineV2` now requires Knowledge Base YAML at runtime
|
|
29
|
+
- All design specs loaded from KB, not constants in code
|
|
30
|
+
|
|
31
|
+
### New Features
|
|
32
|
+
- **📚 Runtime KB Loading** — The 6,300+ line YAML knowledge base is parsed at runtime, not duplicated in code
|
|
33
|
+
- **🎯 H3 Action Title Extraction** — Markdown H3 headings become slide titles (McKinsey "so what" principle)
|
|
34
|
+
- **📊 Tables Preserved Correctly** — Tables stay as tables, never mangled into metric cards
|
|
35
|
+
- **🚫 No Orphan Slides** — Minimum 3 bullets per slide, balanced distribution
|
|
36
|
+
- **✅ 95+ Quality Threshold** — Engine fails if quality score below 95/100
|
|
37
|
+
|
|
38
|
+
### Knowledge Base Integration
|
|
39
|
+
- Word limits from `presentation_types.{type}.validation_rules.words_per_slide`
|
|
40
|
+
- Bullet limits from `presentation_types.{type}.validation_rules.bullets_per_slide`
|
|
41
|
+
- Theme from `presentation_types.{type}.color_palette`
|
|
42
|
+
- Experts from `presentation_types.{type}.primary_experts`
|
|
43
|
+
- Scoring weights from `presentation_types.{type}.scoring_weights`
|
|
44
|
+
|
|
45
|
+
### 7 Specialized Presentation Types
|
|
46
|
+
| Type | Theme | Words/Slide | Key Experts |
|
|
47
|
+
|------|-------|-------------|-------------|
|
|
48
|
+
| `ted_keynote` | Dark | 1-15 | Duarte, Reynolds, Anderson |
|
|
49
|
+
| `sales_pitch` | Modern | 10-30 | Cialdini, Heath |
|
|
50
|
+
| `consulting_deck` | McKinsey | 40-80 | Minto, McKinsey, BCG |
|
|
51
|
+
| `investment_banking` | McKinsey | 60-120 | Wall Street Prep |
|
|
52
|
+
| `investor_pitch` | Startup | 5-30 | Sequoia, YC |
|
|
53
|
+
| `technical_presentation` | Dark | 40-100 | Tufte, C4 Model |
|
|
54
|
+
| `all_hands` | Minimal | 15-40 | Internal Comms |
|
|
42
55
|
|
|
43
56
|
---
|
|
44
57
|
|
package/dist/index.d.mts
CHANGED
|
@@ -714,9 +714,20 @@ declare class SlideGeneratorV2 {
|
|
|
714
714
|
* RULES:
|
|
715
715
|
* 1. Tables ALWAYS become table slides - NEVER extract to metrics
|
|
716
716
|
* 2. Empty sections are SKIPPED - no blank divider slides
|
|
717
|
-
* 3.
|
|
717
|
+
* 3. H3 headings become individual slides with ACTION TITLES (critical for consulting)
|
|
718
|
+
* 4. Sections with minimal content are combined into statement slides
|
|
718
719
|
*/
|
|
719
720
|
private processSectionContent;
|
|
721
|
+
/**
|
|
722
|
+
* Split tokens into subsections based on H3 headers.
|
|
723
|
+
* H3 headers become ACTION TITLES for consulting decks.
|
|
724
|
+
*/
|
|
725
|
+
private splitIntoSubsections;
|
|
726
|
+
/**
|
|
727
|
+
* Process a subsection (H3) into a slide.
|
|
728
|
+
* The H3 title IS the action title.
|
|
729
|
+
*/
|
|
730
|
+
private processSubsection;
|
|
720
731
|
/**
|
|
721
732
|
* Create a table slide - render the table as-is, no extraction.
|
|
722
733
|
*/
|
|
@@ -893,17 +904,15 @@ declare function createRendererV2(presentationType?: PresentationType, themeOver
|
|
|
893
904
|
*
|
|
894
905
|
* This engine orchestrates the ENTIRE presentation creation flow:
|
|
895
906
|
* 1. Analyze content to detect presentation type
|
|
896
|
-
* 2. Load design specs from Knowledge Base
|
|
907
|
+
* 2. Load design specs from Knowledge Base (YAML)
|
|
897
908
|
* 3. Generate slides following expert methodologies
|
|
898
909
|
* 4. Enhance with images (optional, needs API key)
|
|
899
910
|
* 5. Review ruthlessly (must score 95/100+)
|
|
900
911
|
* 6. Output ONLY if quality passes
|
|
901
912
|
*
|
|
902
|
-
* The Knowledge Base drives EVERYTHING
|
|
903
|
-
* -
|
|
904
|
-
* -
|
|
905
|
-
* - Slide structure and word limits
|
|
906
|
-
* - Quality criteria and scoring
|
|
913
|
+
* CRITICAL: The Knowledge Base drives EVERYTHING.
|
|
914
|
+
* The KnowledgeGateway reads from presentation-knowledge.yaml at runtime.
|
|
915
|
+
* NO hardcoded fallbacks - if KB is missing data, we fail loudly.
|
|
907
916
|
*/
|
|
908
917
|
|
|
909
918
|
interface DesignSpecs {
|
|
@@ -912,18 +921,30 @@ interface DesignSpecs {
|
|
|
912
921
|
max: number;
|
|
913
922
|
ideal: number;
|
|
914
923
|
};
|
|
915
|
-
whitespace:
|
|
924
|
+
whitespace: {
|
|
925
|
+
min: number;
|
|
926
|
+
max?: number;
|
|
927
|
+
ideal: number;
|
|
928
|
+
};
|
|
916
929
|
bulletPoints: {
|
|
917
930
|
max: number;
|
|
918
931
|
};
|
|
919
932
|
fonts: {
|
|
920
|
-
title:
|
|
921
|
-
body:
|
|
922
|
-
|
|
933
|
+
title: string;
|
|
934
|
+
body: string;
|
|
935
|
+
maxFonts: number;
|
|
923
936
|
};
|
|
924
937
|
theme: ThemeStyle;
|
|
925
938
|
structure: string;
|
|
926
939
|
experts: string[];
|
|
940
|
+
actionTitlesRequired: boolean;
|
|
941
|
+
sourcesRequired: boolean;
|
|
942
|
+
scoringWeights: {
|
|
943
|
+
visual_quality: number;
|
|
944
|
+
content_quality: number;
|
|
945
|
+
expert_compliance: number;
|
|
946
|
+
accessibility: number;
|
|
947
|
+
};
|
|
927
948
|
}
|
|
928
949
|
interface SlideReview {
|
|
929
950
|
slideIndex: number;
|
|
@@ -966,11 +987,15 @@ interface EngineResult {
|
|
|
966
987
|
}
|
|
967
988
|
declare class PresentationEngineV2 {
|
|
968
989
|
private options;
|
|
990
|
+
private kb;
|
|
969
991
|
constructor(options?: EngineOptions);
|
|
970
992
|
private log;
|
|
971
993
|
/**
|
|
972
994
|
* Generate a world-class presentation from markdown content.
|
|
973
995
|
* Follows knowledge base specs and demands 95+ quality score.
|
|
996
|
+
*
|
|
997
|
+
* CRITICAL: All specs come from the Knowledge Base YAML at runtime.
|
|
998
|
+
* No hardcoded fallbacks - if KB is missing data, we fail loudly.
|
|
974
999
|
*/
|
|
975
1000
|
generate(markdown: string, title?: string): Promise<EngineResult>;
|
|
976
1001
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -714,9 +714,20 @@ declare class SlideGeneratorV2 {
|
|
|
714
714
|
* RULES:
|
|
715
715
|
* 1. Tables ALWAYS become table slides - NEVER extract to metrics
|
|
716
716
|
* 2. Empty sections are SKIPPED - no blank divider slides
|
|
717
|
-
* 3.
|
|
717
|
+
* 3. H3 headings become individual slides with ACTION TITLES (critical for consulting)
|
|
718
|
+
* 4. Sections with minimal content are combined into statement slides
|
|
718
719
|
*/
|
|
719
720
|
private processSectionContent;
|
|
721
|
+
/**
|
|
722
|
+
* Split tokens into subsections based on H3 headers.
|
|
723
|
+
* H3 headers become ACTION TITLES for consulting decks.
|
|
724
|
+
*/
|
|
725
|
+
private splitIntoSubsections;
|
|
726
|
+
/**
|
|
727
|
+
* Process a subsection (H3) into a slide.
|
|
728
|
+
* The H3 title IS the action title.
|
|
729
|
+
*/
|
|
730
|
+
private processSubsection;
|
|
720
731
|
/**
|
|
721
732
|
* Create a table slide - render the table as-is, no extraction.
|
|
722
733
|
*/
|
|
@@ -893,17 +904,15 @@ declare function createRendererV2(presentationType?: PresentationType, themeOver
|
|
|
893
904
|
*
|
|
894
905
|
* This engine orchestrates the ENTIRE presentation creation flow:
|
|
895
906
|
* 1. Analyze content to detect presentation type
|
|
896
|
-
* 2. Load design specs from Knowledge Base
|
|
907
|
+
* 2. Load design specs from Knowledge Base (YAML)
|
|
897
908
|
* 3. Generate slides following expert methodologies
|
|
898
909
|
* 4. Enhance with images (optional, needs API key)
|
|
899
910
|
* 5. Review ruthlessly (must score 95/100+)
|
|
900
911
|
* 6. Output ONLY if quality passes
|
|
901
912
|
*
|
|
902
|
-
* The Knowledge Base drives EVERYTHING
|
|
903
|
-
* -
|
|
904
|
-
* -
|
|
905
|
-
* - Slide structure and word limits
|
|
906
|
-
* - Quality criteria and scoring
|
|
913
|
+
* CRITICAL: The Knowledge Base drives EVERYTHING.
|
|
914
|
+
* The KnowledgeGateway reads from presentation-knowledge.yaml at runtime.
|
|
915
|
+
* NO hardcoded fallbacks - if KB is missing data, we fail loudly.
|
|
907
916
|
*/
|
|
908
917
|
|
|
909
918
|
interface DesignSpecs {
|
|
@@ -912,18 +921,30 @@ interface DesignSpecs {
|
|
|
912
921
|
max: number;
|
|
913
922
|
ideal: number;
|
|
914
923
|
};
|
|
915
|
-
whitespace:
|
|
924
|
+
whitespace: {
|
|
925
|
+
min: number;
|
|
926
|
+
max?: number;
|
|
927
|
+
ideal: number;
|
|
928
|
+
};
|
|
916
929
|
bulletPoints: {
|
|
917
930
|
max: number;
|
|
918
931
|
};
|
|
919
932
|
fonts: {
|
|
920
|
-
title:
|
|
921
|
-
body:
|
|
922
|
-
|
|
933
|
+
title: string;
|
|
934
|
+
body: string;
|
|
935
|
+
maxFonts: number;
|
|
923
936
|
};
|
|
924
937
|
theme: ThemeStyle;
|
|
925
938
|
structure: string;
|
|
926
939
|
experts: string[];
|
|
940
|
+
actionTitlesRequired: boolean;
|
|
941
|
+
sourcesRequired: boolean;
|
|
942
|
+
scoringWeights: {
|
|
943
|
+
visual_quality: number;
|
|
944
|
+
content_quality: number;
|
|
945
|
+
expert_compliance: number;
|
|
946
|
+
accessibility: number;
|
|
947
|
+
};
|
|
927
948
|
}
|
|
928
949
|
interface SlideReview {
|
|
929
950
|
slideIndex: number;
|
|
@@ -966,11 +987,15 @@ interface EngineResult {
|
|
|
966
987
|
}
|
|
967
988
|
declare class PresentationEngineV2 {
|
|
968
989
|
private options;
|
|
990
|
+
private kb;
|
|
969
991
|
constructor(options?: EngineOptions);
|
|
970
992
|
private log;
|
|
971
993
|
/**
|
|
972
994
|
* Generate a world-class presentation from markdown content.
|
|
973
995
|
* Follows knowledge base specs and demands 95+ quality score.
|
|
996
|
+
*
|
|
997
|
+
* CRITICAL: All specs come from the Knowledge Base YAML at runtime.
|
|
998
|
+
* No hardcoded fallbacks - if KB is missing data, we fail loudly.
|
|
974
999
|
*/
|
|
975
1000
|
generate(markdown: string, title?: string): Promise<EngineResult>;
|
|
976
1001
|
/**
|
package/dist/index.js
CHANGED
|
@@ -93861,10 +93861,19 @@ var SlideGeneratorV2 = class {
|
|
|
93861
93861
|
* RULES:
|
|
93862
93862
|
* 1. Tables ALWAYS become table slides - NEVER extract to metrics
|
|
93863
93863
|
* 2. Empty sections are SKIPPED - no blank divider slides
|
|
93864
|
-
* 3.
|
|
93864
|
+
* 3. H3 headings become individual slides with ACTION TITLES (critical for consulting)
|
|
93865
|
+
* 4. Sections with minimal content are combined into statement slides
|
|
93865
93866
|
*/
|
|
93866
93867
|
processSectionContent(section, startIndex) {
|
|
93867
93868
|
const slides = [];
|
|
93869
|
+
const subsections = this.splitIntoSubsections(section.tokens);
|
|
93870
|
+
if (subsections.length > 0) {
|
|
93871
|
+
for (const subsection of subsections) {
|
|
93872
|
+
const subsectionSlides = this.processSubsection(subsection, section.title);
|
|
93873
|
+
slides.push(...subsectionSlides);
|
|
93874
|
+
}
|
|
93875
|
+
return slides;
|
|
93876
|
+
}
|
|
93868
93877
|
const tableTokens = section.tokens.filter((t) => t.type === "table");
|
|
93869
93878
|
const hasList = section.tokens.some((t) => t.type === "list");
|
|
93870
93879
|
const hasSignificantText = this.hasSignificantParagraphs(section.tokens);
|
|
@@ -93891,6 +93900,63 @@ var SlideGeneratorV2 = class {
|
|
|
93891
93900
|
}
|
|
93892
93901
|
return slides;
|
|
93893
93902
|
}
|
|
93903
|
+
/**
|
|
93904
|
+
* Split tokens into subsections based on H3 headers.
|
|
93905
|
+
* H3 headers become ACTION TITLES for consulting decks.
|
|
93906
|
+
*/
|
|
93907
|
+
splitIntoSubsections(tokens) {
|
|
93908
|
+
const subsections = [];
|
|
93909
|
+
let currentSubsection = null;
|
|
93910
|
+
let hasH3 = false;
|
|
93911
|
+
for (const token of tokens) {
|
|
93912
|
+
if (token.type === "heading" && token.depth === 3) {
|
|
93913
|
+
hasH3 = true;
|
|
93914
|
+
if (currentSubsection) {
|
|
93915
|
+
subsections.push(currentSubsection);
|
|
93916
|
+
}
|
|
93917
|
+
currentSubsection = {
|
|
93918
|
+
title: token.text,
|
|
93919
|
+
tokens: []
|
|
93920
|
+
};
|
|
93921
|
+
} else if (currentSubsection) {
|
|
93922
|
+
currentSubsection.tokens.push(token);
|
|
93923
|
+
}
|
|
93924
|
+
}
|
|
93925
|
+
if (currentSubsection && currentSubsection.tokens.length > 0) {
|
|
93926
|
+
subsections.push(currentSubsection);
|
|
93927
|
+
}
|
|
93928
|
+
return hasH3 ? subsections : [];
|
|
93929
|
+
}
|
|
93930
|
+
/**
|
|
93931
|
+
* Process a subsection (H3) into a slide.
|
|
93932
|
+
* The H3 title IS the action title.
|
|
93933
|
+
*/
|
|
93934
|
+
processSubsection(subsection, parentTitle) {
|
|
93935
|
+
const slides = [];
|
|
93936
|
+
const tableTokens = subsection.tokens.filter((t) => t.type === "table");
|
|
93937
|
+
for (const tableToken of tableTokens) {
|
|
93938
|
+
slides.push(this.createTableSlide(subsection.title, tableToken));
|
|
93939
|
+
}
|
|
93940
|
+
const hasList = subsection.tokens.some((t) => t.type === "list");
|
|
93941
|
+
if (hasList) {
|
|
93942
|
+
const listSlides = this.createBulletSlides(subsection.title, subsection.tokens);
|
|
93943
|
+
slides.push(...listSlides);
|
|
93944
|
+
}
|
|
93945
|
+
if (slides.length === 0) {
|
|
93946
|
+
const paragraphs = subsection.tokens.filter((t) => t.type === "paragraph");
|
|
93947
|
+
if (paragraphs.length > 0) {
|
|
93948
|
+
const statement = paragraphs.map((p) => p.text).join("\n\n");
|
|
93949
|
+
slides.push({
|
|
93950
|
+
index: 0,
|
|
93951
|
+
type: "statement",
|
|
93952
|
+
title: subsection.title,
|
|
93953
|
+
// H3 is the action title
|
|
93954
|
+
content: { statement }
|
|
93955
|
+
});
|
|
93956
|
+
}
|
|
93957
|
+
}
|
|
93958
|
+
return slides;
|
|
93959
|
+
}
|
|
93894
93960
|
/**
|
|
93895
93961
|
* Create a table slide - render the table as-is, no extraction.
|
|
93896
93962
|
*/
|
|
@@ -95439,133 +95505,69 @@ function createRendererV2(presentationType = "consulting_deck", themeOverride) {
|
|
|
95439
95505
|
|
|
95440
95506
|
// src/core/PresentationEngineV2.ts
|
|
95441
95507
|
var import_fs9 = require("fs");
|
|
95442
|
-
var
|
|
95443
|
-
|
|
95444
|
-
|
|
95445
|
-
|
|
95446
|
-
|
|
95447
|
-
|
|
95448
|
-
fonts: { title: 72, body: 42, minimum: 36 },
|
|
95449
|
-
theme: "dark",
|
|
95450
|
-
structure: "Sparkline (What Is / What Could Be)",
|
|
95451
|
-
experts: ["Nancy Duarte", "Garr Reynolds", "Carmine Gallo", "Chris Anderson"]
|
|
95452
|
-
},
|
|
95453
|
-
// Sales Pitch - Persuasive, emotional, clear CTA
|
|
95454
|
-
sales_pitch: {
|
|
95455
|
-
wordsPerSlide: { min: 10, max: 35, ideal: 20 },
|
|
95456
|
-
whitespace: "35%+",
|
|
95457
|
-
bulletPoints: { max: 4 },
|
|
95458
|
-
fonts: { title: 56, body: 32, minimum: 28 },
|
|
95459
|
-
theme: "dark",
|
|
95460
|
-
structure: "SPIN (Situation, Problem, Implication, Need-Payoff)",
|
|
95461
|
-
experts: ["Cialdini", "Challenger Sale", "Oren Klaff"]
|
|
95462
|
-
},
|
|
95463
|
-
// Consulting Deck - Data-driven, McKinsey style
|
|
95464
|
-
consulting_deck: {
|
|
95465
|
-
wordsPerSlide: { min: 40, max: 80, ideal: 60 },
|
|
95466
|
-
whitespace: "25-30%",
|
|
95467
|
-
bulletPoints: { max: 7 },
|
|
95468
|
-
fonts: { title: 44, body: 22, minimum: 18 },
|
|
95469
|
-
theme: "mckinsey",
|
|
95470
|
-
structure: "Pyramid Principle (MECE, SCR)",
|
|
95471
|
-
experts: ["Barbara Minto", "McKinsey", "BCG", "Bain"]
|
|
95472
|
-
},
|
|
95473
|
-
// Investment Banking - Dense, financial, formal
|
|
95474
|
-
investment_banking: {
|
|
95475
|
-
wordsPerSlide: { min: 60, max: 120, ideal: 90 },
|
|
95476
|
-
whitespace: "20-25%",
|
|
95477
|
-
bulletPoints: { max: 8 },
|
|
95478
|
-
fonts: { title: 28, body: 12, minimum: 10 },
|
|
95479
|
-
theme: "mckinsey",
|
|
95480
|
-
structure: "Situation-Complication-Hypothesis",
|
|
95481
|
-
experts: ["Wall Street Prep", "Analyst Academy"]
|
|
95482
|
-
},
|
|
95483
|
-
// Investor Pitch - Concise, startup-friendly
|
|
95484
|
-
investor_pitch: {
|
|
95485
|
-
wordsPerSlide: { min: 5, max: 30, ideal: 15 },
|
|
95486
|
-
whitespace: "35%+",
|
|
95487
|
-
bulletPoints: { max: 4 },
|
|
95488
|
-
fonts: { title: 48, body: 28, minimum: 24 },
|
|
95489
|
-
theme: "startup",
|
|
95490
|
-
structure: "Problem \u2192 Solution \u2192 Market \u2192 Traction \u2192 Team \u2192 Ask",
|
|
95491
|
-
experts: ["Sequoia", "Y Combinator", "DocSend"]
|
|
95492
|
-
},
|
|
95493
|
-
// Technical Presentation - Clear diagrams, code-friendly
|
|
95494
|
-
technical_presentation: {
|
|
95495
|
-
wordsPerSlide: { min: 40, max: 100, ideal: 75 },
|
|
95496
|
-
whitespace: "25%+",
|
|
95497
|
-
bulletPoints: { max: 6 },
|
|
95498
|
-
fonts: { title: 44, body: 20, minimum: 14 },
|
|
95499
|
-
theme: "dark",
|
|
95500
|
-
structure: "TL;DR \u2192 Problem \u2192 Architecture \u2192 Tradeoffs \u2192 Next Steps",
|
|
95501
|
-
experts: ["Edward Tufte", "C4 Model", "Google Design Docs"]
|
|
95502
|
-
},
|
|
95503
|
-
// All Hands - Accessible, clear, motivational
|
|
95504
|
-
all_hands: {
|
|
95505
|
-
wordsPerSlide: { min: 15, max: 40, ideal: 25 },
|
|
95506
|
-
whitespace: "30%+",
|
|
95507
|
-
bulletPoints: { max: 5 },
|
|
95508
|
-
fonts: { title: 52, body: 28, minimum: 24 },
|
|
95509
|
-
theme: "minimal",
|
|
95510
|
-
structure: "Updates \u2192 Wins \u2192 Challenges \u2192 What's Next",
|
|
95511
|
-
experts: ["Internal Communications Best Practices"]
|
|
95512
|
-
}
|
|
95508
|
+
var PALETTE_TO_THEME = {
|
|
95509
|
+
dark_executive: "dark",
|
|
95510
|
+
modern_business: "startup",
|
|
95511
|
+
consulting_classic: "mckinsey",
|
|
95512
|
+
executive_professional: "mckinsey",
|
|
95513
|
+
strategy_growth: "minimal"
|
|
95513
95514
|
};
|
|
95514
|
-
|
|
95515
|
-
|
|
95516
|
-
|
|
95517
|
-
|
|
95518
|
-
|
|
95519
|
-
|
|
95520
|
-
|
|
95521
|
-
|
|
95522
|
-
|
|
95523
|
-
|
|
95524
|
-
|
|
95525
|
-
|
|
95526
|
-
|
|
95527
|
-
|
|
95528
|
-
}
|
|
95529
|
-
|
|
95530
|
-
|
|
95531
|
-
|
|
95532
|
-
wordLimitStrict: false,
|
|
95533
|
-
// Consulting allows denser slides
|
|
95534
|
-
requireActionTitles: true,
|
|
95535
|
-
// Titles should state the "so what"
|
|
95536
|
-
requireDataSources: true
|
|
95537
|
-
},
|
|
95538
|
-
investment_banking: {
|
|
95539
|
-
glanceTestSeconds: 10,
|
|
95540
|
-
minScore: 95,
|
|
95541
|
-
wordLimitStrict: false,
|
|
95542
|
-
requireActionTitles: true,
|
|
95543
|
-
requireDataSources: true
|
|
95544
|
-
},
|
|
95545
|
-
investor_pitch: {
|
|
95546
|
-
glanceTestSeconds: 3,
|
|
95547
|
-
minScore: 95,
|
|
95548
|
-
wordLimitStrict: true,
|
|
95549
|
-
requireActionTitles: true,
|
|
95550
|
-
requireDataSources: true
|
|
95551
|
-
},
|
|
95552
|
-
technical_presentation: {
|
|
95553
|
-
glanceTestSeconds: 5,
|
|
95554
|
-
minScore: 95,
|
|
95555
|
-
wordLimitStrict: false,
|
|
95556
|
-
requireActionTitles: false,
|
|
95557
|
-
requireDataSources: true
|
|
95558
|
-
},
|
|
95559
|
-
all_hands: {
|
|
95560
|
-
glanceTestSeconds: 3,
|
|
95561
|
-
minScore: 95,
|
|
95562
|
-
wordLimitStrict: true,
|
|
95563
|
-
requireActionTitles: false,
|
|
95564
|
-
requireDataSources: false
|
|
95515
|
+
async function loadDesignSpecsFromKB(kb, type) {
|
|
95516
|
+
const typeConfig = kb.queryRequired(`presentation_types.${type}`);
|
|
95517
|
+
const validationRules = typeConfig.value.validation_rules;
|
|
95518
|
+
const wordsPerSlide = validationRules.words_per_slide;
|
|
95519
|
+
const whitespace = validationRules.whitespace;
|
|
95520
|
+
const bulletsPerSlide = validationRules.bullets_per_slide;
|
|
95521
|
+
const typography = typeConfig.value.typography;
|
|
95522
|
+
const primaryExperts = typeConfig.value.primary_experts;
|
|
95523
|
+
const colorPalette = typeConfig.value.color_palette || "consulting_classic";
|
|
95524
|
+
const theme = PALETTE_TO_THEME[colorPalette] || "mckinsey";
|
|
95525
|
+
const scoringWeights = typeConfig.value.scoring_weights;
|
|
95526
|
+
let structure = "General presentation structure";
|
|
95527
|
+
if (primaryExperts.some((e) => e.includes("Minto") || e.includes("McKinsey"))) {
|
|
95528
|
+
structure = "Pyramid Principle (MECE, SCR)";
|
|
95529
|
+
} else if (primaryExperts.some((e) => e.includes("Duarte"))) {
|
|
95530
|
+
structure = "Sparkline (What Is / What Could Be)";
|
|
95531
|
+
} else if (primaryExperts.some((e) => e.includes("Cialdini"))) {
|
|
95532
|
+
structure = "Persuasion-driven (SPIN, Challenger)";
|
|
95565
95533
|
}
|
|
95566
|
-
|
|
95534
|
+
return {
|
|
95535
|
+
wordsPerSlide,
|
|
95536
|
+
whitespace,
|
|
95537
|
+
bulletPoints: { max: bulletsPerSlide?.max || 5 },
|
|
95538
|
+
fonts: {
|
|
95539
|
+
title: typography?.titles || "44px, Bold",
|
|
95540
|
+
body: typography?.body || "22px",
|
|
95541
|
+
maxFonts: typography?.max_fonts || 2
|
|
95542
|
+
},
|
|
95543
|
+
theme,
|
|
95544
|
+
structure,
|
|
95545
|
+
experts: primaryExperts,
|
|
95546
|
+
actionTitlesRequired: validationRules.action_titles_required || false,
|
|
95547
|
+
sourcesRequired: validationRules.sources_required || false,
|
|
95548
|
+
scoringWeights: scoringWeights || {
|
|
95549
|
+
visual_quality: 30,
|
|
95550
|
+
content_quality: 30,
|
|
95551
|
+
expert_compliance: 30,
|
|
95552
|
+
accessibility: 10
|
|
95553
|
+
}
|
|
95554
|
+
};
|
|
95555
|
+
}
|
|
95556
|
+
function getQualityCriteria(specs, type) {
|
|
95557
|
+
const isKeynote = type === "ted_keynote" || type === "sales_pitch";
|
|
95558
|
+
const isConsulting = type === "consulting_deck" || type === "investment_banking";
|
|
95559
|
+
return {
|
|
95560
|
+
glanceTestSeconds: isKeynote ? 3 : isConsulting ? 5 : 3,
|
|
95561
|
+
minScore: 95,
|
|
95562
|
+
wordLimitStrict: isKeynote,
|
|
95563
|
+
// Keynotes have strict word limits
|
|
95564
|
+
requireActionTitles: specs.actionTitlesRequired,
|
|
95565
|
+
requireDataSources: specs.sourcesRequired
|
|
95566
|
+
};
|
|
95567
|
+
}
|
|
95567
95568
|
var PresentationEngineV2 = class {
|
|
95568
95569
|
options;
|
|
95570
|
+
kb = null;
|
|
95569
95571
|
constructor(options = {}) {
|
|
95570
95572
|
this.options = {
|
|
95571
95573
|
presentationType: options.presentationType || "consulting_deck",
|
|
@@ -95584,19 +95586,26 @@ var PresentationEngineV2 = class {
|
|
|
95584
95586
|
/**
|
|
95585
95587
|
* Generate a world-class presentation from markdown content.
|
|
95586
95588
|
* Follows knowledge base specs and demands 95+ quality score.
|
|
95589
|
+
*
|
|
95590
|
+
* CRITICAL: All specs come from the Knowledge Base YAML at runtime.
|
|
95591
|
+
* No hardcoded fallbacks - if KB is missing data, we fail loudly.
|
|
95587
95592
|
*/
|
|
95588
95593
|
async generate(markdown, title) {
|
|
95589
95594
|
const warnings = [];
|
|
95595
|
+
this.log("Step 0: Loading Knowledge Base...");
|
|
95596
|
+
this.kb = await initKB();
|
|
95597
|
+
this.log(` KB v${this.kb.getVersion()} loaded`);
|
|
95590
95598
|
this.log("Step 1: Detecting presentation type...");
|
|
95591
95599
|
const detectedType = this.detectPresentationType(markdown);
|
|
95592
95600
|
const presentationType = this.options.presentationType || detectedType;
|
|
95593
95601
|
this.log(` Using type: ${presentationType} (detected: ${detectedType})`);
|
|
95594
95602
|
this.log("Step 2: Loading design specs from Knowledge Base...");
|
|
95595
|
-
const designSpecs =
|
|
95596
|
-
const qualityCriteria =
|
|
95603
|
+
const designSpecs = await loadDesignSpecsFromKB(this.kb, presentationType);
|
|
95604
|
+
const qualityCriteria = getQualityCriteria(designSpecs, presentationType);
|
|
95597
95605
|
this.log(` Theme: ${designSpecs.theme}`);
|
|
95598
95606
|
this.log(` Structure: ${designSpecs.structure}`);
|
|
95599
95607
|
this.log(` Words/slide: ${designSpecs.wordsPerSlide.min}-${designSpecs.wordsPerSlide.max}`);
|
|
95608
|
+
this.log(` Experts: ${designSpecs.experts.slice(0, 2).join(", ")}...`);
|
|
95600
95609
|
this.log("Step 3: Generating slides...");
|
|
95601
95610
|
const generator = createSlideGeneratorV2(presentationType);
|
|
95602
95611
|
let slides = generator.generate(markdown, title);
|
|
@@ -95834,7 +95843,29 @@ SUCCESS: Generated ${slides.length} slides scoring ${review.overallScore}/100`);
|
|
|
95834
95843
|
*/
|
|
95835
95844
|
isActionTitle(title) {
|
|
95836
95845
|
const lower = title.toLowerCase();
|
|
95837
|
-
const
|
|
95846
|
+
const genericTopics = [
|
|
95847
|
+
"executive summary",
|
|
95848
|
+
"summary",
|
|
95849
|
+
"overview",
|
|
95850
|
+
"introduction",
|
|
95851
|
+
"background",
|
|
95852
|
+
"context",
|
|
95853
|
+
"current state",
|
|
95854
|
+
"assessment",
|
|
95855
|
+
"recommendations",
|
|
95856
|
+
"next steps",
|
|
95857
|
+
"conclusion",
|
|
95858
|
+
"appendix",
|
|
95859
|
+
"key findings",
|
|
95860
|
+
"findings",
|
|
95861
|
+
"analysis",
|
|
95862
|
+
"results"
|
|
95863
|
+
];
|
|
95864
|
+
if (genericTopics.some((topic) => lower === topic || lower === topic + "s")) {
|
|
95865
|
+
return false;
|
|
95866
|
+
}
|
|
95867
|
+
const actionIndicators = [
|
|
95868
|
+
// Verbs
|
|
95838
95869
|
"increase",
|
|
95839
95870
|
"decrease",
|
|
95840
95871
|
"reduce",
|
|
@@ -95847,37 +95878,61 @@ SUCCESS: Generated ${slides.length} slides scoring ${review.overallScore}/100`);
|
|
|
95847
95878
|
"build",
|
|
95848
95879
|
"transform",
|
|
95849
95880
|
"accelerate",
|
|
95881
|
+
"cut",
|
|
95882
|
+
"save",
|
|
95883
|
+
"grow",
|
|
95884
|
+
"expand",
|
|
95885
|
+
"optimize",
|
|
95886
|
+
"streamline",
|
|
95887
|
+
// Modal verbs indicating action
|
|
95850
95888
|
"will",
|
|
95851
95889
|
"can",
|
|
95852
95890
|
"should",
|
|
95853
95891
|
"must",
|
|
95854
95892
|
"need",
|
|
95855
95893
|
"require",
|
|
95894
|
+
// Insight verbs
|
|
95856
95895
|
"shows",
|
|
95857
95896
|
"demonstrates",
|
|
95858
95897
|
"reveals",
|
|
95859
95898
|
"indicates",
|
|
95860
95899
|
"suggests",
|
|
95900
|
+
// Cause/effect
|
|
95861
95901
|
"leads to",
|
|
95862
95902
|
"results in",
|
|
95863
95903
|
"enables",
|
|
95864
95904
|
"supports",
|
|
95905
|
+
"drives",
|
|
95906
|
+
// Method indicators
|
|
95865
95907
|
"by",
|
|
95866
95908
|
"through",
|
|
95867
95909
|
"via",
|
|
95868
95910
|
"using",
|
|
95869
|
-
//
|
|
95911
|
+
// Quantified outcomes
|
|
95870
95912
|
"%",
|
|
95871
|
-
"$"
|
|
95872
|
-
|
|
95913
|
+
"$",
|
|
95914
|
+
"x",
|
|
95915
|
+
"10x",
|
|
95916
|
+
"2x",
|
|
95917
|
+
"3x",
|
|
95918
|
+
// Time-bound opportunities
|
|
95919
|
+
"opportunity",
|
|
95920
|
+
"in q",
|
|
95921
|
+
"by q",
|
|
95922
|
+
"timeline",
|
|
95923
|
+
"roadmap",
|
|
95924
|
+
// Comparative
|
|
95925
|
+
"better",
|
|
95926
|
+
"faster",
|
|
95927
|
+
"cheaper",
|
|
95928
|
+
"more efficient"
|
|
95873
95929
|
];
|
|
95874
|
-
return
|
|
95930
|
+
return actionIndicators.some((word) => lower.includes(word));
|
|
95875
95931
|
}
|
|
95876
95932
|
/**
|
|
95877
95933
|
* Assess the flow and narrative structure of the deck.
|
|
95878
95934
|
*/
|
|
95879
95935
|
assessFlow(slides, type) {
|
|
95880
|
-
const specs = KNOWLEDGE_BASE[type];
|
|
95881
95936
|
let score = 100;
|
|
95882
95937
|
const types = slides.map((s) => s.type);
|
|
95883
95938
|
if (types[0] !== "title") score -= 10;
|
package/dist/index.mjs
CHANGED
|
@@ -2145,10 +2145,19 @@ var SlideGeneratorV2 = class {
|
|
|
2145
2145
|
* RULES:
|
|
2146
2146
|
* 1. Tables ALWAYS become table slides - NEVER extract to metrics
|
|
2147
2147
|
* 2. Empty sections are SKIPPED - no blank divider slides
|
|
2148
|
-
* 3.
|
|
2148
|
+
* 3. H3 headings become individual slides with ACTION TITLES (critical for consulting)
|
|
2149
|
+
* 4. Sections with minimal content are combined into statement slides
|
|
2149
2150
|
*/
|
|
2150
2151
|
processSectionContent(section, startIndex) {
|
|
2151
2152
|
const slides = [];
|
|
2153
|
+
const subsections = this.splitIntoSubsections(section.tokens);
|
|
2154
|
+
if (subsections.length > 0) {
|
|
2155
|
+
for (const subsection of subsections) {
|
|
2156
|
+
const subsectionSlides = this.processSubsection(subsection, section.title);
|
|
2157
|
+
slides.push(...subsectionSlides);
|
|
2158
|
+
}
|
|
2159
|
+
return slides;
|
|
2160
|
+
}
|
|
2152
2161
|
const tableTokens = section.tokens.filter((t) => t.type === "table");
|
|
2153
2162
|
const hasList = section.tokens.some((t) => t.type === "list");
|
|
2154
2163
|
const hasSignificantText = this.hasSignificantParagraphs(section.tokens);
|
|
@@ -2175,6 +2184,63 @@ var SlideGeneratorV2 = class {
|
|
|
2175
2184
|
}
|
|
2176
2185
|
return slides;
|
|
2177
2186
|
}
|
|
2187
|
+
/**
|
|
2188
|
+
* Split tokens into subsections based on H3 headers.
|
|
2189
|
+
* H3 headers become ACTION TITLES for consulting decks.
|
|
2190
|
+
*/
|
|
2191
|
+
splitIntoSubsections(tokens) {
|
|
2192
|
+
const subsections = [];
|
|
2193
|
+
let currentSubsection = null;
|
|
2194
|
+
let hasH3 = false;
|
|
2195
|
+
for (const token of tokens) {
|
|
2196
|
+
if (token.type === "heading" && token.depth === 3) {
|
|
2197
|
+
hasH3 = true;
|
|
2198
|
+
if (currentSubsection) {
|
|
2199
|
+
subsections.push(currentSubsection);
|
|
2200
|
+
}
|
|
2201
|
+
currentSubsection = {
|
|
2202
|
+
title: token.text,
|
|
2203
|
+
tokens: []
|
|
2204
|
+
};
|
|
2205
|
+
} else if (currentSubsection) {
|
|
2206
|
+
currentSubsection.tokens.push(token);
|
|
2207
|
+
}
|
|
2208
|
+
}
|
|
2209
|
+
if (currentSubsection && currentSubsection.tokens.length > 0) {
|
|
2210
|
+
subsections.push(currentSubsection);
|
|
2211
|
+
}
|
|
2212
|
+
return hasH3 ? subsections : [];
|
|
2213
|
+
}
|
|
2214
|
+
/**
|
|
2215
|
+
* Process a subsection (H3) into a slide.
|
|
2216
|
+
* The H3 title IS the action title.
|
|
2217
|
+
*/
|
|
2218
|
+
processSubsection(subsection, parentTitle) {
|
|
2219
|
+
const slides = [];
|
|
2220
|
+
const tableTokens = subsection.tokens.filter((t) => t.type === "table");
|
|
2221
|
+
for (const tableToken of tableTokens) {
|
|
2222
|
+
slides.push(this.createTableSlide(subsection.title, tableToken));
|
|
2223
|
+
}
|
|
2224
|
+
const hasList = subsection.tokens.some((t) => t.type === "list");
|
|
2225
|
+
if (hasList) {
|
|
2226
|
+
const listSlides = this.createBulletSlides(subsection.title, subsection.tokens);
|
|
2227
|
+
slides.push(...listSlides);
|
|
2228
|
+
}
|
|
2229
|
+
if (slides.length === 0) {
|
|
2230
|
+
const paragraphs = subsection.tokens.filter((t) => t.type === "paragraph");
|
|
2231
|
+
if (paragraphs.length > 0) {
|
|
2232
|
+
const statement = paragraphs.map((p) => p.text).join("\n\n");
|
|
2233
|
+
slides.push({
|
|
2234
|
+
index: 0,
|
|
2235
|
+
type: "statement",
|
|
2236
|
+
title: subsection.title,
|
|
2237
|
+
// H3 is the action title
|
|
2238
|
+
content: { statement }
|
|
2239
|
+
});
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
return slides;
|
|
2243
|
+
}
|
|
2178
2244
|
/**
|
|
2179
2245
|
* Create a table slide - render the table as-is, no extraction.
|
|
2180
2246
|
*/
|
|
@@ -3723,133 +3789,69 @@ function createRendererV2(presentationType = "consulting_deck", themeOverride) {
|
|
|
3723
3789
|
|
|
3724
3790
|
// src/core/PresentationEngineV2.ts
|
|
3725
3791
|
import { writeFileSync as writeFileSync2 } from "fs";
|
|
3726
|
-
var
|
|
3727
|
-
|
|
3728
|
-
|
|
3729
|
-
|
|
3730
|
-
|
|
3731
|
-
|
|
3732
|
-
fonts: { title: 72, body: 42, minimum: 36 },
|
|
3733
|
-
theme: "dark",
|
|
3734
|
-
structure: "Sparkline (What Is / What Could Be)",
|
|
3735
|
-
experts: ["Nancy Duarte", "Garr Reynolds", "Carmine Gallo", "Chris Anderson"]
|
|
3736
|
-
},
|
|
3737
|
-
// Sales Pitch - Persuasive, emotional, clear CTA
|
|
3738
|
-
sales_pitch: {
|
|
3739
|
-
wordsPerSlide: { min: 10, max: 35, ideal: 20 },
|
|
3740
|
-
whitespace: "35%+",
|
|
3741
|
-
bulletPoints: { max: 4 },
|
|
3742
|
-
fonts: { title: 56, body: 32, minimum: 28 },
|
|
3743
|
-
theme: "dark",
|
|
3744
|
-
structure: "SPIN (Situation, Problem, Implication, Need-Payoff)",
|
|
3745
|
-
experts: ["Cialdini", "Challenger Sale", "Oren Klaff"]
|
|
3746
|
-
},
|
|
3747
|
-
// Consulting Deck - Data-driven, McKinsey style
|
|
3748
|
-
consulting_deck: {
|
|
3749
|
-
wordsPerSlide: { min: 40, max: 80, ideal: 60 },
|
|
3750
|
-
whitespace: "25-30%",
|
|
3751
|
-
bulletPoints: { max: 7 },
|
|
3752
|
-
fonts: { title: 44, body: 22, minimum: 18 },
|
|
3753
|
-
theme: "mckinsey",
|
|
3754
|
-
structure: "Pyramid Principle (MECE, SCR)",
|
|
3755
|
-
experts: ["Barbara Minto", "McKinsey", "BCG", "Bain"]
|
|
3756
|
-
},
|
|
3757
|
-
// Investment Banking - Dense, financial, formal
|
|
3758
|
-
investment_banking: {
|
|
3759
|
-
wordsPerSlide: { min: 60, max: 120, ideal: 90 },
|
|
3760
|
-
whitespace: "20-25%",
|
|
3761
|
-
bulletPoints: { max: 8 },
|
|
3762
|
-
fonts: { title: 28, body: 12, minimum: 10 },
|
|
3763
|
-
theme: "mckinsey",
|
|
3764
|
-
structure: "Situation-Complication-Hypothesis",
|
|
3765
|
-
experts: ["Wall Street Prep", "Analyst Academy"]
|
|
3766
|
-
},
|
|
3767
|
-
// Investor Pitch - Concise, startup-friendly
|
|
3768
|
-
investor_pitch: {
|
|
3769
|
-
wordsPerSlide: { min: 5, max: 30, ideal: 15 },
|
|
3770
|
-
whitespace: "35%+",
|
|
3771
|
-
bulletPoints: { max: 4 },
|
|
3772
|
-
fonts: { title: 48, body: 28, minimum: 24 },
|
|
3773
|
-
theme: "startup",
|
|
3774
|
-
structure: "Problem \u2192 Solution \u2192 Market \u2192 Traction \u2192 Team \u2192 Ask",
|
|
3775
|
-
experts: ["Sequoia", "Y Combinator", "DocSend"]
|
|
3776
|
-
},
|
|
3777
|
-
// Technical Presentation - Clear diagrams, code-friendly
|
|
3778
|
-
technical_presentation: {
|
|
3779
|
-
wordsPerSlide: { min: 40, max: 100, ideal: 75 },
|
|
3780
|
-
whitespace: "25%+",
|
|
3781
|
-
bulletPoints: { max: 6 },
|
|
3782
|
-
fonts: { title: 44, body: 20, minimum: 14 },
|
|
3783
|
-
theme: "dark",
|
|
3784
|
-
structure: "TL;DR \u2192 Problem \u2192 Architecture \u2192 Tradeoffs \u2192 Next Steps",
|
|
3785
|
-
experts: ["Edward Tufte", "C4 Model", "Google Design Docs"]
|
|
3786
|
-
},
|
|
3787
|
-
// All Hands - Accessible, clear, motivational
|
|
3788
|
-
all_hands: {
|
|
3789
|
-
wordsPerSlide: { min: 15, max: 40, ideal: 25 },
|
|
3790
|
-
whitespace: "30%+",
|
|
3791
|
-
bulletPoints: { max: 5 },
|
|
3792
|
-
fonts: { title: 52, body: 28, minimum: 24 },
|
|
3793
|
-
theme: "minimal",
|
|
3794
|
-
structure: "Updates \u2192 Wins \u2192 Challenges \u2192 What's Next",
|
|
3795
|
-
experts: ["Internal Communications Best Practices"]
|
|
3796
|
-
}
|
|
3792
|
+
var PALETTE_TO_THEME = {
|
|
3793
|
+
dark_executive: "dark",
|
|
3794
|
+
modern_business: "startup",
|
|
3795
|
+
consulting_classic: "mckinsey",
|
|
3796
|
+
executive_professional: "mckinsey",
|
|
3797
|
+
strategy_growth: "minimal"
|
|
3797
3798
|
};
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
|
|
3806
|
-
|
|
3807
|
-
|
|
3808
|
-
|
|
3809
|
-
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
}
|
|
3813
|
-
|
|
3814
|
-
|
|
3815
|
-
|
|
3816
|
-
wordLimitStrict: false,
|
|
3817
|
-
// Consulting allows denser slides
|
|
3818
|
-
requireActionTitles: true,
|
|
3819
|
-
// Titles should state the "so what"
|
|
3820
|
-
requireDataSources: true
|
|
3821
|
-
},
|
|
3822
|
-
investment_banking: {
|
|
3823
|
-
glanceTestSeconds: 10,
|
|
3824
|
-
minScore: 95,
|
|
3825
|
-
wordLimitStrict: false,
|
|
3826
|
-
requireActionTitles: true,
|
|
3827
|
-
requireDataSources: true
|
|
3828
|
-
},
|
|
3829
|
-
investor_pitch: {
|
|
3830
|
-
glanceTestSeconds: 3,
|
|
3831
|
-
minScore: 95,
|
|
3832
|
-
wordLimitStrict: true,
|
|
3833
|
-
requireActionTitles: true,
|
|
3834
|
-
requireDataSources: true
|
|
3835
|
-
},
|
|
3836
|
-
technical_presentation: {
|
|
3837
|
-
glanceTestSeconds: 5,
|
|
3838
|
-
minScore: 95,
|
|
3839
|
-
wordLimitStrict: false,
|
|
3840
|
-
requireActionTitles: false,
|
|
3841
|
-
requireDataSources: true
|
|
3842
|
-
},
|
|
3843
|
-
all_hands: {
|
|
3844
|
-
glanceTestSeconds: 3,
|
|
3845
|
-
minScore: 95,
|
|
3846
|
-
wordLimitStrict: true,
|
|
3847
|
-
requireActionTitles: false,
|
|
3848
|
-
requireDataSources: false
|
|
3799
|
+
async function loadDesignSpecsFromKB(kb, type) {
|
|
3800
|
+
const typeConfig = kb.queryRequired(`presentation_types.${type}`);
|
|
3801
|
+
const validationRules = typeConfig.value.validation_rules;
|
|
3802
|
+
const wordsPerSlide = validationRules.words_per_slide;
|
|
3803
|
+
const whitespace = validationRules.whitespace;
|
|
3804
|
+
const bulletsPerSlide = validationRules.bullets_per_slide;
|
|
3805
|
+
const typography = typeConfig.value.typography;
|
|
3806
|
+
const primaryExperts = typeConfig.value.primary_experts;
|
|
3807
|
+
const colorPalette = typeConfig.value.color_palette || "consulting_classic";
|
|
3808
|
+
const theme = PALETTE_TO_THEME[colorPalette] || "mckinsey";
|
|
3809
|
+
const scoringWeights = typeConfig.value.scoring_weights;
|
|
3810
|
+
let structure = "General presentation structure";
|
|
3811
|
+
if (primaryExperts.some((e) => e.includes("Minto") || e.includes("McKinsey"))) {
|
|
3812
|
+
structure = "Pyramid Principle (MECE, SCR)";
|
|
3813
|
+
} else if (primaryExperts.some((e) => e.includes("Duarte"))) {
|
|
3814
|
+
structure = "Sparkline (What Is / What Could Be)";
|
|
3815
|
+
} else if (primaryExperts.some((e) => e.includes("Cialdini"))) {
|
|
3816
|
+
structure = "Persuasion-driven (SPIN, Challenger)";
|
|
3849
3817
|
}
|
|
3850
|
-
|
|
3818
|
+
return {
|
|
3819
|
+
wordsPerSlide,
|
|
3820
|
+
whitespace,
|
|
3821
|
+
bulletPoints: { max: bulletsPerSlide?.max || 5 },
|
|
3822
|
+
fonts: {
|
|
3823
|
+
title: typography?.titles || "44px, Bold",
|
|
3824
|
+
body: typography?.body || "22px",
|
|
3825
|
+
maxFonts: typography?.max_fonts || 2
|
|
3826
|
+
},
|
|
3827
|
+
theme,
|
|
3828
|
+
structure,
|
|
3829
|
+
experts: primaryExperts,
|
|
3830
|
+
actionTitlesRequired: validationRules.action_titles_required || false,
|
|
3831
|
+
sourcesRequired: validationRules.sources_required || false,
|
|
3832
|
+
scoringWeights: scoringWeights || {
|
|
3833
|
+
visual_quality: 30,
|
|
3834
|
+
content_quality: 30,
|
|
3835
|
+
expert_compliance: 30,
|
|
3836
|
+
accessibility: 10
|
|
3837
|
+
}
|
|
3838
|
+
};
|
|
3839
|
+
}
|
|
3840
|
+
function getQualityCriteria(specs, type) {
|
|
3841
|
+
const isKeynote = type === "ted_keynote" || type === "sales_pitch";
|
|
3842
|
+
const isConsulting = type === "consulting_deck" || type === "investment_banking";
|
|
3843
|
+
return {
|
|
3844
|
+
glanceTestSeconds: isKeynote ? 3 : isConsulting ? 5 : 3,
|
|
3845
|
+
minScore: 95,
|
|
3846
|
+
wordLimitStrict: isKeynote,
|
|
3847
|
+
// Keynotes have strict word limits
|
|
3848
|
+
requireActionTitles: specs.actionTitlesRequired,
|
|
3849
|
+
requireDataSources: specs.sourcesRequired
|
|
3850
|
+
};
|
|
3851
|
+
}
|
|
3851
3852
|
var PresentationEngineV2 = class {
|
|
3852
3853
|
options;
|
|
3854
|
+
kb = null;
|
|
3853
3855
|
constructor(options = {}) {
|
|
3854
3856
|
this.options = {
|
|
3855
3857
|
presentationType: options.presentationType || "consulting_deck",
|
|
@@ -3868,19 +3870,26 @@ var PresentationEngineV2 = class {
|
|
|
3868
3870
|
/**
|
|
3869
3871
|
* Generate a world-class presentation from markdown content.
|
|
3870
3872
|
* Follows knowledge base specs and demands 95+ quality score.
|
|
3873
|
+
*
|
|
3874
|
+
* CRITICAL: All specs come from the Knowledge Base YAML at runtime.
|
|
3875
|
+
* No hardcoded fallbacks - if KB is missing data, we fail loudly.
|
|
3871
3876
|
*/
|
|
3872
3877
|
async generate(markdown, title) {
|
|
3873
3878
|
const warnings = [];
|
|
3879
|
+
this.log("Step 0: Loading Knowledge Base...");
|
|
3880
|
+
this.kb = await initKB();
|
|
3881
|
+
this.log(` KB v${this.kb.getVersion()} loaded`);
|
|
3874
3882
|
this.log("Step 1: Detecting presentation type...");
|
|
3875
3883
|
const detectedType = this.detectPresentationType(markdown);
|
|
3876
3884
|
const presentationType = this.options.presentationType || detectedType;
|
|
3877
3885
|
this.log(` Using type: ${presentationType} (detected: ${detectedType})`);
|
|
3878
3886
|
this.log("Step 2: Loading design specs from Knowledge Base...");
|
|
3879
|
-
const designSpecs =
|
|
3880
|
-
const qualityCriteria =
|
|
3887
|
+
const designSpecs = await loadDesignSpecsFromKB(this.kb, presentationType);
|
|
3888
|
+
const qualityCriteria = getQualityCriteria(designSpecs, presentationType);
|
|
3881
3889
|
this.log(` Theme: ${designSpecs.theme}`);
|
|
3882
3890
|
this.log(` Structure: ${designSpecs.structure}`);
|
|
3883
3891
|
this.log(` Words/slide: ${designSpecs.wordsPerSlide.min}-${designSpecs.wordsPerSlide.max}`);
|
|
3892
|
+
this.log(` Experts: ${designSpecs.experts.slice(0, 2).join(", ")}...`);
|
|
3884
3893
|
this.log("Step 3: Generating slides...");
|
|
3885
3894
|
const generator = createSlideGeneratorV2(presentationType);
|
|
3886
3895
|
let slides = generator.generate(markdown, title);
|
|
@@ -4118,7 +4127,29 @@ SUCCESS: Generated ${slides.length} slides scoring ${review.overallScore}/100`);
|
|
|
4118
4127
|
*/
|
|
4119
4128
|
isActionTitle(title) {
|
|
4120
4129
|
const lower = title.toLowerCase();
|
|
4121
|
-
const
|
|
4130
|
+
const genericTopics = [
|
|
4131
|
+
"executive summary",
|
|
4132
|
+
"summary",
|
|
4133
|
+
"overview",
|
|
4134
|
+
"introduction",
|
|
4135
|
+
"background",
|
|
4136
|
+
"context",
|
|
4137
|
+
"current state",
|
|
4138
|
+
"assessment",
|
|
4139
|
+
"recommendations",
|
|
4140
|
+
"next steps",
|
|
4141
|
+
"conclusion",
|
|
4142
|
+
"appendix",
|
|
4143
|
+
"key findings",
|
|
4144
|
+
"findings",
|
|
4145
|
+
"analysis",
|
|
4146
|
+
"results"
|
|
4147
|
+
];
|
|
4148
|
+
if (genericTopics.some((topic) => lower === topic || lower === topic + "s")) {
|
|
4149
|
+
return false;
|
|
4150
|
+
}
|
|
4151
|
+
const actionIndicators = [
|
|
4152
|
+
// Verbs
|
|
4122
4153
|
"increase",
|
|
4123
4154
|
"decrease",
|
|
4124
4155
|
"reduce",
|
|
@@ -4131,37 +4162,61 @@ SUCCESS: Generated ${slides.length} slides scoring ${review.overallScore}/100`);
|
|
|
4131
4162
|
"build",
|
|
4132
4163
|
"transform",
|
|
4133
4164
|
"accelerate",
|
|
4165
|
+
"cut",
|
|
4166
|
+
"save",
|
|
4167
|
+
"grow",
|
|
4168
|
+
"expand",
|
|
4169
|
+
"optimize",
|
|
4170
|
+
"streamline",
|
|
4171
|
+
// Modal verbs indicating action
|
|
4134
4172
|
"will",
|
|
4135
4173
|
"can",
|
|
4136
4174
|
"should",
|
|
4137
4175
|
"must",
|
|
4138
4176
|
"need",
|
|
4139
4177
|
"require",
|
|
4178
|
+
// Insight verbs
|
|
4140
4179
|
"shows",
|
|
4141
4180
|
"demonstrates",
|
|
4142
4181
|
"reveals",
|
|
4143
4182
|
"indicates",
|
|
4144
4183
|
"suggests",
|
|
4184
|
+
// Cause/effect
|
|
4145
4185
|
"leads to",
|
|
4146
4186
|
"results in",
|
|
4147
4187
|
"enables",
|
|
4148
4188
|
"supports",
|
|
4189
|
+
"drives",
|
|
4190
|
+
// Method indicators
|
|
4149
4191
|
"by",
|
|
4150
4192
|
"through",
|
|
4151
4193
|
"via",
|
|
4152
4194
|
"using",
|
|
4153
|
-
//
|
|
4195
|
+
// Quantified outcomes
|
|
4154
4196
|
"%",
|
|
4155
|
-
"$"
|
|
4156
|
-
|
|
4197
|
+
"$",
|
|
4198
|
+
"x",
|
|
4199
|
+
"10x",
|
|
4200
|
+
"2x",
|
|
4201
|
+
"3x",
|
|
4202
|
+
// Time-bound opportunities
|
|
4203
|
+
"opportunity",
|
|
4204
|
+
"in q",
|
|
4205
|
+
"by q",
|
|
4206
|
+
"timeline",
|
|
4207
|
+
"roadmap",
|
|
4208
|
+
// Comparative
|
|
4209
|
+
"better",
|
|
4210
|
+
"faster",
|
|
4211
|
+
"cheaper",
|
|
4212
|
+
"more efficient"
|
|
4157
4213
|
];
|
|
4158
|
-
return
|
|
4214
|
+
return actionIndicators.some((word) => lower.includes(word));
|
|
4159
4215
|
}
|
|
4160
4216
|
/**
|
|
4161
4217
|
* Assess the flow and narrative structure of the deck.
|
|
4162
4218
|
*/
|
|
4163
4219
|
assessFlow(slides, type) {
|
|
4164
|
-
const specs = KNOWLEDGE_BASE[type];
|
|
4165
4220
|
let score = 100;
|
|
4166
4221
|
const types = slides.map((s) => s.type);
|
|
4167
4222
|
if (types[0] !== "title") score -= 10;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-presentation-master",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.0.0",
|
|
4
4
|
"description": "Generate world-class presentations using expert methodologies from Duarte, Reynolds, Gallo, and Anderson. Enforces rigorous quality standards through real visual validation.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|