Files
openmaic/OpenMAIC/tests/bundle/fixtures.ts
2026-08-16 14:58:47 +08:00

198 lines
5.1 KiB
TypeScript

// Shared fixtures for the frozen-bundle tests: a small but realistic courseware
// (slide + quiz + interactive scenes, one agent, narration audio, media) and a
// helper that packages it with the production packager.
import type { GeneratedAgentConfig, Scene, Stage } from '@/lib/types/stage';
import type { MediaFileRecord } from '@/lib/utils/database';
import { packageCourseware } from '@/lib/bundle/packager';
export const AGENT: GeneratedAgentConfig = {
id: 'agent-1',
name: '苏老师',
role: 'teacher',
persona: '耐心、循循善诱的生物学老师',
avatar: '',
color: '#4caf50',
priority: 1,
};
export function textElement(content: string): unknown {
return {
type: 'text',
content,
id: `el-${content.length}`,
left: 0,
top: 0,
width: 100,
height: 20,
rotate: 0,
defaultFontName: 'sans-serif',
defaultColor: '#000',
};
}
export function slideScene(id: string, order: number, title: string): Scene {
return {
id,
stageId: 'cw-1',
title,
order,
content: {
type: 'slide',
canvas: {
id: `canvas-${id}`,
viewportSize: 100,
viewportRatio: 1.6,
theme: { color: '#fff', backgroundColor: '#000', fontName: 'sans-serif' },
elements: [
textElement('<h1>光合作用</h1>'),
textElement('<p>叶绿体是光合作用的场所。</p>'),
],
},
},
actions: [
{
id: `act-${id}`,
type: 'speech',
text: '今天我们来学习光合作用。',
audioId: 'aud-1',
voice: 'v1',
},
],
} as unknown as Scene;
}
export function quizScene(id: string, order: number, title: string): Scene {
return {
id,
stageId: 'cw-1',
title,
order,
content: {
type: 'quiz',
questions: [
{
id: 'q1',
type: 'single',
question: '光合作用发生在细胞的哪个结构?',
options: [
{ label: '线粒体', value: 'A' },
{ label: '叶绿体', value: 'B' },
{ label: '细胞核', value: 'C' },
],
answer: ['B'],
analysis: '叶绿体是光合作用的场所。',
hasAnswer: true,
points: 1,
},
{
id: 'q2',
type: 'short_answer',
question: '简述光合作用的意义。',
commentPrompt: '围绕能量转换和氧气生成作答',
hasAnswer: false,
points: 2,
},
],
},
} as unknown as Scene;
}
export function interactiveScene(id: string, order: number, title: string): Scene {
return {
id,
stageId: 'cw-1',
title,
order,
content: {
type: 'interactive',
html: '<div id="app">虚拟光合实验</div><script>window.__secret = 1;</script>',
},
} as unknown as Scene;
}
export function makeStage(): Stage {
return {
id: 'cw-1',
name: '示例课件:光合作用',
description: '面向初中生的光合作用入门课',
createdAt: 1700000000000,
updatedAt: 1700000000001,
languageDirective: 'zh-CN',
style: 'light',
generatedAgentConfigs: [AGENT],
} as Stage;
}
export function makeScenes(): Scene[] {
return [
slideScene('sc-1', 1, '光合作用概述'),
quizScene('sc-2', 2, '小测验'),
interactiveScene('sc-3', 3, '模拟实验'),
];
}
export function mediaRecord(
id: string,
type: 'image' | 'video',
mimeType: string,
withPoster = false,
): MediaFileRecord {
return {
id,
stageId: 'cw-1',
type,
blob: new Blob([new Uint8Array([1, 2, 3])], { type: mimeType }),
mimeType,
size: 3,
prompt: '一张叶绿体示意图',
params: '{}',
...(withPoster
? { poster: new Blob([new Uint8Array([9, 8, 7])], { type: 'image/jpeg' }) }
: {}),
createdAt: 1700000000000,
} as MediaFileRecord;
}
export const AUDIO_BYTES = new Blob([new Uint8Array([4, 5, 6])], { type: 'audio/mpeg' });
export const FIXED_PUBLISHED_AT = '2026-08-15T00:00:00.000Z';
export interface PackageSampleOptions {
coursewareId?: string;
version?: number;
withMedia?: boolean;
missingAudio?: boolean;
requireComplete?: boolean;
}
/** Package the standard fixture courseware with the production packager. */
export function packageSampleBundle(options: PackageSampleOptions = {}) {
const {
coursewareId = 'cw-1',
version = 1,
withMedia = true,
missingAudio = false,
requireComplete = false,
} = options;
return packageCourseware({
coursewareId,
version,
stage: makeStage(),
scenes: makeScenes(),
mediaRecords: withMedia
? [mediaRecord('cw-1:img-1', 'image', 'image/png'), mediaRecord('cw-1:vid-1', 'video', 'video/mp4', true)]
: [],
resolveAudioBytes: missingAudio
? async () => null
: async (audioId) => (audioId === 'aud-1' ? AUDIO_BYTES : null),
resolveMediaBytes: async (record) =>
record.id.includes('img')
? new Blob([new Uint8Array([7, 7, 7])], { type: 'image/png' })
: new Blob([new Uint8Array([8, 8, 8])], { type: 'video/mp4' }),
publishedAt: FIXED_PUBLISHED_AT,
appVersion: 'test',
requireComplete,
});
}