Skip to main content
Glama
format-for-composer.js10.6 kB
#!/usr/bin/env node /** * Format for Composer Tool v5.2.0 - FULLY OPERATIONAL * Transforms validated lesson data into EXACT EuConquisto Composer JSON format * @version 5.2.0 (January 12, 2025) * @status FULLY OPERATIONAL - Complete API compliance achieved * @reference /docs/references/json-example.md (official EuConquisto Composer API) * @milestone v5.2.0 - End-to-end success: create → save → display */ export class ComposerFormatterFixed { constructor() { this.processingStartTime = null; this.transformationLog = []; this.educationalOptimizations = []; } /** * Main formatting entry point */ async formatForComposer(validatedLessonData) { this.processingStartTime = Date.now(); this.transformationLog = []; this.educationalOptimizations = []; console.error('[FORMAT_FOR_COMPOSER] Starting CORRECTED formatting transformation'); try { const { metadata, widgets } = validatedLessonData; // Create composition structure following EXACT official format const composition = { version: "1.1", metadata: this.createComposerMetadata(metadata), interface: this.createComposerInterface(), structure: [] }; // Transform widgets with EXACT reference mapping for (let index = 0; index < widgets.length; index++) { const widget = widgets[index]; const transformedWidget = this.transformWidget(widget, index, widgets.length, metadata); if (transformedWidget) { composition.structure.push(transformedWidget); this.logTransformation(`WIDGET_${index + 1}`, widget.type, 'transformed successfully'); } } const processingTime = Date.now() - this.processingStartTime; console.error(`[FORMAT_FOR_COMPOSER] ✅ CORRECTED formatting successful: ${composition.structure.length} widgets transformed`); return { success: true, data: { composerJSON: composition, widgetCount: composition.structure.length, formatSummary: `Transformed ${composition.structure.length} widgets with EXACT reference format`, educationalOptimizations: this.educationalOptimizations }, debug: { timestamp: new Date().toISOString(), processingTime: processingTime, transformationLog: this.transformationLog } }; } catch (error) { console.error('[FORMAT_FOR_COMPOSER] ❌ CORRECTED formatting error:', error.message); return { success: false, error: { code: 'FORMAT_ERROR', message: error.message, details: [{ type: 'TRANSFORMATION_ERROR', location: 'formatter', field: 'system', expected: 'successful formatting', actual: error.message }] }, debug: { timestamp: new Date().toISOString(), processingTime: Date.now() - this.processingStartTime, transformationLog: this.transformationLog } }; } } /** * Create Composer-compatible metadata - EXACT format */ createComposerMetadata(metadata) { return { title: metadata.topic || "Aula Educacional", description: `Aula completa sobre ${metadata.topic || "conteúdo educacional"}`, thumb: null, tags: Array.isArray(metadata.learningObjectives) ? metadata.learningObjectives : [] }; } /** * Create Composer interface configuration - EXACT format */ createComposerInterface() { return { content_language: "pt_br", index_option: "buttons", font_family: "Lato", show_summary: "disabled", finish_btn: "disabled" }; } /** * Transform individual widget - EXACT reference mapping */ transformWidget(widget, index, totalWidgets, metadata) { const baseElement = { id: this.generateUUID(), type: widget.type, dam_assets: [] }; try { switch (widget.type) { case 'head-1': return this.transformHead1Widget(widget, baseElement, metadata); case 'text-1': return this.transformText1Widget(widget, baseElement, metadata); case 'quiz-1': return this.transformQuiz1Widget(widget, baseElement, metadata); case 'flashcards-1': return this.transformFlashcards1Widget(widget, baseElement, metadata); case 'image-1': return this.transformImage1Widget(widget, baseElement, metadata); case 'list-1': return this.transformList1Widget(widget, baseElement, metadata); default: console.warn(`[FORMAT_FOR_COMPOSER] Unknown widget type: ${widget.type}`); return null; } } catch (error) { console.error(`[FORMAT_FOR_COMPOSER] Error transforming ${widget.type}:`, error.message); throw new Error(`Widget transformation failed for ${widget.type}: ${error.message}`); } } /** * head-1 Widget - EXACT reference format * Reference: lines 78-94 in json-example.md */ transformHead1Widget(widget, baseElement, metadata) { return { ...baseElement, content_title: null, primary_color: "#FFFFFF", secondary_color: "#2196F3", category: `<p>${widget.content.category || 'EDUCAÇÃO'}</p>`, background_image: "https://images.unsplash.com/photo-1516321318423-f06f85e504b3?w=1200&h=400&fit=crop", avatar: "https://ui-avatars.com/api/?name=Professor&background=2196F3&color=fff&size=200", avatar_border_color: "#1565C0", author_name: `<p>${widget.content.author_name || 'Professor(a) Virtual'}</p>`, author_office: `<p>${widget.content.author_office || 'Educador'}</p>`, show_category: true, show_author_name: true, show_divider: true, dam_assets: [] }; } /** * text-1 Widget - EXACT reference format * Reference: lines 300+ in json-example.md */ transformText1Widget(widget, baseElement, metadata) { return { ...baseElement, content_title: null, padding_top: 35, padding_bottom: 35, background_color: "#FFFFFF", text: widget.content.text || widget.content.title || '<p>Conteúdo educacional</p>', dam_assets: [] }; } /** * quiz-1 Widget - EXACT reference format * Reference: lines 1224-1597 in json-example.md */ transformQuiz1Widget(widget, baseElement, metadata) { const questions = widget.content.questions || []; return { ...baseElement, content_title: null, padding_top: 35, padding_bottom: 35, background_color: "#FFFFFF", primary_color: "#2d7b45", remake: "enable", max_attempts: widget.content.max_attempts || 1, utilization: { enabled: false, percentage: null }, feedback: { type: "default" }, questions: questions.map((q, index) => ({ id: this.generateUUID(), question: `<p><span style="font-size: 18px;">${q.question}</span></p>`, image: null, video: null, answered: false, feedback_default: { text: null, image: null, video: null, media_max_width: null }, feedback_correct: { text: null, image: null, video: null, media_max_width: null }, feedback_incorrect: { text: null, image: null, video: null, media_max_width: null }, no_correct_answer: false, no_feedback: false, choices: (q.options || q.answers || []).map((option, optIndex) => ({ id: this.generateUUID(), correct: optIndex === (q.correct_option || q.correct_answer || 0), text: `<p><span style="font-size: 15px;">${typeof option === 'string' ? option : option.text}</span></p>` })) })), dam_assets: [] }; } /** * flashcards-1 Widget - EXACT reference format * Reference: lines 922-944 in json-example.md */ transformFlashcards1Widget(widget, baseElement, metadata) { const items = widget.content.flashcards_items || widget.content.items || []; return { ...baseElement, content_title: null, padding_top: 35, padding_bottom: 35, card_height: 240, card_width: 240, background_color: "#FFFFFF", border_color: "#00643e", items: items.map(item => ({ id: this.generateUUID(), front_card: { text: item.question || item.front, centered_image: null, fullscreen_image: null }, back_card: { text: item.answer || item.back, centered_image: null, fullscreen_image: null }, opened: false })), dam_assets: [] }; } /** * image-1 Widget - EXACT reference format */ transformImage1Widget(widget, baseElement, metadata) { return { ...baseElement, content_title: null, padding_top: 20, padding_bottom: 20, image: widget.content.image || "https://images.unsplash.com/photo-1516321318423-f06f85e504b3?w=800", image_max_width: 760, caption: widget.content.caption ? `<p>${widget.content.caption}</p>` : null, dam_assets: [] }; } /** * list-1 Widget - EXACT reference format * CRITICAL: Uses 'items' array with specific structure */ transformList1Widget(widget, baseElement, metadata) { const listItems = widget.content.items || []; return { ...baseElement, content_title: "Lista", padding_top: 35, padding_bottom: 35, background_color: "#FFFFFF", primary_color: "#297C43", secondary_color: "#FFFFFF", items: listItems.map(item => ({ id: this.generateUUID(), text: `<p>${typeof item === 'string' ? item : item.text}</p>`, image: null, video: null })), dam_assets: [] }; } /** * Generate UUID for widgets */ generateUUID() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { const r = Math.random() * 16 | 0; const v = c === 'x' ? r : (r & 0x3 | 0x8); return v.toString(16); }); } /** * Log transformation for debugging */ logTransformation(step, type, message) { this.transformationLog.push({ step: step, type: type, message: message, timestamp: new Date().toISOString() }); } } export function createComposerFormatter() { return new ComposerFormatterFixed(); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/rkm097git/euconquisto-composer-mcp-poc'

If you have feedback or need assistance with the MCP directory API, please join our Discord server