162 lines
4.6 KiB
TypeScript
162 lines
4.6 KiB
TypeScript
import { type NextRequest, NextResponse } from "next/server";
|
|
import { auth } from "@/app/(auth)/auth";
|
|
import {
|
|
AGENT_PSD_RENDER_TASK_POLL_AFTER_MS,
|
|
agentPsdTemplateRenderRequestSchema,
|
|
} from "@/lib/agents/psd-render-task-contract";
|
|
import {
|
|
createAgentPsdRenderTask,
|
|
enqueueAgentPsdRenderTask,
|
|
getAgentPsdRenderTaskForUser,
|
|
} from "@/lib/agents/psd-render-task-queue";
|
|
import { describeRemoteAssetLocation } from "@/lib/agents/psd-remote-asset";
|
|
import {
|
|
type AgentPsdTemplateRenderResponse,
|
|
type AgentPsdTemplateRenderStatus,
|
|
} from "@/lib/agents/psd-template-config";
|
|
import {
|
|
getFriendlyRateLimitMessage,
|
|
getUserFacingRequestErrorMessage,
|
|
isRateLimitError,
|
|
} from "@/lib/request-error";
|
|
|
|
export const runtime = "nodejs";
|
|
|
|
function jsonError(status: number, error: string) {
|
|
const payload: AgentPsdTemplateRenderResponse = {
|
|
success: false,
|
|
error,
|
|
};
|
|
return NextResponse.json(payload, { status });
|
|
}
|
|
|
|
function normalizeTaskStatus(
|
|
status: string
|
|
): Extract<AgentPsdTemplateRenderStatus, "pending" | "running"> {
|
|
return status === "running" ? "running" : "pending";
|
|
}
|
|
|
|
export async function GET(request: NextRequest) {
|
|
const session = await auth().catch(() => null);
|
|
if (!session?.user?.id) {
|
|
return jsonError(401, "未登录");
|
|
}
|
|
|
|
const { searchParams } = new URL(request.url);
|
|
const taskId = String(searchParams.get("taskId") || "").trim();
|
|
if (!taskId) {
|
|
return jsonError(400, "缺少 taskId 参数");
|
|
}
|
|
|
|
try {
|
|
const task = await getAgentPsdRenderTaskForUser({
|
|
taskId,
|
|
userId: session.user.id,
|
|
});
|
|
if (!task) {
|
|
return jsonError(404, "导出任务不存在");
|
|
}
|
|
|
|
if (task.status === "succeeded") {
|
|
const result = task.result as AgentPsdTemplateRenderResponse["result"] | null;
|
|
if (!result?.url) {
|
|
return NextResponse.json(
|
|
{
|
|
success: false,
|
|
status: "failed",
|
|
taskId: task.id,
|
|
error: "导出任务已完成,但未返回结果图",
|
|
} satisfies AgentPsdTemplateRenderResponse
|
|
);
|
|
}
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
status: "succeeded",
|
|
taskId: task.id,
|
|
result,
|
|
} satisfies AgentPsdTemplateRenderResponse);
|
|
}
|
|
|
|
if (task.status === "failed") {
|
|
return NextResponse.json({
|
|
success: false,
|
|
status: "failed",
|
|
taskId: task.id,
|
|
error: task.error || "PSD 模板渲染失败",
|
|
} satisfies AgentPsdTemplateRenderResponse);
|
|
}
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
processing: true,
|
|
status: normalizeTaskStatus(task.status),
|
|
taskId: task.id,
|
|
pollAfterMs: AGENT_PSD_RENDER_TASK_POLL_AFTER_MS,
|
|
} satisfies AgentPsdTemplateRenderResponse);
|
|
} catch (error) {
|
|
console.error("[PSD Templates] render status failed:", { taskId, error });
|
|
return jsonError(500, "查询 PSD 导出任务失败");
|
|
}
|
|
}
|
|
|
|
export async function POST(request: NextRequest) {
|
|
const session = await auth().catch(() => null);
|
|
if (!session?.user?.id) {
|
|
return jsonError(401, "未登录");
|
|
}
|
|
|
|
let body: ReturnType<typeof agentPsdTemplateRenderRequestSchema.parse>;
|
|
try {
|
|
body = agentPsdTemplateRenderRequestSchema.parse(await request.json());
|
|
} catch {
|
|
return jsonError(400, "渲染参数不合法");
|
|
}
|
|
|
|
try {
|
|
const task = await createAgentPsdRenderTask({
|
|
userId: session.user.id,
|
|
request: body,
|
|
});
|
|
await enqueueAgentPsdRenderTask(task.id);
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
processing: true,
|
|
status: normalizeTaskStatus(task.status),
|
|
taskId: task.id,
|
|
pollAfterMs: AGENT_PSD_RENDER_TASK_POLL_AFTER_MS,
|
|
} satisfies AgentPsdTemplateRenderResponse);
|
|
} catch (error) {
|
|
console.error("[PSD Templates] render failed:", {
|
|
templateId: body.templateId,
|
|
sourceImage: body.sourceImageUrl
|
|
? describeRemoteAssetLocation(body.sourceImageUrl)
|
|
: null,
|
|
assignedImageCount: Object.keys(body.imageAssignments || {}).length,
|
|
error,
|
|
});
|
|
|
|
if (isRateLimitError(error)) {
|
|
return NextResponse.json(
|
|
{
|
|
success: false,
|
|
error: getFriendlyRateLimitMessage("当前操作过于频繁,请稍后再试"),
|
|
} satisfies AgentPsdTemplateRenderResponse,
|
|
{
|
|
status: 429,
|
|
headers: {
|
|
"Retry-After": "10",
|
|
},
|
|
}
|
|
);
|
|
}
|
|
|
|
const message =
|
|
getUserFacingRequestErrorMessage(error, "PSD 模板渲染失败", {
|
|
rateLimitMessage: getFriendlyRateLimitMessage("当前操作过于频繁,请稍后再试"),
|
|
});
|
|
return jsonError(502, message);
|
|
}
|
|
}
|