fix(tagger): model-neutral session log; changelog for JoyTag

create_tagger_session is shared by both models but logged "WD tagger: using
CPU execution provider" even when loading JoyTag. Make the CPU/DirectML
session logs model-neutral. Add the JoyTag tagging-model picker to the
changelog now that it's runtime-verified.
This commit is contained in:
2026-06-29 10:08:55 +01:00
parent 705f8c2e56
commit 1685134116
4 changed files with 13 additions and 5 deletions
+6
View File
@@ -42,6 +42,12 @@ aims to follow [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
changes grouped into collapsible Added / Changed / Fixed sections. changes grouped into collapsible Added / Changed / Fixed sections.
- **Build badge in Settings** — the version line in Settings → Updates now shows - **Build badge in Settings** — the version line in Settings → Updates now shows
whether the running build is the CPU or CUDA (GPU-accelerated) variant. whether the running build is the CPU or CUDA (GPU-accelerated) variant.
- **Choose your tagging model** — Settings → AI Workspace now lets you switch the
AI tagger between the WD tagger (anime-focused) and **JoyTag**, which also
handles photographic content and is stronger on NSFW concepts — a better fit
for real-photo libraries. Each model downloads on demand, and tags are
attributed to the model that produced them. JoyTag has no built-in rating, so
its explicitness rating is derived from its tags.
### Changed ### Changed
+2 -4
View File
@@ -987,15 +987,13 @@ fn create_tagger_session(path: &Path, acceleration: TaggerAcceleration) -> Resul
let mut builder = match acceleration { let mut builder = match acceleration {
TaggerAcceleration::Cpu => { TaggerAcceleration::Cpu => {
log::info!( log::info!("Tagger: using CPU execution provider ({intra_threads} intra-op threads)");
"WD tagger: using CPU execution provider ({intra_threads} intra-op threads)"
);
builder builder
} }
TaggerAcceleration::Auto => builder TaggerAcceleration::Auto => builder
.with_execution_providers([ep::DirectML::default().build().fail_silently()]) .with_execution_providers([ep::DirectML::default().build().fail_silently()])
.unwrap_or_else(|error| { .unwrap_or_else(|error| {
log::info!("WD tagger: DirectML unavailable, falling back to CPU"); log::info!("Tagger: DirectML unavailable, falling back to CPU");
error.recover() error.recover()
}), }),
TaggerAcceleration::Directml => builder TaggerAcceleration::Directml => builder
+3
View File
@@ -344,6 +344,9 @@ export async function handleMockCommand(cmd: string, payload?: unknown): Promise
return 12; return 12;
case "get_tagger_model_status": case "get_tagger_model_status":
return { model_id: "SmilingWolf/wd-vit-tagger-v3", model_name: "WD ViT Tagger", local_dir: "mock://models/tagger", ready: true, missing_files: [] }; return { model_id: "SmilingWolf/wd-vit-tagger-v3", model_name: "WD ViT Tagger", local_dir: "mock://models/tagger", ready: true, missing_files: [] };
case "get_tagger_model":
case "set_tagger_model":
return p.model ?? "wd";
case "get_tagger_acceleration": case "get_tagger_acceleration":
case "set_tagger_acceleration": case "set_tagger_acceleration":
return p.acceleration ?? "auto"; return p.acceleration ?? "auto";
+2 -1
View File
@@ -2166,7 +2166,8 @@ export const useGalleryStore = create<GalleryState>((set, get) => ({
loadTaggerModel: async () => { loadTaggerModel: async () => {
try { try {
const taggerModel = await invoke<TaggerModel>("get_tagger_model"); const taggerModel = await invoke<TaggerModel>("get_tagger_model");
set({ taggerModel }); // Never clobber the valid default with a missing/blank backend response.
if (taggerModel) set({ taggerModel });
} catch (error) { } catch (error) {
set({ taggerModelError: String(error) }); set({ taggerModelError: String(error) });
} }