- Add canvas project and node database tables - Create canvas workspace with drag, resize, zoom and pan - Add ImageNode with background removal, enhance, extend, angle edit, scene fusion - Add VideoNode with playback controls - Add TextNode for text editing - Integrate AI image generation API (Gemini/Alibaba) - Implement viewport culling for performance optimization - Add canvas entry in top navigation bar
150 lines
4.2 KiB
TypeScript
150 lines
4.2 KiB
TypeScript
import { NextResponse } from "next/server";
|
||
import { auth } from "@/app/(auth)/auth";
|
||
import { getEnabledImageModels, getProviderById } from "@/lib/db/queries";
|
||
import { createGeminiImage } from "@/lib/ai/providers/gemini-image";
|
||
import { createAlibabaImage } from "@/lib/ai/providers/alibaba-image";
|
||
|
||
export const maxDuration = 120;
|
||
|
||
interface GenerateImageRequest {
|
||
prompt: string;
|
||
negativePrompt?: string;
|
||
model?: string; // 模型 ID
|
||
aspectRatio?: string; // 宽高比 "1:1", "16:9" 等
|
||
imageCount?: number; // 生成数量
|
||
referenceImage?: string; // 参考图片(用于图生图)
|
||
}
|
||
|
||
export async function POST(request: Request) {
|
||
try {
|
||
const session = await auth();
|
||
if (!session?.user?.id) {
|
||
return NextResponse.json(
|
||
{ success: false, error: "未登录" },
|
||
{ status: 401 }
|
||
);
|
||
}
|
||
|
||
const body: GenerateImageRequest = await request.json();
|
||
const { prompt, negativePrompt, model, aspectRatio = "1:1", imageCount = 1, referenceImage } = body;
|
||
|
||
if (!prompt) {
|
||
return NextResponse.json(
|
||
{ success: false, error: "请输入提示词" },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
// 获取可用的图片生成模型
|
||
const imageModels = await getEnabledImageModels();
|
||
|
||
if (!imageModels || imageModels.length === 0) {
|
||
return NextResponse.json(
|
||
{ success: false, error: "暂无可用的图片生成模型" },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
// 选择模型(如果指定了 model,使用指定的;否则使用默认的)
|
||
let selectedModel = model
|
||
? imageModels.find(m => m.model.modelId === model)
|
||
: imageModels.find(m => m.model.isDefault) || imageModels[0];
|
||
|
||
if (!selectedModel) {
|
||
selectedModel = imageModels[0];
|
||
}
|
||
|
||
const provider = await getProviderById(selectedModel.model.providerId);
|
||
if (!provider) {
|
||
return NextResponse.json(
|
||
{ success: false, error: "模型提供商配置错误" },
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
|
||
// 计算尺寸
|
||
const sizeMap: Record<string, { width: number; height: number }> = {
|
||
"1:1": { width: 1024, height: 1024 },
|
||
"3:2": { width: 1536, height: 1024 },
|
||
"2:3": { width: 1024, height: 1536 },
|
||
"4:3": { width: 1365, height: 1024 },
|
||
"3:4": { width: 1024, height: 1365 },
|
||
"16:9": { width: 1820, height: 1024 },
|
||
"9:16": { width: 1024, height: 1820 },
|
||
};
|
||
const size = sizeMap[aspectRatio] || sizeMap["1:1"];
|
||
|
||
// 构建消息
|
||
const messages = [
|
||
{
|
||
role: "user" as const,
|
||
content: prompt,
|
||
}
|
||
];
|
||
|
||
// 图片参数
|
||
const imageParams = {
|
||
aspectRatio,
|
||
imageSize: `${size.width}x${size.height}`,
|
||
imageCount,
|
||
negativePrompt,
|
||
};
|
||
|
||
let result;
|
||
|
||
// 根据提供商类型调用不同的生成器
|
||
if (provider.type === "gemini") {
|
||
const geminiProvider = createGeminiImage({
|
||
apiKey: provider.apiKey,
|
||
baseURL: provider.baseUrl,
|
||
});
|
||
|
||
result = await geminiProvider.doGenerate({
|
||
messages,
|
||
modelId: selectedModel.model.modelId,
|
||
imageParams,
|
||
});
|
||
} else if (provider.type === "alibaba-image") {
|
||
const alibabaProvider = createAlibabaImage({
|
||
apiKey: provider.apiKey,
|
||
baseURL: provider.baseUrl,
|
||
});
|
||
|
||
result = await alibabaProvider.doGenerate({
|
||
messages,
|
||
modelId: selectedModel.model.modelId,
|
||
imageParams,
|
||
referenceImage,
|
||
});
|
||
} else {
|
||
return NextResponse.json(
|
||
{ success: false, error: "不支持的图片生成模型类型" },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
if (result.images && result.images.length > 0) {
|
||
return NextResponse.json({
|
||
success: true,
|
||
data: {
|
||
images: result.images,
|
||
model: selectedModel.model.displayName,
|
||
prompt,
|
||
}
|
||
});
|
||
} else {
|
||
return NextResponse.json(
|
||
{ success: false, error: "图片生成失败" },
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
|
||
} catch (error) {
|
||
console.error("[Canvas Generate Image] Error:", error);
|
||
return NextResponse.json(
|
||
{ success: false, error: error instanceof Error ? error.message : "生成失败" },
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}
|