feat(docs): add docs and restructure

This commit is contained in:
BennyKok
2023-12-28 00:06:32 +08:00
parent afc67bc0b9
commit 498374195d
56 changed files with 3751 additions and 54 deletions
@@ -0,0 +1,44 @@
import { parseDataSafe } from "../../../../lib/parseDataSafe";
import { handleResourceUpload } from "@/server/resource";
import { NextResponse } from "next/server";
import { z } from "zod";
const Request = z.object({
file_name: z.string(),
run_id: z.string(),
type: z.string(),
});
export const dynamic = "force-dynamic";
export async function GET(request: Request) {
const [data, error] = await parseDataSafe(Request, request);
if (!data || error) return error;
const { file_name, run_id, type } = data;
try {
const uploadUrl = await handleResourceUpload({
resourceBucket: process.env.SPACES_BUCKET,
resourceId: `outputs/runs/${run_id}/${file_name}`,
resourceType: type,
isPublic: true,
});
return NextResponse.json(
{
url: uploadUrl,
},
{ status: 200 }
);
} catch (error: unknown) {
const errorMessage =
error instanceof Error ? error.message : "Unknown error";
return NextResponse.json(
{
error: errorMessage,
},
{ status: 500 }
);
}
}
+119
View File
@@ -0,0 +1,119 @@
import { parseDataSafe } from "../../../../lib/parseDataSafe";
import { createRun } from "../../../../server/createRun";
import { db } from "@/db/db";
import { deploymentsTable } from "@/db/schema";
import { isKeyRevoked } from "@/server/curdApiKeys";
import { getRunsData } from "@/server/getRunsOutput";
import { parseJWT } from "@/server/parseJWT";
import { replaceCDNUrl } from "@/server/replaceCDNUrl";
import { eq } from "drizzle-orm";
import { NextResponse } from "next/server";
import { z } from "zod";
const Request = z.object({
deployment_id: z.string(),
inputs: z.record(z.string()).optional(),
});
const Request2 = z.object({
run_id: z.string(),
});
async function checkToken(request: Request) {
const token = request.headers.get("Authorization")?.split(" ")?.[1]; // Assuming token is sent as "Bearer your_token"
const userData = token ? parseJWT(token) : undefined;
if (!userData || token === undefined) {
return new NextResponse("Invalid or expired token", {
status: 401,
});
} else {
const revokedKey = await isKeyRevoked(token);
if (revokedKey)
return new NextResponse("Revoked token", {
status: 401,
});
}
}
export async function GET(request: Request) {
const invalidRequest = await checkToken(request);
if (invalidRequest) return invalidRequest;
const [data, error] = await parseDataSafe(Request2, request);
if (!data || error) return error;
const run = await getRunsData(data.run_id);
if (run?.status === "success" && run?.outputs?.length > 0) {
for (let i = 0; i < run.outputs.length; i++) {
const output = run.outputs[i];
if (output.data?.images !== undefined) {
for (let j = 0; j < output.data?.images.length; j++) {
const element = output.data?.images[j];
element.url = replaceCDNUrl(
`${process.env.SPACES_ENDPOINT}/${process.env.SPACES_BUCKET}/outputs/runs/${run.id}/${element.filename}`
);
}
} else if (output.data?.files !== undefined) {
for (let j = 0; j < output.data?.files.length; j++) {
const element = output.data?.files[j];
element.url = replaceCDNUrl(
`${process.env.SPACES_ENDPOINT}/${process.env.SPACES_BUCKET}/outputs/runs/${run.id}/${element.filename}`
);
}
}
}
}
return NextResponse.json(run, {
status: 200,
});
}
export async function POST(request: Request) {
const invalidRequest = await checkToken(request);
if (invalidRequest) return invalidRequest;
const [data, error] = await parseDataSafe(Request, request);
if (!data || error) return error;
const origin = new URL(request.url).origin;
const { deployment_id, inputs } = data;
try {
const deploymentData = await db.query.deploymentsTable.findFirst({
where: eq(deploymentsTable.id, deployment_id),
});
if (!deploymentData) throw new Error("Deployment not found");
const run_id = await createRun(
origin,
deploymentData.workflow_version_id,
deploymentData.machine_id,
inputs
);
if ("error" in run_id) throw new Error(run_id.error);
return NextResponse.json(
{
run_id: "workflow_run_id" in run_id ? run_id.workflow_run_id : "",
},
{
status: 200,
}
);
} catch (error: any) {
return NextResponse.json(
{
error: error.message,
},
{
status: 500,
}
);
}
}
+56
View File
@@ -0,0 +1,56 @@
import { parseDataSafe } from "../../../../lib/parseDataSafe";
import { db } from "@/db/db";
import { workflowRunOutputs, workflowRunsTable } from "@/db/schema";
import { eq } from "drizzle-orm";
import { NextResponse } from "next/server";
import { z } from "zod";
const Request = z.object({
run_id: z.string(),
status: z
.enum(["not-started", "running", "uploading", "success", "failed"])
.optional(),
output_data: z.any().optional(),
});
export async function POST(request: Request) {
const [data, error] = await parseDataSafe(Request, request);
if (!data || error) return error;
const { run_id, status, output_data } = data;
// console.log(run_id, status, output_data);
if (output_data) {
const workflow_run_output = await db.insert(workflowRunOutputs).values({
run_id: run_id,
data: output_data,
});
} else if (status) {
// console.log("status", status);
const workflow_run = await db
.update(workflowRunsTable)
.set({
status: status,
ended_at:
status === "success" || status === "failed" ? new Date() : null,
})
.where(eq(workflowRunsTable.id, run_id))
.returning();
}
// const workflow_version = await db.query.workflowVersionTable.findFirst({
// where: eq(workflowRunsTable.id, workflow_run[0].workflow_version_id),
// });
// revalidatePath(`./${workflow_version?.workflow_id}`);
return NextResponse.json(
{
message: "success",
},
{
status: 200,
}
);
}
+150
View File
@@ -0,0 +1,150 @@
import { parseJWT } from "../../../../server/parseJWT";
import { db } from "@/db/db";
import {
workflowAPIType,
workflowTable,
workflowType,
workflowVersionTable,
} from "@/db/schema";
import { parseDataSafe } from "@/lib/parseDataSafe";
import { sql } from "drizzle-orm";
import { NextResponse } from "next/server";
import { z } from "zod";
const corsHeaders = {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
};
const UploadRequest = z.object({
// user_id: z.string(),
workflow_id: z.string().optional(),
workflow_name: z.string().optional(),
workflow: workflowType,
workflow_api: workflowAPIType,
});
export async function OPTIONS(request: Request) {
return new Response(null, {
status: 204,
headers: {
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS",
"Access-Control-Allow-Headers": "Content-Type, Authorization",
},
});
}
export async function POST(request: Request) {
const token = request.headers.get("Authorization")?.split(" ")?.[1]; // Assuming token is sent as "Bearer your_token"
const userData = token ? parseJWT(token) : undefined;
if (!userData) {
return new NextResponse("Invalid or expired token", {
status: 401,
headers: corsHeaders,
});
}
const { user_id, org_id } = userData;
if (!user_id) return new NextResponse("Invalid user_id", { status: 401 });
const [data, error] = await parseDataSafe(
UploadRequest,
request,
corsHeaders
);
if (!data || error) return error;
const {
// user_id,
workflow,
workflow_api,
workflow_id: _workflow_id,
workflow_name,
} = data;
let workflow_id = _workflow_id;
let version = -1;
// Case 1 new workflow
try {
if ((!workflow_id || workflow_id.length == 0) && workflow_name) {
// Create a new parent workflow
const workflow_parent = await db
.insert(workflowTable)
.values({
user_id,
name: workflow_name,
})
.returning();
workflow_id = workflow_parent[0].id;
// Create a new version
const data = await db
.insert(workflowVersionTable)
.values({
workflow_id: workflow_id,
workflow,
workflow_api,
version: 1,
})
.returning();
version = data[0].version;
} else if (workflow_id) {
// Case 2 update workflow
const data = await db
.insert(workflowVersionTable)
.values({
workflow_id,
workflow: workflow,
workflow_api,
// version: sql`${workflowVersionTable.version} + 1`,
version: sql`(
SELECT COALESCE(MAX(version), 0) + 1
FROM ${workflowVersionTable}
WHERE workflow_id = ${workflow_id}
)`,
})
.returning();
version = data[0].version;
} else {
return NextResponse.json(
{
error: "Invalid request, missing either workflow_id or name",
},
{
status: 500,
statusText: "Invalid request",
headers: corsHeaders,
}
);
}
} catch (error: any) {
return NextResponse.json(
{
error: error.toString(),
},
{
status: 500,
statusText: "Invalid request",
headers: corsHeaders,
}
);
}
return NextResponse.json(
{
workflow_id: workflow_id,
version: version,
},
{
status: 200,
headers: corsHeaders,
}
);
}
+8
View File
@@ -0,0 +1,8 @@
import { getFileDownloadUrl } from "../../../../server/getFileDownloadUrl";
import { NextResponse, type NextRequest } from "next/server";
export async function GET(request: NextRequest) {
const file = new URL(request.url).searchParams.get("file");
if (!file) return NextResponse.redirect("/");
return NextResponse.redirect(await getFileDownloadUrl(file));
}