fix: address gallery auto-tag review images by path, not digest id
The gallery review flow builds its list from /prompt_manager/images/output, whose id is a 16-hex path digest, but posted it as image_id to autotag/single, so the server looked up a database row and every request 404ed. autotagSingleBody (pure, tested) now sends path for output-folder entries and keeps image_id for database rows, which the admin review flow (/images/all) still uses.
This commit is contained in:
@@ -1,7 +1,52 @@
|
||||
// Run with: node --test tests/js/
|
||||
const test = require("node:test");
|
||||
const assert = require("node:assert/strict");
|
||||
const { formatImageCaption, workflowDocumentHtml } = require("../../web/js/image-helpers.js");
|
||||
const {
|
||||
formatImageCaption,
|
||||
workflowDocumentHtml,
|
||||
autotagSingleBody,
|
||||
} = require("../../web/js/image-helpers.js");
|
||||
|
||||
const WD14 = { modelType: "wd14-vit", generalThreshold: 0.35, characterThreshold: 0.85, prompt: "ignored" };
|
||||
const CAPTION = { modelType: "blip", generalThreshold: 0.35, characterThreshold: 0.85, prompt: "describe it" };
|
||||
|
||||
test("autotagSingleBody sends image_id for a database row", () => {
|
||||
const body = autotagSingleBody({ id: 42, prompt_id: 7, image_path: "/out/a.png" }, WD14);
|
||||
assert.equal(body.image_id, 42);
|
||||
assert.equal("path" in body, false);
|
||||
});
|
||||
|
||||
test("autotagSingleBody sends path for an output-folder entry whose id is a digest", () => {
|
||||
const body = autotagSingleBody({ id: "3f2a9c1b0d4e5f67", path: "/out/sub/a.png", filename: "a.png" }, WD14);
|
||||
assert.equal(body.path, "/out/sub/a.png");
|
||||
assert.equal("image_id" in body, false);
|
||||
});
|
||||
|
||||
test("autotagSingleBody prefers path when a numeric-looking string id has no prompt link", () => {
|
||||
const body = autotagSingleBody({ id: "1234567890abcdef", path: "/out/b.png" }, WD14);
|
||||
assert.deepEqual(Object.keys(body).filter((k) => k === "path" || k === "image_id"), ["path"]);
|
||||
});
|
||||
|
||||
test("autotagSingleBody adds wd14 thresholds and no prompt", () => {
|
||||
const body = autotagSingleBody({ id: 1 }, WD14);
|
||||
assert.equal(body.model_type, "wd14-vit");
|
||||
assert.equal(body.general_threshold, 0.35);
|
||||
assert.equal(body.character_threshold, 0.85);
|
||||
assert.equal("prompt" in body, false);
|
||||
});
|
||||
|
||||
test("autotagSingleBody adds the prompt for caption models and no thresholds", () => {
|
||||
const body = autotagSingleBody({ id: 1 }, CAPTION);
|
||||
assert.equal(body.model_type, "blip");
|
||||
assert.equal(body.prompt, "describe it");
|
||||
assert.equal("general_threshold" in body, false);
|
||||
});
|
||||
|
||||
test("autotagSingleBody does not mutate its inputs", () => {
|
||||
const image = Object.freeze({ id: 1 });
|
||||
const settings = Object.freeze({ ...WD14 });
|
||||
assert.doesNotThrow(() => autotagSingleBody(image, settings));
|
||||
});
|
||||
|
||||
const XSS = '"><img src=x onerror=1>';
|
||||
const formatFileSize = (bytes) => `${bytes} B`;
|
||||
|
||||
+2
-10
@@ -3671,16 +3671,8 @@ Seed: ${this.currentMetadata.seed || 'Unknown'}`;
|
||||
this.autoTagState.tagsExpanded = false; // Reset accordion for new image
|
||||
|
||||
try {
|
||||
const requestBody = {
|
||||
image_id: image.id,
|
||||
model_type: this.autoTagState.modelType,
|
||||
};
|
||||
if (this.autoTagState.modelType.startsWith('wd14')) {
|
||||
requestBody.general_threshold = this.autoTagState.generalThreshold;
|
||||
requestBody.character_threshold = this.autoTagState.characterThreshold;
|
||||
} else {
|
||||
requestBody.prompt = this.autoTagState.prompt;
|
||||
}
|
||||
// Review rows come from /images/all (database ids), so this resolves to image_id
|
||||
const requestBody = ImageHelpers.autotagSingleBody(image, this.autoTagState);
|
||||
|
||||
const response = await fetch('/prompt_manager/autotag/single', {
|
||||
method: 'POST',
|
||||
|
||||
+2
-10
@@ -3380,16 +3380,8 @@ Seed: ${this.currentMetadata.seed || 'Unknown'}`;
|
||||
document.getElementById('reviewTagsContainer').innerHTML = '<div class="text-pm-secondary">Generating tags...</div>';
|
||||
|
||||
try {
|
||||
const requestBody = {
|
||||
image_id: image.id,
|
||||
model_type: this.autoTagState.modelType,
|
||||
};
|
||||
if (this.autoTagState.modelType.startsWith('wd14')) {
|
||||
requestBody.general_threshold = this.autoTagState.generalThreshold;
|
||||
requestBody.character_threshold = this.autoTagState.characterThreshold;
|
||||
} else {
|
||||
requestBody.prompt = this.autoTagState.prompt;
|
||||
}
|
||||
// Gallery entries come from /images/output: id is a path digest, so address by path
|
||||
const requestBody = ImageHelpers.autotagSingleBody(image, this.autoTagState);
|
||||
|
||||
const response = await fetch('/prompt_manager/autotag/single', {
|
||||
method: 'POST',
|
||||
|
||||
+28
-1
@@ -62,7 +62,34 @@
|
||||
].join("\n");
|
||||
}
|
||||
|
||||
const api = { formatImageCaption, workflowDocumentHtml };
|
||||
/**
|
||||
* Body for POST /prompt_manager/autotag/single.
|
||||
*
|
||||
* Database rows (admin review, /images/all) have an integer id the server
|
||||
* looks up; output-folder entries (gallery review, /images/output) have a
|
||||
* path digest as id, which would 404, so those are addressed by path.
|
||||
*
|
||||
* @param {{id?: unknown, path?: unknown}} image
|
||||
* @param {{modelType: string, generalThreshold?: number, characterThreshold?: number, prompt?: string}} settings
|
||||
* @returns {object} JSON-serialisable request body
|
||||
*/
|
||||
function autotagSingleBody(image, settings) {
|
||||
const entry = image || {};
|
||||
const target =
|
||||
typeof entry.path === "string" && entry.path && !Number.isInteger(entry.id)
|
||||
? { path: entry.path }
|
||||
: { image_id: entry.id };
|
||||
const modelType = String(settings.modelType || "");
|
||||
const params = modelType.startsWith("wd14")
|
||||
? {
|
||||
general_threshold: settings.generalThreshold,
|
||||
character_threshold: settings.characterThreshold,
|
||||
}
|
||||
: { prompt: settings.prompt };
|
||||
return { ...target, model_type: modelType, ...params };
|
||||
}
|
||||
|
||||
const api = { formatImageCaption, workflowDocumentHtml, autotagSingleBody };
|
||||
if (typeof module !== "undefined" && module.exports) module.exports = api;
|
||||
else root.ImageHelpers = api;
|
||||
})(typeof window !== "undefined" ? window : globalThis);
|
||||
|
||||
Reference in New Issue
Block a user