123 lines
3.4 KiB
TypeScript
123 lines
3.4 KiB
TypeScript
import { randomUUID } from "node:crypto";
|
|
import { NextResponse } from "next/server";
|
|
import { auth } from "@/app/(auth)/auth";
|
|
import {
|
|
getKittyCadModelingCommandError,
|
|
isKittyCadModelingCommandSuccessful,
|
|
sendKittyCadModelingCommand,
|
|
takeKittyCadModelingSnapshot,
|
|
} from "@/lib/kittycad/modeling-session";
|
|
|
|
export const runtime = "nodejs";
|
|
export const maxDuration = 60;
|
|
|
|
type ModelingCommandRequest = {
|
|
captureSnapshot?: boolean;
|
|
cmd?: Record<string, unknown>;
|
|
cmdId?: string;
|
|
sessionId?: string;
|
|
snapshotFormat?: "jpeg" | "png";
|
|
};
|
|
|
|
function readOptionalRecord(value: unknown) {
|
|
return value && typeof value === "object" && !Array.isArray(value)
|
|
? (value as Record<string, unknown>)
|
|
: null;
|
|
}
|
|
|
|
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 = (await request.json()) as ModelingCommandRequest;
|
|
const sessionId = String(body.sessionId || "").trim();
|
|
if (!sessionId) {
|
|
return NextResponse.json(
|
|
{ success: false, error: "缺少官方建模会话 ID" },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
const cmd = readOptionalRecord(body.cmd);
|
|
const cmdType = String(cmd?.type || "").trim();
|
|
if (!cmd || !cmdType) {
|
|
return NextResponse.json(
|
|
{ success: false, error: "缺少有效的官方建模命令" },
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
const cmdId = String(body.cmdId || "").trim() || randomUUID();
|
|
const response = await sendKittyCadModelingCommand({
|
|
cmd: {
|
|
...cmd,
|
|
type: cmdType,
|
|
},
|
|
cmdId,
|
|
sessionId,
|
|
});
|
|
|
|
if (!isKittyCadModelingCommandSuccessful(response)) {
|
|
return NextResponse.json(
|
|
{
|
|
success: false,
|
|
error: getKittyCadModelingCommandError(response),
|
|
payload: response.errors || null,
|
|
},
|
|
{ status: 400 }
|
|
);
|
|
}
|
|
|
|
let snapshotUrl: string | null = null;
|
|
let snapshotError: string | null = null;
|
|
|
|
const shouldCaptureSnapshot =
|
|
body.captureSnapshot === true && cmdType !== "take_snapshot";
|
|
|
|
if (cmdType === "take_snapshot") {
|
|
const contents = String(response.resp?.data?.contents || "").trim();
|
|
const snapshotFormat = body.snapshotFormat || "png";
|
|
snapshotUrl = contents
|
|
? `data:${snapshotFormat === "jpeg" ? "image/jpeg" : "image/png"};base64,${contents}`
|
|
: null;
|
|
} else if (shouldCaptureSnapshot) {
|
|
try {
|
|
const snapshot = await takeKittyCadModelingSnapshot({
|
|
format: body.snapshotFormat || "png",
|
|
sessionId,
|
|
});
|
|
snapshotUrl = snapshot.snapshotUrl;
|
|
} catch (error) {
|
|
snapshotError =
|
|
error instanceof Error ? error.message : "获取官方建模快照失败";
|
|
}
|
|
}
|
|
|
|
return NextResponse.json({
|
|
success: true,
|
|
data: {
|
|
raw: response,
|
|
requestId: response.request_id || cmdId,
|
|
responseData: response.resp?.data || null,
|
|
responseType: response.resp?.type || cmdType,
|
|
snapshotError,
|
|
snapshotUrl,
|
|
},
|
|
});
|
|
} catch (error) {
|
|
return NextResponse.json(
|
|
{
|
|
success: false,
|
|
error: error instanceof Error ? error.message : "发送官方建模命令失败",
|
|
},
|
|
{ status: 500 }
|
|
);
|
|
}
|
|
}
|