diff --git a/web/bun.lockb b/web/bun.lockb index a190950..40d4914 100755 Binary files a/web/bun.lockb and b/web/bun.lockb differ diff --git a/web/package.json b/web/package.json index 0832a42..b977a20 100644 --- a/web/package.json +++ b/web/package.json @@ -95,6 +95,7 @@ "tailwindcss-animate": "^1.0.7", "unist-util-filter": "^5.0.1", "unist-util-visit": "^5.0.0", + "use-debounce": "^10.0.0", "uuid": "^9.0.1", "zod": "^3.22.4", "zustand": "^4.4.7" diff --git a/web/src/components/custom-form/ModelPickerView.tsx b/web/src/components/custom-form/ModelPickerView.tsx index dd093af..10b3565 100644 --- a/web/src/components/custom-form/ModelPickerView.tsx +++ b/web/src/components/custom-form/ModelPickerView.tsx @@ -1,6 +1,7 @@ "use client"; import type { AutoFormInputComponentProps } from "../ui/auto-form/types"; +import { LoadingIcon } from "@/components/LoadingIcon"; import { Button } from "@/components/ui/button"; import { Command, @@ -21,6 +22,7 @@ import { cn } from "@/lib/utils"; import { Check, ChevronsUpDown } from "lucide-react"; import * as React from "react"; import { useRef } from "react"; +import { useDebouncedCallback } from "use-debounce"; import { z } from "zod"; const Model = z.object({ @@ -34,6 +36,114 @@ const Model = z.object({ url: z.string(), }); +export const CivitalModelSchema = z.object({ + items: z.array( + 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(), + }) + ), + }) + ), + metadata: z.object({ + totalItems: z.number(), + currentPage: z.number(), + pageSize: z.number(), + totalPages: z.number(), + nextPage: z.string().optional(), + }), +}); + const ModelList = z.array(Model); export const ModelListWrapper = z.object({ @@ -43,16 +153,132 @@ export const ModelListWrapper = z.object({ export function ModelPickerView({ field, }: Pick) { - const value = (field.value as z.infer) ?? []; + return ( +
+ + + {/* {field.value.length} selected */} + {field.value && ( + +