comfyui-mcp 0.4.1 → 0.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/.dockerignore +24 -0
- package/CHANGELOG.md +61 -0
- package/Dockerfile +50 -0
- package/README.md +67 -2
- package/dist/comfyui/client.d.ts +1 -1
- package/dist/comfyui/client.d.ts.map +1 -1
- package/dist/comfyui/client.js +24 -3
- package/dist/comfyui/client.js.map +1 -1
- package/dist/comfyui/types.d.ts +9 -0
- package/dist/comfyui/types.d.ts.map +1 -1
- package/dist/config.d.ts +3 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +39 -5
- package/dist/config.js.map +1 -1
- package/dist/index.js +27 -10
- package/dist/index.js.map +1 -1
- package/dist/services/api-nodes.d.ts +77 -0
- package/dist/services/api-nodes.d.ts.map +1 -0
- package/dist/services/api-nodes.js +205 -0
- package/dist/services/api-nodes.js.map +1 -0
- package/dist/services/civitai-resolver.d.ts +27 -0
- package/dist/services/civitai-resolver.d.ts.map +1 -0
- package/dist/services/civitai-resolver.js +82 -0
- package/dist/services/civitai-resolver.js.map +1 -0
- package/dist/services/generate-conditioned.d.ts +50 -0
- package/dist/services/generate-conditioned.d.ts.map +1 -0
- package/dist/services/generate-conditioned.js +95 -0
- package/dist/services/generate-conditioned.js.map +1 -0
- package/dist/services/install-comfyui.d.ts +89 -0
- package/dist/services/install-comfyui.d.ts.map +1 -0
- package/dist/services/install-comfyui.js +288 -0
- package/dist/services/install-comfyui.js.map +1 -0
- package/dist/services/manager-config.d.ts +59 -0
- package/dist/services/manager-config.d.ts.map +1 -0
- package/dist/services/manager-config.js +309 -0
- package/dist/services/manager-config.js.map +1 -0
- package/dist/services/model-resolver.d.ts.map +1 -1
- package/dist/services/model-resolver.js +31 -2
- package/dist/services/model-resolver.js.map +1 -1
- package/dist/services/node-bisect.d.ts +105 -0
- package/dist/services/node-bisect.d.ts.map +1 -0
- package/dist/services/node-bisect.js +426 -0
- package/dist/services/node-bisect.js.map +1 -0
- package/dist/services/node-management.d.ts +90 -0
- package/dist/services/node-management.d.ts.map +1 -0
- package/dist/services/node-management.js +377 -0
- package/dist/services/node-management.js.map +1 -0
- package/dist/services/node-snapshots.d.ts +27 -0
- package/dist/services/node-snapshots.d.ts.map +1 -0
- package/dist/services/node-snapshots.js +203 -0
- package/dist/services/node-snapshots.js.map +1 -0
- package/dist/services/update-comfyui.d.ts +34 -0
- package/dist/services/update-comfyui.d.ts.map +1 -0
- package/dist/services/update-comfyui.js +206 -0
- package/dist/services/update-comfyui.js.map +1 -0
- package/dist/services/workflow-autoload.d.ts.map +1 -1
- package/dist/services/workflow-autoload.js +1 -1
- package/dist/services/workflow-autoload.js.map +1 -1
- package/dist/services/workflow-composer.d.ts.map +1 -1
- package/dist/services/workflow-composer.js +145 -0
- package/dist/services/workflow-composer.js.map +1 -1
- package/dist/services/workflow-deps.d.ts +135 -0
- package/dist/services/workflow-deps.d.ts.map +1 -0
- package/dist/services/workflow-deps.js +306 -0
- package/dist/services/workflow-deps.js.map +1 -0
- package/dist/services/workflow-dsl.d.ts +4 -0
- package/dist/services/workflow-dsl.d.ts.map +1 -0
- package/dist/services/workflow-dsl.js +95 -0
- package/dist/services/workflow-dsl.js.map +1 -0
- package/dist/services/workflow-executor.d.ts +2 -0
- package/dist/services/workflow-executor.d.ts.map +1 -1
- package/dist/services/workflow-executor.js +1 -1
- package/dist/services/workflow-executor.js.map +1 -1
- package/dist/services/workspace-env.d.ts +68 -0
- package/dist/services/workspace-env.d.ts.map +1 -0
- package/dist/services/workspace-env.js +371 -0
- package/dist/services/workspace-env.js.map +1 -0
- package/dist/tools/api-nodes.d.ts +9 -0
- package/dist/tools/api-nodes.d.ts.map +1 -0
- package/dist/tools/api-nodes.js +85 -0
- package/dist/tools/api-nodes.js.map +1 -0
- package/dist/tools/generate-conditioned.d.ts +3 -0
- package/dist/tools/generate-conditioned.d.ts.map +1 -0
- package/dist/tools/generate-conditioned.js +78 -0
- package/dist/tools/generate-conditioned.js.map +1 -0
- package/dist/tools/generation-tracker.d.ts.map +1 -1
- package/dist/tools/generation-tracker.js +3 -4
- package/dist/tools/generation-tracker.js.map +1 -1
- package/dist/tools/image-management.d.ts.map +1 -1
- package/dist/tools/image-management.js +1 -3
- package/dist/tools/image-management.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +24 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/install-comfyui.d.ts +3 -0
- package/dist/tools/install-comfyui.d.ts.map +1 -0
- package/dist/tools/install-comfyui.js +51 -0
- package/dist/tools/install-comfyui.js.map +1 -0
- package/dist/tools/manager-config.d.ts +3 -0
- package/dist/tools/manager-config.d.ts.map +1 -0
- package/dist/tools/manager-config.js +45 -0
- package/dist/tools/manager-config.js.map +1 -0
- package/dist/tools/memory-management.js +1 -1
- package/dist/tools/memory-management.js.map +1 -1
- package/dist/tools/model-extras.d.ts +3 -0
- package/dist/tools/model-extras.d.ts.map +1 -0
- package/dist/tools/model-extras.js +135 -0
- package/dist/tools/model-extras.js.map +1 -0
- package/dist/tools/model-management.js +3 -3
- package/dist/tools/model-management.js.map +1 -1
- package/dist/tools/node-bisect.d.ts +3 -0
- package/dist/tools/node-bisect.d.ts.map +1 -0
- package/dist/tools/node-bisect.js +60 -0
- package/dist/tools/node-bisect.js.map +1 -0
- package/dist/tools/node-management.d.ts +3 -0
- package/dist/tools/node-management.d.ts.map +1 -0
- package/dist/tools/node-management.js +143 -0
- package/dist/tools/node-management.js.map +1 -0
- package/dist/tools/node-snapshots.d.ts +3 -0
- package/dist/tools/node-snapshots.d.ts.map +1 -0
- package/dist/tools/node-snapshots.js +59 -0
- package/dist/tools/node-snapshots.js.map +1 -0
- package/dist/tools/queue-management.js +4 -4
- package/dist/tools/queue-management.js.map +1 -1
- package/dist/tools/registry-search.js +4 -4
- package/dist/tools/registry-search.js.map +1 -1
- package/dist/tools/skill-generator.js +2 -2
- package/dist/tools/skill-generator.js.map +1 -1
- package/dist/tools/update-comfyui.d.ts +3 -0
- package/dist/tools/update-comfyui.d.ts.map +1 -0
- package/dist/tools/update-comfyui.js +27 -0
- package/dist/tools/update-comfyui.js.map +1 -0
- package/dist/tools/workflow-autoload.d.ts.map +1 -1
- package/dist/tools/workflow-autoload.js +7 -2
- package/dist/tools/workflow-autoload.js.map +1 -1
- package/dist/tools/workflow-compose.js +3 -3
- package/dist/tools/workflow-compose.js.map +1 -1
- package/dist/tools/workflow-deps.d.ts +3 -0
- package/dist/tools/workflow-deps.d.ts.map +1 -0
- package/dist/tools/workflow-deps.js +111 -0
- package/dist/tools/workflow-deps.js.map +1 -0
- package/dist/tools/workflow-dsl.d.ts +3 -0
- package/dist/tools/workflow-dsl.d.ts.map +1 -0
- package/dist/tools/workflow-dsl.js +29 -0
- package/dist/tools/workflow-dsl.js.map +1 -0
- package/dist/tools/workflow-execute.js +1 -1
- package/dist/tools/workflow-execute.js.map +1 -1
- package/dist/tools/workflow-library.js +3 -3
- package/dist/tools/workflow-library.js.map +1 -1
- package/dist/tools/workspace-env.d.ts +3 -0
- package/dist/tools/workspace-env.d.ts.map +1 -0
- package/dist/tools/workspace-env.js +55 -0
- package/dist/tools/workspace-env.js.map +1 -0
- package/dist/transport/cli.d.ts +15 -0
- package/dist/transport/cli.d.ts.map +1 -0
- package/dist/transport/cli.js +48 -0
- package/dist/transport/cli.js.map +1 -0
- package/dist/transport/comfyui-url.d.ts +12 -0
- package/dist/transport/comfyui-url.d.ts.map +1 -0
- package/dist/transport/comfyui-url.js +15 -0
- package/dist/transport/comfyui-url.js.map +1 -0
- package/dist/transport/http.d.ts +17 -0
- package/dist/transport/http.d.ts.map +1 -0
- package/dist/transport/http.js +95 -0
- package/dist/transport/http.js.map +1 -0
- package/dist/utils/errors.d.ts +6 -0
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +12 -0
- package/dist/utils/errors.js.map +1 -1
- package/glama.json +6 -0
- package/package.json +1 -1
- package/server.json +2 -2
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { ObjectInfo, ComfyUINodeDef, WorkflowJSON } from "../comfyui/types.js";
|
|
2
|
+
/** Injectable dependencies so the logic is unit-testable without a live server. */
|
|
3
|
+
export interface ApiNodesDeps {
|
|
4
|
+
getObjectInfo: () => Promise<ObjectInfo>;
|
|
5
|
+
enqueue: (workflow: WorkflowJSON, options?: {
|
|
6
|
+
disable_random_seed?: boolean;
|
|
7
|
+
extra_data?: Record<string, unknown>;
|
|
8
|
+
}) => Promise<{
|
|
9
|
+
prompt_id: string;
|
|
10
|
+
queue_remaining?: number;
|
|
11
|
+
}>;
|
|
12
|
+
}
|
|
13
|
+
/** True if a node definition is a hosted partner/API node. */
|
|
14
|
+
export declare function isApiNode(def: ComfyUINodeDef): boolean;
|
|
15
|
+
export interface ApiNodeSummary {
|
|
16
|
+
class_type: string;
|
|
17
|
+
display_name: string;
|
|
18
|
+
category: string;
|
|
19
|
+
description: string;
|
|
20
|
+
output: string[];
|
|
21
|
+
deprecated: boolean;
|
|
22
|
+
experimental: boolean;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Discover hosted partner/API nodes available on the connected ComfyUI.
|
|
26
|
+
* Optionally narrow by a case-insensitive substring matched against the
|
|
27
|
+
* class_type, display name, or category (e.g. "image", "kling", "video").
|
|
28
|
+
*/
|
|
29
|
+
export declare function listApiNodes(filter?: string, deps?: ApiNodesDeps): Promise<ApiNodeSummary[]>;
|
|
30
|
+
export interface ApiNodeInputDescriptor {
|
|
31
|
+
name: string;
|
|
32
|
+
type: string | string[];
|
|
33
|
+
required: boolean;
|
|
34
|
+
/** Extra config from /object_info (default, min, max, options, tooltip, ...). */
|
|
35
|
+
config: Record<string, unknown>;
|
|
36
|
+
}
|
|
37
|
+
export interface ApiNodeSchema {
|
|
38
|
+
class_type: string;
|
|
39
|
+
display_name: string;
|
|
40
|
+
category: string;
|
|
41
|
+
description: string;
|
|
42
|
+
is_api_node: boolean;
|
|
43
|
+
/** Whether the node is itself a terminal OUTPUT_NODE (drives execution). */
|
|
44
|
+
is_output_node: boolean;
|
|
45
|
+
/** Visible inputs the caller can/should supply. */
|
|
46
|
+
inputs: ApiNodeInputDescriptor[];
|
|
47
|
+
/**
|
|
48
|
+
* Hidden inputs (e.g. auth_token_comfy_org). The ComfyUI server fills these
|
|
49
|
+
* from the logged-in session — callers should NOT supply them.
|
|
50
|
+
*/
|
|
51
|
+
hidden_inputs: string[];
|
|
52
|
+
output: string[];
|
|
53
|
+
output_name: string[];
|
|
54
|
+
}
|
|
55
|
+
/** Return the input schema for a given API node (from its /object_info entry). */
|
|
56
|
+
export declare function getApiNodeSchema(classType: string, deps?: ApiNodesDeps): Promise<ApiNodeSchema>;
|
|
57
|
+
export interface GenerateWithApiNodeArgs {
|
|
58
|
+
class_type: string;
|
|
59
|
+
inputs: Record<string, unknown>;
|
|
60
|
+
disable_random_seed?: boolean;
|
|
61
|
+
}
|
|
62
|
+
export interface GenerateWithApiNodeResult {
|
|
63
|
+
prompt_id: string;
|
|
64
|
+
queue_remaining?: number;
|
|
65
|
+
/** The minimal single-node workflow that was enqueued. */
|
|
66
|
+
workflow: WorkflowJSON;
|
|
67
|
+
/** Non-fatal guidance (e.g. unknown inputs, auth reminder). */
|
|
68
|
+
notes: string[];
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Build a minimal single-node workflow that runs a chosen API node with the
|
|
72
|
+
* provided inputs and enqueue it. Returns the prompt_id (reuses the existing
|
|
73
|
+
* enqueue path). The API node is typically an output node, so it can stand
|
|
74
|
+
* alone as a complete graph.
|
|
75
|
+
*/
|
|
76
|
+
export declare function generateWithApiNode(args: GenerateWithApiNodeArgs, deps?: ApiNodesDeps): Promise<GenerateWithApiNodeResult>;
|
|
77
|
+
//# sourceMappingURL=api-nodes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-nodes.d.ts","sourceRoot":"","sources":["../../src/services/api-nodes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,UAAU,EACV,cAAc,EAEd,YAAY,EACb,MAAM,qBAAqB,CAAC;AAgC7B,mFAAmF;AACnF,MAAM,WAAW,YAAY;IAC3B,aAAa,EAAE,MAAM,OAAO,CAAC,UAAU,CAAC,CAAC;IACzC,OAAO,EAAE,CACP,QAAQ,EAAE,YAAY,EACtB,OAAO,CAAC,EAAE;QACR,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACtC,KACE,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/D;AAOD,8DAA8D;AAC9D,wBAAgB,SAAS,CAAC,GAAG,EAAE,cAAc,GAAG,OAAO,CAItD;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,MAAM,CAAC,EAAE,MAAM,EACf,IAAI,GAAE,YAA0B,GAC/B,OAAO,CAAC,cAAc,EAAE,CAAC,CA4B3B;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,iFAAiF;IACjF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACjC;AAED,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,OAAO,CAAC;IACrB,4EAA4E;IAC5E,cAAc,EAAE,OAAO,CAAC;IACxB,mDAAmD;IACnD,MAAM,EAAE,sBAAsB,EAAE,CAAC;IACjC;;;OAGG;IACH,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AAqBD,kFAAkF;AAClF,wBAAsB,gBAAgB,CACpC,SAAS,EAAE,MAAM,EACjB,IAAI,GAAE,YAA0B,GAC/B,OAAO,CAAC,aAAa,CAAC,CAgCxB;AAED,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAChC,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,0DAA0D;IAC1D,QAAQ,EAAE,YAAY,CAAC;IACvB,+DAA+D;IAC/D,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,uBAAuB,EAC7B,IAAI,GAAE,YAA0B,GAC/B,OAAO,CAAC,yBAAyB,CAAC,CAsGpC"}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { getObjectInfo } from "../comfyui/client.js";
|
|
2
|
+
import { enqueueWorkflow } from "./workflow-executor.js";
|
|
3
|
+
import { config } from "../config.js";
|
|
4
|
+
import { ValidationError } from "../utils/errors.js";
|
|
5
|
+
/**
|
|
6
|
+
* API / partner-node support, mirroring `comfy-cli generate` (list / schema / run).
|
|
7
|
+
*
|
|
8
|
+
* MECHANISM & ASSUMPTIONS (confirmed against ComfyUI + comfy-cli source):
|
|
9
|
+
* - These nodes run entirely on the *connected* ComfyUI server via its normal
|
|
10
|
+
* HTTP API (/object_info + /prompt), so this works against remote servers too.
|
|
11
|
+
* We reuse the existing client (getObjectInfo) and enqueue helper rather than
|
|
12
|
+
* re-implementing anything.
|
|
13
|
+
* - ComfyUI marks hosted partner/API nodes in /object_info with `api_node: true`
|
|
14
|
+
* (server.py emits this from the node class's `API_NODE` attribute). Their
|
|
15
|
+
* `category` also conventionally starts with "api node/" (e.g.
|
|
16
|
+
* "api node/image/BFL", "api node/video/Kling"). We treat EITHER signal as a
|
|
17
|
+
* match so older/newer ComfyUI builds both work.
|
|
18
|
+
* Ref: comfyanonymous/ComfyUI server.py node_info() and comfy_api_nodes/*.py.
|
|
19
|
+
* - AUTH: API nodes require a Comfy account / API key, but that credential is
|
|
20
|
+
* supplied to the *ComfyUI server* out-of-band — it is injected by the server
|
|
21
|
+
* into the node's HIDDEN inputs (`auth_token_comfy_org` / `api_key_comfy_org`)
|
|
22
|
+
* from the logged-in session. The MCP client does NOT (and should not) place
|
|
23
|
+
* the key in the workflow JSON. If the server isn't authenticated, the job
|
|
24
|
+
* will be enqueued but fail server-side; we surface that as guidance rather
|
|
25
|
+
* than trying to pass credentials ourselves. (Lower-confidence area — see
|
|
26
|
+
* docs.comfy.org/tutorials/api-nodes.)
|
|
27
|
+
*/
|
|
28
|
+
const API_CATEGORY_PREFIX = "api node";
|
|
29
|
+
const defaultDeps = {
|
|
30
|
+
getObjectInfo,
|
|
31
|
+
enqueue: enqueueWorkflow,
|
|
32
|
+
};
|
|
33
|
+
/** True if a node definition is a hosted partner/API node. */
|
|
34
|
+
export function isApiNode(def) {
|
|
35
|
+
if (def.api_node === true)
|
|
36
|
+
return true;
|
|
37
|
+
const category = (def.category ?? "").toLowerCase();
|
|
38
|
+
return category === API_CATEGORY_PREFIX || category.startsWith(`${API_CATEGORY_PREFIX}/`);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Discover hosted partner/API nodes available on the connected ComfyUI.
|
|
42
|
+
* Optionally narrow by a case-insensitive substring matched against the
|
|
43
|
+
* class_type, display name, or category (e.g. "image", "kling", "video").
|
|
44
|
+
*/
|
|
45
|
+
export async function listApiNodes(filter, deps = defaultDeps) {
|
|
46
|
+
const objectInfo = await deps.getObjectInfo();
|
|
47
|
+
const needle = filter?.trim().toLowerCase();
|
|
48
|
+
const results = [];
|
|
49
|
+
for (const [classType, def] of Object.entries(objectInfo)) {
|
|
50
|
+
if (!def || !isApiNode(def))
|
|
51
|
+
continue;
|
|
52
|
+
const summary = {
|
|
53
|
+
class_type: classType,
|
|
54
|
+
display_name: def.display_name || classType,
|
|
55
|
+
category: def.category ?? "",
|
|
56
|
+
description: def.description ?? "",
|
|
57
|
+
output: Array.isArray(def.output) ? def.output : [],
|
|
58
|
+
deprecated: def.deprecated === true,
|
|
59
|
+
experimental: def.experimental === true,
|
|
60
|
+
};
|
|
61
|
+
if (needle) {
|
|
62
|
+
const haystack = `${classType} ${summary.display_name} ${summary.category}`.toLowerCase();
|
|
63
|
+
if (!haystack.includes(needle))
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
results.push(summary);
|
|
67
|
+
}
|
|
68
|
+
results.sort((a, b) => a.class_type.localeCompare(b.class_type));
|
|
69
|
+
return results;
|
|
70
|
+
}
|
|
71
|
+
function describeInputs(specs, required) {
|
|
72
|
+
if (!specs)
|
|
73
|
+
return [];
|
|
74
|
+
return Object.entries(specs).map(([name, spec]) => {
|
|
75
|
+
// Spec shape: [type, config?] where type is a string (e.g. "STRING") or a
|
|
76
|
+
// string[] of enum options (e.g. ["fast", "quality"]).
|
|
77
|
+
const type = Array.isArray(spec) ? spec[0] : spec;
|
|
78
|
+
const config = (Array.isArray(spec) ? spec[1] : undefined) ?? {};
|
|
79
|
+
return {
|
|
80
|
+
name,
|
|
81
|
+
type: type,
|
|
82
|
+
required,
|
|
83
|
+
config: config,
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
/** Return the input schema for a given API node (from its /object_info entry). */
|
|
88
|
+
export async function getApiNodeSchema(classType, deps = defaultDeps) {
|
|
89
|
+
const objectInfo = await deps.getObjectInfo();
|
|
90
|
+
const def = objectInfo[classType];
|
|
91
|
+
if (!def) {
|
|
92
|
+
throw new ValidationError(`Node "${classType}" was not found on the connected ComfyUI. ` +
|
|
93
|
+
`Use list_api_nodes to see available API nodes.`);
|
|
94
|
+
}
|
|
95
|
+
if (!isApiNode(def)) {
|
|
96
|
+
throw new ValidationError(`Node "${classType}" exists but is not an API/partner node ` +
|
|
97
|
+
`(category "${def.category ?? ""}"). Use list_api_nodes to find API nodes.`);
|
|
98
|
+
}
|
|
99
|
+
return {
|
|
100
|
+
class_type: classType,
|
|
101
|
+
display_name: def.display_name || classType,
|
|
102
|
+
category: def.category ?? "",
|
|
103
|
+
description: def.description ?? "",
|
|
104
|
+
is_api_node: true,
|
|
105
|
+
is_output_node: def.output_node === true,
|
|
106
|
+
inputs: [
|
|
107
|
+
...describeInputs(def.input?.required, true),
|
|
108
|
+
...describeInputs(def.input?.optional, false),
|
|
109
|
+
],
|
|
110
|
+
hidden_inputs: def.input?.hidden ? Object.keys(def.input.hidden) : [],
|
|
111
|
+
output: Array.isArray(def.output) ? def.output : [],
|
|
112
|
+
output_name: Array.isArray(def.output_name) ? def.output_name : [],
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Build a minimal single-node workflow that runs a chosen API node with the
|
|
117
|
+
* provided inputs and enqueue it. Returns the prompt_id (reuses the existing
|
|
118
|
+
* enqueue path). The API node is typically an output node, so it can stand
|
|
119
|
+
* alone as a complete graph.
|
|
120
|
+
*/
|
|
121
|
+
export async function generateWithApiNode(args, deps = defaultDeps) {
|
|
122
|
+
const schema = await getApiNodeSchema(args.class_type, deps);
|
|
123
|
+
const notes = [];
|
|
124
|
+
const provided = args.inputs ?? {};
|
|
125
|
+
const knownNames = new Set(schema.inputs.map((i) => i.name));
|
|
126
|
+
// Warn about inputs that aren't part of the node's visible schema (typos,
|
|
127
|
+
// or hidden auth fields the server should fill itself).
|
|
128
|
+
for (const key of Object.keys(provided)) {
|
|
129
|
+
if (!knownNames.has(key)) {
|
|
130
|
+
if (schema.hidden_inputs.includes(key)) {
|
|
131
|
+
notes.push(`Ignoring "${key}": it is a hidden input filled by the ComfyUI server, not the client.`);
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
notes.push(`Unknown input "${key}" for ${args.class_type} (passing through anyway).`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Check required inputs are present (skip enum/combo selectors that ComfyUI
|
|
139
|
+
// can default, but still flag genuinely missing scalars).
|
|
140
|
+
const missingRequired = schema.inputs
|
|
141
|
+
.filter((i) => i.required && !(i.name in provided))
|
|
142
|
+
.map((i) => i.name);
|
|
143
|
+
if (missingRequired.length > 0) {
|
|
144
|
+
notes.push(`Missing required input(s): ${missingRequired.join(", ")}. ` +
|
|
145
|
+
`The server may reject the job. Use get_api_node_schema for details.`);
|
|
146
|
+
}
|
|
147
|
+
// Drop any hidden-input values the caller mistakenly supplied — the server
|
|
148
|
+
// injects auth credentials itself.
|
|
149
|
+
const inputs = {};
|
|
150
|
+
for (const [key, value] of Object.entries(provided)) {
|
|
151
|
+
if (schema.hidden_inputs.includes(key))
|
|
152
|
+
continue;
|
|
153
|
+
inputs[key] = value;
|
|
154
|
+
}
|
|
155
|
+
const workflow = {
|
|
156
|
+
"1": {
|
|
157
|
+
class_type: args.class_type,
|
|
158
|
+
inputs,
|
|
159
|
+
_meta: { title: schema.display_name },
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
// ComfyUI only executes graphs that reach a terminal OUTPUT_NODE; a bare
|
|
163
|
+
// non-output API node fails validation with "prompt_no_outputs". If the API
|
|
164
|
+
// node isn't itself an output node, wire its IMAGE output into a SaveImage.
|
|
165
|
+
if (!schema.is_output_node) {
|
|
166
|
+
const imageIdx = schema.output.findIndex((o) => String(o).toUpperCase() === "IMAGE");
|
|
167
|
+
if (imageIdx >= 0) {
|
|
168
|
+
workflow["2"] = {
|
|
169
|
+
class_type: "SaveImage",
|
|
170
|
+
inputs: { images: ["1", imageIdx], filename_prefix: "ComfyUI" },
|
|
171
|
+
_meta: { title: "Save Image" },
|
|
172
|
+
};
|
|
173
|
+
notes.push("Added a SaveImage output node — ComfyUI requires a terminal output node " +
|
|
174
|
+
"for the prompt to execute.");
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
notes.push(`"${args.class_type}" is not an output node and has no IMAGE output, so no ` +
|
|
178
|
+
"output node was auto-added; the prompt may fail with 'prompt_no_outputs'. " +
|
|
179
|
+
"Wire a terminal output node yourself if needed.");
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// comfy.org API-node credentials travel in /prompt extra_data (the server
|
|
183
|
+
// injects them into the node's hidden inputs). Supply the configured key so
|
|
184
|
+
// API nodes work even when the ComfyUI server isn't logged in itself.
|
|
185
|
+
const extraData = {};
|
|
186
|
+
if (config.comfyApiKey) {
|
|
187
|
+
extraData.api_key_comfy_org = config.comfyApiKey;
|
|
188
|
+
notes.push("Attached COMFY_API_KEY to the request (extra_data.api_key_comfy_org).");
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
notes.push("No COMFY_API_KEY configured — relying on the ComfyUI server's own logged-in " +
|
|
192
|
+
"comfy.org session for API-node auth. Set COMFY_API_KEY if the server isn't logged in.");
|
|
193
|
+
}
|
|
194
|
+
const result = await deps.enqueue(workflow, {
|
|
195
|
+
disable_random_seed: args.disable_random_seed,
|
|
196
|
+
extra_data: Object.keys(extraData).length > 0 ? extraData : undefined,
|
|
197
|
+
});
|
|
198
|
+
return {
|
|
199
|
+
prompt_id: result.prompt_id,
|
|
200
|
+
queue_remaining: result.queue_remaining,
|
|
201
|
+
workflow,
|
|
202
|
+
notes,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
//# sourceMappingURL=api-nodes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-nodes.js","sourceRoot":"","sources":["../../src/services/api-nodes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export interface CivitaiResolved {
|
|
2
|
+
/**
|
|
3
|
+
* Direct download URL. No credentials are embedded — `downloadModel` attaches
|
|
4
|
+
* the CivitAI token as an `Authorization` request header, so the token never
|
|
5
|
+
* leaks into logs, error messages, or redirect URLs.
|
|
6
|
+
*/
|
|
7
|
+
downloadUrl: string;
|
|
8
|
+
/** Suggested filename from CivitAI metadata, when available. */
|
|
9
|
+
filename?: string;
|
|
10
|
+
/** Resolved model-version id. */
|
|
11
|
+
versionId: number;
|
|
12
|
+
/** Model name, when resolvable. */
|
|
13
|
+
modelName?: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Resolve a CivitAI model-version id directly to a download URL.
|
|
17
|
+
* Uses GET /api/v1/model-versions/{id}.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveCivitaiModelVersion(versionId: number): Promise<CivitaiResolved>;
|
|
20
|
+
/**
|
|
21
|
+
* Resolve a CivitAI model id to a download URL.
|
|
22
|
+
* Uses GET /api/v1/models/{id} and picks a model version.
|
|
23
|
+
* If `versionId` is supplied, that specific version is used; otherwise the
|
|
24
|
+
* latest (first listed) version is chosen.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveCivitaiModel(modelId: number, versionId?: number): Promise<CivitaiResolved>;
|
|
27
|
+
//# sourceMappingURL=civitai-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"civitai-resolver.d.ts","sourceRoot":"","sources":["../../src/services/civitai-resolver.ts"],"names":[],"mappings":"AA+BA,MAAM,WAAW,eAAe;IAC9B;;;;OAIG;IACH,WAAW,EAAE,MAAM,CAAC;IACpB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iCAAiC;IACjC,SAAS,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAwDD;;;GAGG;AACH,wBAAsB,0BAA0B,CAC9C,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,eAAe,CAAC,CAK1B;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,eAAe,CAAC,CAyB1B"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { config } from "../config.js";
|
|
2
|
+
import { ModelError, ValidationError } from "../utils/errors.js";
|
|
3
|
+
import { logger } from "../utils/logger.js";
|
|
4
|
+
const CIVITAI_API_BASE = "https://civitai.com/api/v1";
|
|
5
|
+
function authHeaders() {
|
|
6
|
+
const headers = {};
|
|
7
|
+
if (config.civitaiApiToken) {
|
|
8
|
+
headers["Authorization"] = `Bearer ${config.civitaiApiToken}`;
|
|
9
|
+
}
|
|
10
|
+
return headers;
|
|
11
|
+
}
|
|
12
|
+
async function civitaiGet(path) {
|
|
13
|
+
const url = `${CIVITAI_API_BASE}${path}`;
|
|
14
|
+
logger.debug("CivitAI API request", { url });
|
|
15
|
+
const res = await fetch(url, { headers: authHeaders() });
|
|
16
|
+
if (res.status === 404) {
|
|
17
|
+
throw new ModelError(`CivitAI resource not found: ${path}`, {
|
|
18
|
+
url,
|
|
19
|
+
status: 404,
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
if (!res.ok) {
|
|
23
|
+
const body = await res.text().catch(() => "");
|
|
24
|
+
throw new ModelError(`CivitAI API ${res.status}: ${res.statusText}`, {
|
|
25
|
+
url,
|
|
26
|
+
status: res.status,
|
|
27
|
+
body,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
return (await res.json());
|
|
31
|
+
}
|
|
32
|
+
/** Pick the best file from a version's file list: primary first, else the first. */
|
|
33
|
+
function pickFile(version) {
|
|
34
|
+
const files = version.files ?? [];
|
|
35
|
+
return files.find((f) => f.primary) ?? files[0];
|
|
36
|
+
}
|
|
37
|
+
function resolveFromVersion(version, modelName) {
|
|
38
|
+
const file = pickFile(version);
|
|
39
|
+
const downloadUrl = file?.downloadUrl ??
|
|
40
|
+
version.downloadUrl ??
|
|
41
|
+
`https://civitai.com/api/download/models/${version.id}`;
|
|
42
|
+
return {
|
|
43
|
+
downloadUrl,
|
|
44
|
+
filename: file?.name,
|
|
45
|
+
versionId: version.id,
|
|
46
|
+
modelName,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Resolve a CivitAI model-version id directly to a download URL.
|
|
51
|
+
* Uses GET /api/v1/model-versions/{id}.
|
|
52
|
+
*/
|
|
53
|
+
export async function resolveCivitaiModelVersion(versionId) {
|
|
54
|
+
const version = await civitaiGet(`/model-versions/${versionId}`);
|
|
55
|
+
return resolveFromVersion(version);
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolve a CivitAI model id to a download URL.
|
|
59
|
+
* Uses GET /api/v1/models/{id} and picks a model version.
|
|
60
|
+
* If `versionId` is supplied, that specific version is used; otherwise the
|
|
61
|
+
* latest (first listed) version is chosen.
|
|
62
|
+
*/
|
|
63
|
+
export async function resolveCivitaiModel(modelId, versionId) {
|
|
64
|
+
const model = await civitaiGet(`/models/${modelId}`);
|
|
65
|
+
const versions = model.modelVersions ?? [];
|
|
66
|
+
if (versions.length === 0) {
|
|
67
|
+
throw new ModelError(`CivitAI model ${modelId} has no downloadable versions.`, { modelId });
|
|
68
|
+
}
|
|
69
|
+
let version;
|
|
70
|
+
if (versionId !== undefined) {
|
|
71
|
+
version = versions.find((v) => v.id === versionId);
|
|
72
|
+
if (!version) {
|
|
73
|
+
throw new ValidationError(`Model ${modelId} has no version with id ${versionId}. ` +
|
|
74
|
+
`Available versions: ${versions.map((v) => v.id).join(", ")}.`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
else {
|
|
78
|
+
version = versions[0];
|
|
79
|
+
}
|
|
80
|
+
return resolveFromVersion(version, model.name);
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=civitai-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"civitai-resolver.js","sourceRoot":"","sources":["../../src/services/civitai-resolver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { WorkflowJSON } from "../comfyui/types.js";
|
|
2
|
+
interface CommonArgs {
|
|
3
|
+
prompt: string;
|
|
4
|
+
negative_prompt?: string;
|
|
5
|
+
width?: number;
|
|
6
|
+
height?: number;
|
|
7
|
+
steps?: number;
|
|
8
|
+
cfg?: number;
|
|
9
|
+
sampler?: string;
|
|
10
|
+
scheduler?: string;
|
|
11
|
+
seed?: number;
|
|
12
|
+
checkpoint?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ControlNetArgs extends CommonArgs {
|
|
15
|
+
control_image: string;
|
|
16
|
+
controlnet_model?: string;
|
|
17
|
+
strength?: number;
|
|
18
|
+
}
|
|
19
|
+
export interface IpAdapterArgs extends CommonArgs {
|
|
20
|
+
reference_image: string;
|
|
21
|
+
weight?: number;
|
|
22
|
+
preset?: string;
|
|
23
|
+
}
|
|
24
|
+
export interface ConditionedDeps {
|
|
25
|
+
resolveCheckpoint: () => Promise<string | undefined>;
|
|
26
|
+
enqueue: (workflow: WorkflowJSON) => Promise<{
|
|
27
|
+
prompt_id: string;
|
|
28
|
+
queue_remaining?: number;
|
|
29
|
+
}>;
|
|
30
|
+
/** Optional: resolve a local ControlNet model when none is given/defaulted. */
|
|
31
|
+
resolveControlNetModel?: () => Promise<string | undefined>;
|
|
32
|
+
}
|
|
33
|
+
export interface ConditionedResult {
|
|
34
|
+
prompt_id: string;
|
|
35
|
+
queue_remaining?: number;
|
|
36
|
+
checkpoint: string;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Build + enqueue a ControlNet-conditioned txt2img workflow. `control_image`
|
|
40
|
+
* must already exist in ComfyUI's input dir (use upload_image first).
|
|
41
|
+
*/
|
|
42
|
+
export declare function generateWithControlNet(args: ControlNetArgs, deps: ConditionedDeps): Promise<ConditionedResult>;
|
|
43
|
+
/**
|
|
44
|
+
* Build + enqueue an IP-Adapter-conditioned txt2img workflow. Requires the
|
|
45
|
+
* ComfyUI_IPAdapter_plus custom nodes. `reference_image` must already exist in
|
|
46
|
+
* ComfyUI's input dir (use upload_image first).
|
|
47
|
+
*/
|
|
48
|
+
export declare function generateWithIpAdapter(args: IpAdapterArgs, deps: ConditionedDeps): Promise<ConditionedResult>;
|
|
49
|
+
export {};
|
|
50
|
+
//# sourceMappingURL=generate-conditioned.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-conditioned.d.ts","sourceRoot":"","sources":["../../src/services/generate-conditioned.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAKxD,UAAU,UAAU;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD,aAAa,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAc,SAAQ,UAAU;IAC/C,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,eAAe;IAC9B,iBAAiB,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACrD,OAAO,EAAE,CAAC,QAAQ,EAAE,YAAY,KAAK,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,eAAe,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC9F,+EAA+E;IAC/E,sBAAsB,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CAC5D;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACpB;AA0DD;;;GAGG;AACH,wBAAsB,sBAAsB,CAC1C,IAAI,EAAE,cAAc,EACpB,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,iBAAiB,CAAC,CA2B5B;AAED;;;;GAIG;AACH,wBAAsB,qBAAqB,CACzC,IAAI,EAAE,aAAa,EACnB,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,iBAAiB,CAAC,CAgB5B"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { createWorkflow } from "./workflow-composer.js";
|
|
2
|
+
import { DefaultsManager } from "./defaults-manager.js";
|
|
3
|
+
import { ValidationError } from "../utils/errors.js";
|
|
4
|
+
const DEFAULTABLE_KEYS = [
|
|
5
|
+
"negative_prompt",
|
|
6
|
+
"width",
|
|
7
|
+
"height",
|
|
8
|
+
"steps",
|
|
9
|
+
"cfg",
|
|
10
|
+
"sampler",
|
|
11
|
+
"scheduler",
|
|
12
|
+
"seed",
|
|
13
|
+
"checkpoint",
|
|
14
|
+
];
|
|
15
|
+
function withDefaults(args) {
|
|
16
|
+
const seed = {};
|
|
17
|
+
for (const key of DEFAULTABLE_KEYS) {
|
|
18
|
+
const v = args[key];
|
|
19
|
+
if (v !== undefined)
|
|
20
|
+
seed[key] = v;
|
|
21
|
+
}
|
|
22
|
+
return DefaultsManager.apply(seed);
|
|
23
|
+
}
|
|
24
|
+
async function resolveCheckpointOrThrow(explicit, resolved, resolveCheckpoint) {
|
|
25
|
+
let checkpoint = explicit ?? resolved.checkpoint;
|
|
26
|
+
if (!checkpoint)
|
|
27
|
+
checkpoint = await resolveCheckpoint();
|
|
28
|
+
if (!checkpoint) {
|
|
29
|
+
throw new ValidationError("No checkpoint specified, defaulted, or found locally. " +
|
|
30
|
+
"Pass `checkpoint`, set a default via set_defaults, or download one with download_model.");
|
|
31
|
+
}
|
|
32
|
+
return checkpoint;
|
|
33
|
+
}
|
|
34
|
+
function commonTemplateParams(args, resolved, checkpoint) {
|
|
35
|
+
return {
|
|
36
|
+
checkpoint,
|
|
37
|
+
positive_prompt: args.prompt,
|
|
38
|
+
negative_prompt: resolved.negative_prompt,
|
|
39
|
+
width: resolved.width,
|
|
40
|
+
height: resolved.height,
|
|
41
|
+
steps: resolved.steps,
|
|
42
|
+
cfg: resolved.cfg,
|
|
43
|
+
seed: resolved.seed,
|
|
44
|
+
sampler_name: resolved.sampler,
|
|
45
|
+
scheduler: resolved.scheduler,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Build + enqueue a ControlNet-conditioned txt2img workflow. `control_image`
|
|
50
|
+
* must already exist in ComfyUI's input dir (use upload_image first).
|
|
51
|
+
*/
|
|
52
|
+
export async function generateWithControlNet(args, deps) {
|
|
53
|
+
if (!args.control_image) {
|
|
54
|
+
throw new ValidationError("control_image is required (upload it first with upload_image)");
|
|
55
|
+
}
|
|
56
|
+
const resolved = withDefaults(args);
|
|
57
|
+
const checkpoint = await resolveCheckpointOrThrow(args.checkpoint, resolved, deps.resolveCheckpoint);
|
|
58
|
+
let controlnetModel = args.controlnet_model;
|
|
59
|
+
if (!controlnetModel && deps.resolveControlNetModel) {
|
|
60
|
+
controlnetModel = await deps.resolveControlNetModel();
|
|
61
|
+
}
|
|
62
|
+
if (!controlnetModel) {
|
|
63
|
+
throw new ValidationError("No controlnet_model specified and none found locally. Pass `controlnet_model` " +
|
|
64
|
+
"(a file in models/controlnet/) or download one with download_model.");
|
|
65
|
+
}
|
|
66
|
+
const workflow = createWorkflow("controlnet", {
|
|
67
|
+
...commonTemplateParams(args, resolved, checkpoint),
|
|
68
|
+
control_image: args.control_image,
|
|
69
|
+
controlnet_model: controlnetModel,
|
|
70
|
+
strength: args.strength,
|
|
71
|
+
});
|
|
72
|
+
const { prompt_id, queue_remaining } = await deps.enqueue(workflow);
|
|
73
|
+
return { prompt_id, queue_remaining, checkpoint };
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Build + enqueue an IP-Adapter-conditioned txt2img workflow. Requires the
|
|
77
|
+
* ComfyUI_IPAdapter_plus custom nodes. `reference_image` must already exist in
|
|
78
|
+
* ComfyUI's input dir (use upload_image first).
|
|
79
|
+
*/
|
|
80
|
+
export async function generateWithIpAdapter(args, deps) {
|
|
81
|
+
if (!args.reference_image) {
|
|
82
|
+
throw new ValidationError("reference_image is required (upload it first with upload_image)");
|
|
83
|
+
}
|
|
84
|
+
const resolved = withDefaults(args);
|
|
85
|
+
const checkpoint = await resolveCheckpointOrThrow(args.checkpoint, resolved, deps.resolveCheckpoint);
|
|
86
|
+
const workflow = createWorkflow("ip_adapter", {
|
|
87
|
+
...commonTemplateParams(args, resolved, checkpoint),
|
|
88
|
+
reference_image: args.reference_image,
|
|
89
|
+
weight: args.weight,
|
|
90
|
+
preset: args.preset,
|
|
91
|
+
});
|
|
92
|
+
const { prompt_id, queue_remaining } = await deps.enqueue(workflow);
|
|
93
|
+
return { prompt_id, queue_remaining, checkpoint };
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=generate-conditioned.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate-conditioned.js","sourceRoot":"","sources":["../../src/services/generate-conditioned.ts"],"names":[],"mappings":"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"}
|