How the Two-Stage Generation Pipeline Works in OpenMAIC
OpenMAIC transforms raw educational content into interactive classrooms through a sequential two-stage generation pipeline that first produces structured lesson outlines and then constructs rich scenes with content and interactive actions.
The THU-MAIC/OpenMAIC repository implements this architecture to convert PDFs, PowerPoints, and text into AI-driven classroom experiences. Understanding this two-stage generation pipeline is essential for developers extending the platform or troubleshooting generation workflows.
Architecture Overview
The system processes instructional material through distinct phases that separate content planning from presentation design.
Stage 1: Outline Generation
In the first stage, the AI analyzes user inputs—whether text documents, PDFs, or presentations—and produces a structured lesson outline. This outline consists of ordered items that define the pedagogical flow of the lesson. This logic resides primarily in the @openmaic/generation package, which determines what content the lesson will cover.
Stage 2: Scene Construction
For each outline item, the system builds a rich scene through two sub-steps:
- Content generation - Creating slides, text, and media elements
- Action generation - Adding interactive quizzes, simulations, and PBL (Problem-Based Learning) tasks
The completed scene is then persisted to the workspace. This stage determines how each outline item will be presented to learners.
Pipeline Orchestration
The server-side module lib/server/classroom-generation.ts orchestrates the entire workflow. It manages the transition from outline creation to scene generation through a sequential loop:
// lib/server/classroom-generation.ts (excerpt)
for (const [index, safeOutline] of outlines.entries()) {
// 1️⃣ Generate scene content
const content = await generateSceneContent(...);
// 2️⃣ Generate scene actions
const actions = await generateSceneActions(...);
// 3️⃣ Persist the scene
const sceneId = createSceneWithActions(safeOutline, content, actions, api);
}
This orchestration ensures that each outline item is processed completely before moving to the next, while maintaining the ability to retry individual scenes independently.
Scene Generation Implementation
The heavy lifting of scene construction lives in lib/server/scene-generation.ts, specifically within the buildSceneFromOutline function. This function accepts an outline item and coordinates the content and action phases:
// lib/server/scene-generation.ts (excerpt)
export async function buildSceneFromOutline(
outline,
aiCall,
stageId,
assignedImages,
imageMapping,
languageModel,
visionEnabled,
ctx,
agents,
) {
const safeOutline = applyOutlineFallbacks(outline, !!languageModel, { logger });
const langText = buildLanguageText(languageDirective, safeOutline.languageNote);
// ── CONTENT PHASE ──
const content = await generateSceneContent(safeOutline, aiCall, { … });
if (!content) return null;
// ── ACTIONS PHASE ──
const actions = await generateSceneActions(safeOutline, content, aiCall, { … });
// Return a fully‑formed scene ready for persistence
return buildCompleteScene(safeOutline, content, actions, stageId);
}
The function applies fallbacks for missing data, generates language-specific text directives, and ensures that content creation succeeds before attempting action generation.
Design Rationale
The two-stage generation pipeline employs this architecture for three critical reasons:
- Modularity - Outline logic can be modified or replaced without affecting scene generation code, allowing independent iteration of pedagogical planning versus presentation design.
- Parallelism - Once the outline is finalized, individual scenes can be generated and retried independently. If one scene fails, the system can regenerate that specific item without rebuilding the entire classroom.
- Extensibility - Additional phases such as media generation (images, video) and text-to-speech (TTS) are appended after the core two stages without breaking the existing pipeline contract.
Practical Implementation Examples
Generating a Complete Classroom
To initiate the pipeline from application code, use the generateClassroom function:
import { generateClassroom } from '@/lib/server/classroom-generation';
// `input` contains the raw user material (PDF, text, etc.)
const result = await generateClassroom({
input,
stageId: 'stage-123',
onProgress: ({ step, progress }) =>
console.log(`🔄 ${step} – ${progress}%`),
});
console.log('✅ Classroom ready at', result.url);
Building Individual Scenes
For granular control over specific outline items, call buildSceneFromOutline directly:
import { buildSceneFromOutline } from '@/lib/server/scene-generation';
import { callLLM } from '@/lib/ai/llm';
const scene = await buildSceneFromOutline(
outlineItem, // a SceneOutline from the generated outline
callLLM, // LLM call wrapper
'stage-123', // current stage ID
pdfImages, // optional images extracted from PDFs
imageMapping, // optional mapping for those images
languageModel, // optional model for PBL loop fallback
);
if (scene) {
console.log('🖼️ Scene built:', scene.title);
}
Persisting Generated Scenes
After scene creation, persist the results using the StageAPI:
import { StageAPI } from '@/lib/api/stage-api';
import { createSceneWithActions } from '@/lib/server/scene-generation';
const sceneId = createSceneWithActions(
outline,
content,
actions,
StageAPI, // concrete API implementation
);
if (sceneId) {
console.log('💾 Scene stored with ID:', sceneId);
}
Summary
- The two-stage generation pipeline separates lesson planning (outline generation) from presentation building (scene generation) to create interactive OpenMAIC classrooms.
- Stage 1 produces structured lesson outlines via the
@openmaic/generationpackage, determining what content to teach. - Stage 2 constructs rich scenes through
buildSceneFromOutlineinlib/server/scene-generation.ts, first generating content then adding interactive actions. - The orchestration logic in
lib/server/classroom-generation.tsmanages the sequential processing of outline items into complete scenes. - This architecture provides modularity, supports independent retry logic, and allows extensibility for post-processing steps like media generation.
Frequently Asked Questions
What triggers the two-stage generation pipeline in OpenMAIC?
The pipeline initiates when a user uploads instructional material—such as PDF documents, PowerPoint presentations, or plain text—through the generateClassroom function. This function calls the outline generation service to analyze the input and produce the initial lesson structure before proceeding to scene construction.
How does OpenMAIC handle failures during scene generation?
The pipeline processes each outline item independently within a loop in lib/server/classroom-generation.ts. If generateSceneContent or generateSceneActions fails for a specific outline item, that scene can be retried without regenerating the entire classroom or other completed scenes, improving overall robustness.
Can the two stages of the pipeline operate independently?
While the stages are sequential—scene generation requires a completed outline—the architecture supports modularity that allows outline logic to evolve separately from scene construction. Additionally, once an outline exists, individual scenes can be regenerated or modified independently, enabling parallel processing capabilities for performance optimization.
Where is the scene content and action logic implemented?
The core scene building logic resides in lib/server/scene-generation.ts, specifically within the buildSceneFromOutline function. This module handles both the content phase (slides, text, media) and the actions phase (quizzes, simulations), while lib/server/classroom-generation.ts orchestrates the overall workflow and persistence layers.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →