UNPKG

hatch-slidev-builder-mcp

Version:

A comprehensive MCP server for creating Slidev presentations with component library, interactive elements, and team collaboration features

330 lines (315 loc) 12.5 kB
/** * Slidev Builder Orchestration Engine * Combines all 4 layers for intelligent slide generation */ import { ContentIntelligenceEngine } from './ContentIntelligence.js'; import { LayoutOptimizationEngine } from './LayoutOptimization.js'; import { AssetIntelligenceEngine } from './AssetIntelligence.js'; import { StyleOrchestrationEngine } from './StyleOrchestration.js'; export class SlidevBuilderOrchestrator { /** * Main orchestration method - generates complete slide deck */ static async generateSlideDeck(request) { console.log('🚀 Starting 4-Layer Slide Generation Process...'); // Layer 1: Content Intelligence Analysis console.log('📊 Layer 1: Analyzing content structure...'); const contentAnalysis = ContentIntelligenceEngine.analyzeContent(request.content, request.audience); // Generate slides based on content recommendations const slides = []; for (const recommendation of contentAnalysis.slide_recommendations) { console.log(`📝 Generating ${recommendation.slide_type} slide...`); // Layer 2: Layout Optimization console.log('📐 Layer 2: Optimizing layout...'); const layoutRecommendation = LayoutOptimizationEngine.recommendLayout(recommendation.slide_type, contentAnalysis.content_density, request.audience, true // hasVisuals ); // Layer 3: Asset Intelligence console.log('🎨 Layer 3: Curating intelligent assets...'); const assetRecommendation = await AssetIntelligenceEngine.curateAssets({ content_context: request.content, slide_type: recommendation.slide_type, target_audience: request.audience, brand_guidelines: request.brand_guidelines, preferred_style: 'professional' }); // Layer 4: Style Orchestration console.log('🎯 Layer 4: Orchestrating dynamic styles...'); const styleRecommendation = StyleOrchestrationEngine.generateStyleRecommendation(recommendation.slide_type, request.audience, contentAnalysis.content_density, request.brand_guidelines); // Generate slide markdown const slideMarkdown = this.generateSlideMarkdown(recommendation, layoutRecommendation, assetRecommendation, styleRecommendation); slides.push({ id: `slide_${slides.length + 1}`, type: recommendation.slide_type, title: this.generateSlideTitle(recommendation.slide_type, contentAnalysis.key_messages), content: recommendation.content_points.join(', '), layout: layoutRecommendation, assets: assetRecommendation, style: styleRecommendation, markdown: slideMarkdown, estimated_time: recommendation.estimated_time }); } // Calculate presentation metadata const metadata = this.calculatePresentationMetadata(slides, contentAnalysis); // Calculate quality metrics const qualityMetrics = this.calculateQualityMetrics(slides); // Generate optimization suggestions const optimizationSuggestions = this.generateOptimizationSuggestions(slides, qualityMetrics, request); console.log('✅ 4-Layer Slide Generation Complete!'); return { slides, presentation_metadata: metadata, quality_metrics: qualityMetrics, optimization_suggestions: optimizationSuggestions }; } /** * Generate slide markdown combining all layer outputs */ static generateSlideMarkdown(recommendation, layout, assets, style) { const layoutClass = layout.pattern.name; const primaryAsset = assets.assets[0]; let markdown = `--- layout: default class: '${layoutClass}' --- <style> ${style.css_framework} </style> `; // Generate content based on slide type switch (recommendation.slide_type) { case 'hero': markdown += this.generateHeroSlide(recommendation, primaryAsset, style); break; case 'problem': markdown += this.generateProblemSlide(recommendation, primaryAsset, style); break; case 'solution': markdown += this.generateSolutionSlide(recommendation, primaryAsset, style); break; case 'evidence': markdown += this.generateEvidenceSlide(recommendation, assets, style); break; case 'action': markdown += this.generateActionSlide(recommendation, primaryAsset, style); break; default: markdown += this.generateDefaultSlide(recommendation, primaryAsset, style); } return markdown; } /** * Generate hero slide markup */ static generateHeroSlide(recommendation, asset, style) { return ` <div class="slide-header slide-header--hero"> <h1>${this.generateSlideTitle('hero', recommendation.content_points)}</h1> <p class="subtitle">AI-Native Strategic Advisory Capability</p> </div> <div class="hero-content"> ${asset ? `<img src="${asset.url}" alt="${asset.alt_text}" class="hero-image" />` : ''} <div class="hero-highlights"> ${recommendation.content_points.map((point) => `<div class="highlight-item">✨ ${point}</div>`).join('\n ')} </div> </div> <div class="call-to-action"> <p>Transforming Advisory Excellence Through Human-AI Collaboration</p> </div> `; } /** * Generate problem slide markup */ static generateProblemSlide(recommendation, asset, style) { return ` <div class="slide-header slide-header--content"> <h1>🚨 ${this.generateSlideTitle('problem', recommendation.content_points)}</h1> </div> <div class="content-split"> <div class="problem-statement"> <h2>Current Challenges</h2> <ul> ${recommendation.content_points.map((point) => `<li>${point}</li>`).join('\n ')} </ul> </div> <div class="problem-visual"> ${asset ? `<img src="${asset.url}" alt="${asset.alt_text}" />` : ''} </div> </div> `; } /** * Generate solution slide markup */ static generateSolutionSlide(recommendation, asset, style) { return ` <div class="slide-header slide-header--content"> <h1>💡 ${this.generateSlideTitle('solution', recommendation.content_points)}</h1> </div> <div class="solution-grid"> ${recommendation.content_points.map((point, index) => ` <div class="solution-item"> <div class="solution-icon">🔧</div> <h3>Solution ${index + 1}</h3> <p>${point}</p> </div> `).join('')} </div> ${asset ? ` <div class="solution-visual"> <img src="${asset.url}" alt="${asset.alt_text}" /> </div> ` : ''} `; } /** * Generate evidence slide markup */ static generateEvidenceSlide(recommendation, assets, style) { return ` <div class="slide-header slide-header--content"> <h1>📊 ${this.generateSlideTitle('evidence', recommendation.content_points)}</h1> </div> <div class="evidence-container"> <div class="data-table"> <table> <thead> <tr class="data-table--header"> <th>Metric</th> <th>Traditional</th> <th>AI-Native</th> </tr> </thead> <tbody> ${recommendation.content_points.map((point) => ` <tr> <td class="data-table--cell font-bold">${point}</td> <td class="data-table--cell text-center">Standard</td> <td class="data-table--cell text-center text-accent font-bold">Optimized</td> </tr> `).join('')} </tbody> </table> </div> ${assets.assets[0] ? ` <div class="evidence-visual"> <img src="${assets.assets[0].url}" alt="${assets.assets[0].alt_text}" /> </div> ` : ''} </div> `; } /** * Generate action slide markup */ static generateActionSlide(recommendation, asset, style) { return ` <div class="slide-header slide-header--content"> <h1>🚀 ${this.generateSlideTitle('action', recommendation.content_points)}</h1> </div> <div class="action-steps"> ${recommendation.content_points.map((point, index) => ` <div class="action-item"> <div class="step-number">${index + 1}</div> <div class="step-content"> <h3>Next Step</h3> <p>${point}</p> </div> </div> `).join('')} </div> <div class="call-to-action"> <h2>Ready to Transform Your Advisory Practice?</h2> <p>Contact us to discuss your HAIA+ implementation</p> </div> `; } /** * Generate default slide markup */ static generateDefaultSlide(recommendation, asset, style) { return ` <div class="slide-header slide-header--content"> <h1>${this.generateSlideTitle('default', recommendation.content_points)}</h1> </div> <div class="slide-content"> <ul> ${recommendation.content_points.map((point) => `<li>${point}</li>`).join('\n ')} </ul> ${asset ? ` <div class="content-visual"> <img src="${asset.url}" alt="${asset.alt_text}" /> </div> ` : ''} </div> `; } /** * Generate contextual slide titles */ static generateSlideTitle(slideType, contentPoints) { const titles = { 'hero': 'Market Leadership Response', 'problem': 'Current Market Challenges', 'solution': 'Our Strategic Solution', 'evidence': 'Proven Results & Impact', 'action': 'Next Steps Forward' }; return titles[slideType] || 'Key Information'; } /** * Calculate presentation metadata */ static calculatePresentationMetadata(slides, contentAnalysis) { const totalTime = slides.reduce((sum, slide) => sum + slide.estimated_time, 0); return { total_slides: slides.length, estimated_duration: totalTime, complexity_score: contentAnalysis.content_structure.cognitive_load_score, accessibility_score: slides.reduce((sum, slide) => sum + slide.layout.accessibility_score, 0) / slides.length, brand_compliance: slides.reduce((sum, slide) => sum + slide.style.theme.brand_alignment, 0) / slides.length }; } /** * Calculate quality metrics */ static calculateQualityMetrics(slides) { const contentQuality = slides.reduce((sum, slide) => sum + (slide.content.length > 50 ? 0.9 : 0.7), 0) / slides.length; const visualAppeal = slides.reduce((sum, slide) => sum + (slide.assets.assets.length > 0 ? 0.9 : 0.6), 0) / slides.length; const accessibility = slides.reduce((sum, slide) => sum + slide.layout.accessibility_score, 0) / slides.length; const brandAlignment = slides.reduce((sum, slide) => sum + slide.style.theme.brand_alignment, 0) / slides.length; const overallScore = (contentQuality + visualAppeal + accessibility + brandAlignment) / 4; return { content_quality: contentQuality, visual_appeal: visualAppeal, accessibility, brand_alignment: brandAlignment, overall_score: overallScore }; } /** * Generate optimization suggestions */ static generateOptimizationSuggestions(slides, metrics, request) { const suggestions = []; if (metrics.content_quality < 0.8) { suggestions.push('Consider expanding content depth or adding more supporting details'); } if (metrics.visual_appeal < 0.8) { suggestions.push('Add more visual elements like charts, diagrams, or high-quality images'); } if (metrics.accessibility < 0.9) { suggestions.push('Improve accessibility with better color contrast and alt text'); } if (slides.length > 10) { suggestions.push('Consider condensing content - presentations over 10 slides may lose audience attention'); } const totalTime = slides.reduce((sum, slide) => sum + slide.estimated_time, 0); if (request.time_constraint && totalTime > request.time_constraint * 60) { suggestions.push(`Presentation duration (${Math.round(totalTime / 60)}min) exceeds time constraint`); } return suggestions; } }