@thanh01.pmt/presentation-kit 0.2.2 → 0.2.3
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/ai/index.cjs +66 -64
- package/dist/ai/index.cjs.map +1 -1
- package/dist/ai/index.d.cts +1 -1
- package/dist/ai/index.d.ts +1 -1
- package/dist/ai/index.js +60 -58
- package/dist/ai/index.js.map +1 -1
- package/dist/{chunk-HBMXEPZJ.js → chunk-3IKL6SBP.js} +110 -109
- package/dist/chunk-3IKL6SBP.js.map +1 -0
- package/dist/{chunk-OEAOYF7C.cjs → chunk-O5MCKVEA.cjs} +110 -109
- package/dist/chunk-O5MCKVEA.cjs.map +1 -0
- package/dist/index.cjs +8 -8
- package/dist/index.js +2 -2
- package/dist/react/index.cjs +4 -4
- package/dist/react/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-HBMXEPZJ.js.map +0 -1
- package/dist/chunk-OEAOYF7C.cjs.map +0 -1
package/dist/ai/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { SLIDE_LAYOUT_PRESETS, getSlideLayoutPresetsByCategory, getSlideLayoutPresetById, serializeLayoutToComment, updateSlideLayoutInMarkdown, splitMarkdownSlides } from '../chunk-
|
|
1
|
+
import { SLIDE_LAYOUT_PRESETS, getSlideLayoutPresetsByCategory, getSlideLayoutPresetById, serializeLayoutToComment, updateSlideLayoutInMarkdown, splitMarkdownSlides } from '../chunk-3IKL6SBP.js';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
4
|
var listSlidePresetsSchema = z.object({
|
|
@@ -81,7 +81,7 @@ function executeCreateSlideFromPreset(params) {
|
|
|
81
81
|
return {
|
|
82
82
|
success: false,
|
|
83
83
|
slideMarkdown: "",
|
|
84
|
-
error: `
|
|
84
|
+
error: `Preset with ID "${params.presetId}" not found. Use listSlidePresets to see available layout templates.`
|
|
85
85
|
};
|
|
86
86
|
}
|
|
87
87
|
const layoutComment = serializeLayoutToComment(preset.layout);
|
|
@@ -95,20 +95,20 @@ function executeCreateSlideFromPreset(params) {
|
|
|
95
95
|
case "title-hero":
|
|
96
96
|
body = `${subtitle}
|
|
97
97
|
|
|
98
|
-
**
|
|
98
|
+
**Presenter:** ${c.speaker || "Lead Instructor"} | **Duration:** ${c.duration || "45 mins"} | **Topic:** ${c.topic || title}`;
|
|
99
99
|
break;
|
|
100
100
|
case "two-column-split":
|
|
101
101
|
body = `<div class="columns-2">
|
|
102
102
|
<div>
|
|
103
103
|
|
|
104
|
-
### ${c.leftHeader || "
|
|
105
|
-
${c.leftCol || "-
|
|
104
|
+
### ${c.leftHeader || "Approach A"}
|
|
105
|
+
${c.leftCol || "- Point 1\n- Point 2\n- Point 3"}
|
|
106
106
|
|
|
107
107
|
</div>
|
|
108
108
|
<div>
|
|
109
109
|
|
|
110
|
-
### ${c.rightHeader || "
|
|
111
|
-
${c.rightCol || "-
|
|
110
|
+
### ${c.rightHeader || "Approach B"}
|
|
111
|
+
${c.rightCol || "- Point 1\n- Point 2\n- Point 3"}
|
|
112
112
|
|
|
113
113
|
</div>
|
|
114
114
|
</div>`;
|
|
@@ -118,14 +118,14 @@ ${c.rightCol || "- \u0110i\u1EC3m 1\n- \u0110i\u1EC3m 2\n- \u0110i\u1EC3m 3"}
|
|
|
118
118
|
<div>
|
|
119
119
|
|
|
120
120
|
\`\`\`${c.lang || "ts"}
|
|
121
|
-
${c.code || "//
|
|
121
|
+
${c.code || "// Core implementation logic\nconst isValid = true;"}
|
|
122
122
|
\`\`\`
|
|
123
123
|
|
|
124
124
|
</div>
|
|
125
125
|
<div>
|
|
126
126
|
|
|
127
|
-
### \u{1F50D}
|
|
128
|
-
${c.notes || "1. **
|
|
127
|
+
### \u{1F50D} Key Invariants:
|
|
128
|
+
${c.notes || "1. **Validation:** Checks payload before processing\n2. **Execution:** Enforces deterministic state\n3. **Resilience:** Handles edge case errors"}
|
|
129
129
|
|
|
130
130
|
</div>
|
|
131
131
|
</div>`;
|
|
@@ -135,64 +135,64 @@ ${c.notes || "1. **Ph\xE2n t\xEDch d\xF2ng 1:** Kh\u1EDFi t\u1EA1o\n2. **Ph\xE2n
|
|
|
135
135
|
<div>
|
|
136
136
|
|
|
137
137
|
# ${c.metric1Val || "99.9%"}
|
|
138
|
-
### ${c.metric1Title || "
|
|
139
|
-
${c.metric1Desc || "
|
|
138
|
+
### ${c.metric1Title || "Availability"}
|
|
139
|
+
${c.metric1Desc || "Automated multi-region failover routing."}
|
|
140
140
|
|
|
141
141
|
</div>
|
|
142
142
|
<div>
|
|
143
143
|
|
|
144
144
|
# ${c.metric2Val || "10x"}
|
|
145
|
-
### ${c.metric2Title || "
|
|
146
|
-
${c.metric2Desc || "
|
|
145
|
+
### ${c.metric2Title || "Throughput"}
|
|
146
|
+
${c.metric2Desc || "Sub-millisecond processing latency."}
|
|
147
147
|
|
|
148
148
|
</div>
|
|
149
149
|
<div>
|
|
150
150
|
|
|
151
151
|
# ${c.metric3Val || "0"}
|
|
152
|
-
### ${c.metric3Title || "
|
|
153
|
-
${c.metric3Desc || "
|
|
152
|
+
### ${c.metric3Title || "Breaches"}
|
|
153
|
+
${c.metric3Desc || "Continuous SOC2 compliance auditing."}
|
|
154
154
|
|
|
155
155
|
</div>
|
|
156
156
|
</div>`;
|
|
157
157
|
break;
|
|
158
158
|
case "process-flow":
|
|
159
159
|
body = `\`\`\`mermaid
|
|
160
|
-
${c.mermaid || "graph LR\n A[
|
|
160
|
+
${c.mermaid || "graph LR\n A[1. Ingress] --> B[2. Gateway]\n B --> C[3. Service]\n C --> D[4. Storage]"}
|
|
161
161
|
\`\`\`
|
|
162
162
|
|
|
163
|
-
${c.summary || "- **
|
|
163
|
+
${c.summary || "- **Phase 1 & 2:** Client connection and load balancing.\n- **Phase 3 & 4:** Business logic execution and data commit."}`;
|
|
164
164
|
break;
|
|
165
165
|
case "quote-highlight":
|
|
166
|
-
body = `> "${c.quote || "
|
|
166
|
+
body = `> "${c.quote || "Simplicity is prerequisite for reliability."}"
|
|
167
167
|
>
|
|
168
|
-
> \u2014 **${c.author || "
|
|
168
|
+
> \u2014 **${c.author || "Architecture Principle"}**`;
|
|
169
169
|
break;
|
|
170
170
|
case "quiz-checkpoint":
|
|
171
|
-
body = `> **
|
|
171
|
+
body = `> **Question:** ${c.question || "Which architecture pattern best ensures reliable message delivery?"}
|
|
172
172
|
|
|
173
|
-
- **A.** ${c.optA || "
|
|
174
|
-
- **B.** ${c.optB || "
|
|
175
|
-
- **C.** ${c.optC || "
|
|
176
|
-
- **D.** ${c.optD || "
|
|
173
|
+
- **A.** ${c.optA || "Direct synchronous HTTP request with short timeout"}
|
|
174
|
+
- **B.** ${c.optB || "Persistent Message Queue with Dead-Letter Queue (Correct)"}
|
|
175
|
+
- **C.** ${c.optC || "In-memory client cache without persistence"}
|
|
176
|
+
- **D.** ${c.optD || "Silently dropping failed packets"}`;
|
|
177
177
|
break;
|
|
178
178
|
case "tiered-practice-3cards":
|
|
179
179
|
body = `<div class="columns-3">
|
|
180
180
|
<div>
|
|
181
181
|
|
|
182
|
-
### \u{1F949}
|
|
183
|
-
${c.bronze || "-
|
|
182
|
+
### \u{1F949} Bronze Tier
|
|
183
|
+
${c.bronze || "- Implement baseline function\n- Pass 2 sample unit tests"}
|
|
184
184
|
|
|
185
185
|
</div>
|
|
186
186
|
<div>
|
|
187
187
|
|
|
188
|
-
### \u{1F948}
|
|
189
|
-
${c.silver || "-
|
|
188
|
+
### \u{1F948} Silver Tier
|
|
189
|
+
${c.silver || "- Add boundary error handling\n- Optimize algorithm complexity"}
|
|
190
190
|
|
|
191
191
|
</div>
|
|
192
192
|
<div>
|
|
193
193
|
|
|
194
|
-
### \u{1F947}
|
|
195
|
-
${c.gold || "-
|
|
194
|
+
### \u{1F947} Gold Tier
|
|
195
|
+
${c.gold || "- Design extension feature\n- Write automated integration tests"}
|
|
196
196
|
|
|
197
197
|
</div>
|
|
198
198
|
</div>`;
|
|
@@ -210,8 +210,8 @@ ${params.presenterNotes.map((n) => `- ${n}`).join("\n")}
|
|
|
210
210
|
|
|
211
211
|
<!--
|
|
212
212
|
Presenter Notes:
|
|
213
|
-
-
|
|
214
|
-
-
|
|
213
|
+
- Explain the primary concept on this slide.
|
|
214
|
+
- Ask a diagnostic cold-call question to check comprehension.
|
|
215
215
|
-->`;
|
|
216
216
|
const slideMarkdown = `${layoutComment}
|
|
217
217
|
|
|
@@ -230,7 +230,7 @@ function executeApplySlideLayout(params) {
|
|
|
230
230
|
return {
|
|
231
231
|
success: false,
|
|
232
232
|
updatedMarkdown: params.markdown,
|
|
233
|
-
error: `
|
|
233
|
+
error: `Preset with ID "${params.presetId}" not found.`
|
|
234
234
|
};
|
|
235
235
|
}
|
|
236
236
|
layoutData = preset.layout;
|
|
@@ -253,7 +253,7 @@ function executeUpdatePresenterNotes(params) {
|
|
|
253
253
|
return {
|
|
254
254
|
success: false,
|
|
255
255
|
updatedMarkdown: params.markdown,
|
|
256
|
-
error: `Slide index ${params.slideIndex}
|
|
256
|
+
error: `Slide index ${params.slideIndex} out of bounds (total slides: ${slides.length})`
|
|
257
257
|
};
|
|
258
258
|
}
|
|
259
259
|
let slideContent = slides[params.slideIndex];
|
|
@@ -303,21 +303,21 @@ function executeGenerateDeckOutline(params) {
|
|
|
303
303
|
format: formatLabel,
|
|
304
304
|
recommendedSlideCount: targetSlideCount,
|
|
305
305
|
structureGuidelines: [
|
|
306
|
-
|
|
307
|
-
"
|
|
308
|
-
"
|
|
309
|
-
"
|
|
306
|
+
'Apply the "One Idea Per Slide" invariant.',
|
|
307
|
+
"Enforce Word Budget: Maximum 40 words per card or column (Zero-Scroll Invariant).",
|
|
308
|
+
"Target 16:9 aspect ratio in 1280x720 coordinate space.",
|
|
309
|
+
"Every slide must conclude with Presenter Notes: Teacher talk track + 1 diagnostic cold-call question."
|
|
310
310
|
],
|
|
311
311
|
suggestedOutline: [
|
|
312
|
-
{ slide: 1, type: "title-hero", title: `\u{1F680} ${params.topic}`, intent: "
|
|
313
|
-
{ slide: 2, type: "agenda-timeline", title: "\u{1F5FA}\uFE0F
|
|
314
|
-
{ slide: 3, type: "two-column-split", title: "\u26A1
|
|
315
|
-
{ slide: 4, type: "process-flow", title: "\u{1F504}
|
|
316
|
-
{ slide: 5, type: "code-explainer", title: "\u{1F4BB}
|
|
317
|
-
{ slide: 6, type: "metrics-3-card", title: "\u{1F4CA}
|
|
318
|
-
{ slide: 7, type: "tiered-practice-3cards", title: "\u{1F6E0}\uFE0F
|
|
319
|
-
{ slide: 8, type: "quiz-checkpoint", title: "\u{1F3AF}
|
|
320
|
-
{ slide: 9, type: "takeaways-summary", title: "\u{1F3C1}
|
|
312
|
+
{ slide: 1, type: "title-hero", title: `\u{1F680} ${params.topic}`, intent: "Opening hook and speaker credentialing" },
|
|
313
|
+
{ slide: 2, type: "agenda-timeline", title: "\u{1F5FA}\uFE0F Session Milestones", intent: "Set time budget expectations and learning deliverables" },
|
|
314
|
+
{ slide: 3, type: "two-column-split", title: "\u26A1 Problem vs Opportunity", intent: "Contrast legacy bottlenecks against the modern solution" },
|
|
315
|
+
{ slide: 4, type: "process-flow", title: "\u{1F504} Architectural Flow", intent: "High-level system topology and sequence diagram" },
|
|
316
|
+
{ slide: 5, type: "code-explainer", title: "\u{1F4BB} Core Code Walkthrough", intent: "Deep-dive into production implementation logic" },
|
|
317
|
+
{ slide: 6, type: "metrics-3-card", title: "\u{1F4CA} Benchmark Results", intent: "Quantify performance and reliability gains" },
|
|
318
|
+
{ slide: 7, type: "tiered-practice-3cards", title: "\u{1F6E0}\uFE0F Hands-On Challenge", intent: "Differentiated practice across Bronze, Silver, and Gold tiers" },
|
|
319
|
+
{ slide: 8, type: "quiz-checkpoint", title: "\u{1F3AF} Formative Checkpoint", intent: "Real-time diagnostic voting to verify mastery" },
|
|
320
|
+
{ slide: 9, type: "takeaways-summary", title: "\u{1F3C1} Key Takeaways", intent: "Synthesis of 3 core lessons and next action items" }
|
|
321
321
|
].slice(0, Math.max(5, Math.min(targetSlideCount, 10)))
|
|
322
322
|
};
|
|
323
323
|
}
|
|
@@ -350,7 +350,7 @@ Structure decks based on allocated talk time (averaging 1.5 - 2 minutes per slid
|
|
|
350
350
|
## 3. STRICT WORD BUDGET (ZERO-SCROLL INVARIANT)
|
|
351
351
|
- **Hard Limit:** Maximum **35 - 40 words** per card or column.
|
|
352
352
|
- Never write paragraphs longer than 2 sentences. Use structured bullets with bold anchor terms:
|
|
353
|
-
- Format: \`- **
|
|
353
|
+
- Format: \`- **Key Concept:** Concise explanation in a single line.\`
|
|
354
354
|
- Vertical scrolling inside a slide is STRICTLY FORBIDDEN. Content must fit the 16:9 (1280x720) canvas cleanly.
|
|
355
355
|
|
|
356
356
|
---
|
|
@@ -360,12 +360,14 @@ Structure decks based on allocated talk time (averaging 1.5 - 2 minutes per slid
|
|
|
360
360
|
\`\`\`html
|
|
361
361
|
<div class="columns-2">
|
|
362
362
|
<div>
|
|
363
|
-
### \u{1F534}
|
|
364
|
-
-
|
|
363
|
+
### \u{1F534} Legacy / Challenge
|
|
364
|
+
- High idle compute overhead
|
|
365
|
+
- Cascading timeout failures
|
|
365
366
|
</div>
|
|
366
367
|
<div>
|
|
367
|
-
### \u{1F7E2}
|
|
368
|
-
-
|
|
368
|
+
### \u{1F7E2} Modern / Solution
|
|
369
|
+
- Event-driven webhook streams
|
|
370
|
+
- Automatic queue backpressure
|
|
369
371
|
</div>
|
|
370
372
|
</div>
|
|
371
373
|
\`\`\`
|
|
@@ -376,16 +378,16 @@ Structure decks based on allocated talk time (averaging 1.5 - 2 minutes per slid
|
|
|
376
378
|
## 5. MANDATORY PRESENTER NOTES (TEACHER TALK TRACK)
|
|
377
379
|
Every single slide MUST conclude with an HTML comment block containing:
|
|
378
380
|
1. **Talk Track:** 2-3 sentences of what the speaker should say out loud.
|
|
379
|
-
2. **Cold-Call Check Question:** 1 diagnostic question to ask a specific student.
|
|
380
|
-
3. **Scaffolding Tip:** 1 hint if
|
|
381
|
+
2. **Cold-Call Check Question:** 1 diagnostic question to ask a specific student or attendee.
|
|
382
|
+
3. **Scaffolding Tip:** 1 hint or real-world analogy if learners look confused.
|
|
381
383
|
|
|
382
384
|
Example:
|
|
383
385
|
\`\`\`markdown
|
|
384
386
|
<!--
|
|
385
387
|
Presenter Notes:
|
|
386
|
-
-
|
|
387
|
-
- Cold-call: "
|
|
388
|
-
-
|
|
388
|
+
- Walk through the primary bottleneck when scaling database writes under high concurrency.
|
|
389
|
+
- Cold-call: "Alex, if traffic spikes 10x in 1 minute, which subsystem will experience lock contention first?"
|
|
390
|
+
- Scaffolding tip: Remind the room of the I/O saturation trade-off discussed in the previous module.
|
|
389
391
|
-->
|
|
390
392
|
\`\`\`
|
|
391
393
|
|
package/dist/ai/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/ai/schemas.ts","../../src/ai/tools.ts","../../src/ai/prompt.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// ═══════════════════════════════════════════════════════════════════════════════\n// @learnwell/presentation-kit — AI Tool Schemas (Zod)\n// ═══════════════════════════════════════════════════════════════════════════════\n\nimport { z } from 'zod';\n\nexport const listSlidePresetsSchema = z.object({\n category: z.enum([\n 'all',\n 'cover',\n 'content',\n 'split',\n 'code',\n 'metrics',\n 'diagram',\n 'quote',\n 'assessment',\n ]).optional().describe('Optional category filter for layout presets'),\n});\n\nexport const createSlideFromPresetSchema = z.object({\n presetId: z.string().describe(\n 'ID of the layout preset: title-hero, two-column-split, code-explainer, metrics-3-card, process-flow, quote-highlight, quiz-checkpoint, tiered-practice-3cards, agenda-timeline, takeaways-summary'\n ),\n title: z.string().describe('Slide heading or title'),\n subtitle: z.string().optional().describe('Optional subtitle or section context'),\n content: z.record(z.string()).optional().describe(\n 'Key-value pairs for preset sections. For two-column-split: leftCol, rightCol. For code-explainer: code, language, notes. For metrics-3-card: card1Title, card1Val, card1Desc, etc.'\n ),\n customMarkdownBody: z.string().optional().describe(\n 'Raw markdown body to place inside the layout container (overrides content key-value pairs if provided)'\n ),\n presenterNotes: z.array(z.string()).optional().describe(\n 'Teacher talk track, cold-call check questions, or scaffolding notes for this slide'\n ),\n});\n\nexport const applySlideLayoutSchema = z.object({\n markdown: z.string().describe('Full Markdown slide deck content'),\n slideIndex: z.number().int().min(0).describe('0-based index of the target slide to modify'),\n presetId: z.string().optional().describe('Optional preset ID to apply to this slide'),\n boxes: z.array(\n z.object({\n id: z.string(),\n target: z.string().optional(),\n pos: z.tuple([z.number(), z.number(), z.number(), z.number()]).describe('[x, y, width, height] in 1280x720 canvas coordinates'),\n fontSize: z.string().optional(),\n color: z.string().optional(),\n textAlign: z.enum(['left', 'center', 'right', 'justify']).optional(),\n style: z.string().optional(),\n })\n ).optional().describe('Custom boxes if not using presetId'),\n});\n\nexport const updatePresenterNotesSchema = z.object({\n markdown: z.string().describe('Full Markdown slide deck content'),\n slideIndex: z.number().int().min(0).describe('0-based index of the target slide'),\n notes: z.array(z.string()).describe('List of speaker notes / talk tracks to set for this slide'),\n});\n\nexport const generateDeckOutlineSchema = z.object({\n topic: z.string().describe('Main subject or topic of the presentation'),\n durationMins: z.number().int().min(3).max(120).default(15).describe('Estimated duration in minutes (5m: 5-7 slides, 15m: 12-18 slides, 30m: 25-35 slides)'),\n audience: z.string().describe('Target audience profile (e.g. Grade 10 students, junior developers, enterprise clients)'),\n keyObjectives: z.array(z.string()).describe('2-4 key learning or decision objectives'),\n techStack: z.string().optional().describe('Optional programming language, framework, or hardware kit'),\n});\n","// ═══════════════════════════════════════════════════════════════════════════════\n// @learnwell/presentation-kit — AI Tool Handlers\n// Pure execution handlers for Vercel AI SDK / OpenAI tool calls\n// ═══════════════════════════════════════════════════════════════════════════════\n\nimport {\n SLIDE_LAYOUT_PRESETS,\n getSlideLayoutPresetById,\n getSlideLayoutPresetsByCategory,\n type SlideLayoutCategory,\n} from '../core/layout/presets.js';\nimport {\n updateSlideLayoutInMarkdown,\n splitMarkdownSlides,\n serializeLayoutToComment,\n} from '../core/layout/serializer.js';\nimport type { SlideLayoutData } from '../types.js';\n\n/**\n * Execute: listSlidePresets\n */\nexport function executeListSlidePresets(params?: { category?: string }) {\n const category = params?.category;\n const presets = (!category || category === 'all')\n ? SLIDE_LAYOUT_PRESETS\n : getSlideLayoutPresetsByCategory(category as SlideLayoutCategory);\n\n return {\n count: presets.length,\n presets: presets.map(p => ({\n id: p.id,\n name: p.name,\n category: p.category,\n description: p.description,\n boxCount: p.layout.boxes.length,\n snippetPreview: p.markdownSnippet.split('\\n').slice(0, 8).join('\\n') + '\\n...',\n })),\n };\n}\n\n/**\n * Execute: createSlideFromPreset\n */\nexport function executeCreateSlideFromPreset(params: {\n presetId: string;\n title: string;\n subtitle?: string;\n content?: Record<string, string>;\n customMarkdownBody?: string;\n presenterNotes?: string[];\n}): { success: boolean; slideMarkdown: string; presetName?: string; error?: string } {\n const preset = getSlideLayoutPresetById(params.presetId);\n if (!preset) {\n return {\n success: false,\n slideMarkdown: '',\n error: `Không tìm thấy preset với ID: \"${params.presetId}\". Sử dụng listSlidePresets để xem các mẫu có sẵn.`,\n };\n }\n\n const layoutComment = serializeLayoutToComment(preset.layout);\n const title = params.title;\n const subtitle = params.subtitle ? `\\n### ${params.subtitle}` : '';\n\n let body = params.customMarkdownBody;\n\n if (!body) {\n const c = params.content || {};\n switch (preset.id) {\n case 'title-hero':\n body = `${subtitle}\\n\\n**Người trình bày:** ${c.speaker || 'Giảng viên'} | **Thời lượng:** ${c.duration || '45 phút'} | **Chủ đề:** ${c.topic || title}`;\n break;\n\n case 'two-column-split':\n body = `<div class=\"columns-2\">\\n<div>\\n\\n### ${c.leftHeader || 'Cách tiếp cận A'}\\n${c.leftCol || '- Điểm 1\\n- Điểm 2\\n- Điểm 3'}\\n\\n</div>\\n<div>\\n\\n### ${c.rightHeader || 'Cách tiếp cận B'}\\n${c.rightCol || '- Điểm 1\\n- Điểm 2\\n- Điểm 3'}\\n\\n</div>\\n</div>`;\n break;\n\n case 'code-explainer':\n body = `<div class=\"columns-2\">\\n<div>\\n\\n\\`\\`\\`${c.lang || 'ts'}\\n${c.code || '// Code snippet ở đây\\nconst example = true;'}\\n\\`\\`\\`\\n\\n</div>\\n<div>\\n\\n### 🔍 Điểm cốt lõi:\\n${c.notes || '1. **Phân tích dòng 1:** Khởi tạo\\n2. **Phân tích dòng 2:** Thực thi\\n3. **Lưu ý:** Điều kiện biên'}\\n\\n</div>\\n</div>`;\n break;\n\n case 'metrics-3-card':\n body = `<div class=\"columns-3\">\\n<div>\\n\\n# ${c.metric1Val || '99.9%'}\\n### ${c.metric1Title || 'Chỉ số 1'}\\n${c.metric1Desc || 'Mô tả ngắn gọn về chỉ số.'}\\n\\n</div>\\n<div>\\n\\n# ${c.metric2Val || '10x'}\\n### ${c.metric2Title || 'Chỉ số 2'}\\n${c.metric2Desc || 'Mô tả ngắn gọn về chỉ số.'}\\n\\n</div>\\n<div>\\n\\n# ${c.metric3Val || '0'}\\n### ${c.metric3Title || 'Chỉ số 3'}\\n${c.metric3Desc || 'Mô tả ngắn gọn về chỉ số.'}\\n\\n</div>\\n</div>`;\n break;\n\n case 'process-flow':\n body = `\\`\\`\\`mermaid\\n${c.mermaid || 'graph LR\\n A[Bước 1] --> B[Bước 2]\\n B --> C[Bước 3]\\n C --> D[Hoàn thành]'}\\n\\`\\`\\`\\n\\n${c.summary || '- **Giai đoạn 1:** Khởi động\\n- **Giai đoạn 2:** Xử lý dữ liệu\\n- **Giai đoạn 3:** Kết xuất kết quả'}`;\n break;\n\n case 'quote-highlight':\n body = `> \"${c.quote || 'Sự đơn giản là chìa khóa của độ tin cậy.'}\"\\n> \\n> — **${c.author || 'Danh ngôn công nghệ'}**`;\n break;\n\n case 'quiz-checkpoint':\n body = `> **Câu hỏi:** ${c.question || 'Phương án nào sau đây là tối ưu nhất?'}\\n\\n- **A.** ${c.optA || 'Lựa chọn A'}\\n- **B.** ${c.optB || 'Lựa chọn B (Chính xác)'}\\n- **C.** ${c.optC || 'Lựa chọn C'}\\n- **D.** ${c.optD || 'Lựa chọn D'}`;\n break;\n\n case 'tiered-practice-3cards':\n body = `<div class=\"columns-3\">\\n<div>\\n\\n### 🥉 Hạng Đồng (Bronze)\\n${c.bronze || '- Bài tập cơ bản\\n- 1 test case mẫu'}\\n\\n</div>\\n<div>\\n\\n### 🥈 Hạng Bạc (Silver)\\n${c.silver || '- Tối ưu thuật toán\\n- Xử lý điều kiện biên'}\\n\\n</div>\\n<div>\\n\\n### 🥇 Hạng Vàng (Gold)\\n${c.gold || '- Tính năng mở rộng\\n- Tự động hóa unit test'}\\n\\n</div>\\n</div>`;\n break;\n\n default:\n body = preset.markdownSnippet.replace(/^<!--[\\s\\S]*?-->\\n*/, '').replace(/^#\\s+[^\\n]+\\n*/, '').trim();\n }\n }\n\n const notes = params.presenterNotes && params.presenterNotes.length > 0\n ? `\\n\\n<!--\\nPresenter Notes:\\n${params.presenterNotes.map(n => `- ${n}`).join('\\n')}\\n-->`\n : `\\n\\n<!--\\nPresenter Notes:\\n- Giải thích khái niệm chính trên slide.\\n- Đặt câu hỏi tương tác cho cả lớp.\\n-->`;\n\n const slideMarkdown = `${layoutComment}\\n\\n## ${title}${body ? '\\n\\n' + body : ''}${notes}`;\n\n return {\n success: true,\n slideMarkdown,\n presetName: preset.name,\n };\n}\n\n/**\n * Execute: applySlideLayout\n */\nexport function executeApplySlideLayout(params: {\n markdown: string;\n slideIndex: number;\n presetId?: string;\n boxes?: SlideLayoutData['boxes'];\n}): { success: boolean; updatedMarkdown: string; error?: string } {\n let layoutData: SlideLayoutData | null = null;\n\n if (params.presetId) {\n const preset = getSlideLayoutPresetById(params.presetId);\n if (!preset) {\n return {\n success: false,\n updatedMarkdown: params.markdown,\n error: `Không tìm thấy preset với ID: \"${params.presetId}\"`,\n };\n }\n layoutData = preset.layout;\n } else if (params.boxes && params.boxes.length > 0) {\n layoutData = { boxes: params.boxes };\n }\n\n const updatedMarkdown = updateSlideLayoutInMarkdown(\n params.markdown,\n params.slideIndex,\n layoutData\n );\n\n return {\n success: true,\n updatedMarkdown,\n };\n}\n\n/**\n * Execute: updatePresenterNotes\n */\nexport function executeUpdatePresenterNotes(params: {\n markdown: string;\n slideIndex: number;\n notes: string[];\n}): { success: boolean; updatedMarkdown: string; error?: string } {\n const { frontmatter, slides } = splitMarkdownSlides(params.markdown);\n\n if (params.slideIndex < 0 || params.slideIndex >= slides.length) {\n return {\n success: false,\n updatedMarkdown: params.markdown,\n error: `Slide index ${params.slideIndex} ngoài phạm vi (tổng số slides: ${slides.length})`,\n };\n }\n\n let slideContent = slides[params.slideIndex];\n const notesCommentRegex = /<!--\\s*(?:Presenter Notes|Notes):\\s*([\\s\\S]*?)-->/i;\n const newNotesComment = `<!--\\nPresenter Notes:\\n${params.notes.map(n => `- ${n}`).join('\\n')}\\n-->`;\n\n if (notesCommentRegex.test(slideContent)) {\n slideContent = slideContent.replace(notesCommentRegex, newNotesComment);\n } else {\n slideContent = `${slideContent.trimEnd()}\\n\\n${newNotesComment}`;\n }\n\n slides[params.slideIndex] = slideContent;\n const joined = slides.join('\\n---\\n');\n const updatedMarkdown = frontmatter ? `${frontmatter}\\n\\n${joined}` : joined;\n\n return {\n success: true,\n updatedMarkdown,\n };\n}\n\n/**\n * Execute: generateDeckOutline (indexed by talk duration)\n */\nexport function executeGenerateDeckOutline(params: {\n topic: string;\n durationMins: number;\n audience: string;\n keyObjectives: string[];\n techStack?: string;\n}) {\n const d = params.durationMins;\n let targetSlideCount = 12;\n let formatLabel = '15 min (Short Talk)';\n\n if (d <= 7) {\n targetSlideCount = 6;\n formatLabel = '5 min (Lightning Talk)';\n } else if (d <= 20) {\n targetSlideCount = 14;\n formatLabel = '15 min (Short Talk)';\n } else if (d <= 35) {\n targetSlideCount = 28;\n formatLabel = '30 min (Conference Talk)';\n } else {\n targetSlideCount = 42;\n formatLabel = '45-60 min (Keynote / Workshop)';\n }\n\n return {\n topic: params.topic,\n audience: params.audience,\n durationMins: d,\n format: formatLabel,\n recommendedSlideCount: targetSlideCount,\n structureGuidelines: [\n 'Áp dụng nguyên tắc: Một ý tưởng duy nhất trên mỗi slide (One Idea Per Slide).',\n 'Giới hạn từ: Tối đa 40 từ trên mỗi card/cột để chống tràn chữ (Zero Scroll Invariant).',\n 'Tỷ lệ hiển thị: Chuẩn 16:9 với hệ tọa độ 1280x720.',\n 'Bắt buộc có khối Presenter Notes chứa: Talk track giảng viên + 1 câu hỏi tương tác cold-call.',\n ],\n suggestedOutline: [\n { slide: 1, type: 'title-hero', title: `🚀 ${params.topic}`, intent: 'Gây ấn tượng ban đầu và giới thiệu diễn giả' },\n { slide: 2, type: 'agenda-timeline', title: '🗺️ Lộ trình hoạt động', intent: 'Định hình cấu trúc thời gian và kết quả đầu ra' },\n { slide: 3, type: 'two-column-split', title: '⚡ Bối cảnh & Thử thách', intent: 'So sánh cách làm cũ vs vấn đề thực tế' },\n { slide: 4, type: 'process-flow', title: '🔄 Kiến trúc cốt lõi', intent: 'Sơ đồ luồng xử lý tổng quan' },\n { slide: 5, type: 'code-explainer', title: '💻 Phân tích mã nguồn', intent: 'Đi sâu vào implementation kỹ thuật' },\n { slide: 6, type: 'metrics-3-card', title: '📊 3 Chỉ số đo lường', intent: 'Định lượng hiệu năng và tính hiệu quả' },\n { slide: 7, type: 'tiered-practice-3cards', title: '🛠️ Thử thách phân hóa', intent: 'Thực hành tại chỗ theo 3 bậc Bronze-Silver-Gold' },\n { slide: 8, type: 'quiz-checkpoint', title: '🎯 Kiểm tra nhanh', intent: 'Đánh giá mức độ tiếp thu (Formative Checkpoint)' },\n { slide: 9, type: 'takeaways-summary', title: '🏁 Tổng kết cốt lõi', intent: '3 bài học rút ra và nhiệm vụ tiếp theo' },\n ].slice(0, Math.max(5, Math.min(targetSlideCount, 10))),\n };\n}\n","// ═══════════════════════════════════════════════════════════════════════════════\n// @learnwell/presentation-kit — Slide Design Prompt Contract & System Invariants\n// \n// Modeled after battle-tested presentation orchestrators (e.g. slides-ai-plugin)\n// Provides rigorous invariants for LLM slide generation across web & PPTX.\n// ═══════════════════════════════════════════════════════════════════════════════\n\nexport const SLIDE_DESIGN_PROMPT_CONTRACT = `\n# SYSTEM MANDATE: PROFESSIONAL PRESENTATION & SLIDE DESIGN INVARIANTS\n\nYou are an expert Presentation Architect & Visual Designer for educational, technical, and executive decks.\nWhen generating or modifying Marp slide presentations, you MUST STRICTLY obey the following non-negotiable rules:\n\n---\n\n## 1. DURATION-INDEXED SLIDE PACING\nStructure decks based on allocated talk time (averaging 1.5 - 2 minutes per slide):\n- **5 min (Lightning Talk):** 5 - 7 slides [Hook -> 2-3 Core Points -> CTA / Summary]\n- **15 min (Short Tech Talk):** 12 - 16 slides [Title -> Agenda -> Hook -> 3-4 Concepts -> Lab/Demo -> Summary]\n- **30 min (Conference / Class):** 24 - 32 slides [Full 5E Learning Cycle + Interactive Formative Checkpoint]\n- **45-60 min (Keynote / Workshop):** 36 - 50 slides [Modular Micro-cycles + Tiered Hands-on Exercises]\n\n---\n\n## 2. THE \"ONE IDEA PER SLIDE\" RULE\n- Each slide communicates **EXACTLY ONE** pedagogical or architectural concept.\n- Never pack multiple distinct topics into a single slide.\n- If a concept has both theory and code, split into: (Slide A) Concept Diagram -> (Slide B) Code Walkthrough.\n\n---\n\n## 3. STRICT WORD BUDGET (ZERO-SCROLL INVARIANT)\n- **Hard Limit:** Maximum **35 - 40 words** per card or column.\n- Never write paragraphs longer than 2 sentences. Use structured bullets with bold anchor terms:\n - Format: \\`- **Khái niệm then chốt:** Mô tả súc tích trong 1 dòng.\\`\n- Vertical scrolling inside a slide is STRICTLY FORBIDDEN. Content must fit the 16:9 (1280x720) canvas cleanly.\n\n---\n\n## 4. TWO-COLUMN & CARD BALANCED LAYOUTS\n- Avoid centered vertical walls of text. Use responsive side-by-side card wrappers:\n \\`\\`\\`html\n <div class=\"columns-2\">\n <div>\n ### 🔴 Cũ / Thách Thức\n - ...\n </div>\n <div>\n ### 🟢 Mới / Giải Pháp\n - ...\n </div>\n </div>\n \\`\\`\\`\n- For 3 metrics or bronze/silver/gold differentiation, use \\`<div class=\"columns-3\">...</div>\\`.\n\n---\n\n## 5. MANDATORY PRESENTER NOTES (TEACHER TALK TRACK)\nEvery single slide MUST conclude with an HTML comment block containing:\n1. **Talk Track:** 2-3 sentences of what the speaker should say out loud.\n2. **Cold-Call Check Question:** 1 diagnostic question to ask a specific student.\n3. **Scaffolding Tip:** 1 hint if students look confused.\n\nExample:\n\\`\\`\\`markdown\n<!--\nPresenter Notes:\n- Trình bày điểm nghẽn lớn nhất trong việc mở rộng quy mô dữ liệu.\n- Cold-call: \"Em Nguyễn Văn B, nếu số lượng request tăng gấp 10 lần thì điểm nào sẽ sập đầu tiên?\"\n- Gợi ý gợi mở: Nhắc học viên nhớ lại khái niệm I/O bottleneck ở bài trước.\n-->\n\\`\\`\\`\n\n---\n\n## 6. MARP COMPATIBLE YAML LAYOUT HEADERS\nWhen a precise coordinate layout is specified, include the clean YAML block at the very top of the slide:\n\\`\\`\\`markdown\n<!-- layout:\n boxes:\n - id: heading\n target: h2\n pos: [80, 50, 1120, 70]\n fontSize: 2rem\n - id: col-left\n target: '.columns-2 > div:first-child'\n pos: [80, 150, 530, 510]\n - id: col-right\n target: '.columns-2 > div:last-child'\n pos: [670, 150, 530, 510]\n-->\n\\`\\`\\`\n`;\n"]}
|
|
1
|
+
{"version":3,"sources":["../../src/ai/schemas.ts","../../src/ai/tools.ts","../../src/ai/prompt.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// ═══════════════════════════════════════════════════════════════════════════════\n// @learnwell/presentation-kit — AI Tool Schemas (Zod)\n// ═══════════════════════════════════════════════════════════════════════════════\n\nimport { z } from 'zod';\n\nexport const listSlidePresetsSchema = z.object({\n category: z.enum([\n 'all',\n 'cover',\n 'content',\n 'split',\n 'code',\n 'metrics',\n 'diagram',\n 'quote',\n 'assessment',\n ]).optional().describe('Optional category filter for layout presets'),\n});\n\nexport const createSlideFromPresetSchema = z.object({\n presetId: z.string().describe(\n 'ID of the layout preset: title-hero, two-column-split, code-explainer, metrics-3-card, process-flow, quote-highlight, quiz-checkpoint, tiered-practice-3cards, agenda-timeline, takeaways-summary'\n ),\n title: z.string().describe('Slide heading or title'),\n subtitle: z.string().optional().describe('Optional subtitle or section context'),\n content: z.record(z.string()).optional().describe(\n 'Key-value pairs for preset sections. For two-column-split: leftCol, rightCol. For code-explainer: code, language, notes. For metrics-3-card: card1Title, card1Val, card1Desc, etc.'\n ),\n customMarkdownBody: z.string().optional().describe(\n 'Raw markdown body to place inside the layout container (overrides content key-value pairs if provided)'\n ),\n presenterNotes: z.array(z.string()).optional().describe(\n 'Teacher talk track, cold-call check questions, or scaffolding notes for this slide'\n ),\n});\n\nexport const applySlideLayoutSchema = z.object({\n markdown: z.string().describe('Full Markdown slide deck content'),\n slideIndex: z.number().int().min(0).describe('0-based index of the target slide to modify'),\n presetId: z.string().optional().describe('Optional preset ID to apply to this slide'),\n boxes: z.array(\n z.object({\n id: z.string(),\n target: z.string().optional(),\n pos: z.tuple([z.number(), z.number(), z.number(), z.number()]).describe('[x, y, width, height] in 1280x720 canvas coordinates'),\n fontSize: z.string().optional(),\n color: z.string().optional(),\n textAlign: z.enum(['left', 'center', 'right', 'justify']).optional(),\n style: z.string().optional(),\n })\n ).optional().describe('Custom boxes if not using presetId'),\n});\n\nexport const updatePresenterNotesSchema = z.object({\n markdown: z.string().describe('Full Markdown slide deck content'),\n slideIndex: z.number().int().min(0).describe('0-based index of the target slide'),\n notes: z.array(z.string()).describe('List of speaker notes / talk tracks to set for this slide'),\n});\n\nexport const generateDeckOutlineSchema = z.object({\n topic: z.string().describe('Main subject or topic of the presentation'),\n durationMins: z.number().int().min(3).max(120).default(15).describe('Estimated duration in minutes (5m: 5-7 slides, 15m: 12-18 slides, 30m: 25-35 slides)'),\n audience: z.string().describe('Target audience profile (e.g. Grade 10 students, junior developers, enterprise clients)'),\n keyObjectives: z.array(z.string()).describe('2-4 key learning or decision objectives'),\n techStack: z.string().optional().describe('Optional programming language, framework, or hardware kit'),\n});\n","// ═══════════════════════════════════════════════════════════════════════════════\n// @learnwell/presentation-kit — AI Tool Handlers\n// Pure execution handlers for Vercel AI SDK / OpenAI tool calls\n// ═══════════════════════════════════════════════════════════════════════════════\n\nimport {\n SLIDE_LAYOUT_PRESETS,\n getSlideLayoutPresetById,\n getSlideLayoutPresetsByCategory,\n type SlideLayoutCategory,\n} from '../core/layout/presets.js';\nimport {\n updateSlideLayoutInMarkdown,\n splitMarkdownSlides,\n serializeLayoutToComment,\n} from '../core/layout/serializer.js';\nimport type { SlideLayoutData } from '../types.js';\n\n/**\n * Execute: listSlidePresets\n */\nexport function executeListSlidePresets(params?: { category?: string }) {\n const category = params?.category;\n const presets = (!category || category === 'all')\n ? SLIDE_LAYOUT_PRESETS\n : getSlideLayoutPresetsByCategory(category as SlideLayoutCategory);\n\n return {\n count: presets.length,\n presets: presets.map(p => ({\n id: p.id,\n name: p.name,\n category: p.category,\n description: p.description,\n boxCount: p.layout.boxes.length,\n snippetPreview: p.markdownSnippet.split('\\n').slice(0, 8).join('\\n') + '\\n...',\n })),\n };\n}\n\n/**\n * Execute: createSlideFromPreset\n */\nexport function executeCreateSlideFromPreset(params: {\n presetId: string;\n title: string;\n subtitle?: string;\n content?: Record<string, string>;\n customMarkdownBody?: string;\n presenterNotes?: string[];\n}): { success: boolean; slideMarkdown: string; presetName?: string; error?: string } {\n const preset = getSlideLayoutPresetById(params.presetId);\n if (!preset) {\n return {\n success: false,\n slideMarkdown: '',\n error: `Preset with ID \"${params.presetId}\" not found. Use listSlidePresets to see available layout templates.`,\n };\n }\n\n const layoutComment = serializeLayoutToComment(preset.layout);\n const title = params.title;\n const subtitle = params.subtitle ? `\\n### ${params.subtitle}` : '';\n\n let body = params.customMarkdownBody;\n\n if (!body) {\n const c = params.content || {};\n switch (preset.id) {\n case 'title-hero':\n body = `${subtitle}\\n\\n**Presenter:** ${c.speaker || 'Lead Instructor'} | **Duration:** ${c.duration || '45 mins'} | **Topic:** ${c.topic || title}`;\n break;\n\n case 'two-column-split':\n body = `<div class=\"columns-2\">\\n<div>\\n\\n### ${c.leftHeader || 'Approach A'}\\n${c.leftCol || '- Point 1\\n- Point 2\\n- Point 3'}\\n\\n</div>\\n<div>\\n\\n### ${c.rightHeader || 'Approach B'}\\n${c.rightCol || '- Point 1\\n- Point 2\\n- Point 3'}\\n\\n</div>\\n</div>`;\n break;\n\n case 'code-explainer':\n body = `<div class=\"columns-2\">\\n<div>\\n\\n\\`\\`\\`${c.lang || 'ts'}\\n${c.code || '// Core implementation logic\\nconst isValid = true;'}\\n\\`\\`\\`\\n\\n</div>\\n<div>\\n\\n### 🔍 Key Invariants:\\n${c.notes || '1. **Validation:** Checks payload before processing\\n2. **Execution:** Enforces deterministic state\\n3. **Resilience:** Handles edge case errors'}\\n\\n</div>\\n</div>`;\n break;\n\n case 'metrics-3-card':\n body = `<div class=\"columns-3\">\\n<div>\\n\\n# ${c.metric1Val || '99.9%'}\\n### ${c.metric1Title || 'Availability'}\\n${c.metric1Desc || 'Automated multi-region failover routing.'}\\n\\n</div>\\n<div>\\n\\n# ${c.metric2Val || '10x'}\\n### ${c.metric2Title || 'Throughput'}\\n${c.metric2Desc || 'Sub-millisecond processing latency.'}\\n\\n</div>\\n<div>\\n\\n# ${c.metric3Val || '0'}\\n### ${c.metric3Title || 'Breaches'}\\n${c.metric3Desc || 'Continuous SOC2 compliance auditing.'}\\n\\n</div>\\n</div>`;\n break;\n\n case 'process-flow':\n body = `\\`\\`\\`mermaid\\n${c.mermaid || 'graph LR\\n A[1. Ingress] --> B[2. Gateway]\\n B --> C[3. Service]\\n C --> D[4. Storage]'}\\n\\`\\`\\`\\n\\n${c.summary || '- **Phase 1 & 2:** Client connection and load balancing.\\n- **Phase 3 & 4:** Business logic execution and data commit.'}`;\n break;\n\n case 'quote-highlight':\n body = `> \"${c.quote || 'Simplicity is prerequisite for reliability.'}\"\\n> \\n> — **${c.author || 'Architecture Principle'}**`;\n break;\n\n case 'quiz-checkpoint':\n body = `> **Question:** ${c.question || 'Which architecture pattern best ensures reliable message delivery?'}\\n\\n- **A.** ${c.optA || 'Direct synchronous HTTP request with short timeout'}\\n- **B.** ${c.optB || 'Persistent Message Queue with Dead-Letter Queue (Correct)'}\\n- **C.** ${c.optC || 'In-memory client cache without persistence'}\\n- **D.** ${c.optD || 'Silently dropping failed packets'}`;\n break;\n\n case 'tiered-practice-3cards':\n body = `<div class=\"columns-3\">\\n<div>\\n\\n### 🥉 Bronze Tier\\n${c.bronze || '- Implement baseline function\\n- Pass 2 sample unit tests'}\\n\\n</div>\\n<div>\\n\\n### 🥈 Silver Tier\\n${c.silver || '- Add boundary error handling\\n- Optimize algorithm complexity'}\\n\\n</div>\\n<div>\\n\\n### 🥇 Gold Tier\\n${c.gold || '- Design extension feature\\n- Write automated integration tests'}\\n\\n</div>\\n</div>`;\n break;\n\n default:\n body = preset.markdownSnippet.replace(/^<!--[\\s\\S]*?-->\\n*/, '').replace(/^#\\s+[^\\n]+\\n*/, '').trim();\n }\n }\n\n const notes = params.presenterNotes && params.presenterNotes.length > 0\n ? `\\n\\n<!--\\nPresenter Notes:\\n${params.presenterNotes.map(n => `- ${n}`).join('\\n')}\\n-->`\n : `\\n\\n<!--\\nPresenter Notes:\\n- Explain the primary concept on this slide.\\n- Ask a diagnostic cold-call question to check comprehension.\\n-->`;\n\n const slideMarkdown = `${layoutComment}\\n\\n## ${title}${body ? '\\n\\n' + body : ''}${notes}`;\n\n return {\n success: true,\n slideMarkdown,\n presetName: preset.name,\n };\n}\n\n/**\n * Execute: applySlideLayout\n */\nexport function executeApplySlideLayout(params: {\n markdown: string;\n slideIndex: number;\n presetId?: string;\n boxes?: SlideLayoutData['boxes'];\n}): { success: boolean; updatedMarkdown: string; error?: string } {\n let layoutData: SlideLayoutData | null = null;\n\n if (params.presetId) {\n const preset = getSlideLayoutPresetById(params.presetId);\n if (!preset) {\n return {\n success: false,\n updatedMarkdown: params.markdown,\n error: `Preset with ID \"${params.presetId}\" not found.`,\n };\n }\n layoutData = preset.layout;\n } else if (params.boxes && params.boxes.length > 0) {\n layoutData = { boxes: params.boxes };\n }\n\n const updatedMarkdown = updateSlideLayoutInMarkdown(\n params.markdown,\n params.slideIndex,\n layoutData\n );\n\n return {\n success: true,\n updatedMarkdown,\n };\n}\n\n/**\n * Execute: updatePresenterNotes\n */\nexport function executeUpdatePresenterNotes(params: {\n markdown: string;\n slideIndex: number;\n notes: string[];\n}): { success: boolean; updatedMarkdown: string; error?: string } {\n const { frontmatter, slides } = splitMarkdownSlides(params.markdown);\n\n if (params.slideIndex < 0 || params.slideIndex >= slides.length) {\n return {\n success: false,\n updatedMarkdown: params.markdown,\n error: `Slide index ${params.slideIndex} out of bounds (total slides: ${slides.length})`,\n };\n }\n\n let slideContent = slides[params.slideIndex];\n const notesCommentRegex = /<!--\\s*(?:Presenter Notes|Notes):\\s*([\\s\\S]*?)-->/i;\n const newNotesComment = `<!--\\nPresenter Notes:\\n${params.notes.map(n => `- ${n}`).join('\\n')}\\n-->`;\n\n if (notesCommentRegex.test(slideContent)) {\n slideContent = slideContent.replace(notesCommentRegex, newNotesComment);\n } else {\n slideContent = `${slideContent.trimEnd()}\\n\\n${newNotesComment}`;\n }\n\n slides[params.slideIndex] = slideContent;\n const joined = slides.join('\\n---\\n');\n const updatedMarkdown = frontmatter ? `${frontmatter}\\n\\n${joined}` : joined;\n\n return {\n success: true,\n updatedMarkdown,\n };\n}\n\n/**\n * Execute: generateDeckOutline (indexed by talk duration)\n */\nexport function executeGenerateDeckOutline(params: {\n topic: string;\n durationMins: number;\n audience: string;\n keyObjectives: string[];\n techStack?: string;\n}) {\n const d = params.durationMins;\n let targetSlideCount = 12;\n let formatLabel = '15 min (Short Talk)';\n\n if (d <= 7) {\n targetSlideCount = 6;\n formatLabel = '5 min (Lightning Talk)';\n } else if (d <= 20) {\n targetSlideCount = 14;\n formatLabel = '15 min (Short Talk)';\n } else if (d <= 35) {\n targetSlideCount = 28;\n formatLabel = '30 min (Conference Talk)';\n } else {\n targetSlideCount = 42;\n formatLabel = '45-60 min (Keynote / Workshop)';\n }\n\n return {\n topic: params.topic,\n audience: params.audience,\n durationMins: d,\n format: formatLabel,\n recommendedSlideCount: targetSlideCount,\n structureGuidelines: [\n 'Apply the \"One Idea Per Slide\" invariant.',\n 'Enforce Word Budget: Maximum 40 words per card or column (Zero-Scroll Invariant).',\n 'Target 16:9 aspect ratio in 1280x720 coordinate space.',\n 'Every slide must conclude with Presenter Notes: Teacher talk track + 1 diagnostic cold-call question.',\n ],\n suggestedOutline: [\n { slide: 1, type: 'title-hero', title: `🚀 ${params.topic}`, intent: 'Opening hook and speaker credentialing' },\n { slide: 2, type: 'agenda-timeline', title: '🗺️ Session Milestones', intent: 'Set time budget expectations and learning deliverables' },\n { slide: 3, type: 'two-column-split', title: '⚡ Problem vs Opportunity', intent: 'Contrast legacy bottlenecks against the modern solution' },\n { slide: 4, type: 'process-flow', title: '🔄 Architectural Flow', intent: 'High-level system topology and sequence diagram' },\n { slide: 5, type: 'code-explainer', title: '💻 Core Code Walkthrough', intent: 'Deep-dive into production implementation logic' },\n { slide: 6, type: 'metrics-3-card', title: '📊 Benchmark Results', intent: 'Quantify performance and reliability gains' },\n { slide: 7, type: 'tiered-practice-3cards', title: '🛠️ Hands-On Challenge', intent: 'Differentiated practice across Bronze, Silver, and Gold tiers' },\n { slide: 8, type: 'quiz-checkpoint', title: '🎯 Formative Checkpoint', intent: 'Real-time diagnostic voting to verify mastery' },\n { slide: 9, type: 'takeaways-summary', title: '🏁 Key Takeaways', intent: 'Synthesis of 3 core lessons and next action items' },\n ].slice(0, Math.max(5, Math.min(targetSlideCount, 10))),\n };\n}\n","// ═══════════════════════════════════════════════════════════════════════════════\n// @learnwell/presentation-kit — Slide Design Prompt Contract & System Invariants\n// \n// Modeled after battle-tested presentation orchestrators (e.g. slides-ai-plugin)\n// Provides rigorous invariants for LLM slide generation across web & PPTX.\n// ═══════════════════════════════════════════════════════════════════════════════\n\nexport const SLIDE_DESIGN_PROMPT_CONTRACT = `\n# SYSTEM MANDATE: PROFESSIONAL PRESENTATION & SLIDE DESIGN INVARIANTS\n\nYou are an expert Presentation Architect & Visual Designer for educational, technical, and executive decks.\nWhen generating or modifying Marp slide presentations, you MUST STRICTLY obey the following non-negotiable rules:\n\n---\n\n## 1. DURATION-INDEXED SLIDE PACING\nStructure decks based on allocated talk time (averaging 1.5 - 2 minutes per slide):\n- **5 min (Lightning Talk):** 5 - 7 slides [Hook -> 2-3 Core Points -> CTA / Summary]\n- **15 min (Short Tech Talk):** 12 - 16 slides [Title -> Agenda -> Hook -> 3-4 Concepts -> Lab/Demo -> Summary]\n- **30 min (Conference / Class):** 24 - 32 slides [Full 5E Learning Cycle + Interactive Formative Checkpoint]\n- **45-60 min (Keynote / Workshop):** 36 - 50 slides [Modular Micro-cycles + Tiered Hands-on Exercises]\n\n---\n\n## 2. THE \"ONE IDEA PER SLIDE\" RULE\n- Each slide communicates **EXACTLY ONE** pedagogical or architectural concept.\n- Never pack multiple distinct topics into a single slide.\n- If a concept has both theory and code, split into: (Slide A) Concept Diagram -> (Slide B) Code Walkthrough.\n\n---\n\n## 3. STRICT WORD BUDGET (ZERO-SCROLL INVARIANT)\n- **Hard Limit:** Maximum **35 - 40 words** per card or column.\n- Never write paragraphs longer than 2 sentences. Use structured bullets with bold anchor terms:\n - Format: \\`- **Key Concept:** Concise explanation in a single line.\\`\n- Vertical scrolling inside a slide is STRICTLY FORBIDDEN. Content must fit the 16:9 (1280x720) canvas cleanly.\n\n---\n\n## 4. TWO-COLUMN & CARD BALANCED LAYOUTS\n- Avoid centered vertical walls of text. Use responsive side-by-side card wrappers:\n \\`\\`\\`html\n <div class=\"columns-2\">\n <div>\n ### 🔴 Legacy / Challenge\n - High idle compute overhead\n - Cascading timeout failures\n </div>\n <div>\n ### 🟢 Modern / Solution\n - Event-driven webhook streams\n - Automatic queue backpressure\n </div>\n </div>\n \\`\\`\\`\n- For 3 metrics or bronze/silver/gold differentiation, use \\`<div class=\"columns-3\">...</div>\\`.\n\n---\n\n## 5. MANDATORY PRESENTER NOTES (TEACHER TALK TRACK)\nEvery single slide MUST conclude with an HTML comment block containing:\n1. **Talk Track:** 2-3 sentences of what the speaker should say out loud.\n2. **Cold-Call Check Question:** 1 diagnostic question to ask a specific student or attendee.\n3. **Scaffolding Tip:** 1 hint or real-world analogy if learners look confused.\n\nExample:\n\\`\\`\\`markdown\n<!--\nPresenter Notes:\n- Walk through the primary bottleneck when scaling database writes under high concurrency.\n- Cold-call: \"Alex, if traffic spikes 10x in 1 minute, which subsystem will experience lock contention first?\"\n- Scaffolding tip: Remind the room of the I/O saturation trade-off discussed in the previous module.\n-->\n\\`\\`\\`\n\n---\n\n## 6. MARP COMPATIBLE YAML LAYOUT HEADERS\nWhen a precise coordinate layout is specified, include the clean YAML block at the very top of the slide:\n\\`\\`\\`markdown\n<!-- layout:\n boxes:\n - id: heading\n target: h2\n pos: [80, 50, 1120, 70]\n fontSize: 2rem\n - id: col-left\n target: '.columns-2 > div:first-child'\n pos: [80, 150, 530, 510]\n - id: col-right\n target: '.columns-2 > div:last-child'\n pos: [670, 150, 530, 510]\n-->\n\\`\\`\\`\n`;\n"]}
|