@enslo/sd-metadata 1.5.0 → 1.6.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.ja.md +1 -1
- package/README.md +1 -1
- package/dist/index.d.ts +12 -2
- package/dist/index.js +420 -301
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -4,6 +4,14 @@ var Result = {
|
|
|
4
4
|
error: (error) => ({ ok: false, error })
|
|
5
5
|
};
|
|
6
6
|
|
|
7
|
+
// src/utils/object.ts
|
|
8
|
+
function trimObject(obj) {
|
|
9
|
+
const result = Object.fromEntries(
|
|
10
|
+
Object.entries(obj).filter(([, value]) => value !== void 0)
|
|
11
|
+
);
|
|
12
|
+
return Object.keys(result).length === 0 ? void 0 : result;
|
|
13
|
+
}
|
|
14
|
+
|
|
7
15
|
// src/parsers/a1111.ts
|
|
8
16
|
function parseA1111(entries) {
|
|
9
17
|
const parametersEntry = entries.find(
|
|
@@ -24,21 +32,8 @@ function parseA1111(entries) {
|
|
|
24
32
|
const version = settingsMap.get("Version");
|
|
25
33
|
const app = settingsMap.get("App");
|
|
26
34
|
const software = detectSoftwareVariant(version, app);
|
|
27
|
-
const metadata = {
|
|
28
|
-
software,
|
|
29
|
-
prompt,
|
|
30
|
-
negativePrompt,
|
|
31
|
-
width,
|
|
32
|
-
height
|
|
33
|
-
};
|
|
34
35
|
const modelName = settingsMap.get("Model");
|
|
35
36
|
const modelHash = settingsMap.get("Model hash");
|
|
36
|
-
if (modelName || modelHash) {
|
|
37
|
-
metadata.model = {
|
|
38
|
-
name: modelName,
|
|
39
|
-
hash: modelHash
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
37
|
const sampler = settingsMap.get("Sampler");
|
|
43
38
|
const scheduler = settingsMap.get("Schedule type");
|
|
44
39
|
const steps = parseNumber(settingsMap.get("Steps"));
|
|
@@ -47,29 +42,30 @@ function parseA1111(entries) {
|
|
|
47
42
|
);
|
|
48
43
|
const seed = parseNumber(settingsMap.get("Seed"));
|
|
49
44
|
const clipSkip = parseNumber(settingsMap.get("Clip skip"));
|
|
50
|
-
|
|
51
|
-
|
|
45
|
+
const hiresScale = parseNumber(settingsMap.get("Hires upscale"));
|
|
46
|
+
const upscaler = settingsMap.get("Hires upscaler");
|
|
47
|
+
const hiresSteps = parseNumber(settingsMap.get("Hires steps"));
|
|
48
|
+
const denoise = parseNumber(settingsMap.get("Denoising strength"));
|
|
49
|
+
const hiresSize = settingsMap.get("Hires size");
|
|
50
|
+
const [hiresWidth] = parseSize(hiresSize ?? "");
|
|
51
|
+
const scale = hiresScale ?? (hiresWidth > 0 ? hiresWidth / width : void 0);
|
|
52
|
+
return Result.ok({
|
|
53
|
+
software,
|
|
54
|
+
prompt,
|
|
55
|
+
negativePrompt,
|
|
56
|
+
width,
|
|
57
|
+
height,
|
|
58
|
+
model: trimObject({ name: modelName, hash: modelHash }),
|
|
59
|
+
sampling: trimObject({
|
|
52
60
|
sampler,
|
|
53
61
|
scheduler,
|
|
54
62
|
steps,
|
|
55
63
|
cfg,
|
|
56
64
|
seed,
|
|
57
65
|
clipSkip
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
const upscaler = settingsMap.get("Hires upscaler");
|
|
62
|
-
const hiresSteps = parseNumber(settingsMap.get("Hires steps"));
|
|
63
|
-
const denoise = parseNumber(settingsMap.get("Denoising strength"));
|
|
64
|
-
const hiresSize = settingsMap.get("Hires size");
|
|
65
|
-
if ([hiresScale, hiresSize, upscaler, hiresSteps, denoise].some(
|
|
66
|
-
(v) => v !== void 0
|
|
67
|
-
)) {
|
|
68
|
-
const [hiresWidth] = parseSize(hiresSize ?? "");
|
|
69
|
-
const scale = hiresScale ?? hiresWidth / width;
|
|
70
|
-
metadata.hires = { scale, upscaler, steps: hiresSteps, denoise };
|
|
71
|
-
}
|
|
72
|
-
return Result.ok(metadata);
|
|
66
|
+
}),
|
|
67
|
+
hires: trimObject({ scale, upscaler, steps: hiresSteps, denoise })
|
|
68
|
+
});
|
|
73
69
|
}
|
|
74
70
|
function parseParametersText(text) {
|
|
75
71
|
const negativeIndex = text.indexOf("Negative prompt:");
|
|
@@ -133,13 +129,6 @@ function detectSoftwareVariant(version, app) {
|
|
|
133
129
|
return "sd-webui";
|
|
134
130
|
}
|
|
135
131
|
|
|
136
|
-
// src/utils/entries.ts
|
|
137
|
-
function buildEntryRecord(entries) {
|
|
138
|
-
return Object.freeze(
|
|
139
|
-
Object.fromEntries(entries.map((e) => [e.keyword, e.text]))
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
132
|
// src/utils/json.ts
|
|
144
133
|
function parseJson(text) {
|
|
145
134
|
try {
|
|
@@ -152,7 +141,37 @@ function parseJson(text) {
|
|
|
152
141
|
}
|
|
153
142
|
}
|
|
154
143
|
|
|
144
|
+
// src/utils/entries.ts
|
|
145
|
+
function buildEntryRecord(entries) {
|
|
146
|
+
return Object.freeze(
|
|
147
|
+
Object.fromEntries(entries.map((e) => [e.keyword, e.text]))
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
function extractFromCommentJson(entryRecord, key) {
|
|
151
|
+
if (!entryRecord.Comment?.startsWith("{")) return void 0;
|
|
152
|
+
const parsed = parseJson(entryRecord.Comment);
|
|
153
|
+
if (!parsed.ok) return void 0;
|
|
154
|
+
const value = parsed.value[key];
|
|
155
|
+
if (typeof value === "string") return value;
|
|
156
|
+
if (typeof value === "object" && value !== null) return JSON.stringify(value);
|
|
157
|
+
return void 0;
|
|
158
|
+
}
|
|
159
|
+
|
|
155
160
|
// src/parsers/comfyui.ts
|
|
161
|
+
var CIVITAI_EXTENSION_KEYS = ["extra", "extraMetadata", "resource-stack"];
|
|
162
|
+
var COMFYUI_NODE_KEYS = {
|
|
163
|
+
sampler: ["Sampler"],
|
|
164
|
+
positiveClip: ["PositiveCLIP_Base"],
|
|
165
|
+
negativeClip: ["NegativeCLIP_Base"],
|
|
166
|
+
latentImage: ["EmptyLatentImage"],
|
|
167
|
+
checkpoint: ["CheckpointLoader_Base"],
|
|
168
|
+
hiresModelUpscale: [
|
|
169
|
+
"HiresFix_ModelUpscale_UpscaleModelLoader",
|
|
170
|
+
"PostUpscale_ModelUpscale_UpscaleModelLoader"
|
|
171
|
+
],
|
|
172
|
+
hiresImageScale: ["HiresFix_ImageScale", "PostUpscale_ImageScale"],
|
|
173
|
+
hiresSampler: ["HiresFix_Sampler"]
|
|
174
|
+
};
|
|
156
175
|
function parseComfyUI(entries) {
|
|
157
176
|
const entryRecord = buildEntryRecord(entries);
|
|
158
177
|
const promptText = findPromptJson(entryRecord);
|
|
@@ -167,99 +186,35 @@ function parseComfyUI(entries) {
|
|
|
167
186
|
});
|
|
168
187
|
}
|
|
169
188
|
const prompt = parsed.value;
|
|
170
|
-
|
|
171
|
-
if (!nodes.some((node) => "class_type" in node)) {
|
|
189
|
+
if (!Object.values(prompt).some((node) => "class_type" in node)) {
|
|
172
190
|
return Result.error({ type: "unsupportedFormat" });
|
|
173
191
|
}
|
|
174
|
-
const
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
const
|
|
180
|
-
const
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
|
|
185
|
-
const width = latentWidth || extraMeta?.width || 0;
|
|
186
|
-
const height = latentHeight || extraMeta?.height || 0;
|
|
187
|
-
const metadata = {
|
|
192
|
+
const nodes = Object.fromEntries(
|
|
193
|
+
Object.entries(prompt).filter(
|
|
194
|
+
([key]) => !CIVITAI_EXTENSION_KEYS.includes(key)
|
|
195
|
+
)
|
|
196
|
+
);
|
|
197
|
+
const comfyMetadata = extractComfyUIMetadata(prompt);
|
|
198
|
+
const civitaiMetadata = extractCivitaiMetadata(
|
|
199
|
+
extractExtraMetadata(prompt, entryRecord)
|
|
200
|
+
);
|
|
201
|
+
const merged = mergeMetadata(civitaiMetadata, comfyMetadata);
|
|
202
|
+
return Result.ok({
|
|
188
203
|
software: "comfyui",
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
if (
|
|
198
|
-
|
|
199
|
-
} else if (extraMeta?.baseModel) {
|
|
200
|
-
metadata.model = { name: extraMeta.baseModel };
|
|
201
|
-
}
|
|
202
|
-
if (ksampler) {
|
|
203
|
-
metadata.sampling = {
|
|
204
|
-
seed: ksampler.inputs.seed,
|
|
205
|
-
steps: ksampler.inputs.steps,
|
|
206
|
-
cfg: ksampler.inputs.cfg,
|
|
207
|
-
sampler: ksampler.inputs.sampler_name,
|
|
208
|
-
scheduler: ksampler.inputs.scheduler
|
|
209
|
-
};
|
|
210
|
-
} else if (extraMeta) {
|
|
211
|
-
metadata.sampling = {
|
|
212
|
-
seed: extraMeta.seed,
|
|
213
|
-
steps: extraMeta.steps,
|
|
214
|
-
cfg: extraMeta.cfgScale,
|
|
215
|
-
sampler: extraMeta.sampler
|
|
216
|
-
};
|
|
217
|
-
}
|
|
218
|
-
const hiresModel = findNode(prompt, [
|
|
219
|
-
"HiresFix_ModelUpscale_UpscaleModelLoader",
|
|
220
|
-
"PostUpscale_ModelUpscale_UpscaleModelLoader"
|
|
221
|
-
])?.inputs;
|
|
222
|
-
const hiresScale = findNode(prompt, [
|
|
223
|
-
"HiresFix_ImageScale",
|
|
224
|
-
"PostUpscale_ImageScale"
|
|
225
|
-
])?.inputs;
|
|
226
|
-
const hiresSampler = findNode(prompt, ["HiresFix_Sampler"])?.inputs;
|
|
227
|
-
if (hiresModel && hiresScale) {
|
|
228
|
-
const hiresWidth = hiresScale.width;
|
|
229
|
-
const scale = latentWidth > 0 ? Math.round(hiresWidth / latentWidth * 100) / 100 : void 0;
|
|
230
|
-
if (hiresSampler) {
|
|
231
|
-
metadata.hires = {
|
|
232
|
-
upscaler: hiresModel.model_name,
|
|
233
|
-
scale,
|
|
234
|
-
steps: hiresSampler.steps,
|
|
235
|
-
denoise: hiresSampler.denoise
|
|
236
|
-
};
|
|
237
|
-
} else {
|
|
238
|
-
metadata.upscale = {
|
|
239
|
-
upscaler: hiresModel.model_name,
|
|
240
|
-
scale
|
|
241
|
-
};
|
|
242
|
-
}
|
|
243
|
-
}
|
|
244
|
-
if (extraMeta?.transformations) {
|
|
245
|
-
const upscaleTransform = extraMeta.transformations.find(
|
|
246
|
-
(t) => t.type === "upscale"
|
|
247
|
-
);
|
|
248
|
-
if (upscaleTransform) {
|
|
249
|
-
const originalWidth = extraMeta.width ?? width;
|
|
250
|
-
if (originalWidth > 0 && upscaleTransform.upscaleWidth) {
|
|
251
|
-
const scale = upscaleTransform.upscaleWidth / originalWidth;
|
|
252
|
-
metadata.upscale = {
|
|
253
|
-
scale: Math.round(scale * 100) / 100
|
|
254
|
-
};
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
return Result.ok(metadata);
|
|
204
|
+
nodes,
|
|
205
|
+
...merged
|
|
206
|
+
});
|
|
207
|
+
}
|
|
208
|
+
function cleanJsonString(json) {
|
|
209
|
+
return json.replace(/\0+$/, "").replace(/:\s*NaN\b/g, ": null");
|
|
210
|
+
}
|
|
211
|
+
function calculateScale(targetWidth, baseWidth) {
|
|
212
|
+
if (baseWidth <= 0 || targetWidth <= 0) return void 0;
|
|
213
|
+
return Math.round(targetWidth / baseWidth * 100) / 100;
|
|
259
214
|
}
|
|
260
215
|
function findPromptJson(entryRecord) {
|
|
261
216
|
if (entryRecord.prompt) {
|
|
262
|
-
return entryRecord.prompt
|
|
217
|
+
return cleanJsonString(entryRecord.prompt);
|
|
263
218
|
}
|
|
264
219
|
const candidates = [
|
|
265
220
|
entryRecord.Comment,
|
|
@@ -273,7 +228,7 @@ function findPromptJson(entryRecord) {
|
|
|
273
228
|
for (const candidate of candidates) {
|
|
274
229
|
if (!candidate) continue;
|
|
275
230
|
if (candidate.startsWith("{")) {
|
|
276
|
-
const cleaned = candidate
|
|
231
|
+
const cleaned = cleanJsonString(candidate);
|
|
277
232
|
const parsed = parseJson(cleaned);
|
|
278
233
|
if (!parsed.ok) continue;
|
|
279
234
|
if (parsed.value.prompt && typeof parsed.value.prompt === "object") {
|
|
@@ -293,14 +248,174 @@ function findNode(prompt, keys) {
|
|
|
293
248
|
function extractText(node) {
|
|
294
249
|
return typeof node?.inputs.text === "string" ? node.inputs.text : "";
|
|
295
250
|
}
|
|
296
|
-
function
|
|
251
|
+
function extractPromptTexts(prompt) {
|
|
252
|
+
const positiveClip = findNode(prompt, COMFYUI_NODE_KEYS.positiveClip);
|
|
253
|
+
const negativeClip = findNode(prompt, COMFYUI_NODE_KEYS.negativeClip);
|
|
254
|
+
return {
|
|
255
|
+
promptText: extractText(positiveClip),
|
|
256
|
+
negativeText: extractText(negativeClip)
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
function extractDimensions(prompt) {
|
|
260
|
+
const latentImage = findNode(prompt, COMFYUI_NODE_KEYS.latentImage);
|
|
261
|
+
return {
|
|
262
|
+
width: latentImage ? Number(latentImage.inputs.width) || 0 : 0,
|
|
263
|
+
height: latentImage ? Number(latentImage.inputs.height) || 0 : 0
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function extractSamplingFromKSampler(ksampler) {
|
|
267
|
+
if (!ksampler) return void 0;
|
|
268
|
+
return {
|
|
269
|
+
seed: ksampler.inputs.seed,
|
|
270
|
+
steps: ksampler.inputs.steps,
|
|
271
|
+
cfg: ksampler.inputs.cfg,
|
|
272
|
+
sampler: ksampler.inputs.sampler_name,
|
|
273
|
+
scheduler: ksampler.inputs.scheduler
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
function extractModelFromCheckpoint(checkpoint) {
|
|
277
|
+
if (!checkpoint?.inputs?.ckpt_name) return void 0;
|
|
278
|
+
return { name: String(checkpoint.inputs.ckpt_name) };
|
|
279
|
+
}
|
|
280
|
+
function extractComfyUIMetadata(prompt) {
|
|
281
|
+
const { promptText, negativeText } = extractPromptTexts(prompt);
|
|
282
|
+
const { width, height } = extractDimensions(prompt);
|
|
283
|
+
const ksampler = findNode(prompt, COMFYUI_NODE_KEYS.sampler);
|
|
284
|
+
const checkpoint = findNode(prompt, COMFYUI_NODE_KEYS.checkpoint);
|
|
285
|
+
const hiresModel = findNode(
|
|
286
|
+
prompt,
|
|
287
|
+
COMFYUI_NODE_KEYS.hiresModelUpscale
|
|
288
|
+
)?.inputs;
|
|
289
|
+
const hiresScale = findNode(
|
|
290
|
+
prompt,
|
|
291
|
+
COMFYUI_NODE_KEYS.hiresImageScale
|
|
292
|
+
)?.inputs;
|
|
293
|
+
const hiresSampler = findNode(prompt, COMFYUI_NODE_KEYS.hiresSampler)?.inputs;
|
|
294
|
+
return trimObject({
|
|
295
|
+
prompt: promptText || void 0,
|
|
296
|
+
negativePrompt: negativeText || void 0,
|
|
297
|
+
width: width > 0 ? width : void 0,
|
|
298
|
+
height: height > 0 ? height : void 0,
|
|
299
|
+
model: extractModelFromCheckpoint(checkpoint),
|
|
300
|
+
sampling: extractSamplingFromKSampler(ksampler),
|
|
301
|
+
...buildHiresOrUpscale(hiresModel, hiresScale, hiresSampler, width)
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
function buildHiresOrUpscale(hiresModel, hiresScale, hiresSampler, baseWidth) {
|
|
305
|
+
if (!hiresModel || !hiresScale) return {};
|
|
306
|
+
const hiresWidth = hiresScale.width;
|
|
307
|
+
const scale = calculateScale(hiresWidth, baseWidth);
|
|
308
|
+
if (hiresSampler) {
|
|
309
|
+
return {
|
|
310
|
+
hires: {
|
|
311
|
+
upscaler: hiresModel.model_name,
|
|
312
|
+
scale,
|
|
313
|
+
steps: hiresSampler.steps,
|
|
314
|
+
denoise: hiresSampler.denoise
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
return {
|
|
319
|
+
upscale: {
|
|
320
|
+
upscaler: hiresModel.model_name,
|
|
321
|
+
scale
|
|
322
|
+
}
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
function extractExtraMetadata(prompt, entryRecord) {
|
|
297
326
|
const extraMetaField = prompt.extraMetadata;
|
|
298
|
-
if (typeof extraMetaField
|
|
299
|
-
|
|
300
|
-
|
|
327
|
+
if (typeof extraMetaField === "string") {
|
|
328
|
+
const parsed = parseJson(extraMetaField);
|
|
329
|
+
if (parsed.ok) return parsed.value;
|
|
330
|
+
}
|
|
331
|
+
if (entryRecord?.extraMetadata) {
|
|
332
|
+
const parsed = parseJson(entryRecord.extraMetadata);
|
|
333
|
+
if (parsed.ok) return parsed.value;
|
|
334
|
+
}
|
|
335
|
+
return void 0;
|
|
336
|
+
}
|
|
337
|
+
function extractCivitaiMetadata(extraMeta) {
|
|
338
|
+
if (!extraMeta) return void 0;
|
|
339
|
+
const upscale = buildCivitaiUpscale(extraMeta);
|
|
340
|
+
const sampling = buildCivitaiSampling(extraMeta);
|
|
341
|
+
return trimObject({
|
|
342
|
+
prompt: extraMeta.prompt,
|
|
343
|
+
negativePrompt: extraMeta.negativePrompt,
|
|
344
|
+
width: extraMeta.width,
|
|
345
|
+
height: extraMeta.height,
|
|
346
|
+
model: extraMeta.baseModel ? { name: extraMeta.baseModel } : void 0,
|
|
347
|
+
...sampling,
|
|
348
|
+
...upscale
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
function buildCivitaiUpscale(extraMeta) {
|
|
352
|
+
if (!extraMeta.transformations) return {};
|
|
353
|
+
const upscaleTransform = extraMeta.transformations.find(
|
|
354
|
+
(t) => t.type === "upscale"
|
|
355
|
+
);
|
|
356
|
+
if (!upscaleTransform?.upscaleWidth) return {};
|
|
357
|
+
const scale = calculateScale(
|
|
358
|
+
upscaleTransform.upscaleWidth,
|
|
359
|
+
extraMeta.width ?? 0
|
|
360
|
+
);
|
|
361
|
+
if (scale === void 0) return {};
|
|
362
|
+
return {
|
|
363
|
+
upscale: { scale }
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
function buildCivitaiSampling(extraMeta) {
|
|
367
|
+
if (extraMeta.seed === void 0 && extraMeta.steps === void 0 && extraMeta.cfgScale === void 0 && extraMeta.sampler === void 0) {
|
|
368
|
+
return {};
|
|
369
|
+
}
|
|
370
|
+
return {
|
|
371
|
+
sampling: {
|
|
372
|
+
seed: extraMeta.seed,
|
|
373
|
+
steps: extraMeta.steps,
|
|
374
|
+
cfg: extraMeta.cfgScale,
|
|
375
|
+
sampler: extraMeta.sampler
|
|
376
|
+
}
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
function mergeMetadata(base, override) {
|
|
380
|
+
const merged = { ...base, ...override };
|
|
381
|
+
return {
|
|
382
|
+
// Required fields with defaults
|
|
383
|
+
prompt: merged.prompt ?? "",
|
|
384
|
+
negativePrompt: merged.negativePrompt ?? "",
|
|
385
|
+
width: merged.width ?? 0,
|
|
386
|
+
height: merged.height ?? 0,
|
|
387
|
+
// Optional fields - only include if defined
|
|
388
|
+
...trimObject({
|
|
389
|
+
model: merged.model,
|
|
390
|
+
sampling: merged.sampling,
|
|
391
|
+
hires: merged.hires,
|
|
392
|
+
upscale: merged.upscale
|
|
393
|
+
})
|
|
394
|
+
};
|
|
301
395
|
}
|
|
302
396
|
|
|
303
397
|
// src/parsers/detect.ts
|
|
398
|
+
var MARKERS = {
|
|
399
|
+
// Unique chunk keywords
|
|
400
|
+
INVOKEAI: "invokeai_metadata",
|
|
401
|
+
TENSORART: "generation_data",
|
|
402
|
+
STABILITY_MATRIX: "smproj",
|
|
403
|
+
EASYDIFFUSION: "use_stable_diffusion_model",
|
|
404
|
+
CIVITAI_EXTRA: "extraMetadata",
|
|
405
|
+
// Content patterns
|
|
406
|
+
SWARMUI: "sui_image_params",
|
|
407
|
+
SWARM_VERSION: "swarm_version",
|
|
408
|
+
COMFYUI_NODE: "class_type",
|
|
409
|
+
NOVELAI_SCHEDULE: "noise_schedule",
|
|
410
|
+
NOVELAI_V4: "v4_prompt",
|
|
411
|
+
NOVELAI_UNCOND: "uncond_scale",
|
|
412
|
+
CIVITAI_NS: "civitai:",
|
|
413
|
+
CIVITAI_RESOURCES: "Civitai resources:",
|
|
414
|
+
RUINED_FOOOCUS: "RuinedFooocus",
|
|
415
|
+
HF_MODEL: '"Model"',
|
|
416
|
+
HF_RESOLUTION: '"resolution"',
|
|
417
|
+
FOOOCUS_BASE: '"base_model"'
|
|
418
|
+
};
|
|
304
419
|
function detectSoftware(entries) {
|
|
305
420
|
const entryRecord = buildEntryRecord(entries);
|
|
306
421
|
const uniqueResult = detectUniqueKeywords(entryRecord);
|
|
@@ -317,20 +432,23 @@ function detectUniqueKeywords(entryRecord) {
|
|
|
317
432
|
if (entryRecord.Software?.startsWith("NovelAI")) {
|
|
318
433
|
return "novelai";
|
|
319
434
|
}
|
|
320
|
-
if (
|
|
435
|
+
if (MARKERS.INVOKEAI in entryRecord) {
|
|
321
436
|
return "invokeai";
|
|
322
437
|
}
|
|
323
|
-
if (
|
|
438
|
+
if (MARKERS.TENSORART in entryRecord) {
|
|
324
439
|
return "tensorart";
|
|
325
440
|
}
|
|
326
|
-
if (
|
|
441
|
+
if (MARKERS.STABILITY_MATRIX in entryRecord) {
|
|
327
442
|
return "stability-matrix";
|
|
328
443
|
}
|
|
329
444
|
if ("negative_prompt" in entryRecord || "Negative Prompt" in entryRecord) {
|
|
330
445
|
return "easydiffusion";
|
|
331
446
|
}
|
|
447
|
+
if (MARKERS.CIVITAI_EXTRA in entryRecord) {
|
|
448
|
+
return "civitai";
|
|
449
|
+
}
|
|
332
450
|
const parameters = entryRecord.parameters;
|
|
333
|
-
if (parameters?.includes(
|
|
451
|
+
if (parameters?.includes(MARKERS.SWARMUI)) {
|
|
334
452
|
return "swarmui";
|
|
335
453
|
}
|
|
336
454
|
const comment = entryRecord.Comment;
|
|
@@ -342,15 +460,18 @@ function detectUniqueKeywords(entryRecord) {
|
|
|
342
460
|
function detectFromCommentJson(comment) {
|
|
343
461
|
try {
|
|
344
462
|
const parsed = JSON.parse(comment);
|
|
345
|
-
if (
|
|
463
|
+
if (MARKERS.INVOKEAI in parsed) {
|
|
346
464
|
return "invokeai";
|
|
347
465
|
}
|
|
348
|
-
if (
|
|
466
|
+
if (MARKERS.TENSORART in parsed) {
|
|
349
467
|
return "tensorart";
|
|
350
468
|
}
|
|
351
|
-
if (
|
|
469
|
+
if (MARKERS.STABILITY_MATRIX in parsed) {
|
|
352
470
|
return "stability-matrix";
|
|
353
471
|
}
|
|
472
|
+
if (MARKERS.CIVITAI_EXTRA in parsed) {
|
|
473
|
+
return "civitai";
|
|
474
|
+
}
|
|
354
475
|
if ("prompt" in parsed && "workflow" in parsed) {
|
|
355
476
|
const workflow = parsed.workflow;
|
|
356
477
|
const prompt = parsed.prompt;
|
|
@@ -360,12 +481,12 @@ function detectFromCommentJson(comment) {
|
|
|
360
481
|
return "comfyui";
|
|
361
482
|
}
|
|
362
483
|
}
|
|
363
|
-
if (
|
|
484
|
+
if (MARKERS.SWARMUI in parsed) {
|
|
364
485
|
return "swarmui";
|
|
365
486
|
}
|
|
366
487
|
if ("prompt" in parsed && "parameters" in parsed) {
|
|
367
488
|
const params = String(parsed.parameters || "");
|
|
368
|
-
if (params.includes(
|
|
489
|
+
if (params.includes(MARKERS.SWARMUI) || params.includes(MARKERS.SWARM_VERSION)) {
|
|
369
490
|
return "swarmui";
|
|
370
491
|
}
|
|
371
492
|
}
|
|
@@ -383,10 +504,10 @@ function detectComfyUIEntries(entryRecord) {
|
|
|
383
504
|
if ("prompt" in entryRecord) {
|
|
384
505
|
const promptText = entryRecord.prompt;
|
|
385
506
|
if (promptText?.startsWith("{")) {
|
|
386
|
-
if (promptText.includes(
|
|
507
|
+
if (promptText.includes(MARKERS.SWARMUI)) {
|
|
387
508
|
return "swarmui";
|
|
388
509
|
}
|
|
389
|
-
if (promptText.includes(
|
|
510
|
+
if (promptText.includes(MARKERS.COMFYUI_NODE)) {
|
|
390
511
|
return "comfyui";
|
|
391
512
|
}
|
|
392
513
|
}
|
|
@@ -400,25 +521,25 @@ function detectFromTextContent(text) {
|
|
|
400
521
|
return detectFromA1111Format(text);
|
|
401
522
|
}
|
|
402
523
|
function detectFromJsonFormat(json) {
|
|
403
|
-
if (json.includes(
|
|
524
|
+
if (json.includes(MARKERS.SWARMUI)) {
|
|
404
525
|
return "swarmui";
|
|
405
526
|
}
|
|
406
|
-
if (json.includes(
|
|
527
|
+
if (json.includes(`"software":"${MARKERS.RUINED_FOOOCUS}"`) || json.includes(`"software": "${MARKERS.RUINED_FOOOCUS}"`)) {
|
|
407
528
|
return "ruined-fooocus";
|
|
408
529
|
}
|
|
409
|
-
if (json.includes(
|
|
530
|
+
if (json.includes(`"${MARKERS.EASYDIFFUSION}"`)) {
|
|
410
531
|
return "easydiffusion";
|
|
411
532
|
}
|
|
412
|
-
if (json.includes(
|
|
533
|
+
if (json.includes(MARKERS.CIVITAI_NS) || json.includes(`"${MARKERS.CIVITAI_EXTRA}"`)) {
|
|
413
534
|
return "civitai";
|
|
414
535
|
}
|
|
415
|
-
if (json.includes(
|
|
536
|
+
if (json.includes(`"${MARKERS.NOVELAI_V4}"`) || json.includes(`"${MARKERS.NOVELAI_SCHEDULE}"`) || json.includes(`"${MARKERS.NOVELAI_UNCOND}"`) || json.includes('"Software":"NovelAI"') || json.includes(`\\"${MARKERS.NOVELAI_SCHEDULE}\\"`) || json.includes(`\\"${MARKERS.NOVELAI_V4}\\"`)) {
|
|
416
537
|
return "novelai";
|
|
417
538
|
}
|
|
418
|
-
if (json.includes(
|
|
539
|
+
if (json.includes(MARKERS.HF_MODEL) && json.includes(MARKERS.HF_RESOLUTION)) {
|
|
419
540
|
return "hf-space";
|
|
420
541
|
}
|
|
421
|
-
if (json.includes('"prompt"') && json.includes(
|
|
542
|
+
if (json.includes('"prompt"') && json.includes(MARKERS.FOOOCUS_BASE)) {
|
|
422
543
|
return "fooocus";
|
|
423
544
|
}
|
|
424
545
|
if (json.includes('"prompt"') || json.includes('"nodes"')) {
|
|
@@ -427,7 +548,7 @@ function detectFromJsonFormat(json) {
|
|
|
427
548
|
return null;
|
|
428
549
|
}
|
|
429
550
|
function detectFromA1111Format(text) {
|
|
430
|
-
if (text.includes(
|
|
551
|
+
if (text.includes(MARKERS.SWARMUI) || text.includes(MARKERS.SWARM_VERSION)) {
|
|
431
552
|
return "swarmui";
|
|
432
553
|
}
|
|
433
554
|
const versionMatch = text.match(/Version:\s*([^\s,]+)/);
|
|
@@ -446,7 +567,7 @@ function detectFromA1111Format(text) {
|
|
|
446
567
|
if (text.includes("App: SD.Next") || text.includes("App:SD.Next")) {
|
|
447
568
|
return "sd-next";
|
|
448
569
|
}
|
|
449
|
-
if (text.includes(
|
|
570
|
+
if (text.includes(MARKERS.CIVITAI_RESOURCES)) {
|
|
450
571
|
return "civitai";
|
|
451
572
|
}
|
|
452
573
|
if (text.includes("Steps:") && text.includes("Sampler:")) {
|
|
@@ -606,33 +727,23 @@ function parseHfSpace(entries) {
|
|
|
606
727
|
negativePrompt: json.negative_prompt ?? "",
|
|
607
728
|
width,
|
|
608
729
|
height,
|
|
609
|
-
model: {
|
|
730
|
+
model: trimObject({
|
|
610
731
|
name: json.Model,
|
|
611
732
|
hash: json["Model hash"]
|
|
612
|
-
},
|
|
613
|
-
sampling: {
|
|
733
|
+
}),
|
|
734
|
+
sampling: trimObject({
|
|
614
735
|
sampler: json.sampler,
|
|
615
736
|
steps: json.num_inference_steps,
|
|
616
737
|
cfg: json.guidance_scale,
|
|
617
738
|
seed: json.seed
|
|
618
|
-
}
|
|
739
|
+
})
|
|
619
740
|
};
|
|
620
741
|
return Result.ok(metadata);
|
|
621
742
|
}
|
|
622
743
|
|
|
623
744
|
// src/parsers/invokeai.ts
|
|
624
745
|
function extractInvokeAIMetadata(entryRecord) {
|
|
625
|
-
|
|
626
|
-
return entryRecord.invokeai_metadata;
|
|
627
|
-
}
|
|
628
|
-
if (!entryRecord.Comment) {
|
|
629
|
-
return void 0;
|
|
630
|
-
}
|
|
631
|
-
const commentParsed = parseJson(entryRecord.Comment);
|
|
632
|
-
if (!commentParsed.ok || !("invokeai_metadata" in commentParsed.value)) {
|
|
633
|
-
return void 0;
|
|
634
|
-
}
|
|
635
|
-
return JSON.stringify(commentParsed.value.invokeai_metadata);
|
|
746
|
+
return entryRecord.invokeai_metadata ?? extractFromCommentJson(entryRecord, "invokeai_metadata");
|
|
636
747
|
}
|
|
637
748
|
function parseInvokeAI(entries) {
|
|
638
749
|
const entryRecord = buildEntryRecord(entries);
|
|
@@ -650,28 +761,23 @@ function parseInvokeAI(entries) {
|
|
|
650
761
|
const data = parsed.value;
|
|
651
762
|
const width = data.width ?? 0;
|
|
652
763
|
const height = data.height ?? 0;
|
|
653
|
-
|
|
764
|
+
return Result.ok({
|
|
654
765
|
software: "invokeai",
|
|
655
766
|
prompt: data.positive_prompt ?? "",
|
|
656
767
|
negativePrompt: data.negative_prompt ?? "",
|
|
657
768
|
width,
|
|
658
|
-
height
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
};
|
|
665
|
-
}
|
|
666
|
-
if (data.seed !== void 0 || data.steps !== void 0 || data.cfg_scale !== void 0 || data.scheduler !== void 0) {
|
|
667
|
-
metadata.sampling = {
|
|
769
|
+
height,
|
|
770
|
+
model: trimObject({
|
|
771
|
+
name: data.model?.name,
|
|
772
|
+
hash: data.model?.hash
|
|
773
|
+
}),
|
|
774
|
+
sampling: trimObject({
|
|
668
775
|
seed: data.seed,
|
|
669
776
|
steps: data.steps,
|
|
670
777
|
cfg: data.cfg_scale,
|
|
671
778
|
sampler: data.scheduler
|
|
672
|
-
}
|
|
673
|
-
}
|
|
674
|
-
return Result.ok(metadata);
|
|
779
|
+
})
|
|
780
|
+
});
|
|
675
781
|
}
|
|
676
782
|
|
|
677
783
|
// src/parsers/novelai.ts
|
|
@@ -699,35 +805,31 @@ function parseNovelAI(entries) {
|
|
|
699
805
|
const height = comment.height ?? 0;
|
|
700
806
|
const prompt = comment.v4_prompt?.caption?.base_caption ?? comment.prompt ?? "";
|
|
701
807
|
const negativePrompt = comment.v4_negative_prompt?.caption?.base_caption ?? comment.uc ?? "";
|
|
702
|
-
const
|
|
808
|
+
const charCaptions = comment.v4_prompt?.caption?.char_captions;
|
|
809
|
+
const characterPrompts = charCaptions && charCaptions.length > 0 ? charCaptions.map((cc) => {
|
|
810
|
+
if (!cc.char_caption) return null;
|
|
811
|
+
return {
|
|
812
|
+
prompt: cc.char_caption,
|
|
813
|
+
center: cc.centers?.[0]
|
|
814
|
+
};
|
|
815
|
+
}).filter((cp) => cp !== null) : void 0;
|
|
816
|
+
return Result.ok({
|
|
703
817
|
software: "novelai",
|
|
704
818
|
prompt,
|
|
705
819
|
negativePrompt,
|
|
706
820
|
width,
|
|
707
|
-
height
|
|
708
|
-
|
|
709
|
-
if (comment.steps !== void 0 || comment.scale !== void 0 || comment.seed !== void 0 || comment.noise_schedule !== void 0 || comment.sampler !== void 0) {
|
|
710
|
-
metadata.sampling = {
|
|
821
|
+
height,
|
|
822
|
+
sampling: trimObject({
|
|
711
823
|
steps: comment.steps,
|
|
712
824
|
cfg: comment.scale,
|
|
713
825
|
seed: comment.seed,
|
|
714
826
|
sampler: comment.sampler,
|
|
715
827
|
scheduler: comment.noise_schedule
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
if (!cc.char_caption) return null;
|
|
722
|
-
return {
|
|
723
|
-
prompt: cc.char_caption,
|
|
724
|
-
center: cc.centers?.[0]
|
|
725
|
-
};
|
|
726
|
-
}).filter((cp) => cp !== null);
|
|
727
|
-
metadata.useCoords = comment.v4_prompt?.use_coords;
|
|
728
|
-
metadata.useOrder = comment.v4_prompt?.use_order;
|
|
729
|
-
}
|
|
730
|
-
return Result.ok(metadata);
|
|
828
|
+
}),
|
|
829
|
+
characterPrompts,
|
|
830
|
+
useCoords: characterPrompts ? comment.v4_prompt?.use_coords : void 0,
|
|
831
|
+
useOrder: characterPrompts ? comment.v4_prompt?.use_order : void 0
|
|
832
|
+
});
|
|
731
833
|
}
|
|
732
834
|
|
|
733
835
|
// src/parsers/ruined-fooocus.ts
|
|
@@ -777,43 +879,18 @@ function parseStabilityMatrix(entries) {
|
|
|
777
879
|
if (!comfyResult.ok || comfyResult.value.software !== "comfyui") {
|
|
778
880
|
return Result.error({ type: "unsupportedFormat" });
|
|
779
881
|
}
|
|
780
|
-
const
|
|
882
|
+
const jsonText = entryRecord["parameters-json"] ?? extractFromCommentJson(entryRecord, "parameters-json");
|
|
883
|
+
const parsed = jsonText ? parseJson(jsonText) : void 0;
|
|
884
|
+
const data = parsed?.ok ? parsed.value : void 0;
|
|
885
|
+
return Result.ok({
|
|
781
886
|
...comfyResult.value,
|
|
782
|
-
software: "stability-matrix"
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
if (commentParsed.ok) {
|
|
790
|
-
const commentData = commentParsed.value;
|
|
791
|
-
if (typeof commentData["parameters-json"] === "string") {
|
|
792
|
-
jsonText = commentData["parameters-json"];
|
|
793
|
-
} else if (typeof commentData["parameters-json"] === "object") {
|
|
794
|
-
jsonText = JSON.stringify(commentData["parameters-json"]);
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
if (jsonText) {
|
|
799
|
-
const parsed = parseJson(jsonText);
|
|
800
|
-
if (parsed.ok) {
|
|
801
|
-
const data = parsed.value;
|
|
802
|
-
if (data.PositivePrompt !== void 0) {
|
|
803
|
-
metadata.prompt = data.PositivePrompt;
|
|
804
|
-
}
|
|
805
|
-
if (data.NegativePrompt !== void 0) {
|
|
806
|
-
metadata.negativePrompt = data.NegativePrompt;
|
|
807
|
-
}
|
|
808
|
-
if (data.ModelName !== void 0 || data.ModelHash !== void 0) {
|
|
809
|
-
metadata.model = {
|
|
810
|
-
name: data.ModelName,
|
|
811
|
-
hash: data.ModelHash
|
|
812
|
-
};
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
return Result.ok(metadata);
|
|
887
|
+
software: "stability-matrix",
|
|
888
|
+
// Override prompts from parameters-json (more complete than workflow)
|
|
889
|
+
prompt: data?.PositivePrompt ?? comfyResult.value.prompt,
|
|
890
|
+
negativePrompt: data?.NegativePrompt ?? comfyResult.value.negativePrompt,
|
|
891
|
+
// Override model if either name or hash is provided
|
|
892
|
+
model: data?.ModelName !== void 0 || data?.ModelHash !== void 0 ? { name: data?.ModelName, hash: data?.ModelHash } : comfyResult.value.model
|
|
893
|
+
});
|
|
817
894
|
}
|
|
818
895
|
|
|
819
896
|
// src/parsers/swarmui.ts
|
|
@@ -852,67 +929,37 @@ function parseSwarmUI(entries) {
|
|
|
852
929
|
}
|
|
853
930
|
const width = params.width ?? 0;
|
|
854
931
|
const height = params.height ?? 0;
|
|
855
|
-
const
|
|
932
|
+
const promptSource = entryRecord.prompt || entryRecord.Make;
|
|
933
|
+
const promptParsed = promptSource ? parseJson(promptSource) : void 0;
|
|
934
|
+
const nodes = promptParsed?.ok ? promptParsed.value : void 0;
|
|
935
|
+
return Result.ok({
|
|
856
936
|
software: "swarmui",
|
|
857
937
|
prompt: params.prompt ?? "",
|
|
858
938
|
negativePrompt: params.negativeprompt ?? "",
|
|
859
939
|
width,
|
|
860
|
-
height
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
const promptParsed = parseJson(promptSource);
|
|
865
|
-
if (promptParsed.ok) {
|
|
866
|
-
metadata.nodes = promptParsed.value;
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
if (params.model) {
|
|
870
|
-
metadata.model = {
|
|
871
|
-
name: params.model
|
|
872
|
-
};
|
|
873
|
-
}
|
|
874
|
-
if (params.seed !== void 0 || params.steps !== void 0 || params.cfgscale !== void 0 || params.sampler !== void 0 || params.scheduler !== void 0) {
|
|
875
|
-
metadata.sampling = {
|
|
940
|
+
height,
|
|
941
|
+
nodes,
|
|
942
|
+
model: trimObject({ name: params.model }),
|
|
943
|
+
sampling: trimObject({
|
|
876
944
|
seed: params.seed,
|
|
877
945
|
steps: params.steps,
|
|
878
946
|
cfg: params.cfgscale,
|
|
879
947
|
sampler: params.sampler,
|
|
880
948
|
scheduler: params.scheduler
|
|
881
|
-
}
|
|
882
|
-
|
|
883
|
-
if (params.refinerupscale !== void 0 || params.refinerupscalemethod !== void 0 || params.refinercontrolpercentage !== void 0) {
|
|
884
|
-
metadata.hires = {
|
|
949
|
+
}),
|
|
950
|
+
hires: trimObject({
|
|
885
951
|
scale: params.refinerupscale,
|
|
886
952
|
upscaler: params.refinerupscalemethod,
|
|
887
953
|
denoise: params.refinercontrolpercentage
|
|
888
|
-
}
|
|
889
|
-
}
|
|
890
|
-
return Result.ok(metadata);
|
|
954
|
+
})
|
|
955
|
+
});
|
|
891
956
|
}
|
|
892
957
|
|
|
893
958
|
// src/parsers/tensorart.ts
|
|
894
959
|
function parseTensorArt(entries) {
|
|
895
960
|
const entryRecord = buildEntryRecord(entries);
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
if (!dataText && entryRecord.Comment?.startsWith("{")) {
|
|
899
|
-
const commentParsed = parseJson(
|
|
900
|
-
entryRecord.Comment
|
|
901
|
-
);
|
|
902
|
-
if (commentParsed.ok) {
|
|
903
|
-
const commentData = commentParsed.value;
|
|
904
|
-
if (typeof commentData.generation_data === "string") {
|
|
905
|
-
dataText = commentData.generation_data;
|
|
906
|
-
} else if (typeof commentData.generation_data === "object") {
|
|
907
|
-
dataText = JSON.stringify(commentData.generation_data);
|
|
908
|
-
}
|
|
909
|
-
if (typeof commentData.prompt === "string") {
|
|
910
|
-
promptChunk = commentData.prompt;
|
|
911
|
-
} else if (typeof commentData.prompt === "object") {
|
|
912
|
-
promptChunk = JSON.stringify(commentData.prompt);
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
}
|
|
961
|
+
const dataText = entryRecord.generation_data ?? extractFromCommentJson(entryRecord, "generation_data");
|
|
962
|
+
const promptChunk = entryRecord.prompt ?? extractFromCommentJson(entryRecord, "prompt");
|
|
916
963
|
if (!dataText) {
|
|
917
964
|
return Result.error({ type: "unsupportedFormat" });
|
|
918
965
|
}
|
|
@@ -937,30 +984,26 @@ function parseTensorArt(entries) {
|
|
|
937
984
|
message: "Invalid JSON in prompt chunk"
|
|
938
985
|
});
|
|
939
986
|
}
|
|
940
|
-
const
|
|
987
|
+
const baseSeed = data.seed ? Number(data.seed) : void 0;
|
|
988
|
+
const seed = baseSeed === -1 ? findActualSeed(promptParsed.value) : baseSeed;
|
|
989
|
+
return Result.ok({
|
|
941
990
|
software: "tensorart",
|
|
942
991
|
prompt: data.prompt ?? "",
|
|
943
992
|
negativePrompt: data.negativePrompt ?? "",
|
|
944
993
|
width,
|
|
945
994
|
height,
|
|
946
|
-
nodes: promptParsed.value
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
}
|
|
954
|
-
if (data.seed !== void 0 || data.steps !== void 0 || data.cfgScale !== void 0 || data.clipSkip !== void 0) {
|
|
955
|
-
const baseSeed = data.seed ? Number(data.seed) : void 0;
|
|
956
|
-
metadata.sampling = {
|
|
957
|
-
seed: baseSeed === -1 ? findActualSeed(promptParsed.value) : baseSeed,
|
|
995
|
+
nodes: promptParsed.value,
|
|
996
|
+
model: trimObject({
|
|
997
|
+
name: data.baseModel?.modelFileName,
|
|
998
|
+
hash: data.baseModel?.hash
|
|
999
|
+
}),
|
|
1000
|
+
sampling: trimObject({
|
|
1001
|
+
seed,
|
|
958
1002
|
steps: data.steps,
|
|
959
1003
|
cfg: data.cfgScale,
|
|
960
1004
|
clipSkip: data.clipSkip
|
|
961
|
-
}
|
|
962
|
-
}
|
|
963
|
-
return Result.ok(metadata);
|
|
1005
|
+
})
|
|
1006
|
+
});
|
|
964
1007
|
}
|
|
965
1008
|
function findActualSeed(nodes) {
|
|
966
1009
|
const samplerNode = findSamplerNode(nodes);
|
|
@@ -987,8 +1030,16 @@ function parseMetadata(entries) {
|
|
|
987
1030
|
return parseHfSpace(entries);
|
|
988
1031
|
case "civitai": {
|
|
989
1032
|
const comfyResult = parseComfyUI(entries);
|
|
990
|
-
if (comfyResult.ok)
|
|
991
|
-
|
|
1033
|
+
if (comfyResult.ok) {
|
|
1034
|
+
comfyResult.value.software = "civitai";
|
|
1035
|
+
return comfyResult;
|
|
1036
|
+
}
|
|
1037
|
+
const a1111Result = parseA1111(entries);
|
|
1038
|
+
if (a1111Result.ok) {
|
|
1039
|
+
a1111Result.value.software = "civitai";
|
|
1040
|
+
return a1111Result;
|
|
1041
|
+
}
|
|
1042
|
+
return a1111Result;
|
|
992
1043
|
}
|
|
993
1044
|
case "comfyui": {
|
|
994
1045
|
const comfyResult = parseComfyUI(entries);
|
|
@@ -1644,7 +1695,7 @@ function sourceToKeyword(source) {
|
|
|
1644
1695
|
}
|
|
1645
1696
|
|
|
1646
1697
|
// src/api/read.ts
|
|
1647
|
-
function read(input) {
|
|
1698
|
+
function read(input, options) {
|
|
1648
1699
|
const data = toUint8Array(input);
|
|
1649
1700
|
const format = detectFormat(data);
|
|
1650
1701
|
if (!format) {
|
|
@@ -1661,7 +1712,7 @@ function read(input) {
|
|
|
1661
1712
|
return { status: "unrecognized", raw };
|
|
1662
1713
|
}
|
|
1663
1714
|
const metadata = parseResult.value;
|
|
1664
|
-
if (metadata.width === 0 || metadata.height === 0) {
|
|
1715
|
+
if (!options?.strict && (metadata.width === 0 || metadata.height === 0)) {
|
|
1665
1716
|
const dims = HELPERS[format].readDimensions(data);
|
|
1666
1717
|
if (dims) {
|
|
1667
1718
|
metadata.width = metadata.width || dims.width;
|
|
@@ -1852,6 +1903,69 @@ function convertA1111SegmentsToPng(segments) {
|
|
|
1852
1903
|
return createEncodedChunk("parameters", userComment.data, "dynamic");
|
|
1853
1904
|
}
|
|
1854
1905
|
|
|
1906
|
+
// src/converters/civitai.ts
|
|
1907
|
+
var CIVITAI_SPECIAL_KEYS = ["extra", "extraMetadata", "resource-stack"];
|
|
1908
|
+
function convertCivitaiPngToSegments(chunks) {
|
|
1909
|
+
const parametersChunk = chunks.find((c) => c.keyword === "parameters");
|
|
1910
|
+
if (parametersChunk && !parametersChunk.text.trimStart().startsWith("{")) {
|
|
1911
|
+
return convertA1111PngToSegments(chunks);
|
|
1912
|
+
}
|
|
1913
|
+
const data = {};
|
|
1914
|
+
for (const chunk of chunks) {
|
|
1915
|
+
if (chunk.keyword === "prompt") {
|
|
1916
|
+
const parsed = parseJson(chunk.text);
|
|
1917
|
+
if (parsed.ok && typeof parsed.value === "object" && parsed.value) {
|
|
1918
|
+
Object.assign(data, parsed.value);
|
|
1919
|
+
}
|
|
1920
|
+
} else if (chunk.keyword === "extraMetadata") {
|
|
1921
|
+
data[chunk.keyword] = chunk.text;
|
|
1922
|
+
} else {
|
|
1923
|
+
const parsed = parseJson(chunk.text);
|
|
1924
|
+
data[chunk.keyword] = parsed.ok ? parsed.value : chunk.text;
|
|
1925
|
+
}
|
|
1926
|
+
}
|
|
1927
|
+
return [
|
|
1928
|
+
{
|
|
1929
|
+
source: { type: "exifUserComment" },
|
|
1930
|
+
data: JSON.stringify(data)
|
|
1931
|
+
}
|
|
1932
|
+
];
|
|
1933
|
+
}
|
|
1934
|
+
function convertCivitaiSegmentsToPng(segments) {
|
|
1935
|
+
const userComment = findSegment(segments, "exifUserComment");
|
|
1936
|
+
if (!userComment) return [];
|
|
1937
|
+
const isJson = userComment.data.trimStart().startsWith("{");
|
|
1938
|
+
if (!isJson) {
|
|
1939
|
+
return convertA1111SegmentsToPng(segments);
|
|
1940
|
+
}
|
|
1941
|
+
const parsed = parseJson(userComment.data);
|
|
1942
|
+
if (!parsed.ok) {
|
|
1943
|
+
return convertA1111SegmentsToPng(segments);
|
|
1944
|
+
}
|
|
1945
|
+
const data = parsed.value;
|
|
1946
|
+
const promptData = {};
|
|
1947
|
+
const chunks = [];
|
|
1948
|
+
for (const [key, value] of Object.entries(data)) {
|
|
1949
|
+
if (CIVITAI_SPECIAL_KEYS.includes(key)) {
|
|
1950
|
+
chunks.push(
|
|
1951
|
+
...createEncodedChunk(key, stringify(value), "text-utf8-raw")
|
|
1952
|
+
);
|
|
1953
|
+
} else {
|
|
1954
|
+
promptData[key] = value;
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
if (Object.keys(promptData).length > 0) {
|
|
1958
|
+
chunks.unshift(
|
|
1959
|
+
...createEncodedChunk(
|
|
1960
|
+
"prompt",
|
|
1961
|
+
JSON.stringify(promptData),
|
|
1962
|
+
"text-utf8-raw"
|
|
1963
|
+
)
|
|
1964
|
+
);
|
|
1965
|
+
}
|
|
1966
|
+
return chunks;
|
|
1967
|
+
}
|
|
1968
|
+
|
|
1855
1969
|
// src/converters/base-json.ts
|
|
1856
1970
|
function convertKvPngToSegments(chunks) {
|
|
1857
1971
|
const data = {};
|
|
@@ -2101,7 +2215,7 @@ function convertMetadata(parseResult, targetFormat) {
|
|
|
2101
2215
|
});
|
|
2102
2216
|
}
|
|
2103
2217
|
const raw = parseResult.raw;
|
|
2104
|
-
if (raw.format ===
|
|
2218
|
+
if (raw.format === targetFormat) {
|
|
2105
2219
|
return Result.ok(raw);
|
|
2106
2220
|
}
|
|
2107
2221
|
const software = parseResult.metadata.software;
|
|
@@ -2166,15 +2280,20 @@ var convertHfSpace = createFormatConverter(
|
|
|
2166
2280
|
createPngToSegments("parameters"),
|
|
2167
2281
|
createSegmentsToPng("parameters", "text-unicode-escape")
|
|
2168
2282
|
);
|
|
2283
|
+
var convertCivitai = createFormatConverter(
|
|
2284
|
+
convertCivitaiPngToSegments,
|
|
2285
|
+
convertCivitaiSegmentsToPng
|
|
2286
|
+
);
|
|
2169
2287
|
var softwareConverters = {
|
|
2170
2288
|
// NovelAI
|
|
2171
2289
|
novelai: convertNovelai,
|
|
2172
|
-
// A1111-format (sd-webui, forge, forge-neo,
|
|
2290
|
+
// A1111-format (sd-webui, forge, forge-neo, sd-next)
|
|
2173
2291
|
"sd-webui": convertA1111,
|
|
2174
2292
|
"sd-next": convertA1111,
|
|
2175
2293
|
forge: convertA1111,
|
|
2176
2294
|
"forge-neo": convertA1111,
|
|
2177
|
-
|
|
2295
|
+
// CivitAI Orchestration format
|
|
2296
|
+
civitai: convertCivitai,
|
|
2178
2297
|
// ComfyUI-format (comfyui, tensorart, stability-matrix)
|
|
2179
2298
|
comfyui: convertComfyUI,
|
|
2180
2299
|
tensorart: convertComfyUI,
|