fix(ai-tags): refresh tagger readiness for lightbox
Load the selected tagger model and model status during app startup so the lightbox AI tags action does not stay disabled until Settings refreshes the state. Refresh readiness after tagger downloads complete and replace stale WD-specific unavailable copy with generic AI tagger wording.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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() {
|
||||
</span>
|
||||
) : null}
|
||||
{selectedImage.media_kind === "image" ? (
|
||||
<Tooltip label={!(taggerModelStatus?.ready ?? false) ? "WD Tagger model not downloaded" : "Queue AI tagging for this image"} followCursor>
|
||||
<Tooltip label={taggerButtonTooltip} followCursor>
|
||||
<button
|
||||
className="rounded-md border border-white/10 bg-white/5 px-2 py-0.5 text-[10px] text-gray-400 transition-colors hover:bg-white/10 hover:text-white disabled:cursor-not-allowed disabled:opacity-40"
|
||||
disabled={!(taggerModelStatus?.ready ?? false) || taggingQueued}
|
||||
disabled={!taggerReady || taggingQueued}
|
||||
onClick={() => {
|
||||
setTaggingQueued(true);
|
||||
void queueTaggingForImage(selectedImage.id).catch(() => undefined);
|
||||
|
||||
@@ -322,7 +322,7 @@ export function SettingsModal() {
|
||||
: taggerModelProgress
|
||||
? `Downloading ${taggerModelProgress.completed_files}/${taggerModelProgress.total_files}`
|
||||
: taggerModelPreparing
|
||||
? "Preparing WD Tagger..."
|
||||
? "Preparing AI tagger..."
|
||||
: taggerReady
|
||||
? "Installed"
|
||||
: "Install model";
|
||||
|
||||
@@ -43,7 +43,7 @@ export function StepAiFeatures() {
|
||||
<div className="min-w-0">
|
||||
<p className="text-sm text-white">Automatic tags for every image</p>
|
||||
<p className="mt-1 text-xs leading-relaxed text-gray-500">
|
||||
The WD tagger model (~1.3 GB download) labels images so you can search with{" "}
|
||||
The AI tagger model labels images so you can search with{" "}
|
||||
<code className="rounded bg-gray-900 px-1 py-0.5 text-[11px] text-gray-200 light-theme:bg-gray-800 light-theme:text-gray-100">/t</code> — tags look like:
|
||||
</p>
|
||||
<span className="mt-2 flex flex-wrap gap-1.5">
|
||||
|
||||
@@ -3010,6 +3010,9 @@ export const useGalleryStore = create<GalleryState>((set, get) => ({
|
||||
taggerModelProgress: event.payload.done ? null : event.payload,
|
||||
taggerModelPreparing: !event.payload.done,
|
||||
});
|
||||
if (event.payload.done) {
|
||||
void get().loadTaggerModelStatus();
|
||||
}
|
||||
});
|
||||
|
||||
const unlistenImages = await listen<IndexedImagesBatch>("indexed-images", (event) => {
|
||||
|
||||
Reference in New Issue
Block a user