rest
This commit is contained in:
@@ -33,7 +33,7 @@ CREATE TABLE IF NOT EXISTS "comfyui_deploy"."checkpoints" (
|
||||
"updated_at" timestamp DEFAULT now() NOT NULL
|
||||
);
|
||||
--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "comfyui_deploy"."checkpointVolumeTable" (
|
||||
CREATE TABLE IF NOT EXISTS "comfyui_deploy"."checkpoint_volume" (
|
||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||
"user_id" text,
|
||||
"org_id" text,
|
||||
@@ -56,7 +56,7 @@ EXCEPTION
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "comfyui_deploy"."checkpointVolumeTable" ADD CONSTRAINT "checkpointVolumeTable_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "comfyui_deploy"."users"("id") ON DELETE no action ON UPDATE no action;
|
||||
ALTER TABLE "comfyui_deploy"."checkpoint_volume" ADD CONSTRAINT "checkpoint_volume_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "comfyui_deploy"."users"("id") ON DELETE no action ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"id": "66dbc84a-6cd8-4692-9d24-fdcac227b23c",
|
||||
"id": "4d5b29d0-848f-4c2e-a2cd-2932f1fa38c6",
|
||||
"prevId": "db06ea66-92c2-4ebe-93c1-6cb8a90ccd8b",
|
||||
"version": "5",
|
||||
"dialect": "pg",
|
||||
@@ -250,8 +250,8 @@
|
||||
"compositePrimaryKeys": {},
|
||||
"uniqueConstraints": {}
|
||||
},
|
||||
"checkpointVolumeTable": {
|
||||
"name": "checkpointVolumeTable",
|
||||
"checkpoint_volume": {
|
||||
"name": "checkpoint_volume",
|
||||
"schema": "comfyui_deploy",
|
||||
"columns": {
|
||||
"id": {
|
||||
@@ -303,9 +303,9 @@
|
||||
},
|
||||
"indexes": {},
|
||||
"foreignKeys": {
|
||||
"checkpointVolumeTable_user_id_users_id_fk": {
|
||||
"name": "checkpointVolumeTable_user_id_users_id_fk",
|
||||
"tableFrom": "checkpointVolumeTable",
|
||||
"checkpoint_volume_user_id_users_id_fk": {
|
||||
"name": "checkpoint_volume_user_id_users_id_fk",
|
||||
"tableFrom": "checkpoint_volume",
|
||||
"tableTo": "users",
|
||||
"columnsFrom": [
|
||||
"user_id"
|
||||
|
||||
@@ -222,8 +222,8 @@
|
||||
{
|
||||
"idx": 31,
|
||||
"version": "5",
|
||||
"when": 1705963548821,
|
||||
"tag": "0031_common_deathbird",
|
||||
"when": 1705975916818,
|
||||
"tag": "0031_safe_multiple_man",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
|
||||
+10
-193
@@ -1,3 +1,4 @@
|
||||
import { CivitaiModelResponse } from "@/types/civitai";
|
||||
import { type InferSelectModel, relations } from "drizzle-orm";
|
||||
import {
|
||||
boolean,
|
||||
@@ -331,198 +332,9 @@ export const apiKeyTable = dbSchema.table("api_keys", {
|
||||
updated_at: timestamp("updated_at").defaultNow().notNull(),
|
||||
});
|
||||
|
||||
// const civitaiModelVersion = z.object({
|
||||
// id: z.number(),
|
||||
// modelId: z.number(),
|
||||
// name: z.string(),
|
||||
// createdAt: z.string(),
|
||||
// updatedAt: z.string(),
|
||||
// status: z.string(),
|
||||
// publishedAt: z.string(),
|
||||
// trainedWords: z.array(z.string()).optional(),
|
||||
// trainingStatus: z.string().optional(),
|
||||
// trainingDetails: z.string().optional(),
|
||||
// baseModel: z.string(),
|
||||
// baseModelType: z.string(),
|
||||
// earlyAccessTimeFrame: z.number(),
|
||||
// description: z.string().optional(),
|
||||
// vaeId: z.string().optional(),
|
||||
// stats: z.object({
|
||||
// downloadCount: z.number(),
|
||||
// ratingCount: z.number(),
|
||||
// rating: z.number(),
|
||||
// }),
|
||||
// files: z.array(z.object({
|
||||
// id: z.number(),
|
||||
// sizeKB: z.number(),
|
||||
// name: z.string(),
|
||||
// type: z.string(),
|
||||
// metadata: z.object({
|
||||
// fp: z.string(),
|
||||
// size: z.string(),
|
||||
// format: z.string(),
|
||||
// }),
|
||||
// pickleScanResult: z.string(),
|
||||
// pickleScanMessage: z.string().optional(),
|
||||
// virusScanResult: z.string(),
|
||||
// virusScanMessage: z.string().optional(),
|
||||
// scannedAt: z.string(),
|
||||
// hashes: z.object({
|
||||
// AutoV1: z.string(),
|
||||
// AutoV2: z.string(),
|
||||
// SHA256: z.string(),
|
||||
// CRC32: z.string(),
|
||||
// BLAKE3: z.string(),
|
||||
// AutoV3: z.string(),
|
||||
// }),
|
||||
// downloadUrl: z.string(),
|
||||
// primary: z.boolean(),
|
||||
// })),
|
||||
// images: z.array(z.object({
|
||||
// url: z.string(),
|
||||
// nsfw: z.string(),
|
||||
// width: z.number(),
|
||||
// height: z.number(),
|
||||
// hash: z.string(),
|
||||
// type: z.string(),
|
||||
// metadata: z.object({
|
||||
// hash: z.string(),
|
||||
// size: z.number(),
|
||||
// width: z.number(),
|
||||
// height: z.number(),
|
||||
// }),
|
||||
// meta: z.any(),
|
||||
// })),
|
||||
// downloadUrl: z.string(),
|
||||
// });
|
||||
//
|
||||
// const civitaiModelResponseType = z.object({
|
||||
// id: z.number(),
|
||||
// name: z.string(),
|
||||
// description: z.string().optional(),
|
||||
// type: z.string(),
|
||||
// poi: z.boolean(),
|
||||
// nsfw: z.boolean(),
|
||||
// allowNoCredit: z.boolean(),
|
||||
// allowCommercialUse: z.string(),
|
||||
// allowDerivatives: z.boolean(),
|
||||
// allowDifferentLicense: z.boolean(),
|
||||
// stats: z.object({
|
||||
// downloadCount: z.number(),
|
||||
// favoriteCount: z.number(),
|
||||
// commentCount: z.number(),
|
||||
// ratingCount: z.number(),
|
||||
// rating: z.number(),
|
||||
// tippedAmountCount: z.number(),
|
||||
// }),
|
||||
// creator: z.object({
|
||||
// username: z.string(),
|
||||
// image: z.string(),
|
||||
// }),
|
||||
// tags: z.array(z.string()),
|
||||
// modelVersions: z.array(civitaiModelVersion),
|
||||
// });
|
||||
|
||||
export const CivitaiModel = z.object({
|
||||
id: z.number(),
|
||||
name: z.string(),
|
||||
description: z.string(),
|
||||
type: z.string(),
|
||||
// poi: z.boolean(),
|
||||
// nsfw: z.boolean(),
|
||||
// allowNoCredit: z.boolean(),
|
||||
// allowCommercialUse: z.string(),
|
||||
// allowDerivatives: z.boolean(),
|
||||
// allowDifferentLicense: z.boolean(),
|
||||
// stats: z.object({
|
||||
// downloadCount: z.number(),
|
||||
// favoriteCount: z.number(),
|
||||
// commentCount: z.number(),
|
||||
// ratingCount: z.number(),
|
||||
// rating: z.number(),
|
||||
// tippedAmountCount: z.number(),
|
||||
// }),
|
||||
creator: z
|
||||
.object({
|
||||
username: z.string().nullable(),
|
||||
image: z.string().nullable().default(null),
|
||||
})
|
||||
.nullable(),
|
||||
tags: z.array(z.string()),
|
||||
modelVersions: z.array(
|
||||
z.object({
|
||||
id: z.number(),
|
||||
modelId: z.number(),
|
||||
name: z.string(),
|
||||
createdAt: z.string(),
|
||||
updatedAt: z.string(),
|
||||
status: z.string(),
|
||||
publishedAt: z.string(),
|
||||
trainedWords: z.array(z.unknown()),
|
||||
trainingStatus: z.string().nullable(),
|
||||
trainingDetails: z.string().nullable(),
|
||||
baseModel: z.string(),
|
||||
baseModelType: z.string().nullable(),
|
||||
earlyAccessTimeFrame: z.number(),
|
||||
description: z.string().nullable(),
|
||||
vaeId: z.number().nullable(),
|
||||
stats: z.object({
|
||||
downloadCount: z.number(),
|
||||
ratingCount: z.number(),
|
||||
rating: z.number(),
|
||||
}),
|
||||
files: z.array(
|
||||
z.object({
|
||||
id: z.number(),
|
||||
sizeKB: z.number(),
|
||||
name: z.string(),
|
||||
type: z.string(),
|
||||
// metadata: z.object({
|
||||
// fp: z.string().nullable().optional(),
|
||||
// size: z.string().nullable().optional(),
|
||||
// format: z.string().nullable().optional(),
|
||||
// }),
|
||||
// pickleScanResult: z.string(),
|
||||
// pickleScanMessage: z.string(),
|
||||
// virusScanResult: z.string(),
|
||||
// virusScanMessage: z.string().nullable(),
|
||||
// scannedAt: z.string(),
|
||||
// hashes: z.object({
|
||||
// AutoV1: z.string().nullable().optional(),
|
||||
// AutoV2: z.string().nullable().optional(),
|
||||
// SHA256: z.string().nullable().optional(),
|
||||
// CRC32: z.string().nullable().optional(),
|
||||
// BLAKE3: z.string().nullable().optional(),
|
||||
// }),
|
||||
downloadUrl: z.string(),
|
||||
// primary: z.boolean().default(false),
|
||||
}),
|
||||
),
|
||||
images: z.array(
|
||||
z.object({
|
||||
id: z.number(),
|
||||
url: z.string(),
|
||||
nsfw: z.string(),
|
||||
width: z.number(),
|
||||
height: z.number(),
|
||||
hash: z.string(),
|
||||
type: z.string(),
|
||||
metadata: z.object({
|
||||
hash: z.string(),
|
||||
width: z.number(),
|
||||
height: z.number(),
|
||||
}),
|
||||
meta: z.any(),
|
||||
}),
|
||||
),
|
||||
downloadUrl: z.string(),
|
||||
}),
|
||||
),
|
||||
});
|
||||
|
||||
export const resourceUpload = pgEnum("resource_upload", [
|
||||
"started",
|
||||
"failed",
|
||||
"error",
|
||||
"succeded",
|
||||
]);
|
||||
|
||||
@@ -552,7 +364,7 @@ export const checkpointTable = dbSchema.table("checkpoints", {
|
||||
civitai_url: text("civitai_url"),
|
||||
civitai_download_url: text("civitai_download_url"),
|
||||
civitai_model_response: jsonb("civitai_model_response").$type<
|
||||
z.infer<typeof CivitaiModel>
|
||||
z.infer<typeof CivitaiModelResponse>
|
||||
>(),
|
||||
|
||||
hf_url: text("hf_url"),
|
||||
@@ -563,6 +375,7 @@ export const checkpointTable = dbSchema.table("checkpoints", {
|
||||
status: resourceUpload("status").notNull().default("started"),
|
||||
upload_machine_id: text("upload_machine_id"),
|
||||
upload_type: modelUploadType("upload_type").notNull(),
|
||||
build_log: text("build_log"),
|
||||
|
||||
created_at: timestamp("created_at").defaultNow().notNull(),
|
||||
updated_at: timestamp("updated_at").defaultNow().notNull(),
|
||||
@@ -579,7 +392,7 @@ export const insertCivitaiCheckpointSchema = createInsertSchema(
|
||||
},
|
||||
);
|
||||
|
||||
export const checkpointVolumeTable = dbSchema.table("checkpointVolumeTable", {
|
||||
export const checkpointVolumeTable = dbSchema.table("checkpoint_volume", {
|
||||
id: uuid("id").primaryKey().defaultRandom().notNull(),
|
||||
user_id: text("user_id")
|
||||
.references(() => usersTable.id, {
|
||||
@@ -605,8 +418,12 @@ export const checkpointRelations = relations(checkpointTable, ({ one }) => ({
|
||||
|
||||
export const checkpointVolumeRelations = relations(
|
||||
checkpointVolumeTable,
|
||||
({ many }) => ({
|
||||
({ many, one }) => ({
|
||||
checkpoint: many(checkpointTable),
|
||||
user: one(usersTable, {
|
||||
fields: [checkpointVolumeTable.user_id],
|
||||
references: [usersTable.id],
|
||||
}),
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -4,9 +4,8 @@ import { auth } from "@clerk/nextjs";
|
||||
import {
|
||||
checkpointTable,
|
||||
CheckpointType,
|
||||
checkpointVolumeTable,
|
||||
volumeTable,
|
||||
CheckpointVolumeType,
|
||||
CivitaiModel,
|
||||
} from "@/db/schema";
|
||||
import { withServerPromise } from "./withServerPromise";
|
||||
import { redirect } from "next/navigation";
|
||||
@@ -15,6 +14,7 @@ import type { z } from "zod";
|
||||
import { headers } from "next/headers";
|
||||
import { addCivitaiCheckpointSchema } from "./addCheckpointSchema";
|
||||
import { and, eq, isNull } from "drizzle-orm";
|
||||
import { CivitaiModelResponse } from "@/types/civitai";
|
||||
|
||||
export async function getCheckpoints() {
|
||||
const { userId, orgId } = auth();
|
||||
@@ -57,17 +57,17 @@ export async function getCheckpointVolumes() {
|
||||
if (!userId) throw new Error("No user id");
|
||||
const checkpointVolume = await db
|
||||
.select()
|
||||
.from(checkpointVolumeTable)
|
||||
.from(volumeTable)
|
||||
.where(
|
||||
and(
|
||||
orgId
|
||||
? eq(checkpointVolumeTable.org_id, orgId)
|
||||
? eq(volumeTable.org_id, orgId)
|
||||
// make sure org_id is null
|
||||
: and(
|
||||
eq(checkpointVolumeTable.user_id, userId),
|
||||
isNull(checkpointVolumeTable.org_id),
|
||||
eq(volumeTable.user_id, userId),
|
||||
isNull(volumeTable.org_id),
|
||||
),
|
||||
eq(checkpointVolumeTable.disabled, false),
|
||||
eq(volumeTable.disabled, false),
|
||||
),
|
||||
);
|
||||
return checkpointVolume;
|
||||
@@ -79,7 +79,7 @@ export async function addCheckpointVolume() {
|
||||
|
||||
// Insert the new volume into the checkpointVolumeTable
|
||||
const insertedVolume = await db
|
||||
.insert(checkpointVolumeTable)
|
||||
.insert(volumeTable)
|
||||
.values({
|
||||
user_id: userId,
|
||||
org_id: orgId,
|
||||
@@ -115,11 +115,10 @@ export const addCivitaiCheckpoint = withServerPromise(
|
||||
const civitaiModelRes = await fetch(url)
|
||||
.then((x) => x.json())
|
||||
.then((a) => {
|
||||
console.log(a)
|
||||
return CivitaiModel.parse(a);
|
||||
return CivitaiModelResponse.parse(a);
|
||||
});
|
||||
|
||||
if (civitaiModelRes.modelVersions?.length === 0) {
|
||||
if (civitaiModelRes?.modelVersions?.length === 0) {
|
||||
return; // no versions to download
|
||||
}
|
||||
|
||||
@@ -155,6 +154,8 @@ export const addCivitaiCheckpoint = withServerPromise(
|
||||
upload_type: "civitai",
|
||||
civitai_id: civitaiModelRes.id.toString(),
|
||||
civitai_version_id: selectedModelVersionId,
|
||||
civitai_url: data.civitai_url,
|
||||
civitai_download_url: selectedModelVersion.downloadUrl,
|
||||
civitai_model_response: civitaiModelRes,
|
||||
checkpoint_volume_id: cVolume.id,
|
||||
})
|
||||
@@ -192,22 +193,23 @@ async function uploadCheckpoint(
|
||||
body: JSON.stringify({
|
||||
download_url: data.civitai_url,
|
||||
volume_name: v.volume_name,
|
||||
volume_id: v.id,
|
||||
callback_url: `${protocol}://${domain}/api/volume-updated`,
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
if (!result.ok) {
|
||||
// const error_log = await result.text();
|
||||
// await db
|
||||
// .update(checkpointTable)
|
||||
// .set({
|
||||
// ...data,
|
||||
// status: "error",
|
||||
// build_log: error_log,
|
||||
// })
|
||||
// .where(eq(machinesTable.id, b.id));
|
||||
// throw new Error(`Error: ${result.statusText} ${error_log}`);
|
||||
const error_log = await result.text();
|
||||
await db
|
||||
.update(checkpointTable)
|
||||
.set({
|
||||
...data,
|
||||
status: "error",
|
||||
build_log: error_log,
|
||||
})
|
||||
.where(eq(checkpointTable.id, b.id));
|
||||
throw new Error(`Error: ${result.statusText} ${error_log}`);
|
||||
} else {
|
||||
// setting the build machine id
|
||||
const json = await result.json();
|
||||
@@ -215,8 +217,8 @@ async function uploadCheckpoint(
|
||||
.update(checkpointTable)
|
||||
.set({
|
||||
...data,
|
||||
// build_machine_instance_id: json.build_machine_instance_id,
|
||||
upload_machine_id: json.build_machine_instance_id,
|
||||
})
|
||||
.where(eq(machinesTable.id, b.id));
|
||||
.where(eq(checkpointTable.id, b.id));
|
||||
}
|
||||
}
|
||||
|
||||
+108
-37
@@ -1,8 +1,102 @@
|
||||
import { z } from 'zod';
|
||||
|
||||
// from chatgpt https://chat.openai.com/share/4985d20b-30b1-4a28-87f6-6ebf84a1040e
|
||||
|
||||
export const creatorSchema = z.object({
|
||||
username: z.string(),
|
||||
image: z.string(),
|
||||
username: z.string().optional(),
|
||||
image: z.string().url().optional(),
|
||||
});
|
||||
|
||||
export const fileMetadataSchema = z.object({
|
||||
fp: z.string().optional(),
|
||||
size: z.string().optional(),
|
||||
format: z.string().optional(),
|
||||
});
|
||||
|
||||
export const fileSchema = z.object({
|
||||
id: z.number(),
|
||||
sizeKB: z.number().optional(),
|
||||
name: z.string(),
|
||||
type: z.string().optional(),
|
||||
metadata: fileMetadataSchema.optional(),
|
||||
pickleScanResult: z.string().optional(),
|
||||
pickleScanMessage: z.string().nullable(),
|
||||
virusScanResult: z.string().optional(),
|
||||
virusScanMessage: z.string().nullable(),
|
||||
scannedAt: z.string().optional(),
|
||||
hashes: z.record(z.string()).optional(),
|
||||
downloadUrl: z.string().url(),
|
||||
primary: z.boolean().optional().optional(),
|
||||
});
|
||||
|
||||
export const imageMetadataSchema = z.object({
|
||||
hash: z.string(),
|
||||
width: z.number(),
|
||||
height: z.number(),
|
||||
});
|
||||
|
||||
export const imageMetaSchema = z.object({
|
||||
ENSD: z.string().optional(),
|
||||
Size: z.string().optional(),
|
||||
seed: z.number().optional(),
|
||||
Model: z.string().optional(),
|
||||
steps: z.number().optional(),
|
||||
hashes: z.record(z.string()).optional(),
|
||||
prompt: z.string().optional(),
|
||||
sampler: z.string().optional(),
|
||||
cfgScale: z.number().optional(),
|
||||
ClipSkip: z.number().optional(),
|
||||
resources: z.array(
|
||||
z.object({
|
||||
hash: z.string().optional(),
|
||||
name: z.string(),
|
||||
type: z.string(),
|
||||
weight: z.number().optional(),
|
||||
})
|
||||
).optional(),
|
||||
ModelHash: z.string().optional(),
|
||||
HiresSteps: z.string().optional(),
|
||||
HiresUpscale: z.string().optional(),
|
||||
HiresUpscaler: z.string().optional(),
|
||||
negativePrompt: z.string(),
|
||||
DenoisingStrength: z.number().optional(),
|
||||
});
|
||||
|
||||
export const imageSchema = z.object({
|
||||
url: z.string().url().optional(),
|
||||
nsfw: z.enum(["None", "Soft", "Mature"]).optional(),
|
||||
width: z.number().optional(),
|
||||
height: z.number().optional(),
|
||||
hash: z.string().optional(),
|
||||
type: z.string().optional(),
|
||||
metadata: imageMetadataSchema.optional(),
|
||||
meta: imageMetaSchema.optional(),
|
||||
});
|
||||
|
||||
export const modelVersionSchema = z.object({
|
||||
id: z.number(),
|
||||
modelId: z.number(),
|
||||
name: z.string(),
|
||||
createdAt: z.string().optional(),
|
||||
updatedAt: z.string().optional(),
|
||||
status: z.enum(["Published", "Unpublished"]).optional(),
|
||||
publishedAt: z.string().optional(),
|
||||
trainedWords: z.array(z.string()).nullable(),
|
||||
trainingStatus: z.string().nullable(),
|
||||
trainingDetails: z.string().nullable(),
|
||||
baseModel: z.string().optional(),
|
||||
baseModelType: z.string().optional(),
|
||||
earlyAccessTimeFrame: z.number().optional(),
|
||||
description: z.string().nullable(),
|
||||
vaeId: z.string().nullable(),
|
||||
stats: z.object({
|
||||
downloadCount: z.number(),
|
||||
ratingCount: z.number(),
|
||||
rating: z.number(),
|
||||
}).optional(),
|
||||
files: z.array(fileSchema),
|
||||
images: z.array(imageSchema),
|
||||
downloadUrl: z.string().url(),
|
||||
});
|
||||
|
||||
export const statsSchema = z.object({
|
||||
@@ -14,42 +108,19 @@ export const statsSchema = z.object({
|
||||
tippedAmountCount: z.number(),
|
||||
});
|
||||
|
||||
export const modelVersionSchema = z.object({
|
||||
export const CivitaiModelResponse = z.object({
|
||||
id: z.number(),
|
||||
modelId: z.number(),
|
||||
name: z.string(),
|
||||
createdAt: z.string(),
|
||||
updatedAt: z.string(),
|
||||
status: z.string(),
|
||||
publishedAt: z.string(),
|
||||
trainedWords: z.array(z.any()), // Replace with more specific type if known
|
||||
trainingStatus: z.any().optional(),
|
||||
trainingDetails: z.any().optional(),
|
||||
baseModel: z.string(),
|
||||
baseModelType: z.string(),
|
||||
earlyAccessTimeFrame: z.number(),
|
||||
name: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
vaeId: z.any().optional(), // Replace with more specific type if known
|
||||
stats: statsSchema.optional(), // If stats structure is known, replace with specific type
|
||||
files: z.array(z.any()), // Replace with more specific type if known
|
||||
images: z.array(z.any()), // Replace with more specific type if known
|
||||
downloadUrl: z.string(),
|
||||
});
|
||||
|
||||
export const CivitaiModel = z.object({
|
||||
id: z.number(),
|
||||
name: z.string(),
|
||||
description: z.string(),
|
||||
type: z.string(),
|
||||
poi: z.boolean(),
|
||||
nsfw: z.boolean(),
|
||||
allowNoCredit: z.boolean(),
|
||||
allowCommercialUse: z.string(),
|
||||
allowDerivatives: z.boolean(),
|
||||
allowDifferentLicense: z.boolean(),
|
||||
stats: statsSchema,
|
||||
creator: creatorSchema,
|
||||
tags: z.array(z.string()),
|
||||
type: z.enum(["Checkpoint", "Lora"]),
|
||||
poi: z.boolean().optional(),
|
||||
nsfw: z.boolean().optional(),
|
||||
allowNoCredit: z.boolean().optional(),
|
||||
allowCommercialUse: z.enum(["Rent"]).optional(),
|
||||
allowDerivatives: z.boolean().optional(),
|
||||
allowDifferentLicense: z.boolean().optional(),
|
||||
stats: statsSchema.optional(),
|
||||
creator: creatorSchema.optional(),
|
||||
tags: z.array(z.string()).optional(),
|
||||
modelVersions: z.array(modelVersionSchema),
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user