93 lines
3.3 KiB
TypeScript
93 lines
3.3 KiB
TypeScript
import { NextResponse } from 'next/server';
|
|
import { startGenerationLock } from '@/lib/generationLocks';
|
|
import { generateAssetPack } from '@/lib/packGenerator';
|
|
import { detectProvider } from '@/lib/providers';
|
|
import { loadSession, saveSession } from '@/lib/storage';
|
|
import type { AssetPack, GeneratePackRequest, GeneratePackResponse, GenSession, PackKind } from '@/lib/types';
|
|
|
|
export const runtime = 'nodejs';
|
|
export const dynamic = 'force-dynamic';
|
|
|
|
const PACK_KINDS: PackKind[] = ['patent', 'accessories', 'production', 'marketing'];
|
|
|
|
async function persistPackProgress(session: GenSession, imageId: string, pack: AssetPack) {
|
|
session.characterSpec = pack.characterSpec;
|
|
session.packs = [
|
|
...(session.packs ?? []).filter(existing => !(existing.kind === pack.kind && existing.sourceImageId === imageId)),
|
|
{ ...pack, assets: [...pack.assets] },
|
|
];
|
|
await saveSession(session);
|
|
}
|
|
|
|
export async function POST(req: Request) {
|
|
const { sessionId, imageId, kind, background = false } = (await req.json()) as GeneratePackRequest;
|
|
if (!sessionId || !imageId || !PACK_KINDS.includes(kind)) {
|
|
return NextResponse.json({ error: 'sessionId, imageId and valid kind required' }, { status: 400 });
|
|
}
|
|
|
|
const session = await loadSession(sessionId);
|
|
if (!session) return NextResponse.json({ error: 'session not found' }, { status: 404 });
|
|
|
|
const sourceImage = session.images.find(image => image.id === imageId);
|
|
if (!sourceImage) return NextResponse.json({ error: 'image not found' }, { status: 404 });
|
|
if (sourceImage.status !== 'selected') {
|
|
return NextResponse.json({ error: 'image must be selected before generating packs' }, { status: 400 });
|
|
}
|
|
|
|
const baseSession = session;
|
|
const baseSourceImage = sourceImage;
|
|
const releaseLock = startGenerationLock(`pack:${sessionId}:${imageId}:${kind}`);
|
|
if (!releaseLock) {
|
|
return NextResponse.json({
|
|
ok: true,
|
|
background: true,
|
|
running: true,
|
|
kind,
|
|
provider: detectProvider(),
|
|
}, { status: 202 });
|
|
}
|
|
const release = releaseLock;
|
|
|
|
async function run() {
|
|
try {
|
|
const { pack, manifest, provider } = await generateAssetPack({
|
|
session: baseSession,
|
|
sourceImage: baseSourceImage,
|
|
kind,
|
|
onProgress: progressPack => persistPackProgress(baseSession, imageId, progressPack),
|
|
});
|
|
baseSession.characterSpec = pack.characterSpec;
|
|
baseSession.packs = [
|
|
...(baseSession.packs ?? []).filter(existing => !(existing.kind === kind && existing.sourceImageId === imageId)),
|
|
pack,
|
|
];
|
|
baseSession.exports = [
|
|
...(baseSession.exports ?? []).filter(existing => !(existing.packKind === kind && existing.source.sourceImageId === imageId)),
|
|
manifest,
|
|
];
|
|
await saveSession(baseSession);
|
|
return { pack, manifest, provider } satisfies GeneratePackResponse;
|
|
} finally {
|
|
release();
|
|
}
|
|
}
|
|
|
|
if (background) {
|
|
void run().catch(error => console.error(`[pack:${kind}] background generation failed`, error));
|
|
return NextResponse.json({
|
|
ok: true,
|
|
background: true,
|
|
kind,
|
|
provider: detectProvider(),
|
|
}, { status: 202 });
|
|
}
|
|
|
|
try {
|
|
const response = await run();
|
|
|
|
return NextResponse.json(response);
|
|
} catch (error) {
|
|
return NextResponse.json({ error: String(error) }, { status: 500 });
|
|
}
|
|
}
|