104 lines
3.2 KiB
JavaScript
104 lines
3.2 KiB
JavaScript
#!/usr/bin/env node
|
|
|
|
import { createServer } from 'node:http';
|
|
|
|
function readPort(argv) {
|
|
if (argv.length !== 2 || argv[0] !== '--port' || !/^\d+$/.test(argv[1])) {
|
|
throw new Error('Usage: node generation-node-smoke-server.mjs --port <port>');
|
|
}
|
|
const port = Number(argv[1]);
|
|
if (port < 1 || port > 65_535) throw new Error(`Invalid port: ${argv[1]}`);
|
|
return port;
|
|
}
|
|
|
|
const port = readPort(process.argv.slice(2));
|
|
const outlinePayload = JSON.stringify({
|
|
languageDirective: 'Teach in English with concise explanations.',
|
|
courseTitle: 'Node Smoke Course',
|
|
outlines: [
|
|
{
|
|
id: 'scene_1',
|
|
type: 'slide',
|
|
title: 'Smoke-Test Outline',
|
|
description: 'Confirms outline generation through an OpenAI-compatible endpoint.',
|
|
keyPoints: ['Package import', 'HTTP model seam', 'Outline validation'],
|
|
order: 1,
|
|
},
|
|
],
|
|
});
|
|
|
|
const slideContentPayload = JSON.stringify({
|
|
elements: [
|
|
{
|
|
type: 'text',
|
|
left: 80,
|
|
top: 80,
|
|
width: 840,
|
|
height: 100,
|
|
content: 'Dependency injection keeps model routing outside the generation package.',
|
|
},
|
|
],
|
|
background: { type: 'solid', color: '#ffffff' },
|
|
remark: 'A deterministic slide generated by the bare-Node consumer smoke.',
|
|
});
|
|
|
|
const slideActionsPayload = JSON.stringify([
|
|
{
|
|
type: 'text',
|
|
content: 'Dependency injection lets the caller control the model while generation stays pure.',
|
|
},
|
|
]);
|
|
|
|
const server = createServer((request, response) => {
|
|
if (request.method === 'GET' && request.url === '/health') {
|
|
response.writeHead(200, { 'content-type': 'text/plain' });
|
|
response.end('ok');
|
|
return;
|
|
}
|
|
if (request.method !== 'POST' || request.url !== '/chat/completions') {
|
|
response.writeHead(404, { 'content-type': 'application/json' });
|
|
response.end(JSON.stringify({ error: 'not found' }));
|
|
return;
|
|
}
|
|
|
|
let body = '';
|
|
request.setEncoding('utf8');
|
|
request.on('data', (chunk) => {
|
|
body += chunk;
|
|
});
|
|
request.on('end', () => {
|
|
try {
|
|
const payload = JSON.parse(body);
|
|
if (!payload.model || !Array.isArray(payload.messages)) {
|
|
throw new Error('model and messages are required');
|
|
}
|
|
const system = payload.messages.find((message) => message.role === 'system')?.content;
|
|
const content =
|
|
typeof system === 'string' && system.startsWith('# Slide Content Generator')
|
|
? slideContentPayload
|
|
: typeof system === 'string' && system.startsWith('# Slide Action Generator')
|
|
? slideActionsPayload
|
|
: outlinePayload;
|
|
response.writeHead(200, { 'content-type': 'application/json' });
|
|
response.end(
|
|
JSON.stringify({
|
|
id: 'chatcmpl-generation-smoke',
|
|
object: 'chat.completion',
|
|
choices: [{ index: 0, message: { role: 'assistant', content } }],
|
|
}),
|
|
);
|
|
} catch (error) {
|
|
response.writeHead(400, { 'content-type': 'application/json' });
|
|
response.end(JSON.stringify({ error: String(error) }));
|
|
}
|
|
});
|
|
});
|
|
|
|
server.listen(port, '127.0.0.1', () => {
|
|
console.log(`Generation smoke server listening on http://127.0.0.1:${port}`);
|
|
});
|
|
|
|
const close = () => server.close(() => process.exit(0));
|
|
process.on('SIGINT', close);
|
|
process.on('SIGTERM', close);
|