48 lines
1.8 KiB
JavaScript
48 lines
1.8 KiB
JavaScript
const PURPOSES = new Set(['inline_image', 'hero', 'card_cover', 'feed_cover']);
|
|
|
|
export function attachMindSpaceImageGenerationRoutes(router, { getService } = {}) {
|
|
router.post('/mindspace/v1/images/generate', async (req, res) => {
|
|
const service = getService?.();
|
|
if (!service) {
|
|
return res.status(503).json({
|
|
ok: false,
|
|
fallback: true,
|
|
code: 'runtime_unavailable',
|
|
message: '图片生成服务未配置',
|
|
});
|
|
}
|
|
const purpose = String(req.body?.purpose ?? '').trim().toLowerCase();
|
|
const prompt = String(req.body?.prompt ?? '').trim();
|
|
if (!PURPOSES.has(purpose)) {
|
|
return res.status(400).json({ message: '不支持的图片生成用途' });
|
|
}
|
|
if (!prompt || prompt.length > 1600) {
|
|
return res.status(400).json({ message: '图片描述不能为空且不能超过 1600 字符' });
|
|
}
|
|
const headerIdempotencyKey = String(req.get('idempotency-key') ?? '').trim();
|
|
const bodyIdempotencyKey = String(req.body?.idempotency_key ?? '').trim();
|
|
const idempotencyKey = headerIdempotencyKey || bodyIdempotencyKey || undefined;
|
|
if (idempotencyKey && idempotencyKey.length > 128) {
|
|
return res.status(400).json({ message: '幂等键不能超过 128 字符' });
|
|
}
|
|
const result = await service.generate({
|
|
userId: req.currentUser.id,
|
|
purpose,
|
|
prompt,
|
|
negativePrompt: req.body?.negative_prompt,
|
|
consumerRef: `mindspace:${req.requestId ?? 'request'}:${purpose}`,
|
|
idempotencyKey,
|
|
});
|
|
if (!result.ok) {
|
|
const unavailable = new Set([
|
|
'runtime_unavailable',
|
|
'image_make_unavailable',
|
|
'IMAGE_MAKE_HTTP_ERROR',
|
|
'IMAGE_MAKE_TIMEOUT',
|
|
]).has(result.code);
|
|
return res.status(unavailable ? 503 : 409).json(result);
|
|
}
|
|
return res.status(201).json({ data: result });
|
|
});
|
|
}
|