diff --git a/src/components/SettingsModal.tsx b/src/components/SettingsModal.tsx index f6ea576..cee18b0 100644 --- a/src/components/SettingsModal.tsx +++ b/src/components/SettingsModal.tsx @@ -4,6 +4,7 @@ import { FfmpegStatusRow } from "./onboarding/StepWelcome"; import { ThemedDropdown } from "./ThemedDropdown"; import { getChangelogForVersion } from "../changelog"; import { Tooltip } from "./Tooltip"; +import { TAGGER_MODELS } from "../taggerModels"; type SettingsSection = "workspace" | "general"; @@ -101,22 +102,6 @@ function ScopeButton({ scope, current, onSelect, children }: { ); } -// Display metadata for each selectable tagging model. -const TAGGER_MODELS: Record = { - wd: { - name: "WD SwinV2 Tagger v3", - tab: "WD (anime)", - description: - "Anime-focused vision model by SmilingWolf. Generates booru-style tags with configurable confidence thresholds.", - }, - joytag: { - name: "JoyTag", - tab: "JoyTag (general)", - description: - "Booru-schema tagger that also handles photographic content and is strong on NSFW concepts. The explicitness rating is derived from its tags.", - }, -}; - function TaggerModelButton({ model, current, onSelect, children }: { model: TaggerModel; current: TaggerModel; @@ -445,16 +430,18 @@ export function SettingsModal() { - - - +
+ + + +
diff --git a/src/components/onboarding/StepAiFeatures.tsx b/src/components/onboarding/StepAiFeatures.tsx index 049bf25..c32b679 100644 --- a/src/components/onboarding/StepAiFeatures.tsx +++ b/src/components/onboarding/StepAiFeatures.tsx @@ -1,5 +1,6 @@ import { useEffect } from "react"; -import { TaggerModelProgress, useGalleryStore } from "../../store"; +import { TaggerModel, TaggerModelProgress, useGalleryStore } from "../../store"; +import { TAGGER_MODELS } from "../../taggerModels"; import { FakeProgressBar, formatBytes } from "./fakes"; const FAKE_TAGS = ["landscape", "sunset", "outdoors", "no_humans", "ocean", "cloudy_sky"]; @@ -15,19 +16,47 @@ function taggerDownloadFraction(progress: TaggerModelProgress | null): number | return null; } +function TaggerModelChoice({ model, current, disabled, onSelect }: { + model: TaggerModel; + current: TaggerModel; + disabled: boolean; + onSelect: (model: TaggerModel) => void; +}) { + const active = model === current; + return ( + + ); +} + export function StepAiFeatures() { const taggerModelStatus = useGalleryStore((s) => s.taggerModelStatus); const taggerModelPreparing = useGalleryStore((s) => s.taggerModelPreparing); const taggerModelProgress = useGalleryStore((s) => s.taggerModelProgress); const taggerModelError = useGalleryStore((s) => s.taggerModelError); + const taggerModel = useGalleryStore((s) => s.taggerModel); const prepareTaggerModel = useGalleryStore((s) => s.prepareTaggerModel); + const loadTaggerModel = useGalleryStore((s) => s.loadTaggerModel); const loadTaggerModelStatus = useGalleryStore((s) => s.loadTaggerModelStatus); + const setTaggerModel = useGalleryStore((s) => s.setTaggerModel); useEffect(() => { + void loadTaggerModel(); void loadTaggerModelStatus(); - }, [loadTaggerModelStatus]); + }, [loadTaggerModel, loadTaggerModelStatus]); const taggerReady = taggerModelStatus?.ready ?? false; + const taggerStatusLabel = taggerReady ? "Installed" : taggerModelPreparing ? "Preparing" : "Not installed"; return (
@@ -46,6 +75,26 @@ export function StepAiFeatures() { The AI tagger model labels images so you can search with{" "} /t — tags look like:

+
+ {(["wd", "joytag"] as const).map((model) => ( + { + if (nextModel === taggerModel) return; + void setTaggerModel(nextModel); + }} + /> + ))} +
+

+ Current: {TAGGER_MODELS[taggerModel].name} · {taggerStatusLabel} +

+

+ {TAGGER_MODELS[taggerModel].description} +

{FAKE_TAGS.map((tag) => ( diff --git a/src/taggerModels.ts b/src/taggerModels.ts new file mode 100644 index 0000000..e3ac289 --- /dev/null +++ b/src/taggerModels.ts @@ -0,0 +1,16 @@ +import type { TaggerModel } from "./store"; + +export const TAGGER_MODELS: Record = { + wd: { + name: "WD SwinV2 Tagger v3", + tab: "WD (anime)", + description: + "Anime-focused vision model by SmilingWolf. Generates booru-style tags with configurable confidence thresholds.", + }, + joytag: { + name: "JoyTag", + tab: "JoyTag (general)", + description: + "Booru-schema tagger that also handles photographic content and is strong on NSFW concepts. The explicitness rating is derived from its tags.", + }, +};