claude-presentation-master 8.2.0 → 8.3.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/dist/index.d.mts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +117 -44
- package/dist/index.mjs +117 -44
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -1067,6 +1067,8 @@ declare class ContentAnalyzer {
|
|
|
1067
1067
|
/**
|
|
1068
1068
|
* Extract SCQA structure (Barbara Minto)
|
|
1069
1069
|
* CRITICAL: Answer must be clean prose, NOT bullet points
|
|
1070
|
+
* @param text - The content text to analyze
|
|
1071
|
+
* @param subtitle - Optional subtitle to exclude (prevents redundancy with title slide)
|
|
1070
1072
|
*/
|
|
1071
1073
|
private extractSCQA;
|
|
1072
1074
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1067,6 +1067,8 @@ declare class ContentAnalyzer {
|
|
|
1067
1067
|
/**
|
|
1068
1068
|
* Extract SCQA structure (Barbara Minto)
|
|
1069
1069
|
* CRITICAL: Answer must be clean prose, NOT bullet points
|
|
1070
|
+
* @param text - The content text to analyze
|
|
1071
|
+
* @param subtitle - Optional subtitle to exclude (prevents redundancy with title slide)
|
|
1070
1072
|
*/
|
|
1071
1073
|
private extractSCQA;
|
|
1072
1074
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1186,7 +1186,7 @@ var ContentAnalyzer = class {
|
|
|
1186
1186
|
logger.step(`Detected type: ${detectedType}`);
|
|
1187
1187
|
const sections = this.extractSections(text);
|
|
1188
1188
|
logger.step(`Found ${sections.length} sections`);
|
|
1189
|
-
const scqa = this.extractSCQA(text);
|
|
1189
|
+
const scqa = this.extractSCQA(text, subtitle);
|
|
1190
1190
|
const sparkline = this.extractSparkline(text);
|
|
1191
1191
|
const keyMessages = this.extractKeyMessages(text);
|
|
1192
1192
|
const dataPoints = this.extractDataPoints(text);
|
|
@@ -1453,15 +1453,24 @@ var ContentAnalyzer = class {
|
|
|
1453
1453
|
/**
|
|
1454
1454
|
* Extract SCQA structure (Barbara Minto)
|
|
1455
1455
|
* CRITICAL: Answer must be clean prose, NOT bullet points
|
|
1456
|
+
* @param text - The content text to analyze
|
|
1457
|
+
* @param subtitle - Optional subtitle to exclude (prevents redundancy with title slide)
|
|
1456
1458
|
*/
|
|
1457
|
-
extractSCQA(text) {
|
|
1459
|
+
extractSCQA(text, subtitle) {
|
|
1458
1460
|
const paragraphs = text.split(/\n\n+/).filter((p) => p.trim());
|
|
1461
|
+
const normalizedSubtitle = (subtitle || "").toLowerCase().trim();
|
|
1462
|
+
const isSubtitle = (para) => {
|
|
1463
|
+
if (!normalizedSubtitle) return false;
|
|
1464
|
+
const normalized = para.toLowerCase().trim();
|
|
1465
|
+
return normalized === normalizedSubtitle || normalized.includes(normalizedSubtitle) || normalizedSubtitle.includes(normalized);
|
|
1466
|
+
};
|
|
1459
1467
|
let situation = "";
|
|
1460
1468
|
let complication = "";
|
|
1461
1469
|
let question = "";
|
|
1462
1470
|
let answer = "";
|
|
1463
1471
|
for (const para of paragraphs.slice(0, 5)) {
|
|
1464
1472
|
if (para.startsWith("-") || para.startsWith("#") || para.startsWith("|")) continue;
|
|
1473
|
+
if (isSubtitle(para)) continue;
|
|
1465
1474
|
if (this.containsSignals(para.toLowerCase(), this.situationSignals)) {
|
|
1466
1475
|
situation = this.extractFirstSentence(para);
|
|
1467
1476
|
break;
|
|
@@ -1489,6 +1498,7 @@ var ContentAnalyzer = class {
|
|
|
1489
1498
|
if (!situation && paragraphs.length > 0) {
|
|
1490
1499
|
for (const para of paragraphs.slice(0, 5)) {
|
|
1491
1500
|
if (!para.startsWith("-") && !para.startsWith("#") && para.length > 50) {
|
|
1501
|
+
if (isSubtitle(para)) continue;
|
|
1492
1502
|
situation = this.extractFirstSentence(para);
|
|
1493
1503
|
break;
|
|
1494
1504
|
}
|
|
@@ -1935,7 +1945,8 @@ var ContentPatternClassifier = class {
|
|
|
1935
1945
|
if (!match || !match[1]) return null;
|
|
1936
1946
|
const value = match[1];
|
|
1937
1947
|
const afterNumber = content.slice(content.indexOf(value) + value.length);
|
|
1938
|
-
const
|
|
1948
|
+
const contextRaw = afterNumber.trim().split(/[\n\r]|-\s|[.!?]|(?=\d+%)|(?=\$\d)/)[0] || "";
|
|
1949
|
+
const context = contextRaw.trim().slice(0, 60);
|
|
1939
1950
|
return { value, context };
|
|
1940
1951
|
}
|
|
1941
1952
|
/**
|
|
@@ -2632,6 +2643,16 @@ var SlideFactory = class {
|
|
|
2632
2643
|
continue;
|
|
2633
2644
|
}
|
|
2634
2645
|
this.usedContent.add(contentKey);
|
|
2646
|
+
const normalizedHeader = section.header.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
2647
|
+
const normalizedTitle = analysis.title.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
2648
|
+
const normalizedSubtitle = (analysis.subtitle || "").toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
2649
|
+
const normalizedContent = (section.content || "").toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
2650
|
+
const headerMatchesTitle = normalizedHeader === normalizedTitle || normalizedTitle.includes(normalizedHeader) || normalizedHeader.includes(normalizedTitle);
|
|
2651
|
+
const contentMatchesSubtitle = normalizedContent && (normalizedContent === normalizedSubtitle || normalizedSubtitle.includes(normalizedContent) || normalizedContent.includes(normalizedSubtitle));
|
|
2652
|
+
if (headerMatchesTitle && (contentMatchesSubtitle || !section.content || section.content.length < 30)) {
|
|
2653
|
+
logger.warn(`Section "${section.header}" skipped - duplicates title slide`);
|
|
2654
|
+
continue;
|
|
2655
|
+
}
|
|
2635
2656
|
const headerLower = section.header.toLowerCase();
|
|
2636
2657
|
const isCTASection = headerLower.includes("call to action") || headerLower.includes("next step") || headerLower.includes("take action") || headerLower.includes("get started") || headerLower.includes("start today");
|
|
2637
2658
|
if (isCTASection) {
|
|
@@ -2811,47 +2832,69 @@ var SlideFactory = class {
|
|
|
2811
2832
|
const scqa = analysis.scqa;
|
|
2812
2833
|
const titles = this.config.scqaTitles;
|
|
2813
2834
|
const minBodyLength = 20;
|
|
2835
|
+
const normalizedTitle = analysis.title.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
2836
|
+
const normalizedSubtitle = (analysis.subtitle || "").toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
2837
|
+
const duplicatesHeadline = (body) => {
|
|
2838
|
+
if (!body) return true;
|
|
2839
|
+
const normalizedBody = body.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
2840
|
+
if (!normalizedBody || normalizedBody.length < 10) return false;
|
|
2841
|
+
const titleMatch = normalizedTitle.length > 5 && (normalizedBody === normalizedTitle || normalizedTitle.includes(normalizedBody) || normalizedBody.includes(normalizedTitle));
|
|
2842
|
+
const subtitleMatch = normalizedSubtitle.length > 5 && (normalizedBody === normalizedSubtitle || normalizedSubtitle.includes(normalizedBody) || normalizedBody.includes(normalizedSubtitle));
|
|
2843
|
+
return titleMatch || subtitleMatch;
|
|
2844
|
+
};
|
|
2814
2845
|
const situationBody = scqa?.situation ? this.truncateText(scqa.situation, this.config.rules.wordsPerSlide.max) : "";
|
|
2815
2846
|
if (situationBody.length >= minBodyLength && !this.usedContent.has("scqa-situation")) {
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2847
|
+
if (duplicatesHeadline(situationBody)) {
|
|
2848
|
+
logger.warn(`SCQA Situation skipped - duplicates title/subtitle: "${situationBody.slice(0, 50)}..."`);
|
|
2849
|
+
} else {
|
|
2850
|
+
this.usedContent.add("scqa-situation");
|
|
2851
|
+
slides.push({
|
|
2852
|
+
index: slides.length,
|
|
2853
|
+
type: "single-statement",
|
|
2854
|
+
data: {
|
|
2855
|
+
title: titles.situation,
|
|
2856
|
+
// FROM KB - not hardcoded 'Current Situation'
|
|
2857
|
+
body: situationBody
|
|
2858
|
+
},
|
|
2859
|
+
classes: ["situation-slide"]
|
|
2860
|
+
});
|
|
2861
|
+
}
|
|
2827
2862
|
}
|
|
2828
2863
|
const complicationBody = scqa?.complication ? this.truncateText(scqa.complication, this.config.rules.wordsPerSlide.max) : "";
|
|
2829
2864
|
if (complicationBody.length >= minBodyLength && !this.usedContent.has("scqa-complication")) {
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2865
|
+
if (duplicatesHeadline(complicationBody)) {
|
|
2866
|
+
logger.warn(`SCQA Complication skipped - duplicates title/subtitle`);
|
|
2867
|
+
} else {
|
|
2868
|
+
this.usedContent.add("scqa-complication");
|
|
2869
|
+
slides.push({
|
|
2870
|
+
index: slides.length,
|
|
2871
|
+
type: "single-statement",
|
|
2872
|
+
data: {
|
|
2873
|
+
title: titles.complication,
|
|
2874
|
+
// FROM KB - not hardcoded 'The Challenge'
|
|
2875
|
+
body: complicationBody
|
|
2876
|
+
},
|
|
2877
|
+
classes: ["complication-slide"]
|
|
2878
|
+
});
|
|
2879
|
+
}
|
|
2841
2880
|
}
|
|
2842
2881
|
const questionBody = scqa?.question ? this.truncateText(scqa.question, this.config.rules.wordsPerSlide.max) : "";
|
|
2843
2882
|
if (questionBody.length >= minBodyLength && !this.usedContent.has("scqa-question")) {
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2883
|
+
if (duplicatesHeadline(questionBody)) {
|
|
2884
|
+
logger.warn(`SCQA Question skipped - duplicates title/subtitle`);
|
|
2885
|
+
} else {
|
|
2886
|
+
this.usedContent.add("scqa-question");
|
|
2887
|
+
slides.push({
|
|
2888
|
+
index: slides.length,
|
|
2889
|
+
type: "single-statement",
|
|
2890
|
+
data: {
|
|
2891
|
+
title: titles.question,
|
|
2892
|
+
// FROM KB - not hardcoded 'The Question'
|
|
2893
|
+
body: questionBody
|
|
2894
|
+
},
|
|
2895
|
+
classes: ["question-slide"]
|
|
2896
|
+
});
|
|
2897
|
+
}
|
|
2855
2898
|
}
|
|
2856
2899
|
}
|
|
2857
2900
|
addSparklineSlides(slides, analysis) {
|
|
@@ -2904,14 +2947,41 @@ var SlideFactory = class {
|
|
|
2904
2947
|
// CONTENT SLIDES - ALL values from KB
|
|
2905
2948
|
// ===========================================================================
|
|
2906
2949
|
createBigNumberSlide(index, section, pattern) {
|
|
2907
|
-
|
|
2908
|
-
|
|
2950
|
+
let bigNumber = null;
|
|
2951
|
+
let sourceBullet = null;
|
|
2952
|
+
for (const bullet of section.bullets) {
|
|
2953
|
+
const extracted = this.classifier.extractBigNumber(bullet);
|
|
2954
|
+
if (extracted) {
|
|
2955
|
+
bigNumber = extracted;
|
|
2956
|
+
sourceBullet = bullet;
|
|
2957
|
+
break;
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
if (!bigNumber) {
|
|
2961
|
+
bigNumber = this.classifier.extractBigNumber(section.header);
|
|
2962
|
+
}
|
|
2963
|
+
if (!bigNumber && section.content) {
|
|
2964
|
+
bigNumber = this.classifier.extractBigNumber(section.content);
|
|
2965
|
+
}
|
|
2909
2966
|
const actualValue = bigNumber?.value || pattern.bigNumberValue;
|
|
2910
2967
|
if (!actualValue) {
|
|
2911
2968
|
logger.warn(`No number found for big-number slide, falling back to single-statement`);
|
|
2912
2969
|
return this.createSingleStatementSlide(index, section);
|
|
2913
2970
|
}
|
|
2914
|
-
|
|
2971
|
+
let contextContent = bigNumber?.context || "";
|
|
2972
|
+
if (sourceBullet && !contextContent) {
|
|
2973
|
+
contextContent = sourceBullet.replace(actualValue, "").trim();
|
|
2974
|
+
}
|
|
2975
|
+
if (!contextContent) {
|
|
2976
|
+
contextContent = section.content || section.header;
|
|
2977
|
+
}
|
|
2978
|
+
let cleanTitle = section.header;
|
|
2979
|
+
if (actualValue && cleanTitle.includes(actualValue.replace(/[,$%]/g, ""))) {
|
|
2980
|
+
cleanTitle = cleanTitle.replace(new RegExp(`\\$?${actualValue.replace(/[,$%]/g, "").replace(/\./g, "\\.?")}[KMBkmb]?`, "gi"), "").replace(/\s+/g, " ").trim();
|
|
2981
|
+
}
|
|
2982
|
+
if (!cleanTitle || cleanTitle.length < 5) {
|
|
2983
|
+
cleanTitle = bigNumber?.context?.split(/[.!?]/)[0] || section.header;
|
|
2984
|
+
}
|
|
2915
2985
|
const craftedContext = this.craftExpertContent(
|
|
2916
2986
|
contextContent,
|
|
2917
2987
|
"big_number",
|
|
@@ -2921,7 +2991,7 @@ var SlideFactory = class {
|
|
|
2921
2991
|
index,
|
|
2922
2992
|
type: "big-number",
|
|
2923
2993
|
data: {
|
|
2924
|
-
title:
|
|
2994
|
+
title: cleanTitle,
|
|
2925
2995
|
keyMessage: actualValue,
|
|
2926
2996
|
body: craftedContext
|
|
2927
2997
|
},
|
|
@@ -5668,12 +5738,15 @@ var VisualQualityEvaluator = class {
|
|
|
5668
5738
|
glanceTest += 1;
|
|
5669
5739
|
glanceNotes.push("Clean, minimal text - passes glance test easily");
|
|
5670
5740
|
}
|
|
5671
|
-
|
|
5741
|
+
const isAgendaSlide = slideType === "agenda" || (slideData.classes || []).includes("agenda-slide");
|
|
5742
|
+
const bulletLimit = isAgendaSlide ? 8 : 5;
|
|
5743
|
+
const bulletWarning = isAgendaSlide ? 6 : 3;
|
|
5744
|
+
if (slideData.bullets.length > bulletLimit) {
|
|
5672
5745
|
glanceTest -= 4;
|
|
5673
5746
|
glanceNotes.push("Too many bullets - cannot scan in 3 seconds");
|
|
5674
|
-
} else if (slideData.bullets.length >
|
|
5675
|
-
glanceTest -= 2;
|
|
5676
|
-
glanceNotes.push("Multiple bullets - needs careful structuring");
|
|
5747
|
+
} else if (slideData.bullets.length > bulletWarning) {
|
|
5748
|
+
glanceTest -= isAgendaSlide ? 1 : 2;
|
|
5749
|
+
glanceNotes.push(isAgendaSlide ? "Agenda with many items" : "Multiple bullets - needs careful structuring");
|
|
5677
5750
|
}
|
|
5678
5751
|
if (slideData.hasImage || slideData.hasChart) {
|
|
5679
5752
|
glanceTest += 1;
|
package/dist/index.mjs
CHANGED
|
@@ -1117,7 +1117,7 @@ var ContentAnalyzer = class {
|
|
|
1117
1117
|
logger.step(`Detected type: ${detectedType}`);
|
|
1118
1118
|
const sections = this.extractSections(text);
|
|
1119
1119
|
logger.step(`Found ${sections.length} sections`);
|
|
1120
|
-
const scqa = this.extractSCQA(text);
|
|
1120
|
+
const scqa = this.extractSCQA(text, subtitle);
|
|
1121
1121
|
const sparkline = this.extractSparkline(text);
|
|
1122
1122
|
const keyMessages = this.extractKeyMessages(text);
|
|
1123
1123
|
const dataPoints = this.extractDataPoints(text);
|
|
@@ -1384,15 +1384,24 @@ var ContentAnalyzer = class {
|
|
|
1384
1384
|
/**
|
|
1385
1385
|
* Extract SCQA structure (Barbara Minto)
|
|
1386
1386
|
* CRITICAL: Answer must be clean prose, NOT bullet points
|
|
1387
|
+
* @param text - The content text to analyze
|
|
1388
|
+
* @param subtitle - Optional subtitle to exclude (prevents redundancy with title slide)
|
|
1387
1389
|
*/
|
|
1388
|
-
extractSCQA(text) {
|
|
1390
|
+
extractSCQA(text, subtitle) {
|
|
1389
1391
|
const paragraphs = text.split(/\n\n+/).filter((p) => p.trim());
|
|
1392
|
+
const normalizedSubtitle = (subtitle || "").toLowerCase().trim();
|
|
1393
|
+
const isSubtitle = (para) => {
|
|
1394
|
+
if (!normalizedSubtitle) return false;
|
|
1395
|
+
const normalized = para.toLowerCase().trim();
|
|
1396
|
+
return normalized === normalizedSubtitle || normalized.includes(normalizedSubtitle) || normalizedSubtitle.includes(normalized);
|
|
1397
|
+
};
|
|
1390
1398
|
let situation = "";
|
|
1391
1399
|
let complication = "";
|
|
1392
1400
|
let question = "";
|
|
1393
1401
|
let answer = "";
|
|
1394
1402
|
for (const para of paragraphs.slice(0, 5)) {
|
|
1395
1403
|
if (para.startsWith("-") || para.startsWith("#") || para.startsWith("|")) continue;
|
|
1404
|
+
if (isSubtitle(para)) continue;
|
|
1396
1405
|
if (this.containsSignals(para.toLowerCase(), this.situationSignals)) {
|
|
1397
1406
|
situation = this.extractFirstSentence(para);
|
|
1398
1407
|
break;
|
|
@@ -1420,6 +1429,7 @@ var ContentAnalyzer = class {
|
|
|
1420
1429
|
if (!situation && paragraphs.length > 0) {
|
|
1421
1430
|
for (const para of paragraphs.slice(0, 5)) {
|
|
1422
1431
|
if (!para.startsWith("-") && !para.startsWith("#") && para.length > 50) {
|
|
1432
|
+
if (isSubtitle(para)) continue;
|
|
1423
1433
|
situation = this.extractFirstSentence(para);
|
|
1424
1434
|
break;
|
|
1425
1435
|
}
|
|
@@ -1866,7 +1876,8 @@ var ContentPatternClassifier = class {
|
|
|
1866
1876
|
if (!match || !match[1]) return null;
|
|
1867
1877
|
const value = match[1];
|
|
1868
1878
|
const afterNumber = content.slice(content.indexOf(value) + value.length);
|
|
1869
|
-
const
|
|
1879
|
+
const contextRaw = afterNumber.trim().split(/[\n\r]|-\s|[.!?]|(?=\d+%)|(?=\$\d)/)[0] || "";
|
|
1880
|
+
const context = contextRaw.trim().slice(0, 60);
|
|
1870
1881
|
return { value, context };
|
|
1871
1882
|
}
|
|
1872
1883
|
/**
|
|
@@ -2563,6 +2574,16 @@ var SlideFactory = class {
|
|
|
2563
2574
|
continue;
|
|
2564
2575
|
}
|
|
2565
2576
|
this.usedContent.add(contentKey);
|
|
2577
|
+
const normalizedHeader = section.header.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
2578
|
+
const normalizedTitle = analysis.title.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
2579
|
+
const normalizedSubtitle = (analysis.subtitle || "").toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
2580
|
+
const normalizedContent = (section.content || "").toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
2581
|
+
const headerMatchesTitle = normalizedHeader === normalizedTitle || normalizedTitle.includes(normalizedHeader) || normalizedHeader.includes(normalizedTitle);
|
|
2582
|
+
const contentMatchesSubtitle = normalizedContent && (normalizedContent === normalizedSubtitle || normalizedSubtitle.includes(normalizedContent) || normalizedContent.includes(normalizedSubtitle));
|
|
2583
|
+
if (headerMatchesTitle && (contentMatchesSubtitle || !section.content || section.content.length < 30)) {
|
|
2584
|
+
logger.warn(`Section "${section.header}" skipped - duplicates title slide`);
|
|
2585
|
+
continue;
|
|
2586
|
+
}
|
|
2566
2587
|
const headerLower = section.header.toLowerCase();
|
|
2567
2588
|
const isCTASection = headerLower.includes("call to action") || headerLower.includes("next step") || headerLower.includes("take action") || headerLower.includes("get started") || headerLower.includes("start today");
|
|
2568
2589
|
if (isCTASection) {
|
|
@@ -2742,47 +2763,69 @@ var SlideFactory = class {
|
|
|
2742
2763
|
const scqa = analysis.scqa;
|
|
2743
2764
|
const titles = this.config.scqaTitles;
|
|
2744
2765
|
const minBodyLength = 20;
|
|
2766
|
+
const normalizedTitle = analysis.title.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
2767
|
+
const normalizedSubtitle = (analysis.subtitle || "").toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
2768
|
+
const duplicatesHeadline = (body) => {
|
|
2769
|
+
if (!body) return true;
|
|
2770
|
+
const normalizedBody = body.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
2771
|
+
if (!normalizedBody || normalizedBody.length < 10) return false;
|
|
2772
|
+
const titleMatch = normalizedTitle.length > 5 && (normalizedBody === normalizedTitle || normalizedTitle.includes(normalizedBody) || normalizedBody.includes(normalizedTitle));
|
|
2773
|
+
const subtitleMatch = normalizedSubtitle.length > 5 && (normalizedBody === normalizedSubtitle || normalizedSubtitle.includes(normalizedBody) || normalizedBody.includes(normalizedSubtitle));
|
|
2774
|
+
return titleMatch || subtitleMatch;
|
|
2775
|
+
};
|
|
2745
2776
|
const situationBody = scqa?.situation ? this.truncateText(scqa.situation, this.config.rules.wordsPerSlide.max) : "";
|
|
2746
2777
|
if (situationBody.length >= minBodyLength && !this.usedContent.has("scqa-situation")) {
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2778
|
+
if (duplicatesHeadline(situationBody)) {
|
|
2779
|
+
logger.warn(`SCQA Situation skipped - duplicates title/subtitle: "${situationBody.slice(0, 50)}..."`);
|
|
2780
|
+
} else {
|
|
2781
|
+
this.usedContent.add("scqa-situation");
|
|
2782
|
+
slides.push({
|
|
2783
|
+
index: slides.length,
|
|
2784
|
+
type: "single-statement",
|
|
2785
|
+
data: {
|
|
2786
|
+
title: titles.situation,
|
|
2787
|
+
// FROM KB - not hardcoded 'Current Situation'
|
|
2788
|
+
body: situationBody
|
|
2789
|
+
},
|
|
2790
|
+
classes: ["situation-slide"]
|
|
2791
|
+
});
|
|
2792
|
+
}
|
|
2758
2793
|
}
|
|
2759
2794
|
const complicationBody = scqa?.complication ? this.truncateText(scqa.complication, this.config.rules.wordsPerSlide.max) : "";
|
|
2760
2795
|
if (complicationBody.length >= minBodyLength && !this.usedContent.has("scqa-complication")) {
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2796
|
+
if (duplicatesHeadline(complicationBody)) {
|
|
2797
|
+
logger.warn(`SCQA Complication skipped - duplicates title/subtitle`);
|
|
2798
|
+
} else {
|
|
2799
|
+
this.usedContent.add("scqa-complication");
|
|
2800
|
+
slides.push({
|
|
2801
|
+
index: slides.length,
|
|
2802
|
+
type: "single-statement",
|
|
2803
|
+
data: {
|
|
2804
|
+
title: titles.complication,
|
|
2805
|
+
// FROM KB - not hardcoded 'The Challenge'
|
|
2806
|
+
body: complicationBody
|
|
2807
|
+
},
|
|
2808
|
+
classes: ["complication-slide"]
|
|
2809
|
+
});
|
|
2810
|
+
}
|
|
2772
2811
|
}
|
|
2773
2812
|
const questionBody = scqa?.question ? this.truncateText(scqa.question, this.config.rules.wordsPerSlide.max) : "";
|
|
2774
2813
|
if (questionBody.length >= minBodyLength && !this.usedContent.has("scqa-question")) {
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2814
|
+
if (duplicatesHeadline(questionBody)) {
|
|
2815
|
+
logger.warn(`SCQA Question skipped - duplicates title/subtitle`);
|
|
2816
|
+
} else {
|
|
2817
|
+
this.usedContent.add("scqa-question");
|
|
2818
|
+
slides.push({
|
|
2819
|
+
index: slides.length,
|
|
2820
|
+
type: "single-statement",
|
|
2821
|
+
data: {
|
|
2822
|
+
title: titles.question,
|
|
2823
|
+
// FROM KB - not hardcoded 'The Question'
|
|
2824
|
+
body: questionBody
|
|
2825
|
+
},
|
|
2826
|
+
classes: ["question-slide"]
|
|
2827
|
+
});
|
|
2828
|
+
}
|
|
2786
2829
|
}
|
|
2787
2830
|
}
|
|
2788
2831
|
addSparklineSlides(slides, analysis) {
|
|
@@ -2835,14 +2878,41 @@ var SlideFactory = class {
|
|
|
2835
2878
|
// CONTENT SLIDES - ALL values from KB
|
|
2836
2879
|
// ===========================================================================
|
|
2837
2880
|
createBigNumberSlide(index, section, pattern) {
|
|
2838
|
-
|
|
2839
|
-
|
|
2881
|
+
let bigNumber = null;
|
|
2882
|
+
let sourceBullet = null;
|
|
2883
|
+
for (const bullet of section.bullets) {
|
|
2884
|
+
const extracted = this.classifier.extractBigNumber(bullet);
|
|
2885
|
+
if (extracted) {
|
|
2886
|
+
bigNumber = extracted;
|
|
2887
|
+
sourceBullet = bullet;
|
|
2888
|
+
break;
|
|
2889
|
+
}
|
|
2890
|
+
}
|
|
2891
|
+
if (!bigNumber) {
|
|
2892
|
+
bigNumber = this.classifier.extractBigNumber(section.header);
|
|
2893
|
+
}
|
|
2894
|
+
if (!bigNumber && section.content) {
|
|
2895
|
+
bigNumber = this.classifier.extractBigNumber(section.content);
|
|
2896
|
+
}
|
|
2840
2897
|
const actualValue = bigNumber?.value || pattern.bigNumberValue;
|
|
2841
2898
|
if (!actualValue) {
|
|
2842
2899
|
logger.warn(`No number found for big-number slide, falling back to single-statement`);
|
|
2843
2900
|
return this.createSingleStatementSlide(index, section);
|
|
2844
2901
|
}
|
|
2845
|
-
|
|
2902
|
+
let contextContent = bigNumber?.context || "";
|
|
2903
|
+
if (sourceBullet && !contextContent) {
|
|
2904
|
+
contextContent = sourceBullet.replace(actualValue, "").trim();
|
|
2905
|
+
}
|
|
2906
|
+
if (!contextContent) {
|
|
2907
|
+
contextContent = section.content || section.header;
|
|
2908
|
+
}
|
|
2909
|
+
let cleanTitle = section.header;
|
|
2910
|
+
if (actualValue && cleanTitle.includes(actualValue.replace(/[,$%]/g, ""))) {
|
|
2911
|
+
cleanTitle = cleanTitle.replace(new RegExp(`\\$?${actualValue.replace(/[,$%]/g, "").replace(/\./g, "\\.?")}[KMBkmb]?`, "gi"), "").replace(/\s+/g, " ").trim();
|
|
2912
|
+
}
|
|
2913
|
+
if (!cleanTitle || cleanTitle.length < 5) {
|
|
2914
|
+
cleanTitle = bigNumber?.context?.split(/[.!?]/)[0] || section.header;
|
|
2915
|
+
}
|
|
2846
2916
|
const craftedContext = this.craftExpertContent(
|
|
2847
2917
|
contextContent,
|
|
2848
2918
|
"big_number",
|
|
@@ -2852,7 +2922,7 @@ var SlideFactory = class {
|
|
|
2852
2922
|
index,
|
|
2853
2923
|
type: "big-number",
|
|
2854
2924
|
data: {
|
|
2855
|
-
title:
|
|
2925
|
+
title: cleanTitle,
|
|
2856
2926
|
keyMessage: actualValue,
|
|
2857
2927
|
body: craftedContext
|
|
2858
2928
|
},
|
|
@@ -5599,12 +5669,15 @@ var VisualQualityEvaluator = class {
|
|
|
5599
5669
|
glanceTest += 1;
|
|
5600
5670
|
glanceNotes.push("Clean, minimal text - passes glance test easily");
|
|
5601
5671
|
}
|
|
5602
|
-
|
|
5672
|
+
const isAgendaSlide = slideType === "agenda" || (slideData.classes || []).includes("agenda-slide");
|
|
5673
|
+
const bulletLimit = isAgendaSlide ? 8 : 5;
|
|
5674
|
+
const bulletWarning = isAgendaSlide ? 6 : 3;
|
|
5675
|
+
if (slideData.bullets.length > bulletLimit) {
|
|
5603
5676
|
glanceTest -= 4;
|
|
5604
5677
|
glanceNotes.push("Too many bullets - cannot scan in 3 seconds");
|
|
5605
|
-
} else if (slideData.bullets.length >
|
|
5606
|
-
glanceTest -= 2;
|
|
5607
|
-
glanceNotes.push("Multiple bullets - needs careful structuring");
|
|
5678
|
+
} else if (slideData.bullets.length > bulletWarning) {
|
|
5679
|
+
glanceTest -= isAgendaSlide ? 1 : 2;
|
|
5680
|
+
glanceNotes.push(isAgendaSlide ? "Agenda with many items" : "Multiple bullets - needs careful structuring");
|
|
5608
5681
|
}
|
|
5609
5682
|
if (slideData.hasImage || slideData.hasChart) {
|
|
5610
5683
|
glanceTest += 1;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "claude-presentation-master",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.3.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",
|