Skip to content

Commit 4db6d25

Browse files
committed
Create debug-to-api-prompt.ts
1 parent b290bc0 commit 4db6d25

1 file changed

Lines changed: 248 additions & 0 deletions

File tree

MyApp/debug-to-api-prompt.ts

Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
#!/usr/bin/env bun
2+
3+
import { LGraph, LGraphNode, LiteGraph } from '@comfyorg/litegraph'
4+
5+
import {
6+
ComfyWorkflowJSON,
7+
validateComfyWorkflow
8+
} from './schemas/comfyWorkflowSchema'
9+
10+
import { graphToPrompt } from "./utils/executionUtil"
11+
12+
// Ensure proper initialization
13+
if (typeof globalThis !== 'undefined') {
14+
;(globalThis as any).__COMFYUI_FRONTEND_VERSION__ = '1.0.0-test'
15+
}
16+
17+
// Mock node classes based on the object info
18+
function createMockNodeClass(nodeType: string, nodeInfo: any) {
19+
class MockNode extends LGraphNode {
20+
static override title = nodeInfo.display_name || nodeType
21+
static comfyClass = nodeType
22+
override comfyClass: string
23+
24+
constructor() {
25+
super(nodeType)
26+
this.comfyClass = nodeType
27+
this.title = nodeInfo.display_name || nodeType
28+
29+
// Add inputs in the correct order
30+
if (nodeInfo.input?.required) {
31+
const inputOrder =
32+
nodeInfo.input_order?.required || Object.keys(nodeInfo.input.required)
33+
34+
inputOrder.forEach((inputName: string) => {
35+
const inputDef = nodeInfo.input.required[inputName]
36+
if (inputDef) {
37+
this.addInput(inputName, inputDef[0])
38+
}
39+
})
40+
}
41+
42+
// Add outputs
43+
if (nodeInfo.output) {
44+
nodeInfo.output.forEach((outputType: string, index: number) => {
45+
const outputName = nodeInfo.output_name?.[index] || outputType
46+
this.addOutput(outputName, outputType)
47+
})
48+
}
49+
50+
// Add widgets for required inputs that are not connections
51+
if (nodeInfo.input?.required) {
52+
const inputOrder =
53+
nodeInfo.input_order?.required || Object.keys(nodeInfo.input.required)
54+
55+
inputOrder.forEach((inputName: string) => {
56+
const inputDef = nodeInfo.input.required[inputName]
57+
if (!inputDef) return
58+
59+
const [inputType, inputConfig] = inputDef
60+
61+
const isConnectionType =
62+
typeof inputType === 'string' &&
63+
[
64+
'MODEL',
65+
'CLIP',
66+
'VAE',
67+
'CONDITIONING',
68+
'LATENT',
69+
'IMAGE'
70+
].includes(inputType)
71+
72+
if (!isConnectionType) {
73+
let defaultValue = inputConfig?.default
74+
if (inputType === 'STRING') {
75+
defaultValue = defaultValue || ''
76+
} else if (inputType === 'INT') {
77+
defaultValue = defaultValue || 0
78+
} else if (inputType === 'FLOAT') {
79+
defaultValue = defaultValue || 0.0
80+
} else if (Array.isArray(inputType)) {
81+
defaultValue = defaultValue || inputType[0]
82+
}
83+
84+
this.addWidget('text', inputName, defaultValue, () => {})
85+
}
86+
})
87+
}
88+
}
89+
}
90+
91+
return MockNode
92+
}
93+
94+
function registerObjectInfoNodeDefinitions(comfyObjectInfo: any) {
95+
console.log(`Registering ${Object.keys(comfyObjectInfo).length} node types...`)
96+
97+
Object.entries(comfyObjectInfo).forEach(
98+
([nodeType, nodeInfo]: [string, any]) => {
99+
try {
100+
const MockNodeClass = createMockNodeClass(nodeType, nodeInfo)
101+
LiteGraph.registerNodeType(nodeType, MockNodeClass)
102+
} catch (error) {
103+
console.error(`Failed to register node type ${nodeType}:`, error.message)
104+
}
105+
}
106+
)
107+
console.log('Node registration completed')
108+
}
109+
110+
function createNodeFromData(
111+
nodeData: any,
112+
graph: LGraph,
113+
nodeMap: Map<string | number, LGraphNode>,
114+
comfyObjectInfo: any,
115+
errors: string[]
116+
) {
117+
console.log(`Creating node: ${nodeData.type} (ID: ${nodeData.id})`)
118+
119+
const node = LiteGraph.createNode(nodeData.type)
120+
if (!node) {
121+
const error = `Failed to create node of type: ${nodeData.type}`
122+
errors.push(error)
123+
console.error(error)
124+
return
125+
}
126+
127+
// Set basic node properties
128+
node.id = nodeData.id
129+
node.pos = [nodeData.pos[0], nodeData.pos[1]] as [number, number]
130+
if (nodeData.size) {
131+
node.size = [nodeData.size[0], nodeData.size[1]] as [number, number]
132+
}
133+
134+
// Add node to graph and store in map
135+
graph.add(node)
136+
nodeMap.set(nodeData.id, node)
137+
console.log(`Node ${nodeData.type} (ID: ${nodeData.id}) created successfully`)
138+
}
139+
140+
function createWorkflowGraph(
141+
comfyObjectInfo: any,
142+
workflow: ComfyWorkflowJSON,
143+
errors: string[]
144+
) {
145+
console.log('Creating workflow graph...')
146+
const graph = new LGraph()
147+
const nodeMap = new Map<string | number, LGraphNode>()
148+
149+
console.log(`Processing ${workflow.nodes.length} nodes...`)
150+
151+
// First pass: Create all nodes
152+
for (const nodeData of workflow.nodes) {
153+
try {
154+
createNodeFromData(nodeData, graph, nodeMap, comfyObjectInfo, errors)
155+
} catch (error) {
156+
const errorMsg = `Error creating node ${nodeData.type} (ID: ${nodeData.id}): ${error.message}`
157+
errors.push(errorMsg)
158+
console.error(errorMsg)
159+
}
160+
}
161+
162+
console.log(`Created ${nodeMap.size} nodes successfully`)
163+
console.log('Graph creation completed')
164+
return graph
165+
}
166+
167+
async function generateWorkflowApiPrompt(graph: LGraph) {
168+
console.log('Generating API prompt...')
169+
console.log('Graph nodes count:', graph._nodes.length)
170+
171+
// This is where the error likely occurs
172+
try {
173+
const apiPrompt = await graphToPrompt(graph)
174+
console.log('API prompt generated successfully')
175+
return apiPrompt
176+
} catch (error) {
177+
console.error('Error in graphToPrompt:', error.message)
178+
console.error('Stack:', error.stack)
179+
throw error
180+
}
181+
}
182+
183+
async function createApiPrompt(objectInfo: any, workflow: ComfyWorkflowJSON, errors: string[]) {
184+
console.log('Starting API prompt creation...')
185+
186+
registerObjectInfoNodeDefinitions(objectInfo)
187+
188+
const workflowGraph = createWorkflowGraph(objectInfo, workflow, errors)
189+
190+
const result = await generateWorkflowApiPrompt(workflowGraph)
191+
const prompt = result.output
192+
return prompt
193+
}
194+
195+
;(async () => {
196+
const cliArgs = Bun.argv.slice(2)
197+
198+
if (cliArgs.length != 2) {
199+
console.log(`USAGE ${import.meta.file} <path-to-object_info.json> <path-to-workflow.json>`)
200+
process.exit(1);
201+
}
202+
203+
try {
204+
console.log('=== Starting Debug Version ===')
205+
console.log('Args:', cliArgs)
206+
207+
console.log('Loading object info...')
208+
const objectInfoFile = Bun.file(cliArgs[0])
209+
if (!await objectInfoFile.exists()) {
210+
throw new Error(`${cliArgs[0]} does not exist`)
211+
}
212+
const objectInfoJson = await objectInfoFile.text()
213+
const objectInfo = JSON.parse(objectInfoJson)
214+
console.log(`Object info loaded: ${Object.keys(objectInfo).length} node types`)
215+
216+
console.log('Loading workflow...')
217+
const workflowFile = Bun.file(cliArgs[1])
218+
if (!await workflowFile.exists()) {
219+
throw new Error(`${cliArgs[1]} does not exist`)
220+
}
221+
const workflowJson = await workflowFile.text()
222+
const workflowData = JSON.parse(workflowJson)
223+
console.log(`Workflow loaded: ${workflowData.nodes?.length || 0} nodes`)
224+
225+
console.log('Validating workflow...')
226+
const workflow = await validateComfyWorkflow(workflowData)
227+
if (!workflow) {
228+
throw new Error(`${cliArgs[1]} is not a valid workflow`)
229+
}
230+
console.log('Workflow validation passed')
231+
232+
const errors: string[] = []
233+
const apiPrompt = await createApiPrompt(objectInfo, workflow, errors)
234+
235+
if (errors.length > 0) {
236+
console.error('Errors encountered:')
237+
errors.forEach(error => console.error(' -', error))
238+
}
239+
240+
console.log('=== SUCCESS ===')
241+
console.log(JSON.stringify(apiPrompt, null, 2))
242+
} catch (e) {
243+
console.error('=== FATAL ERROR ===')
244+
console.error(`${e.message ?? e}`)
245+
console.error('Stack:', e.stack)
246+
process.exit(1);
247+
}
248+
})()

0 commit comments

Comments
 (0)