diff --git a/app/src/components/home/ModelFinder.tsx b/app/src/components/home/ModelFinder.tsx index 0c84f5ef..3163aab9 100644 --- a/app/src/components/home/ModelFinder.tsx +++ b/app/src/components/home/ModelFinder.tsx @@ -16,7 +16,7 @@ import { modelEvent } from "@/events/model.ts"; import { levelSelector } from "@/store/subscription.ts"; import { teenagerSelector } from "@/store/package.ts"; import { ToastAction } from "@/components/ui/toast.tsx"; -import { useMemo } from "react"; +import { useEffect, useMemo, useState } from "react"; import { Sparkles } from "lucide-react"; import { goAuth } from "@/utils/app.ts"; @@ -55,6 +55,8 @@ function ModelFinder(props: ModelSelectorProps) { const student = useSelector(teenagerSelector); const list = useSelector(selectModelList); + const [sync, setSync] = useState(false); + modelEvent.bind((target: string) => { if (supportModels.find((m) => m.id === target)) { if (model === target) return; @@ -64,7 +66,10 @@ function ModelFinder(props: ModelSelectorProps) { }); const models = useMemo(() => { - const raw = supportModels.filter((model) => list.includes(model.id)); + const raw = list.length + ? supportModels.filter((model) => list.includes(model.id)) + : supportModels.filter((model) => model.default); + return [ ...raw.map((model: Model): SelectItemProps => filterModel(model, level)), { @@ -73,7 +78,14 @@ function ModelFinder(props: ModelSelectorProps) { value: t("market.model"), }, ]; - }, [supportModels, level, student]); + }, [supportModels, level, student, sync]); + + useEffect(() => { + setInterval(() => { + if (supportModels.length === 0) return; + setSync(!sync); + }, 500); + }, []); return ( (false); const update = async (): Promise => { - const resp = await updateMarket(form); + const preflight = form.filter((_, idx) => doCheck(idx)); + const resp = await updateMarket(preflight); if (!resp.status) { toast(t("admin.market.update-failed"), { diff --git a/app/src/utils/storage.ts b/app/src/utils/storage.ts index e14207b1..9185635d 100644 --- a/app/src/utils/storage.ts +++ b/app/src/utils/storage.ts @@ -11,6 +11,11 @@ export function getPreferenceModels(): string[] { } export function loadPreferenceModels(models: Model[]): Model[] { + models = models.filter((item) => + item.id.length > 0 && + item.name.length > 0 + ); + // sort by preference const preference = getPreferenceModels(); @@ -31,27 +36,38 @@ export function setOfflineModels(models: Model[]): void { } export function parseOfflineModels(models: string): Model[] { - const parsed = JSON.parse(models); - if (!Array.isArray(parsed)) return []; - return parsed - .map((item): Model | null => { - if (!item || typeof item !== "object") return null; - return { - id: item.id || "", - name: item.name || "", - description: item.description || "", - free: item.free || false, - auth: item.auth || false, - default: item.default || false, - high_context: item.high_context || false, - avatar: item.avatar || "", - tag: item.tag || [], - } as Model; - }) - .filter((item): item is Model => item !== null); + try { + const parsed = JSON.parse(models); + if (!Array.isArray(parsed)) return []; + return parsed + .map((item): Model | null => { + if (!item || typeof item !== "object") { + return null; + } + + if (!item.id || !item.name) { + return null; + } + + return { + id: item.id || "", + name: item.name || "", + description: item.description || "", + free: item.free || false, + auth: item.auth || false, + default: item.default || false, + high_context: item.high_context || false, + avatar: item.avatar || "", + tag: item.tag || [], + } as Model; + }) + .filter((item): item is Model => item !== null); + } catch { + return []; + } } export function getOfflineModels(): Model[] { const memory = getMemory("model_offline"); - return memory.length ? parseOfflineModels(memory) : []; + return memory && memory.length ? parseOfflineModels(memory) : []; }