Files
openmaic/OpenMAIC/scripts/generation-node-smoke.mjs
2026-08-16 14:58:47 +08:00

110 lines
3.4 KiB
JavaScript

#!/usr/bin/env node
import {
buildCompleteScene,
generateSceneActions,
generateSceneContent,
generateSceneOutlinesFromRequirements,
} from '@openmaic/generation';
import { validateScene } from '@openmaic/dsl';
function parseFlags(argv) {
const values = new Map();
for (let index = 0; index < argv.length; index += 2) {
const flag = argv[index];
const value = argv[index + 1];
if (!flag?.startsWith('--') || value === undefined || value.startsWith('--')) {
throw new Error(`Expected a value after ${flag ?? 'the final flag'}`);
}
if (!['--requirement', '--endpoint', '--model', '--api-key'].includes(flag)) {
throw new Error(`Unknown flag: ${flag}`);
}
values.set(flag, value);
}
for (const required of ['--requirement', '--endpoint', '--model']) {
if (!values.get(required)) throw new Error(`Missing required flag: ${required}`);
}
return values;
}
const flags = parseFlags(process.argv.slice(2));
const endpoint = flags.get('--endpoint').replace(/\/+$/, '');
const model = flags.get('--model');
const apiKey = flags.get('--api-key');
const logger = {
debug: () => undefined,
info: () => undefined,
warn: (...args) => console.warn(...args),
error: (...args) => console.error(...args),
};
const aiCall = async (systemPrompt, userPrompt) => {
const headers = { 'content-type': 'application/json' };
if (apiKey) headers.authorization = `Bearer ${apiKey}`;
const response = await fetch(`${endpoint}/chat/completions`, {
method: 'POST',
headers,
body: JSON.stringify({
model,
messages: [
{ role: 'system', content: systemPrompt },
{ role: 'user', content: userPrompt },
],
}),
});
if (!response.ok) {
throw new Error(`Model endpoint returned ${response.status}: ${await response.text()}`);
}
const payload = await response.json();
const content = payload?.choices?.[0]?.message?.content;
if (typeof content !== 'string') {
throw new Error('Model endpoint response did not contain choices[0].message.content');
}
return content;
};
const result = await generateSceneOutlinesFromRequirements(
{ requirement: flags.get('--requirement') },
undefined,
undefined,
aiCall,
{ logger },
);
if (!result.success || !result.data) {
throw new Error(result.error || 'Outline generation failed');
}
if (result.data.outlines.length === 0) {
throw new Error('Outline generation returned no outlines');
}
for (const outline of result.data.outlines) {
if (!outline.title || !outline.type) {
throw new Error('Outline generation returned an outline without a title or type');
}
}
const slideOutline = result.data.outlines.find((outline) => outline.type === 'slide');
if (!slideOutline) throw new Error('Outline generation returned no slide outline');
const content = await generateSceneContent(slideOutline, aiCall, { logger });
if (!content || !('elements' in content)) {
throw new Error('Slide content generation failed');
}
const actions = await generateSceneActions(slideOutline, content, aiCall, { logger });
const scene = buildCompleteScene(slideOutline, content, actions, 'node-smoke-stage', {
sceneId: 'node-smoke-scene',
});
if (!scene) throw new Error('Slide scene assembly failed');
const sceneValidation = validateScene(scene);
if (!sceneValidation.valid) {
throw new Error(
`Generated scene failed DSL validation: ${JSON.stringify(sceneValidation.errors)}`,
);
}
console.log(JSON.stringify({ ...result.data, scene, sceneValidation }, null, 2));