@enslo/sd-metadata 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +223 -49
- package/dist/index.d.ts +80 -37
- package/dist/index.js +62 -21
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/index.js
CHANGED
|
@@ -407,23 +407,45 @@ function convertSwarmUIPngToSegments(chunks) {
|
|
|
407
407
|
}
|
|
408
408
|
const parsed = parseJson(parametersChunk.text);
|
|
409
409
|
const data = parsed.ok ? parsed.value : parametersChunk.text;
|
|
410
|
-
|
|
410
|
+
const segments = [
|
|
411
411
|
{
|
|
412
412
|
source: { type: "exifUserComment" },
|
|
413
413
|
data: typeof data === "string" ? data : JSON.stringify(data)
|
|
414
414
|
}
|
|
415
415
|
];
|
|
416
|
+
const promptChunk = chunks.find((c) => c.keyword === "prompt");
|
|
417
|
+
if (promptChunk) {
|
|
418
|
+
segments.push({
|
|
419
|
+
source: { type: "exifMake" },
|
|
420
|
+
data: promptChunk.text
|
|
421
|
+
});
|
|
422
|
+
}
|
|
423
|
+
return segments;
|
|
416
424
|
}
|
|
417
425
|
function convertSwarmUISegmentsToPng(segments) {
|
|
418
426
|
const userComment = findSegment(segments, "exifUserComment");
|
|
419
427
|
if (!userComment) {
|
|
420
428
|
return [];
|
|
421
429
|
}
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
430
|
+
const chunks = [];
|
|
431
|
+
const make = findSegment(segments, "exifMake");
|
|
432
|
+
if (make) {
|
|
433
|
+
chunks.push(
|
|
434
|
+
...createEncodedChunk(
|
|
435
|
+
"prompt",
|
|
436
|
+
make.data,
|
|
437
|
+
getEncodingStrategy("swarmui")
|
|
438
|
+
)
|
|
439
|
+
);
|
|
440
|
+
}
|
|
441
|
+
chunks.push(
|
|
442
|
+
...createEncodedChunk(
|
|
443
|
+
"parameters",
|
|
444
|
+
userComment.data,
|
|
445
|
+
getEncodingStrategy("swarmui")
|
|
446
|
+
)
|
|
426
447
|
);
|
|
448
|
+
return chunks;
|
|
427
449
|
}
|
|
428
450
|
|
|
429
451
|
// src/converters/index.ts
|
|
@@ -560,7 +582,6 @@ function parseA1111(entries) {
|
|
|
560
582
|
const app = settingsMap.get("App");
|
|
561
583
|
const software = detectSoftwareVariant(version, app);
|
|
562
584
|
const metadata = {
|
|
563
|
-
type: "a1111",
|
|
564
585
|
software,
|
|
565
586
|
prompt,
|
|
566
587
|
negativePrompt,
|
|
@@ -709,12 +730,13 @@ function parseComfyUI(entries) {
|
|
|
709
730
|
const width = latentWidth || extraMeta?.width || 0;
|
|
710
731
|
const height = latentHeight || extraMeta?.height || 0;
|
|
711
732
|
const metadata = {
|
|
712
|
-
type: "comfyui",
|
|
713
733
|
software: "comfyui",
|
|
714
734
|
prompt: positiveText,
|
|
715
735
|
negativePrompt: negativeText,
|
|
716
736
|
width,
|
|
717
|
-
height
|
|
737
|
+
height,
|
|
738
|
+
nodes: prompt
|
|
739
|
+
// Store the parsed node graph
|
|
718
740
|
};
|
|
719
741
|
const checkpoint = findNode(prompt, ["CheckpointLoader_Base"])?.inputs?.ckpt_name;
|
|
720
742
|
if (checkpoint) {
|
|
@@ -1006,7 +1028,6 @@ function parseFromEntries(entryRecord) {
|
|
|
1006
1028
|
const width = Number(entryRecord.width ?? entryRecord.Width) || 0;
|
|
1007
1029
|
const height = Number(entryRecord.height ?? entryRecord.Height) || 0;
|
|
1008
1030
|
const metadata = {
|
|
1009
|
-
type: "a1111",
|
|
1010
1031
|
software: "easydiffusion",
|
|
1011
1032
|
prompt: prompt.trim(),
|
|
1012
1033
|
negativePrompt: negativePrompt.trim(),
|
|
@@ -1037,7 +1058,6 @@ function parseFromJson(json) {
|
|
|
1037
1058
|
const width = getValue(json, "width", "Width") ?? 0;
|
|
1038
1059
|
const height = getValue(json, "height", "Height") ?? 0;
|
|
1039
1060
|
const metadata = {
|
|
1040
|
-
type: "a1111",
|
|
1041
1061
|
software: "easydiffusion",
|
|
1042
1062
|
prompt: prompt.trim(),
|
|
1043
1063
|
negativePrompt: negativePrompt.trim(),
|
|
@@ -1077,7 +1097,6 @@ function parseFooocus(entries) {
|
|
|
1077
1097
|
return Result.error({ type: "unsupportedFormat" });
|
|
1078
1098
|
}
|
|
1079
1099
|
const metadata = {
|
|
1080
|
-
type: "a1111",
|
|
1081
1100
|
software: "fooocus",
|
|
1082
1101
|
prompt: json.prompt?.trim() ?? "",
|
|
1083
1102
|
negativePrompt: json.negative_prompt?.trim() ?? "",
|
|
@@ -1121,7 +1140,6 @@ function parseHfSpace(entries) {
|
|
|
1121
1140
|
};
|
|
1122
1141
|
const { width, height } = parseResolution(json.resolution);
|
|
1123
1142
|
const metadata = {
|
|
1124
|
-
type: "a1111",
|
|
1125
1143
|
software: "hf-space",
|
|
1126
1144
|
prompt: json.prompt ?? "",
|
|
1127
1145
|
negativePrompt: json.negative_prompt ?? "",
|
|
@@ -1172,7 +1190,6 @@ function parseInvokeAI(entries) {
|
|
|
1172
1190
|
const width = data.width ?? 0;
|
|
1173
1191
|
const height = data.height ?? 0;
|
|
1174
1192
|
const metadata = {
|
|
1175
|
-
type: "invokeai",
|
|
1176
1193
|
software: "invokeai",
|
|
1177
1194
|
prompt: data.positive_prompt ?? "",
|
|
1178
1195
|
negativePrompt: data.negative_prompt ?? "",
|
|
@@ -1222,7 +1239,6 @@ function parseNovelAI(entries) {
|
|
|
1222
1239
|
const prompt = comment.v4_prompt?.caption?.base_caption ?? comment.prompt ?? "";
|
|
1223
1240
|
const negativePrompt = comment.v4_negative_prompt?.caption?.base_caption ?? comment.uc ?? "";
|
|
1224
1241
|
const metadata = {
|
|
1225
|
-
type: "novelai",
|
|
1226
1242
|
software: "novelai",
|
|
1227
1243
|
prompt,
|
|
1228
1244
|
negativePrompt,
|
|
@@ -1272,7 +1288,6 @@ function parseRuinedFooocus(entries) {
|
|
|
1272
1288
|
return Result.error({ type: "unsupportedFormat" });
|
|
1273
1289
|
}
|
|
1274
1290
|
const metadata = {
|
|
1275
|
-
type: "a1111",
|
|
1276
1291
|
software: "ruined-fooocus",
|
|
1277
1292
|
prompt: json.Prompt?.trim() ?? "",
|
|
1278
1293
|
negativePrompt: json.Negative?.trim() ?? "",
|
|
@@ -1298,12 +1313,11 @@ function parseRuinedFooocus(entries) {
|
|
|
1298
1313
|
function parseStabilityMatrix(entries) {
|
|
1299
1314
|
const entryRecord = buildEntryRecord(entries);
|
|
1300
1315
|
const comfyResult = parseComfyUI(entries);
|
|
1301
|
-
if (!comfyResult.ok) {
|
|
1316
|
+
if (!comfyResult.ok || comfyResult.value.software !== "comfyui") {
|
|
1302
1317
|
return Result.error({ type: "unsupportedFormat" });
|
|
1303
1318
|
}
|
|
1304
1319
|
const metadata = {
|
|
1305
1320
|
...comfyResult.value,
|
|
1306
|
-
type: "comfyui",
|
|
1307
1321
|
software: "stability-matrix"
|
|
1308
1322
|
};
|
|
1309
1323
|
const jsonText = entryRecord["parameters-json"];
|
|
@@ -1365,13 +1379,19 @@ function parseSwarmUI(entries) {
|
|
|
1365
1379
|
const width = params.width ?? 0;
|
|
1366
1380
|
const height = params.height ?? 0;
|
|
1367
1381
|
const metadata = {
|
|
1368
|
-
type: "swarmui",
|
|
1369
1382
|
software: "swarmui",
|
|
1370
1383
|
prompt: params.prompt ?? "",
|
|
1371
1384
|
negativePrompt: params.negativeprompt ?? "",
|
|
1372
1385
|
width,
|
|
1373
1386
|
height
|
|
1374
1387
|
};
|
|
1388
|
+
const promptSource = entryRecord.prompt || entryRecord.Make;
|
|
1389
|
+
if (promptSource) {
|
|
1390
|
+
const promptParsed = parseJson(promptSource);
|
|
1391
|
+
if (promptParsed.ok) {
|
|
1392
|
+
metadata.nodes = promptParsed.value;
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1375
1395
|
if (params.model) {
|
|
1376
1396
|
metadata.model = {
|
|
1377
1397
|
name: params.model
|
|
@@ -1414,13 +1434,24 @@ function parseTensorArt(entries) {
|
|
|
1414
1434
|
const data = parsed.value;
|
|
1415
1435
|
const width = data.width ?? 0;
|
|
1416
1436
|
const height = data.height ?? 0;
|
|
1437
|
+
const promptChunk = entryRecord.prompt;
|
|
1438
|
+
if (!promptChunk) {
|
|
1439
|
+
return Result.error({ type: "unsupportedFormat" });
|
|
1440
|
+
}
|
|
1441
|
+
const promptParsed = parseJson(promptChunk);
|
|
1442
|
+
if (!promptParsed.ok) {
|
|
1443
|
+
return Result.error({
|
|
1444
|
+
type: "parseError",
|
|
1445
|
+
message: "Invalid JSON in prompt chunk"
|
|
1446
|
+
});
|
|
1447
|
+
}
|
|
1417
1448
|
const metadata = {
|
|
1418
|
-
type: "comfyui",
|
|
1419
1449
|
software: "tensorart",
|
|
1420
1450
|
prompt: data.prompt ?? "",
|
|
1421
1451
|
negativePrompt: data.negativePrompt ?? "",
|
|
1422
1452
|
width,
|
|
1423
|
-
height
|
|
1453
|
+
height,
|
|
1454
|
+
nodes: promptParsed.value
|
|
1424
1455
|
};
|
|
1425
1456
|
if (data.baseModel?.modelFileName || data.baseModel?.hash) {
|
|
1426
1457
|
metadata.model = {
|
|
@@ -1429,8 +1460,9 @@ function parseTensorArt(entries) {
|
|
|
1429
1460
|
};
|
|
1430
1461
|
}
|
|
1431
1462
|
if (data.seed !== void 0 || data.steps !== void 0 || data.cfgScale !== void 0 || data.clipSkip !== void 0) {
|
|
1463
|
+
const baseSeed = data.seed ? Number(data.seed) : void 0;
|
|
1432
1464
|
metadata.sampling = {
|
|
1433
|
-
seed:
|
|
1465
|
+
seed: baseSeed === -1 ? findActualSeed(promptParsed.value) : baseSeed,
|
|
1434
1466
|
steps: data.steps,
|
|
1435
1467
|
cfg: data.cfgScale,
|
|
1436
1468
|
clipSkip: data.clipSkip
|
|
@@ -1438,6 +1470,15 @@ function parseTensorArt(entries) {
|
|
|
1438
1470
|
}
|
|
1439
1471
|
return Result.ok(metadata);
|
|
1440
1472
|
}
|
|
1473
|
+
function findActualSeed(nodes) {
|
|
1474
|
+
const samplerNode = findSamplerNode(nodes);
|
|
1475
|
+
return samplerNode && typeof samplerNode.inputs.seed === "number" ? samplerNode.inputs.seed : -1;
|
|
1476
|
+
}
|
|
1477
|
+
function findSamplerNode(nodes) {
|
|
1478
|
+
return Object.values(nodes).find(
|
|
1479
|
+
(node) => node.class_type === "KSampler" || node.class_type.toLowerCase().includes("sampler")
|
|
1480
|
+
);
|
|
1481
|
+
}
|
|
1441
1482
|
|
|
1442
1483
|
// src/parsers/index.ts
|
|
1443
1484
|
function parseMetadata(entries) {
|