comfyui-mcp 0.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/.mcp.json +11 -0
- package/dist/comfyui/client.d.ts +16 -0
- package/dist/comfyui/client.d.ts.map +1 -0
- package/dist/comfyui/client.js +75 -0
- package/dist/comfyui/client.js.map +1 -0
- package/dist/comfyui/events.d.ts +9 -0
- package/dist/comfyui/events.d.ts.map +1 -0
- package/dist/comfyui/events.js +40 -0
- package/dist/comfyui/events.js.map +1 -0
- package/dist/comfyui/types.d.ts +66 -0
- package/dist/comfyui/types.d.ts.map +1 -0
- package/dist/comfyui/types.js +3 -0
- package/dist/comfyui/types.js.map +1 -0
- package/dist/config.d.ts +28 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +93 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/services/mermaid-converter.d.ts +8 -0
- package/dist/services/mermaid-converter.d.ts.map +1 -0
- package/dist/services/mermaid-converter.js +235 -0
- package/dist/services/mermaid-converter.js.map +1 -0
- package/dist/services/mermaid-parser.d.ts +31 -0
- package/dist/services/mermaid-parser.d.ts.map +1 -0
- package/dist/services/mermaid-parser.js +464 -0
- package/dist/services/mermaid-parser.js.map +1 -0
- package/dist/services/model-resolver.d.ts +25 -0
- package/dist/services/model-resolver.d.ts.map +1 -0
- package/dist/services/model-resolver.js +123 -0
- package/dist/services/model-resolver.js.map +1 -0
- package/dist/services/registry-client.d.ts +28 -0
- package/dist/services/registry-client.d.ts.map +1 -0
- package/dist/services/registry-client.js +32 -0
- package/dist/services/registry-client.js.map +1 -0
- package/dist/services/skill-generator.d.ts +33 -0
- package/dist/services/skill-generator.d.ts.map +1 -0
- package/dist/services/skill-generator.js +438 -0
- package/dist/services/skill-generator.js.map +1 -0
- package/dist/services/workflow-composer.d.ts +43 -0
- package/dist/services/workflow-composer.d.ts.map +1 -0
- package/dist/services/workflow-composer.js +333 -0
- package/dist/services/workflow-composer.js.map +1 -0
- package/dist/services/workflow-executor.d.ts +15 -0
- package/dist/services/workflow-executor.d.ts.map +1 -0
- package/dist/services/workflow-executor.js +63 -0
- package/dist/services/workflow-executor.js.map +1 -0
- package/dist/tools/index.d.ts +3 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +15 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/model-management.d.ts +3 -0
- package/dist/tools/model-management.d.ts.map +1 -0
- package/dist/tools/model-management.js +97 -0
- package/dist/tools/model-management.js.map +1 -0
- package/dist/tools/registry-search.d.ts +3 -0
- package/dist/tools/registry-search.d.ts.map +1 -0
- package/dist/tools/registry-search.js +70 -0
- package/dist/tools/registry-search.js.map +1 -0
- package/dist/tools/skill-generator.d.ts +3 -0
- package/dist/tools/skill-generator.d.ts.map +1 -0
- package/dist/tools/skill-generator.js +42 -0
- package/dist/tools/skill-generator.js.map +1 -0
- package/dist/tools/workflow-compose.d.ts +3 -0
- package/dist/tools/workflow-compose.d.ts.map +1 -0
- package/dist/tools/workflow-compose.js +180 -0
- package/dist/tools/workflow-compose.js.map +1 -0
- package/dist/tools/workflow-execute.d.ts +3 -0
- package/dist/tools/workflow-execute.d.ts.map +1 -0
- package/dist/tools/workflow-execute.js +115 -0
- package/dist/tools/workflow-execute.js.map +1 -0
- package/dist/tools/workflow-visualize.d.ts +3 -0
- package/dist/tools/workflow-visualize.d.ts.map +1 -0
- package/dist/tools/workflow-visualize.js +111 -0
- package/dist/tools/workflow-visualize.js.map +1 -0
- package/dist/utils/errors.d.ts +24 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +65 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/image.d.ts +4 -0
- package/dist/utils/image.d.ts.map +1 -0
- package/dist/utils/image.js +10 -0
- package/dist/utils/image.js.map +1 -0
- package/dist/utils/logger.d.ts +7 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +22 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +34 -0
|
@@ -0,0 +1,464 @@
|
|
|
1
|
+
import { ValidationError } from "../utils/errors.js";
|
|
2
|
+
import { logger } from "../utils/logger.js";
|
|
3
|
+
/**
|
|
4
|
+
* Parse a mermaid flowchart string into structured nodes and edges.
|
|
5
|
+
*/
|
|
6
|
+
export function parseMermaid(mermaidText) {
|
|
7
|
+
// Strip code fence if present
|
|
8
|
+
let text = mermaidText.trim();
|
|
9
|
+
if (text.startsWith("```")) {
|
|
10
|
+
text = text.replace(/^```(?:mermaid)?\s*\n?/, "").replace(/\n?```\s*$/, "");
|
|
11
|
+
}
|
|
12
|
+
const lines = text.split("\n").map((l) => l.trim());
|
|
13
|
+
const nodes = new Map();
|
|
14
|
+
const edges = [];
|
|
15
|
+
let direction = "LR";
|
|
16
|
+
for (const line of lines) {
|
|
17
|
+
// Parse direction from flowchart declaration
|
|
18
|
+
const dirMatch = line.match(/^flowchart\s+(LR|TB|TD|RL)$/);
|
|
19
|
+
if (dirMatch) {
|
|
20
|
+
direction = dirMatch[1] === "TD" ? "TB" : dirMatch[1];
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
// Skip subgraph/end/style/linkStyle lines
|
|
24
|
+
if (line.startsWith("subgraph ") ||
|
|
25
|
+
line === "end" ||
|
|
26
|
+
line.startsWith("style ") ||
|
|
27
|
+
line.startsWith("linkStyle ") ||
|
|
28
|
+
line === "") {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
// Try to parse as edge: sourceId -->|TYPE| targetId OR sourceId --> targetId
|
|
32
|
+
const edgeMatch = line.match(/^(\S+)\s+--+>(?:\|([^|]*)\|)?\s*(\S+)$/);
|
|
33
|
+
if (edgeMatch) {
|
|
34
|
+
edges.push({
|
|
35
|
+
sourceId: edgeMatch[1],
|
|
36
|
+
targetId: edgeMatch[3],
|
|
37
|
+
dataType: edgeMatch[2] || undefined,
|
|
38
|
+
});
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
// Try to parse as node definition with various shapes
|
|
42
|
+
const nodeResult = parseNodeLine(line);
|
|
43
|
+
if (nodeResult) {
|
|
44
|
+
nodes.set(nodeResult.id, nodeResult);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (nodes.size === 0) {
|
|
48
|
+
throw new ValidationError("Could not parse any nodes from mermaid text. Expected format: flowchart LR/TB with node definitions.");
|
|
49
|
+
}
|
|
50
|
+
return { nodes, edges, direction };
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Parse a single node definition line.
|
|
54
|
+
* Handles all shape variants:
|
|
55
|
+
* id["label"] — rectangle (loading, utility)
|
|
56
|
+
* id(["label"]) — stadium (conditioning)
|
|
57
|
+
* id{{"label"}} — hexagon (sampling)
|
|
58
|
+
* id("label") — rounded (image)
|
|
59
|
+
* id((("label"))) — triple circle (output)
|
|
60
|
+
* id(("label")) — double circle
|
|
61
|
+
*/
|
|
62
|
+
function parseNodeLine(line) {
|
|
63
|
+
// Match: id followed by shape-wrapped label
|
|
64
|
+
// The id is one or more non-whitespace chars at the start (before the shape opener)
|
|
65
|
+
const patterns = [
|
|
66
|
+
// Triple circle: id((("label")))
|
|
67
|
+
/^(\S+?)\(\(\("(.+?)"\)\)\)$/,
|
|
68
|
+
// Double circle: id(("label"))
|
|
69
|
+
/^(\S+?)\(\("(.+?)"\)\)$/,
|
|
70
|
+
// Hexagon: id{{"label"}}
|
|
71
|
+
/^(\S+?)\{\{"(.+?)"\}\}$/,
|
|
72
|
+
// Stadium: id(["label"])
|
|
73
|
+
/^(\S+?)\(\["(.+?)"\]\)$/,
|
|
74
|
+
// Rounded: id("label")
|
|
75
|
+
/^(\S+?)\("(.+?)"\)$/,
|
|
76
|
+
// Rectangle: id["label"]
|
|
77
|
+
/^(\S+?)\["(.+?)"\]$/,
|
|
78
|
+
];
|
|
79
|
+
for (const pattern of patterns) {
|
|
80
|
+
const match = line.match(pattern);
|
|
81
|
+
if (match) {
|
|
82
|
+
const id = match[1];
|
|
83
|
+
const rawLabel = match[2];
|
|
84
|
+
return parseLabel(id, rawLabel);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Parse the inner label text.
|
|
91
|
+
* Format: "ClassName\nkey:value key2:value2"
|
|
92
|
+
* or: "Title\nkey:value key2:value2"
|
|
93
|
+
*/
|
|
94
|
+
function parseLabel(id, rawLabel) {
|
|
95
|
+
// Unescape mermaid HTML entities
|
|
96
|
+
const label = rawLabel.replace(/#quot;/g, '"');
|
|
97
|
+
// Split on literal \n (the escaped newline in mermaid syntax)
|
|
98
|
+
const parts = label.split("\\n");
|
|
99
|
+
const title = parts[0].trim();
|
|
100
|
+
const values = {};
|
|
101
|
+
if (parts.length > 1) {
|
|
102
|
+
// The rest is space-separated key:value pairs
|
|
103
|
+
const valuesStr = parts.slice(1).join(" ");
|
|
104
|
+
// Parse key:value pairs. Values can contain colons (filenames like model.safetensors),
|
|
105
|
+
// so we match key up to first colon, then value up to next key or end.
|
|
106
|
+
// Pattern: word chars + colon + value (up to next space-followed-by-word-colon, or end)
|
|
107
|
+
const kvRegex = /(\w+):(.+?)(?=\s+\w+:|$)/g;
|
|
108
|
+
let kvMatch;
|
|
109
|
+
while ((kvMatch = kvRegex.exec(valuesStr)) !== null) {
|
|
110
|
+
values[kvMatch[1]] = kvMatch[2].trim();
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return { id, label: title, values };
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Resolve a parsed mermaid graph into a valid ComfyUI workflow JSON
|
|
117
|
+
* using node definitions from /object_info.
|
|
118
|
+
*/
|
|
119
|
+
export function resolveWorkflow(parsed, objectInfo) {
|
|
120
|
+
const workflow = {};
|
|
121
|
+
const warnings = [];
|
|
122
|
+
// Build lookup: display_name → class_type
|
|
123
|
+
const displayNameMap = new Map();
|
|
124
|
+
for (const [className, def] of Object.entries(objectInfo)) {
|
|
125
|
+
if (def.display_name) {
|
|
126
|
+
displayNameMap.set(def.display_name.toLowerCase(), className);
|
|
127
|
+
}
|
|
128
|
+
// Also map the class name itself (case-insensitive)
|
|
129
|
+
displayNameMap.set(className.toLowerCase(), className);
|
|
130
|
+
}
|
|
131
|
+
// Phase 1: Resolve each node's class_type
|
|
132
|
+
const nodeClassTypes = new Map();
|
|
133
|
+
for (const [id, node] of parsed.nodes) {
|
|
134
|
+
const resolved = resolveClassType(node.label, objectInfo, displayNameMap);
|
|
135
|
+
if (resolved) {
|
|
136
|
+
nodeClassTypes.set(id, resolved);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
// Try inferring from connection data type signature
|
|
140
|
+
const inferred = inferClassTypeFromConnections(id, parsed.edges, objectInfo);
|
|
141
|
+
if (inferred) {
|
|
142
|
+
nodeClassTypes.set(id, inferred);
|
|
143
|
+
logger.info(`Node ${id}: Inferred class_type "${inferred}" from connection signature for label "${node.label}"`);
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
warnings.push(`Node ${id}: Could not resolve "${node.label}" to a known ComfyUI node type. Using label as class_type.`);
|
|
147
|
+
nodeClassTypes.set(id, node.label);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
// Phase 2: Create workflow nodes with empty inputs
|
|
152
|
+
for (const [id, node] of parsed.nodes) {
|
|
153
|
+
const classType = nodeClassTypes.get(id);
|
|
154
|
+
workflow[id] = {
|
|
155
|
+
class_type: classType,
|
|
156
|
+
inputs: {},
|
|
157
|
+
};
|
|
158
|
+
// If the label differs from class_type, preserve it as _meta.title
|
|
159
|
+
if (node.label !== classType) {
|
|
160
|
+
workflow[id]._meta = { title: node.label };
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
// Phase 3: Wire connections using edge data types + object_info
|
|
164
|
+
for (const edge of parsed.edges) {
|
|
165
|
+
const sourceClassType = nodeClassTypes.get(edge.sourceId);
|
|
166
|
+
const targetClassType = nodeClassTypes.get(edge.targetId);
|
|
167
|
+
if (!sourceClassType || !targetClassType) {
|
|
168
|
+
warnings.push(`Edge ${edge.sourceId} → ${edge.targetId}: source or target node not found, skipping.`);
|
|
169
|
+
continue;
|
|
170
|
+
}
|
|
171
|
+
const sourceDef = objectInfo[sourceClassType];
|
|
172
|
+
const targetDef = objectInfo[targetClassType];
|
|
173
|
+
if (!sourceDef || !targetDef) {
|
|
174
|
+
warnings.push(`Edge ${edge.sourceId} → ${edge.targetId}: missing object_info for ${!sourceDef ? sourceClassType : targetClassType}. Using best guess.`);
|
|
175
|
+
// Best effort: put connection as first matching input
|
|
176
|
+
if (edge.dataType) {
|
|
177
|
+
const inputName = guessInputNameByType(edge.dataType, targetClassType);
|
|
178
|
+
if (inputName) {
|
|
179
|
+
workflow[edge.targetId].inputs[inputName] = [edge.sourceId, 0];
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
// Find the output index on the source that produces this data type
|
|
185
|
+
let outputIndex = 0;
|
|
186
|
+
if (edge.dataType && sourceDef.output) {
|
|
187
|
+
const idx = sourceDef.output.indexOf(edge.dataType);
|
|
188
|
+
if (idx >= 0) {
|
|
189
|
+
outputIndex = idx;
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
warnings.push(`Edge ${edge.sourceId} → ${edge.targetId}: data type "${edge.dataType}" not found in ${sourceClassType} outputs [${sourceDef.output.join(", ")}]. Using index 0.`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
// Find the input name on the target that accepts this data type.
|
|
196
|
+
// Use the source node's title as a hint for disambiguation
|
|
197
|
+
// (e.g., "Positive Prompt" → positive, "Negative Prompt" → negative).
|
|
198
|
+
const sourceTitle = parsed.nodes.get(edge.sourceId)?.label ?? "";
|
|
199
|
+
const inputName = findInputForType(targetDef, edge.dataType, workflow[edge.targetId].inputs, sourceTitle);
|
|
200
|
+
if (inputName) {
|
|
201
|
+
workflow[edge.targetId].inputs[inputName] = [edge.sourceId, outputIndex];
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
warnings.push(`Edge ${edge.sourceId} → ${edge.targetId}: could not find input on ${targetClassType} that accepts "${edge.dataType}".`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// Phase 4: Fill widget values from parsed labels
|
|
208
|
+
for (const [id, node] of parsed.nodes) {
|
|
209
|
+
const classType = nodeClassTypes.get(id);
|
|
210
|
+
const def = objectInfo[classType];
|
|
211
|
+
if (!def)
|
|
212
|
+
continue;
|
|
213
|
+
for (const [key, rawValue] of Object.entries(node.values)) {
|
|
214
|
+
// Don't overwrite connections
|
|
215
|
+
if (isConnectionValue(workflow[id].inputs[key]))
|
|
216
|
+
continue;
|
|
217
|
+
// Coerce value to the correct type based on objectInfo
|
|
218
|
+
const coerced = coerceValue(key, rawValue, def);
|
|
219
|
+
if (coerced !== undefined) {
|
|
220
|
+
workflow[id].inputs[key] = coerced;
|
|
221
|
+
}
|
|
222
|
+
else {
|
|
223
|
+
// Fall back to string
|
|
224
|
+
workflow[id].inputs[key] = rawValue;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// Phase 5: Fill remaining required inputs with defaults from objectInfo
|
|
229
|
+
for (const [id] of parsed.nodes) {
|
|
230
|
+
const classType = nodeClassTypes.get(id);
|
|
231
|
+
const def = objectInfo[classType];
|
|
232
|
+
if (!def)
|
|
233
|
+
continue;
|
|
234
|
+
fillDefaults(workflow[id], def, warnings, id);
|
|
235
|
+
}
|
|
236
|
+
return { workflow, warnings };
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Infer class_type by matching a node's connection signature against all known node types.
|
|
240
|
+
* E.g., a node that receives CLIP and outputs CONDITIONING is very likely CLIPTextEncode.
|
|
241
|
+
*/
|
|
242
|
+
function inferClassTypeFromConnections(nodeId, edges, objectInfo) {
|
|
243
|
+
// Collect incoming and outgoing data types for this node
|
|
244
|
+
const incomingTypes = new Set();
|
|
245
|
+
const outgoingTypes = new Set();
|
|
246
|
+
for (const edge of edges) {
|
|
247
|
+
if (edge.targetId === nodeId && edge.dataType) {
|
|
248
|
+
incomingTypes.add(edge.dataType);
|
|
249
|
+
}
|
|
250
|
+
if (edge.sourceId === nodeId && edge.dataType) {
|
|
251
|
+
outgoingTypes.add(edge.dataType);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
if (incomingTypes.size === 0 && outgoingTypes.size === 0)
|
|
255
|
+
return null;
|
|
256
|
+
// Score each node type by how well it matches the signature
|
|
257
|
+
let bestMatch = null;
|
|
258
|
+
let bestScore = 0;
|
|
259
|
+
for (const [className, def] of Object.entries(objectInfo)) {
|
|
260
|
+
let score = 0;
|
|
261
|
+
// Check outgoing types match outputs
|
|
262
|
+
if (outgoingTypes.size > 0) {
|
|
263
|
+
const outputSet = new Set(def.output);
|
|
264
|
+
for (const t of outgoingTypes) {
|
|
265
|
+
if (outputSet.has(t))
|
|
266
|
+
score += 2;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// Check incoming types match inputs
|
|
270
|
+
if (incomingTypes.size > 0) {
|
|
271
|
+
const allInputs = {
|
|
272
|
+
...def.input.required,
|
|
273
|
+
...def.input.optional,
|
|
274
|
+
};
|
|
275
|
+
const inputTypes = new Set(Object.values(allInputs).map((spec) => typeof spec[0] === "string" ? spec[0] : ""));
|
|
276
|
+
for (const t of incomingTypes) {
|
|
277
|
+
if (inputTypes.has(t))
|
|
278
|
+
score += 1;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
if (score > bestScore) {
|
|
282
|
+
bestScore = score;
|
|
283
|
+
bestMatch = className;
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
// Require a minimum score to avoid false matches
|
|
287
|
+
return bestScore >= 2 ? bestMatch : null;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Resolve a label to a known class_type.
|
|
291
|
+
*/
|
|
292
|
+
function resolveClassType(label, objectInfo, displayNameMap) {
|
|
293
|
+
// Direct match against class names
|
|
294
|
+
if (objectInfo[label])
|
|
295
|
+
return label;
|
|
296
|
+
// Case-insensitive match
|
|
297
|
+
const lower = label.toLowerCase();
|
|
298
|
+
const fromDisplay = displayNameMap.get(lower);
|
|
299
|
+
if (fromDisplay)
|
|
300
|
+
return fromDisplay;
|
|
301
|
+
// Fuzzy: try removing spaces (e.g., "Checkpoint Loader Simple" → "CheckpointLoaderSimple")
|
|
302
|
+
const noSpaces = label.replace(/\s+/g, "");
|
|
303
|
+
if (objectInfo[noSpaces])
|
|
304
|
+
return noSpaces;
|
|
305
|
+
// Try display name without spaces
|
|
306
|
+
const fromDisplayNoSpaces = displayNameMap.get(noSpaces.toLowerCase());
|
|
307
|
+
if (fromDisplayNoSpaces)
|
|
308
|
+
return fromDisplayNoSpaces;
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Find an input on the target node that accepts the given data type.
|
|
313
|
+
* Avoids assigning to an input that already has a connection.
|
|
314
|
+
* Uses sourceTitle as a hint when multiple inputs accept the same type
|
|
315
|
+
* (e.g., KSampler has both "positive" and "negative" CONDITIONING inputs).
|
|
316
|
+
*/
|
|
317
|
+
function findInputForType(targetDef, dataType, currentInputs, sourceTitle) {
|
|
318
|
+
if (!dataType)
|
|
319
|
+
return null;
|
|
320
|
+
const allInputs = {
|
|
321
|
+
...targetDef.input.required,
|
|
322
|
+
...targetDef.input.optional,
|
|
323
|
+
};
|
|
324
|
+
// Collect all matching, unwired inputs
|
|
325
|
+
const candidates = [];
|
|
326
|
+
for (const [inputName, spec] of Object.entries(allInputs)) {
|
|
327
|
+
if (isConnectionValue(currentInputs[inputName]))
|
|
328
|
+
continue;
|
|
329
|
+
const acceptedType = spec[0];
|
|
330
|
+
const matches = (typeof acceptedType === "string" && acceptedType === dataType) ||
|
|
331
|
+
(Array.isArray(acceptedType) && acceptedType.includes(dataType));
|
|
332
|
+
if (matches) {
|
|
333
|
+
candidates.push(inputName);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
if (candidates.length === 0)
|
|
337
|
+
return null;
|
|
338
|
+
if (candidates.length === 1)
|
|
339
|
+
return candidates[0];
|
|
340
|
+
// Multiple candidates — use sourceTitle to pick the best match.
|
|
341
|
+
// E.g., title "Positive Prompt" should match input named "positive",
|
|
342
|
+
// and "Negative Prompt" should match "negative".
|
|
343
|
+
if (sourceTitle) {
|
|
344
|
+
const titleLower = sourceTitle.toLowerCase();
|
|
345
|
+
for (const inputName of candidates) {
|
|
346
|
+
if (titleLower.includes(inputName.toLowerCase())) {
|
|
347
|
+
return inputName;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
// Fall back to first available
|
|
352
|
+
return candidates[0];
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Fallback: guess input name from data type for common patterns.
|
|
356
|
+
*/
|
|
357
|
+
function guessInputNameByType(dataType, _targetClassType) {
|
|
358
|
+
const typeToInput = {
|
|
359
|
+
MODEL: "model",
|
|
360
|
+
CLIP: "clip",
|
|
361
|
+
VAE: "vae",
|
|
362
|
+
CONDITIONING: "positive", // ambiguous but common
|
|
363
|
+
LATENT: "latent_image",
|
|
364
|
+
IMAGE: "images",
|
|
365
|
+
MASK: "mask",
|
|
366
|
+
CONTROL_NET: "control_net",
|
|
367
|
+
UPSCALE_MODEL: "upscale_model",
|
|
368
|
+
};
|
|
369
|
+
return typeToInput[dataType] ?? null;
|
|
370
|
+
}
|
|
371
|
+
/**
|
|
372
|
+
* Coerce a string value to the expected type based on objectInfo.
|
|
373
|
+
*/
|
|
374
|
+
function coerceValue(key, rawValue, def) {
|
|
375
|
+
const spec = findInputSpec(key, def);
|
|
376
|
+
if (!spec)
|
|
377
|
+
return undefined;
|
|
378
|
+
const [typeOrEnum, options] = spec;
|
|
379
|
+
// Enum type (array of allowed string values)
|
|
380
|
+
if (Array.isArray(typeOrEnum)) {
|
|
381
|
+
// Return the raw value if it's in the enum, otherwise closest match
|
|
382
|
+
if (typeOrEnum.includes(rawValue))
|
|
383
|
+
return rawValue;
|
|
384
|
+
// Try case-insensitive
|
|
385
|
+
const found = typeOrEnum.find((v) => typeof v === "string" && v.toLowerCase() === rawValue.toLowerCase());
|
|
386
|
+
return found ?? rawValue;
|
|
387
|
+
}
|
|
388
|
+
switch (typeOrEnum) {
|
|
389
|
+
case "INT": {
|
|
390
|
+
const n = Number(rawValue);
|
|
391
|
+
return Number.isFinite(n) ? Math.round(n) : undefined;
|
|
392
|
+
}
|
|
393
|
+
case "FLOAT": {
|
|
394
|
+
const n = Number(rawValue);
|
|
395
|
+
return Number.isFinite(n) ? n : undefined;
|
|
396
|
+
}
|
|
397
|
+
case "BOOLEAN":
|
|
398
|
+
return rawValue === "true" || rawValue === "1";
|
|
399
|
+
case "STRING":
|
|
400
|
+
return rawValue;
|
|
401
|
+
default:
|
|
402
|
+
// Unknown type — might be a connection type like MODEL, CLIP
|
|
403
|
+
// Don't set scalar values for connection types
|
|
404
|
+
return undefined;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Find the input spec for a given key in a node definition.
|
|
409
|
+
*/
|
|
410
|
+
function findInputSpec(key, def) {
|
|
411
|
+
if (def.input.required?.[key])
|
|
412
|
+
return def.input.required[key];
|
|
413
|
+
if (def.input.optional?.[key])
|
|
414
|
+
return def.input.optional[key];
|
|
415
|
+
return null;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Fill required inputs that weren't set by connections or parsed values.
|
|
419
|
+
*/
|
|
420
|
+
function fillDefaults(node, def, warnings, nodeId) {
|
|
421
|
+
const required = def.input.required ?? {};
|
|
422
|
+
for (const [inputName, spec] of Object.entries(required)) {
|
|
423
|
+
// Skip if already set
|
|
424
|
+
if (node.inputs[inputName] !== undefined)
|
|
425
|
+
continue;
|
|
426
|
+
const [typeOrEnum, options] = spec;
|
|
427
|
+
// Connection types (MODEL, CLIP, etc.) — can't fill with defaults, skip
|
|
428
|
+
if (typeof typeOrEnum === "string" &&
|
|
429
|
+
typeOrEnum === typeOrEnum.toUpperCase() &&
|
|
430
|
+
typeOrEnum.length > 1 &&
|
|
431
|
+
!["INT", "FLOAT", "STRING", "BOOLEAN"].includes(typeOrEnum)) {
|
|
432
|
+
continue;
|
|
433
|
+
}
|
|
434
|
+
// Enum: use first option as default
|
|
435
|
+
if (Array.isArray(typeOrEnum) && typeOrEnum.length > 0) {
|
|
436
|
+
node.inputs[inputName] = typeOrEnum[0];
|
|
437
|
+
continue;
|
|
438
|
+
}
|
|
439
|
+
// Use explicit default if available
|
|
440
|
+
if (options && "default" in options) {
|
|
441
|
+
node.inputs[inputName] = options.default;
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
// No default available
|
|
445
|
+
logger.debug(`Node ${nodeId} (${node.class_type}): required input "${inputName}" has no value or default`);
|
|
446
|
+
}
|
|
447
|
+
// Also fill optional inputs that have defaults (for completeness)
|
|
448
|
+
const optional = def.input.optional ?? {};
|
|
449
|
+
for (const [inputName, spec] of Object.entries(optional)) {
|
|
450
|
+
if (node.inputs[inputName] !== undefined)
|
|
451
|
+
continue;
|
|
452
|
+
const [, options] = spec;
|
|
453
|
+
if (options && "default" in options) {
|
|
454
|
+
node.inputs[inputName] = options.default;
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
function isConnectionValue(value) {
|
|
459
|
+
return (Array.isArray(value) &&
|
|
460
|
+
value.length === 2 &&
|
|
461
|
+
typeof value[0] === "string" &&
|
|
462
|
+
typeof value[1] === "number");
|
|
463
|
+
}
|
|
464
|
+
//# sourceMappingURL=mermaid-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mermaid-parser.js","sourceRoot":"","sources":["../../src/services/mermaid-parser.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare const MODEL_SUBDIRS: readonly ["checkpoints", "loras", "vae", "upscale_models", "controlnet", "embeddings", "clip", "diffusers", "gligen", "hypernetworks", "photomaker", "style_models", "unet"];
|
|
2
|
+
export type ModelType = (typeof MODEL_SUBDIRS)[number];
|
|
3
|
+
export interface HFModelResult {
|
|
4
|
+
id: string;
|
|
5
|
+
modelId: string;
|
|
6
|
+
author: string;
|
|
7
|
+
tags: string[];
|
|
8
|
+
downloads: number;
|
|
9
|
+
likes: number;
|
|
10
|
+
lastModified: string;
|
|
11
|
+
}
|
|
12
|
+
export interface LocalModel {
|
|
13
|
+
name: string;
|
|
14
|
+
path: string;
|
|
15
|
+
size: number;
|
|
16
|
+
modified: string;
|
|
17
|
+
type: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function searchHuggingFaceModels(query: string, options?: {
|
|
20
|
+
filter?: string;
|
|
21
|
+
limit?: number;
|
|
22
|
+
}): Promise<HFModelResult[]>;
|
|
23
|
+
export declare function listLocalModels(modelType?: string): Promise<LocalModel[]>;
|
|
24
|
+
export declare function downloadModel(url: string, targetSubfolder: string, filename?: string): Promise<string>;
|
|
25
|
+
//# sourceMappingURL=model-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-resolver.d.ts","sourceRoot":"","sources":["../../src/services/model-resolver.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,aAAa,8KAchB,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,aAAa,CAAC,CAAC,MAAM,CAAC,CAAC;AAEvD,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;CACd;AASD,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,MAAM,EACb,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAChD,OAAO,CAAC,aAAa,EAAE,CAAC,CAoC1B;AAED,wBAAsB,eAAe,CACnC,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,UAAU,EAAE,CAAC,CAqCvB;AAED,wBAAsB,aAAa,CACjC,GAAG,EAAE,MAAM,EACX,eAAe,EAAE,MAAM,EACvB,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CAqCjB"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { readdir, stat, mkdir } from "node:fs/promises";
|
|
2
|
+
import { createWriteStream } from "node:fs";
|
|
3
|
+
import { pipeline } from "node:stream/promises";
|
|
4
|
+
import { Readable } from "node:stream";
|
|
5
|
+
import { join, basename } from "node:path";
|
|
6
|
+
import { config } from "../config.js";
|
|
7
|
+
import { ModelError } from "../utils/errors.js";
|
|
8
|
+
import { logger } from "../utils/logger.js";
|
|
9
|
+
export const MODEL_SUBDIRS = [
|
|
10
|
+
"checkpoints",
|
|
11
|
+
"loras",
|
|
12
|
+
"vae",
|
|
13
|
+
"upscale_models",
|
|
14
|
+
"controlnet",
|
|
15
|
+
"embeddings",
|
|
16
|
+
"clip",
|
|
17
|
+
"diffusers",
|
|
18
|
+
"gligen",
|
|
19
|
+
"hypernetworks",
|
|
20
|
+
"photomaker",
|
|
21
|
+
"style_models",
|
|
22
|
+
"unet",
|
|
23
|
+
];
|
|
24
|
+
function getModelsRoot() {
|
|
25
|
+
if (!config.comfyuiPath) {
|
|
26
|
+
throw new ModelError("COMFYUI_PATH is not configured. Set the COMFYUI_PATH environment variable.");
|
|
27
|
+
}
|
|
28
|
+
return join(config.comfyuiPath, "models");
|
|
29
|
+
}
|
|
30
|
+
export async function searchHuggingFaceModels(query, options = {}) {
|
|
31
|
+
const { filter, limit = 10 } = options;
|
|
32
|
+
const params = new URLSearchParams({
|
|
33
|
+
search: query,
|
|
34
|
+
limit: String(limit),
|
|
35
|
+
});
|
|
36
|
+
if (filter)
|
|
37
|
+
params.set("filter", filter);
|
|
38
|
+
const headers = {};
|
|
39
|
+
if (config.huggingfaceToken) {
|
|
40
|
+
headers["Authorization"] = `Bearer ${config.huggingfaceToken}`;
|
|
41
|
+
}
|
|
42
|
+
const url = `https://huggingface.co/api/models?${params}`;
|
|
43
|
+
logger.debug("HuggingFace API request", { url });
|
|
44
|
+
const res = await fetch(url, { headers });
|
|
45
|
+
if (!res.ok) {
|
|
46
|
+
const body = await res.text().catch(() => "");
|
|
47
|
+
throw new ModelError(`HuggingFace API ${res.status}: ${res.statusText}`, { url, status: res.status, body });
|
|
48
|
+
}
|
|
49
|
+
const data = (await res.json());
|
|
50
|
+
return data.map((m) => ({
|
|
51
|
+
id: String(m.id ?? m._id ?? ""),
|
|
52
|
+
modelId: String(m.modelId ?? m.id ?? ""),
|
|
53
|
+
author: String(m.author ?? ""),
|
|
54
|
+
tags: Array.isArray(m.tags) ? m.tags.map(String) : [],
|
|
55
|
+
downloads: Number(m.downloads ?? 0),
|
|
56
|
+
likes: Number(m.likes ?? 0),
|
|
57
|
+
lastModified: String(m.lastModified ?? ""),
|
|
58
|
+
}));
|
|
59
|
+
}
|
|
60
|
+
export async function listLocalModels(modelType) {
|
|
61
|
+
const modelsRoot = getModelsRoot();
|
|
62
|
+
const dirsToScan = modelType
|
|
63
|
+
? [modelType]
|
|
64
|
+
: [...MODEL_SUBDIRS];
|
|
65
|
+
const results = [];
|
|
66
|
+
for (const dir of dirsToScan) {
|
|
67
|
+
const dirPath = join(modelsRoot, dir);
|
|
68
|
+
let entries;
|
|
69
|
+
try {
|
|
70
|
+
entries = await readdir(dirPath);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// Directory doesn't exist -- skip silently
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
for (const entry of entries) {
|
|
77
|
+
const filePath = join(dirPath, entry);
|
|
78
|
+
try {
|
|
79
|
+
const info = await stat(filePath);
|
|
80
|
+
if (!info.isFile())
|
|
81
|
+
continue;
|
|
82
|
+
results.push({
|
|
83
|
+
name: entry,
|
|
84
|
+
path: filePath,
|
|
85
|
+
size: info.size,
|
|
86
|
+
modified: info.mtime.toISOString(),
|
|
87
|
+
type: dir,
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
// Skip files we can't stat
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return results;
|
|
96
|
+
}
|
|
97
|
+
export async function downloadModel(url, targetSubfolder, filename) {
|
|
98
|
+
const modelsRoot = getModelsRoot();
|
|
99
|
+
const targetDir = join(modelsRoot, targetSubfolder);
|
|
100
|
+
// Ensure target directory exists
|
|
101
|
+
await mkdir(targetDir, { recursive: true });
|
|
102
|
+
const resolvedFilename = filename ?? (basename(new URL(url).pathname) || "model.safetensors");
|
|
103
|
+
const targetPath = join(targetDir, resolvedFilename);
|
|
104
|
+
logger.info(`Downloading model to ${targetPath}`, { url });
|
|
105
|
+
const headers = {};
|
|
106
|
+
if (config.huggingfaceToken && url.includes("huggingface.co")) {
|
|
107
|
+
headers["Authorization"] = `Bearer ${config.huggingfaceToken}`;
|
|
108
|
+
}
|
|
109
|
+
const res = await fetch(url, { headers });
|
|
110
|
+
if (!res.ok) {
|
|
111
|
+
throw new ModelError(`Download failed: ${res.status} ${res.statusText}`, { url, status: res.status });
|
|
112
|
+
}
|
|
113
|
+
if (!res.body) {
|
|
114
|
+
throw new ModelError("Download response has no body", { url });
|
|
115
|
+
}
|
|
116
|
+
const nodeStream = Readable.fromWeb(res.body);
|
|
117
|
+
const fileStream = createWriteStream(targetPath);
|
|
118
|
+
await pipeline(nodeStream, fileStream);
|
|
119
|
+
const info = await stat(targetPath);
|
|
120
|
+
logger.info(`Download complete: ${resolvedFilename} (${(info.size / 1024 / 1024).toFixed(1)} MB)`);
|
|
121
|
+
return targetPath;
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=model-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-resolver.js","sourceRoot":"","sources":["../../src/services/model-resolver.ts"],"names":[],"mappings":"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"}
|