test(ui-lab): add tagger readiness scenarios
Add UI Lab scenarios for uninstalled WD and JoyTag tagger states so the lightbox and AI Workspace readiness flows can be exercised directly. Make the Settings title-bar button accessible by label to support reliable UI Lab automation.
This commit is contained in:
@@ -147,6 +147,7 @@ export function TitleBar() {
|
|||||||
<Tooltip label="Settings (right-click to switch theme)" anchorToCursor>
|
<Tooltip label="Settings (right-click to switch theme)" anchorToCursor>
|
||||||
<button
|
<button
|
||||||
ref={settingsBtnRef}
|
ref={settingsBtnRef}
|
||||||
|
aria-label="Settings"
|
||||||
onClick={() => setSettingsOpen(true)}
|
onClick={() => setSettingsOpen(true)}
|
||||||
onContextMenu={handleSettingsContextMenu}
|
onContextMenu={handleSettingsContextMenu}
|
||||||
className="group flex h-full w-10 items-center justify-center text-gray-600 transition-colors duration-100 hover:bg-white/6 hover:text-gray-300"
|
className="group flex h-full w-10 items-center justify-center text-gray-600 transition-colors duration-100 hover:bg-white/6 hover:text-gray-300"
|
||||||
|
|||||||
+61
-4
@@ -1,5 +1,15 @@
|
|||||||
import { emit } from "@tauri-apps/api/event";
|
import { emit } from "@tauri-apps/api/event";
|
||||||
import type { Album, ExploreTagEntry, Folder, ImageRecord, ImageTag, SortOrder } from "../store";
|
import type {
|
||||||
|
Album,
|
||||||
|
ExploreTagEntry,
|
||||||
|
Folder,
|
||||||
|
ImageRecord,
|
||||||
|
ImageTag,
|
||||||
|
SortOrder,
|
||||||
|
TaggerModel,
|
||||||
|
TaggerModelStatus,
|
||||||
|
TaggerRuntimeProbe,
|
||||||
|
} from "../store";
|
||||||
import { compareImages, createMockDb, mockExif } from "./mockFixtures";
|
import { compareImages, createMockDb, mockExif } from "./mockFixtures";
|
||||||
import { getMockScenario } from "./mockScenarios";
|
import { getMockScenario } from "./mockScenarios";
|
||||||
|
|
||||||
@@ -7,6 +17,8 @@ const db = createMockDb(getMockScenario());
|
|||||||
let nextFolderId = 100;
|
let nextFolderId = 100;
|
||||||
let nextAlbumId = 100;
|
let nextAlbumId = 100;
|
||||||
let nextTagId = 10_000;
|
let nextTagId = 10_000;
|
||||||
|
let mockTaggerModel: TaggerModel = db.scenario === "joytag-unready" ? "joytag" : "wd";
|
||||||
|
let mockTaggerReady = db.scenario !== "unready" && db.scenario !== "joytag-unready";
|
||||||
|
|
||||||
type AnyPayload = Record<string, any> | undefined;
|
type AnyPayload = Record<string, any> | undefined;
|
||||||
type Rgb = [number, number, number];
|
type Rgb = [number, number, number];
|
||||||
@@ -55,6 +67,42 @@ function page<T>(items: T[], offset = 0, limit = 200) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function mockTaggerStatus(): TaggerModelStatus {
|
||||||
|
const modelInfo =
|
||||||
|
mockTaggerModel === "joytag"
|
||||||
|
? {
|
||||||
|
model_id: "fancyfeast/joytag",
|
||||||
|
model_name: "JoyTag",
|
||||||
|
local_dir: "mock://models/joytag",
|
||||||
|
label_file: "top_tags.txt",
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
model_id: "SmilingWolf/wd-swinv2-tagger-v3",
|
||||||
|
model_name: "wd-swinv2-tagger-v3",
|
||||||
|
local_dir: "mock://models/wd-swinv2-tagger-v3",
|
||||||
|
label_file: "selected_tags.csv",
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
model_id: modelInfo.model_id,
|
||||||
|
model_name: modelInfo.model_name,
|
||||||
|
local_dir: modelInfo.local_dir,
|
||||||
|
ready: mockTaggerReady,
|
||||||
|
missing_files: mockTaggerReady ? [] : ["model.onnx", modelInfo.label_file],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function mockTaggerRuntimeProbe(): TaggerRuntimeProbe {
|
||||||
|
if (!mockTaggerReady) {
|
||||||
|
throw new Error(`${mockTaggerStatus().model_name} is missing required model files`);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
ready: true,
|
||||||
|
acceleration: "auto",
|
||||||
|
session: { file: "model.onnx", inputs: ["input"], outputs: ["tags"] },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function filterImages(input: ImageRecord[], payload: unknown): ImageRecord[] {
|
function filterImages(input: ImageRecord[], payload: unknown): ImageRecord[] {
|
||||||
const p = params(payload);
|
const p = params(payload);
|
||||||
const query = String(p.search ?? p.query ?? "").trim().toLowerCase();
|
const query = String(p.search ?? p.query ?? "").trim().toLowerCase();
|
||||||
@@ -463,10 +511,19 @@ export async function handleMockCommand(cmd: string, payload?: unknown): Promise
|
|||||||
return reset;
|
return reset;
|
||||||
}
|
}
|
||||||
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 mockTaggerStatus();
|
||||||
case "get_tagger_model":
|
case "get_tagger_model":
|
||||||
|
return mockTaggerModel;
|
||||||
case "set_tagger_model":
|
case "set_tagger_model":
|
||||||
return p.model ?? "wd";
|
mockTaggerModel = p.model ?? "wd";
|
||||||
|
mockTaggerReady = db.scenario !== "unready" && db.scenario !== "joytag-unready";
|
||||||
|
return mockTaggerModel;
|
||||||
|
case "prepare_tagger_model":
|
||||||
|
mockTaggerReady = true;
|
||||||
|
return mockTaggerStatus();
|
||||||
|
case "delete_tagger_model":
|
||||||
|
mockTaggerReady = false;
|
||||||
|
return mockTaggerStatus();
|
||||||
case "get_tagger_acceleration":
|
case "get_tagger_acceleration":
|
||||||
case "set_tagger_acceleration":
|
case "set_tagger_acceleration":
|
||||||
return p.acceleration ?? "auto";
|
return p.acceleration ?? "auto";
|
||||||
@@ -477,7 +534,7 @@ export async function handleMockCommand(cmd: string, payload?: unknown): Promise
|
|||||||
case "set_tagger_batch_size":
|
case "set_tagger_batch_size":
|
||||||
return p.batch_size ?? 8;
|
return p.batch_size ?? 8;
|
||||||
case "probe_tagger_runtime":
|
case "probe_tagger_runtime":
|
||||||
return { ready: true, acceleration: "auto", session: { file: "model.onnx", inputs: ["input"], outputs: ["tags"] } };
|
return mockTaggerRuntimeProbe();
|
||||||
case "get_tagging_queue_scope":
|
case "get_tagging_queue_scope":
|
||||||
return "all";
|
return "all";
|
||||||
case "get_tagging_queue_folder_ids":
|
case "get_tagging_queue_folder_ids":
|
||||||
|
|||||||
@@ -1,4 +1,14 @@
|
|||||||
export type MockScenario = "rich" | "empty" | "busy" | "duplicates" | "album" | "errors" | "huge" | "extreme";
|
export type MockScenario =
|
||||||
|
| "rich"
|
||||||
|
| "empty"
|
||||||
|
| "busy"
|
||||||
|
| "duplicates"
|
||||||
|
| "album"
|
||||||
|
| "errors"
|
||||||
|
| "huge"
|
||||||
|
| "extreme"
|
||||||
|
| "unready"
|
||||||
|
| "joytag-unready";
|
||||||
|
|
||||||
const SCENARIOS = new Set<MockScenario>([
|
const SCENARIOS = new Set<MockScenario>([
|
||||||
"rich",
|
"rich",
|
||||||
@@ -9,6 +19,8 @@ const SCENARIOS = new Set<MockScenario>([
|
|||||||
"errors",
|
"errors",
|
||||||
"huge",
|
"huge",
|
||||||
"extreme",
|
"extreme",
|
||||||
|
"unready",
|
||||||
|
"joytag-unready",
|
||||||
]);
|
]);
|
||||||
|
|
||||||
export function getMockScenario(): MockScenario {
|
export function getMockScenario(): MockScenario {
|
||||||
|
|||||||
Reference in New Issue
Block a user