@enslo/sd-metadata 2.1.0 โ 2.2.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/CHANGELOG.md +428 -0
- package/README.ja.md +9 -23
- package/README.md +10 -24
- package/dist/index.d.ts +4 -2
- package/dist/index.global.js +7 -7
- package/dist/index.js +467 -222
- package/dist/index.js.map +1 -1
- package/docs/types.ja.md +799 -0
- package/docs/types.md +799 -0
- package/package.json +11 -13
- package/LICENSE +0 -21
package/docs/types.md
ADDED
|
@@ -0,0 +1,799 @@
|
|
|
1
|
+
# Type Documentation
|
|
2
|
+
|
|
3
|
+
๐ **[ๆฅๆฌ่ช็ใฏใใกใ](./types.ja.md)**
|
|
4
|
+
|
|
5
|
+
Complete type reference for `@enslo/sd-metadata`.
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Core Types](#core-types)
|
|
10
|
+
- [`ParseResult`](#parseresult)
|
|
11
|
+
- [`BaseMetadata`](#basemetadata)
|
|
12
|
+
- [`GenerationMetadata`](#generationmetadata)
|
|
13
|
+
- [`GenerationSoftware`](#generationsoftware)
|
|
14
|
+
- [`EmbedMetadata`](#embedmetadata)
|
|
15
|
+
- [`RawMetadata`](#rawmetadata)
|
|
16
|
+
- [`WriteResult`](#writeresult)
|
|
17
|
+
- [Metadata Types](#metadata-types)
|
|
18
|
+
- [`StandardMetadata`](#standardmetadata)
|
|
19
|
+
- [`NovelAIMetadata`](#novelaimetadata)
|
|
20
|
+
- [`ComfyUIMetadata`](#comfyuimetadata)
|
|
21
|
+
- [Settings Types](#settings-types)
|
|
22
|
+
- [`ModelSettings`](#modelsettings)
|
|
23
|
+
- [`SamplingSettings`](#samplingsettings)
|
|
24
|
+
- [`HiresSettings`](#hiressettings)
|
|
25
|
+
- [`UpscaleSettings`](#upscalesettings)
|
|
26
|
+
- [`CharacterPrompt`](#characterprompt)
|
|
27
|
+
- [ComfyUI Types](#comfyui-types)
|
|
28
|
+
- [`ComfyNodeGraph`](#comfynodegraph)
|
|
29
|
+
- [`ComfyNode`](#comfynode)
|
|
30
|
+
- [`ComfyNodeInputValue`](#comfynodeinputvalue)
|
|
31
|
+
- [`ComfyNodeReference`](#comfynodereference)
|
|
32
|
+
- [Format-Specific Types](#format-specific-types)
|
|
33
|
+
- [`PngTextChunk`](#pngtextchunk)
|
|
34
|
+
- [`TExtChunk`](#textchunk)
|
|
35
|
+
- [`ITXtChunk`](#itxtchunk)
|
|
36
|
+
- [`MetadataSegment`](#metadatasegment)
|
|
37
|
+
- [`MetadataSegmentSource`](#metadatasegmentsource)
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Core Types
|
|
42
|
+
|
|
43
|
+
### `ParseResult`
|
|
44
|
+
|
|
45
|
+
The result type returned by the `read()` function.
|
|
46
|
+
|
|
47
|
+
```typescript
|
|
48
|
+
type ParseResult =
|
|
49
|
+
| { status: 'success'; metadata: GenerationMetadata; raw: RawMetadata }
|
|
50
|
+
| { status: 'unrecognized'; raw: RawMetadata }
|
|
51
|
+
| { status: 'empty' }
|
|
52
|
+
| { status: 'invalid'; message?: string };
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Status Values:**
|
|
56
|
+
|
|
57
|
+
- **`success`**: Metadata was successfully parsed
|
|
58
|
+
- `metadata`: Unified metadata object
|
|
59
|
+
- `raw`: Original format-specific data for round-trip conversion
|
|
60
|
+
- **`unrecognized`**: Image has metadata but format is not recognized
|
|
61
|
+
- `raw`: Original metadata is preserved
|
|
62
|
+
- **`empty`**: No metadata found in the image
|
|
63
|
+
- **`invalid`**: Corrupted or unsupported image format
|
|
64
|
+
- `message`: Optional error description
|
|
65
|
+
|
|
66
|
+
**Example:**
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
import { read } from '@enslo/sd-metadata';
|
|
70
|
+
|
|
71
|
+
const result = read(imageData);
|
|
72
|
+
|
|
73
|
+
switch (result.status) {
|
|
74
|
+
case 'success':
|
|
75
|
+
console.log(`Generated by ${result.metadata.software}`);
|
|
76
|
+
console.log(`Prompt: ${result.metadata.prompt}`);
|
|
77
|
+
break;
|
|
78
|
+
|
|
79
|
+
case 'unrecognized':
|
|
80
|
+
console.log('Unknown metadata format');
|
|
81
|
+
break;
|
|
82
|
+
|
|
83
|
+
case 'empty':
|
|
84
|
+
console.log('No metadata');
|
|
85
|
+
break;
|
|
86
|
+
|
|
87
|
+
case 'invalid':
|
|
88
|
+
console.error(`Invalid image: ${result.message}`);
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
### `BaseMetadata`
|
|
96
|
+
|
|
97
|
+
Common fields shared by all metadata types. This is the foundation for both `GenerationMetadata` variants and `EmbedMetadata`.
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
export interface BaseMetadata {
|
|
101
|
+
/** Positive prompt */
|
|
102
|
+
prompt: string;
|
|
103
|
+
/** Negative prompt */
|
|
104
|
+
negativePrompt: string;
|
|
105
|
+
/** Image width in pixels */
|
|
106
|
+
width: number;
|
|
107
|
+
/** Image height in pixels */
|
|
108
|
+
height: number;
|
|
109
|
+
/** Model settings */
|
|
110
|
+
model?: ModelSettings;
|
|
111
|
+
/** Sampling settings */
|
|
112
|
+
sampling?: SamplingSettings;
|
|
113
|
+
/** Hires.fix settings (if applied) */
|
|
114
|
+
hires?: HiresSettings;
|
|
115
|
+
/** Upscale settings (if applied) */
|
|
116
|
+
upscale?: UpscaleSettings;
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Example:**
|
|
121
|
+
|
|
122
|
+
```typescript
|
|
123
|
+
import type { BaseMetadata } from '@enslo/sd-metadata';
|
|
124
|
+
|
|
125
|
+
// Use BaseMetadata when you only need common generation fields
|
|
126
|
+
function displayMetadata(meta: BaseMetadata) {
|
|
127
|
+
console.log('Prompt:', meta.prompt);
|
|
128
|
+
console.log('Size:', meta.width, 'x', meta.height);
|
|
129
|
+
console.log('Model:', meta.model?.name);
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
### `GenerationMetadata`
|
|
136
|
+
|
|
137
|
+
Unified metadata structure. Discriminated union of all supported metadata types. All variants extend `BaseMetadata`.
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
type GenerationMetadata =
|
|
141
|
+
| NovelAIMetadata
|
|
142
|
+
| ComfyUIMetadata
|
|
143
|
+
| StandardMetadata;
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**Metadata Type Mapping:**
|
|
147
|
+
|
|
148
|
+
| Metadata Type | `software` values |
|
|
149
|
+
| ------------- | ----------------- |
|
|
150
|
+
| `StandardMetadata` | `'sd-webui'` \| `'sd-next'` \| `'forge'` \| `'forge-classic'` \| `'forge-neo'` \| `'reforge'` \| `'easy-reforge'` \| `'invokeai'` \| `'civitai'` \| `'hf-space'` \| `'easydiffusion'` \| `'fooocus'` \| `'ruined-fooocus'` \| `'draw-things'` |
|
|
151
|
+
| `NovelAIMetadata` | `'novelai'` |
|
|
152
|
+
| `ComfyUIMetadata` | `'comfyui'` \| `'tensorart'` \| `'stability-matrix'` \| `'swarmui'` |
|
|
153
|
+
|
|
154
|
+
**Type narrowing example:**
|
|
155
|
+
|
|
156
|
+
```typescript
|
|
157
|
+
if (metadata.software === 'novelai') {
|
|
158
|
+
// TypeScript knows metadata is NovelAIMetadata
|
|
159
|
+
console.log(metadata.characterPrompts);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (metadata.software === 'comfyui' ||
|
|
163
|
+
metadata.software === 'tensorart' ||
|
|
164
|
+
metadata.software === 'stability-matrix' ||
|
|
165
|
+
metadata.software === 'swarmui') {
|
|
166
|
+
// TypeScript knows metadata is ComfyUIMetadata
|
|
167
|
+
if (metadata.nodes) {
|
|
168
|
+
console.log('Has workflow:', Object.keys(metadata.nodes).length);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
### `GenerationSoftware`
|
|
176
|
+
|
|
177
|
+
String literal union of all supported software identifiers. Used as the discriminator for `GenerationMetadata` and as the key type for `softwareLabels`.
|
|
178
|
+
|
|
179
|
+
```typescript
|
|
180
|
+
type GenerationSoftware =
|
|
181
|
+
| 'novelai'
|
|
182
|
+
| 'comfyui'
|
|
183
|
+
| 'swarmui'
|
|
184
|
+
| 'tensorart'
|
|
185
|
+
| 'stability-matrix'
|
|
186
|
+
| 'invokeai'
|
|
187
|
+
| 'sd-webui'
|
|
188
|
+
| 'forge'
|
|
189
|
+
| 'forge-classic'
|
|
190
|
+
| 'forge-neo'
|
|
191
|
+
| 'reforge'
|
|
192
|
+
| 'easy-reforge'
|
|
193
|
+
| 'sd-next'
|
|
194
|
+
| 'civitai'
|
|
195
|
+
| 'hf-space'
|
|
196
|
+
| 'easydiffusion'
|
|
197
|
+
| 'fooocus'
|
|
198
|
+
| 'ruined-fooocus'
|
|
199
|
+
| 'draw-things';
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Example:**
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
import { softwareLabels } from '@enslo/sd-metadata';
|
|
206
|
+
import type { GenerationSoftware } from '@enslo/sd-metadata';
|
|
207
|
+
|
|
208
|
+
function displaySoftware(software: GenerationSoftware): string {
|
|
209
|
+
return softwareLabels[software];
|
|
210
|
+
}
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
### `EmbedMetadata`
|
|
216
|
+
|
|
217
|
+
User-created custom metadata for the `embed()` and `stringify()` functions. While `GenerationMetadata` represents parsed output from a known AI tool, `EmbedMetadata` is designed for composing metadata from scratch. Extends `BaseMetadata` with optional NovelAI character prompts and arbitrary key-value extras for the settings line.
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
export type EmbedMetadata = BaseMetadata &
|
|
221
|
+
Pick<NovelAIMetadata, 'characterPrompts'> & {
|
|
222
|
+
extras?: Record<string, string | number>;
|
|
223
|
+
};
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
**Example:**
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
import { embed } from '@enslo/sd-metadata';
|
|
230
|
+
import type { EmbedMetadata } from '@enslo/sd-metadata';
|
|
231
|
+
|
|
232
|
+
const metadata: EmbedMetadata = {
|
|
233
|
+
prompt: 'masterpiece, 1girl',
|
|
234
|
+
negativePrompt: 'lowres',
|
|
235
|
+
width: 512,
|
|
236
|
+
height: 768,
|
|
237
|
+
sampling: { steps: 20, sampler: 'Euler a', cfg: 7, seed: 12345 },
|
|
238
|
+
model: { name: 'model.safetensors' },
|
|
239
|
+
extras: { Version: 'v1.0' },
|
|
240
|
+
};
|
|
241
|
+
|
|
242
|
+
const result = embed(imageData, metadata);
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
---
|
|
246
|
+
|
|
247
|
+
### `RawMetadata`
|
|
248
|
+
|
|
249
|
+
Preserves the original metadata structure for lossless round-trip conversion.
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
type RawMetadata =
|
|
253
|
+
| { format: 'png'; chunks: PngTextChunk[] }
|
|
254
|
+
| { format: 'jpeg'; segments: MetadataSegment[] }
|
|
255
|
+
| { format: 'webp'; segments: MetadataSegment[] };
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
**Why is this needed?**
|
|
259
|
+
|
|
260
|
+
When you read metadata from an image and convert it to a different format (e.g., PNG โ JPEG), `RawMetadata` preserves the original structure. This allows you to convert back to the original format without losing any information.
|
|
261
|
+
|
|
262
|
+
**Round-trip conversion example:**
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
import { read, write } from '@enslo/sd-metadata';
|
|
266
|
+
import { convertImageFormat } from 'some-image-library';
|
|
267
|
+
|
|
268
|
+
// Read metadata from PNG
|
|
269
|
+
const pngData = readFileSync('image.png');
|
|
270
|
+
const parseResult = read(pngData);
|
|
271
|
+
|
|
272
|
+
if (parseResult.status === 'success') {
|
|
273
|
+
// Convert image to JPEG
|
|
274
|
+
const jpegImageData = convertImageFormat(pngData, 'jpeg');
|
|
275
|
+
|
|
276
|
+
// Write metadata to JPEG
|
|
277
|
+
const jpegWithMeta = write(jpegImageData, parseResult);
|
|
278
|
+
|
|
279
|
+
// Later: convert back to PNG
|
|
280
|
+
const pngImageData = convertImageFormat(jpegWithMeta.value, 'png');
|
|
281
|
+
const pngWithMeta = write(pngImageData, parseResult);
|
|
282
|
+
|
|
283
|
+
// Original PNG metadata structure is fully preserved!
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
Without `raw`, metadata would be converted to a generic format and lose format-specific details when converting back.
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
### `WriteResult`
|
|
292
|
+
|
|
293
|
+
Result type returned by the `write()` function.
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
export type WriteResult =
|
|
297
|
+
| { ok: true; value: Uint8Array; warning?: WriteWarning }
|
|
298
|
+
| { ok: false; error: { type: string; message?: string } };
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
**Success:**
|
|
302
|
+
|
|
303
|
+
```typescript
|
|
304
|
+
if (result.ok) {
|
|
305
|
+
saveFile('output.png', result.value);
|
|
306
|
+
if (result.warning) {
|
|
307
|
+
console.warn('Metadata was dropped:', result.warning.reason);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
**Error:**
|
|
313
|
+
|
|
314
|
+
```typescript
|
|
315
|
+
if (!result.ok) {
|
|
316
|
+
console.error(`Write failed: ${result.error.type}`);
|
|
317
|
+
if (result.error.message) {
|
|
318
|
+
console.error(result.error.message);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**Error Types:**
|
|
324
|
+
|
|
325
|
+
- `unsupportedFormat`: Image format not supported
|
|
326
|
+
- `conversionFailed`: Metadata conversion failed
|
|
327
|
+
- `writeFailed`: Failed to write metadata to image
|
|
328
|
+
|
|
329
|
+
### `WriteWarning`
|
|
330
|
+
|
|
331
|
+
Warning type for write operations.
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
export type WriteWarning = {
|
|
335
|
+
type: 'metadataDropped';
|
|
336
|
+
reason: 'unrecognizedCrossFormat';
|
|
337
|
+
};
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
Returned when metadata was intentionally dropped during a write operation (e.g., unrecognized metadata with cross-format conversion).
|
|
341
|
+
|
|
342
|
+
---
|
|
343
|
+
|
|
344
|
+
## Metadata Types
|
|
345
|
+
|
|
346
|
+
### `StandardMetadata`
|
|
347
|
+
|
|
348
|
+
Standard parameters format used by most SD tools.
|
|
349
|
+
|
|
350
|
+
```typescript
|
|
351
|
+
export interface StandardMetadata extends BaseMetadata {
|
|
352
|
+
software:
|
|
353
|
+
| 'sd-webui'
|
|
354
|
+
| 'forge'
|
|
355
|
+
| 'forge-classic'
|
|
356
|
+
| 'forge-neo'
|
|
357
|
+
| 'reforge'
|
|
358
|
+
| 'easy-reforge'
|
|
359
|
+
| 'sd-next'
|
|
360
|
+
| 'invokeai'
|
|
361
|
+
| 'civitai'
|
|
362
|
+
| 'hf-space'
|
|
363
|
+
| 'easydiffusion'
|
|
364
|
+
| 'fooocus'
|
|
365
|
+
| 'ruined-fooocus'
|
|
366
|
+
| 'draw-things';
|
|
367
|
+
}
|
|
368
|
+
```
|
|
369
|
+
|
|
370
|
+
Inherits all fields from `BaseMetadata`. This is the most common metadata type, representing baseline generation metadata without tool-specific extensions. Many tools use this structure, including SD WebUI, Forge family (Forge, Forge Classic, Forge Neo, reForge, EasyReforge), SD.Next, InvokeAI, and others.
|
|
371
|
+
|
|
372
|
+
**Example:**
|
|
373
|
+
|
|
374
|
+
```typescript
|
|
375
|
+
if (metadata.software === 'forge' || metadata.software === 'sd-webui') {
|
|
376
|
+
console.log('Using standard format metadata');
|
|
377
|
+
console.log('Sampler:', metadata.sampling?.sampler);
|
|
378
|
+
console.log('Steps:', metadata.sampling?.steps);
|
|
379
|
+
}
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
---
|
|
383
|
+
|
|
384
|
+
### `NovelAIMetadata`
|
|
385
|
+
|
|
386
|
+
Metadata specific to NovelAI-generated images.
|
|
387
|
+
|
|
388
|
+
```typescript
|
|
389
|
+
export interface NovelAIMetadata extends BaseMetadata {
|
|
390
|
+
software: 'novelai';
|
|
391
|
+
/** V4 character prompts (when using character placement) */
|
|
392
|
+
characterPrompts?: CharacterPrompt[];
|
|
393
|
+
/** Use character coordinates for placement */
|
|
394
|
+
useCoords?: boolean;
|
|
395
|
+
/** Use character order */
|
|
396
|
+
useOrder?: boolean;
|
|
397
|
+
}
|
|
398
|
+
```
|
|
399
|
+
|
|
400
|
+
**Unique Features:**
|
|
401
|
+
|
|
402
|
+
- **Character Placement (V4)**: NovelAI V4 supports placing multiple characters at specific coordinates
|
|
403
|
+
- `characterPrompts`: Array of character-specific prompts with optional positions
|
|
404
|
+
- `useCoords`, `useOrder`: Control character placement behavior
|
|
405
|
+
|
|
406
|
+
**Example:**
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
if (metadata.software === 'novelai' && metadata.characterPrompts) {
|
|
410
|
+
metadata.characterPrompts.forEach(char => {
|
|
411
|
+
console.log(`Character: ${char.prompt}`);
|
|
412
|
+
if (char.center) {
|
|
413
|
+
console.log(` Position: (${char.center.x}, ${char.center.y})`);
|
|
414
|
+
}
|
|
415
|
+
});
|
|
416
|
+
}
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
### `ComfyUIMetadata`
|
|
422
|
+
|
|
423
|
+
Metadata from ComfyUI and compatible tools (TensorArt, Stability Matrix, SwarmUI).
|
|
424
|
+
|
|
425
|
+
```typescript
|
|
426
|
+
export type ComfyUIMetadata =
|
|
427
|
+
| BasicComfyUIMetadata
|
|
428
|
+
| SwarmUIMetadata;
|
|
429
|
+
|
|
430
|
+
// Internal types:
|
|
431
|
+
interface BasicComfyUIMetadata extends BaseMetadata {
|
|
432
|
+
software: 'comfyui' | 'tensorart' | 'stability-matrix';
|
|
433
|
+
nodes: ComfyNodeGraph; // required
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
interface SwarmUIMetadata extends BaseMetadata {
|
|
437
|
+
software: 'swarmui';
|
|
438
|
+
nodes?: ComfyNodeGraph; // optional
|
|
439
|
+
}
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
**Unique Features:**
|
|
443
|
+
|
|
444
|
+
- **ComfyUI/TensorArt/Stability Matrix**: `nodes` is always present in all formats
|
|
445
|
+
- **SwarmUI**: `nodes` may be present in all formats when converted from PNG (extended support)
|
|
446
|
+
|
|
447
|
+
**Example:**
|
|
448
|
+
|
|
449
|
+
```typescript
|
|
450
|
+
if (metadata.software === 'comfyui') {
|
|
451
|
+
// nodes is guaranteed to exist for ComfyUI
|
|
452
|
+
console.log('Node count:', Object.keys(metadata.nodes).length);
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (metadata.software === 'swarmui') {
|
|
456
|
+
// nodes might not exist for native SwarmUI JPEG/WebP
|
|
457
|
+
// but will be present if converted from PNG
|
|
458
|
+
if (metadata.nodes) {
|
|
459
|
+
console.log('Has workflow (PNG or converted)');
|
|
460
|
+
} else {
|
|
461
|
+
console.log('Native JPEG/WebP: Parameters only');
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
// Type narrowing works across all ComfyUI-compatible tools
|
|
466
|
+
if (metadata.software === 'comfyui' ||
|
|
467
|
+
metadata.software === 'tensorart' ||
|
|
468
|
+
metadata.software === 'stability-matrix' ||
|
|
469
|
+
metadata.software === 'swarmui') {
|
|
470
|
+
// TypeScript knows metadata is ComfyUIMetadata
|
|
471
|
+
// But you need to check metadata.nodes before using it
|
|
472
|
+
if (metadata.nodes) {
|
|
473
|
+
// Find checkpoint node
|
|
474
|
+
for (const [nodeId, node] of Object.entries(metadata.nodes)) {
|
|
475
|
+
if (node.class_type === 'CheckpointLoaderSimple') {
|
|
476
|
+
console.log('Model:', node.inputs.ckpt_name);
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
```
|
|
482
|
+
|
|
483
|
+
## Settings Types
|
|
484
|
+
|
|
485
|
+
### `ModelSettings`
|
|
486
|
+
|
|
487
|
+
Model configuration used for image generation.
|
|
488
|
+
|
|
489
|
+
```typescript
|
|
490
|
+
export interface ModelSettings {
|
|
491
|
+
/** Model name (e.g., "sd_xl_base_1.0.safetensors") */
|
|
492
|
+
name?: string;
|
|
493
|
+
/** Model hash for verification */
|
|
494
|
+
hash?: string;
|
|
495
|
+
/** VAE (Variational AutoEncoder) name */
|
|
496
|
+
vae?: string;
|
|
497
|
+
}
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
**Example:**
|
|
501
|
+
|
|
502
|
+
```typescript
|
|
503
|
+
if (metadata.model) {
|
|
504
|
+
console.log('Model:', metadata.model.name);
|
|
505
|
+
console.log('Hash:', metadata.model.hash);
|
|
506
|
+
console.log('VAE:', metadata.model.vae || 'Default');
|
|
507
|
+
}
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
---
|
|
511
|
+
|
|
512
|
+
### `SamplingSettings`
|
|
513
|
+
|
|
514
|
+
Sampling parameters used during generation.
|
|
515
|
+
|
|
516
|
+
```typescript
|
|
517
|
+
export interface SamplingSettings {
|
|
518
|
+
/** Sampler algorithm (e.g., "Euler a", "DPM++ 2M Karras") */
|
|
519
|
+
sampler?: string;
|
|
520
|
+
/** Scheduler type (if separate from sampler) */
|
|
521
|
+
scheduler?: string;
|
|
522
|
+
/** Number of sampling steps */
|
|
523
|
+
steps?: number;
|
|
524
|
+
/** CFG (Classifier Free Guidance) scale */
|
|
525
|
+
cfg?: number;
|
|
526
|
+
/** Random seed for reproducibility */
|
|
527
|
+
seed?: number;
|
|
528
|
+
/** CLIP skip layers */
|
|
529
|
+
clipSkip?: number;
|
|
530
|
+
/** Denoising strength (ComfyUI only). Omitted when 1.0 (txt2img default) */
|
|
531
|
+
denoise?: number;
|
|
532
|
+
}
|
|
533
|
+
```
|
|
534
|
+
|
|
535
|
+
**Example:**
|
|
536
|
+
|
|
537
|
+
```typescript
|
|
538
|
+
if (metadata.sampling) {
|
|
539
|
+
console.log('Sampler:', metadata.sampling.sampler);
|
|
540
|
+
console.log('Steps:', metadata.sampling.steps);
|
|
541
|
+
console.log('CFG Scale:', metadata.sampling.cfg);
|
|
542
|
+
console.log('Seed:', metadata.sampling.seed);
|
|
543
|
+
}
|
|
544
|
+
```
|
|
545
|
+
|
|
546
|
+
---
|
|
547
|
+
|
|
548
|
+
### `HiresSettings`
|
|
549
|
+
|
|
550
|
+
Hires.fix (high-resolution fix) settings.
|
|
551
|
+
|
|
552
|
+
```typescript
|
|
553
|
+
export interface HiresSettings {
|
|
554
|
+
/** Upscale factor */
|
|
555
|
+
scale?: number;
|
|
556
|
+
/** Upscaler name */
|
|
557
|
+
upscaler?: string;
|
|
558
|
+
/** Hires steps */
|
|
559
|
+
steps?: number;
|
|
560
|
+
/** Hires denoising strength */
|
|
561
|
+
denoise?: number;
|
|
562
|
+
}
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
Applied during generation to improve high-resolution output quality.
|
|
566
|
+
|
|
567
|
+
---
|
|
568
|
+
|
|
569
|
+
### `UpscaleSettings`
|
|
570
|
+
|
|
571
|
+
Post-generation upscale settings.
|
|
572
|
+
|
|
573
|
+
```typescript
|
|
574
|
+
export interface UpscaleSettings {
|
|
575
|
+
/** Upscaler name */
|
|
576
|
+
upscaler?: string;
|
|
577
|
+
/** Scale factor */
|
|
578
|
+
scale?: number;
|
|
579
|
+
}
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
Applied after initial generation as a separate upscaling step.
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
### `CharacterPrompt`
|
|
587
|
+
|
|
588
|
+
Character positioning for NovelAI V4 images.
|
|
589
|
+
|
|
590
|
+
```typescript
|
|
591
|
+
export interface CharacterPrompt {
|
|
592
|
+
/** Character-specific prompt */
|
|
593
|
+
prompt: string;
|
|
594
|
+
/** Character position in image (normalized 0-1) */
|
|
595
|
+
center?: { x: number; y: number };
|
|
596
|
+
}
|
|
597
|
+
```
|
|
598
|
+
|
|
599
|
+
**Example:**
|
|
600
|
+
|
|
601
|
+
```typescript
|
|
602
|
+
const character: CharacterPrompt = {
|
|
603
|
+
prompt: "1girl, long hair, blue eyes",
|
|
604
|
+
center: { x: 0.3, y: 0.5 } // Left side, vertically centered
|
|
605
|
+
};
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
---
|
|
609
|
+
|
|
610
|
+
## ComfyUI Types
|
|
611
|
+
|
|
612
|
+
### `ComfyNodeGraph`
|
|
613
|
+
|
|
614
|
+
Map of node IDs to their corresponding node data.
|
|
615
|
+
|
|
616
|
+
```typescript
|
|
617
|
+
export type ComfyNodeGraph = Record<string, ComfyNode>;
|
|
618
|
+
```
|
|
619
|
+
|
|
620
|
+
**Example:**
|
|
621
|
+
|
|
622
|
+
```typescript
|
|
623
|
+
const graph: ComfyNodeGraph = {
|
|
624
|
+
"CheckpointLoader_Base": { /* ... */ },
|
|
625
|
+
"KSampler_Primary": { /* ... */ },
|
|
626
|
+
"SaveImage_Final": { /* ... */ }
|
|
627
|
+
};
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
---
|
|
631
|
+
|
|
632
|
+
### `ComfyNode`
|
|
633
|
+
|
|
634
|
+
A single node in the ComfyUI workflow graph.
|
|
635
|
+
|
|
636
|
+
```typescript
|
|
637
|
+
export interface ComfyNode {
|
|
638
|
+
/** Node class type (e.g., "CheckpointLoaderSimple", "KSampler") */
|
|
639
|
+
class_type: string;
|
|
640
|
+
/** Node inputs */
|
|
641
|
+
inputs: Record<string, ComfyNodeInputValue>;
|
|
642
|
+
/** Node metadata (ComfyUI only) */
|
|
643
|
+
_meta?: {
|
|
644
|
+
/** Node title for display */
|
|
645
|
+
title?: string;
|
|
646
|
+
};
|
|
647
|
+
/** Change detection hash (rare, for caching) */
|
|
648
|
+
is_changed?: string[] | null;
|
|
649
|
+
}
|
|
650
|
+
```
|
|
651
|
+
|
|
652
|
+
**Example:**
|
|
653
|
+
|
|
654
|
+
```typescript
|
|
655
|
+
const ksampler: ComfyNode = {
|
|
656
|
+
class_type: "KSampler",
|
|
657
|
+
inputs: {
|
|
658
|
+
model: ["CheckpointLoader", 0],
|
|
659
|
+
seed: 12345,
|
|
660
|
+
steps: 20,
|
|
661
|
+
cfg: 7.0,
|
|
662
|
+
sampler_name: "euler_a",
|
|
663
|
+
scheduler: "normal",
|
|
664
|
+
denoise: 1.0
|
|
665
|
+
},
|
|
666
|
+
_meta: {
|
|
667
|
+
title: "Primary Sampler"
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
```
|
|
671
|
+
|
|
672
|
+
---
|
|
673
|
+
|
|
674
|
+
### `ComfyNodeInputValue`
|
|
675
|
+
|
|
676
|
+
Possible values for node inputs.
|
|
677
|
+
|
|
678
|
+
```typescript
|
|
679
|
+
export type ComfyNodeInputValue =
|
|
680
|
+
| string
|
|
681
|
+
| number
|
|
682
|
+
| boolean
|
|
683
|
+
| ComfyNodeReference
|
|
684
|
+
| ComfyNodeInputValue[];
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
Can be a primitive value, a reference to another node, or an array.
|
|
688
|
+
|
|
689
|
+
---
|
|
690
|
+
|
|
691
|
+
### `ComfyNodeReference`
|
|
692
|
+
|
|
693
|
+
Reference to another node's output.
|
|
694
|
+
|
|
695
|
+
```typescript
|
|
696
|
+
export type ComfyNodeReference = [nodeId: string, outputIndex: number];
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
**Example:**
|
|
700
|
+
|
|
701
|
+
```typescript
|
|
702
|
+
const modelReference: ComfyNodeReference = ["CheckpointLoader_Base", 0];
|
|
703
|
+
|
|
704
|
+
// Used in node inputs:
|
|
705
|
+
{
|
|
706
|
+
model: ["CheckpointLoader_Base", 0], // References output 0 of CheckpointLoader_Base
|
|
707
|
+
positive: ["CLIPTextEncode_Positive", 0]
|
|
708
|
+
}
|
|
709
|
+
```
|
|
710
|
+
|
|
711
|
+
---
|
|
712
|
+
|
|
713
|
+
## Format-Specific Types
|
|
714
|
+
|
|
715
|
+
> **Note:** These types are mainly for advanced use cases or internal implementation details. Most users don't need to work with these types directly.
|
|
716
|
+
|
|
717
|
+
### `PngTextChunk`
|
|
718
|
+
|
|
719
|
+
PNG text chunk types (tEXt or iTXt).
|
|
720
|
+
|
|
721
|
+
```typescript
|
|
722
|
+
export type PngTextChunk = TExtChunk | ITXtChunk;
|
|
723
|
+
```
|
|
724
|
+
|
|
725
|
+
---
|
|
726
|
+
|
|
727
|
+
### `TExtChunk`
|
|
728
|
+
|
|
729
|
+
PNG tEXt chunk (Latin-1 encoded).
|
|
730
|
+
|
|
731
|
+
```typescript
|
|
732
|
+
export interface TExtChunk {
|
|
733
|
+
type: 'tEXt';
|
|
734
|
+
/** Chunk keyword (e.g., "parameters", "Comment") */
|
|
735
|
+
keyword: string;
|
|
736
|
+
/** Text content */
|
|
737
|
+
text: string;
|
|
738
|
+
}
|
|
739
|
+
```
|
|
740
|
+
|
|
741
|
+
---
|
|
742
|
+
|
|
743
|
+
### `ITXtChunk`
|
|
744
|
+
|
|
745
|
+
PNG iTXt chunk (UTF-8 international text).
|
|
746
|
+
|
|
747
|
+
```typescript
|
|
748
|
+
export interface ITXtChunk {
|
|
749
|
+
type: 'iTXt';
|
|
750
|
+
/** Chunk keyword */
|
|
751
|
+
keyword: string;
|
|
752
|
+
/** Compression flag (0=uncompressed, 1=compressed) */
|
|
753
|
+
compressionFlag: number;
|
|
754
|
+
/** Compression method (0=zlib/deflate) */
|
|
755
|
+
compressionMethod: number;
|
|
756
|
+
/** Language tag (BCP 47) */
|
|
757
|
+
languageTag: string;
|
|
758
|
+
/** Translated keyword */
|
|
759
|
+
translatedKeyword: string;
|
|
760
|
+
/** Text content */
|
|
761
|
+
text: string;
|
|
762
|
+
}
|
|
763
|
+
```
|
|
764
|
+
|
|
765
|
+
---
|
|
766
|
+
|
|
767
|
+
### `MetadataSegment`
|
|
768
|
+
|
|
769
|
+
JPEG/WebP metadata segment with source tracking.
|
|
770
|
+
|
|
771
|
+
```typescript
|
|
772
|
+
export interface MetadataSegment {
|
|
773
|
+
/** Source location of this segment */
|
|
774
|
+
source: MetadataSegmentSource;
|
|
775
|
+
/** Raw metadata string */
|
|
776
|
+
data: string;
|
|
777
|
+
}
|
|
778
|
+
```
|
|
779
|
+
|
|
780
|
+
Used for round-trip conversion to write metadata back to the correct location.
|
|
781
|
+
|
|
782
|
+
---
|
|
783
|
+
|
|
784
|
+
### `MetadataSegmentSource`
|
|
785
|
+
|
|
786
|
+
Source location of a metadata segment.
|
|
787
|
+
|
|
788
|
+
```typescript
|
|
789
|
+
export type MetadataSegmentSource =
|
|
790
|
+
| { type: 'exifUserComment' }
|
|
791
|
+
| { type: 'exifImageDescription'; prefix?: string }
|
|
792
|
+
| { type: 'exifMake'; prefix?: string }
|
|
793
|
+
| { type: 'jpegCom' }
|
|
794
|
+
| { type: 'xmpPacket' };
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
Tracks where the metadata came from in JPEG/WebP files for accurate round-tripping.
|
|
798
|
+
|
|
799
|
+
---
|