diff --git a/src-tauri/src/tagger.rs b/src-tauri/src/tagger.rs index af1771e..9cac6a3 100644 --- a/src-tauri/src/tagger.rs +++ b/src-tauri/src/tagger.rs @@ -466,7 +466,8 @@ pub fn probe_tagger_runtime(app_data_dir: &Path) -> Result { let status = tagger_model_status(app_data_dir); if !status.ready { anyhow::bail!( - "WD Tagger model is missing {} required file(s): {}", + "{} is missing {} required file(s): {}", + status.model_name, status.missing_files.len(), status.missing_files.join(", ") ); diff --git a/src/App.tsx b/src/App.tsx index 61945f4..1986c0c 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -23,6 +23,8 @@ export default function App() { const loadBackgroundJobProgress = useGalleryStore((state) => state.loadBackgroundJobProgress); const loadImages = useGalleryStore((state) => state.loadImages); const loadCaptionModelStatus = useGalleryStore((state) => state.loadCaptionModelStatus); + const loadTaggerModelStatus = useGalleryStore((state) => state.loadTaggerModelStatus); + const loadTaggerModel = useGalleryStore((state) => state.loadTaggerModel); const loadDuplicateScanCache = useGalleryStore((state) => state.loadDuplicateScanCache); const loadAlbums = useGalleryStore((state) => state.loadAlbums); const loadMutedFolderIds = useGalleryStore((state) => state.loadMutedFolderIds); @@ -53,6 +55,8 @@ export default function App() { loadFolders().then(async () => { void loadBackgroundJobProgress(); void loadCaptionModelStatus(); + void loadTaggerModel(); + void loadTaggerModelStatus(); void loadDuplicateScanCache(); await loadAlbums(); await loadImages(true); diff --git a/src/components/Lightbox.tsx b/src/components/Lightbox.tsx index bedb93f..22c4730 100644 --- a/src/components/Lightbox.tsx +++ b/src/components/Lightbox.tsx @@ -156,6 +156,7 @@ export function Lightbox() { const addUserTag = useGalleryStore((state) => state.addUserTag); const removeTag = useGalleryStore((state) => state.removeTag); const taggerModelStatus = useGalleryStore((state) => state.taggerModelStatus); + const loadTaggerModelStatus = useGalleryStore((state) => state.loadTaggerModelStatus); const queueTaggingForImage = useGalleryStore((state) => state.queueTaggingForImage); const albums = useGalleryStore((state) => state.albums); const addToAlbum = useGalleryStore((state) => state.addToAlbum); @@ -254,6 +255,13 @@ export function Lightbox() { const canStartSlideshow = slideshowImages.length > 0; const canFindSimilar = selectedImage?.embedding_status === "ready"; const canSearchRegion = canFindSimilar && selectedImage?.media_kind === "image"; + const taggerReady = taggerModelStatus?.ready ?? false; + const taggerStatusKnown = taggerModelStatus !== null; + const taggerButtonTooltip = !taggerStatusKnown + ? "Checking AI tagger model..." + : taggerReady + ? "Queue AI tagging for this image" + : "AI tagger model not installed"; const goPrev = useCallback(() => { if (currentIndex > 0) openImage(images[currentIndex - 1]); @@ -421,6 +429,11 @@ export function Lightbox() { return () => { cancelled = true; }; }, [selectedImage?.id, selectedImage?.media_kind, getImageExif]); + useEffect(() => { + if (selectedImage?.media_kind !== "image" || taggerStatusKnown) return; + void loadTaggerModelStatus(); + }, [loadTaggerModelStatus, selectedImage?.media_kind, taggerStatusKnown]); + // Reset the queued state once the worker finishes so the button is usable again useEffect(() => { if (selectedImage?.ai_tagged_at) setTaggingQueued(false); @@ -1156,10 +1169,10 @@ export function Lightbox() { ) : null} {selectedImage.media_kind === "image" ? ( - +