164 lines
7.6 KiB
Markdown
164 lines
7.6 KiB
Markdown
# ComfyUI-AsyncOutput
|
|
|
|
Simple Source Code
|
|
|
|
```python
|
|
class AsyncOutputCollectionNode:
|
|
def __init__(self):
|
|
pass
|
|
|
|
@classmethod
|
|
def INPUT_TYPES(s):
|
|
return {
|
|
"required": {
|
|
"incoming_input": ("STRING", { "forceInput": True }),
|
|
"key_id": ("STRING", {})
|
|
},
|
|
"hidden": {
|
|
"unique_id": "UNIQUE_ID"
|
|
}
|
|
}
|
|
|
|
RETURN_TYPES = ("STRING",)
|
|
RETURN_NAMES = ("passthough_output",)
|
|
CATEGORY = f'{MAIN_CATEGORY}/String'
|
|
FUNCTION = "collect"
|
|
|
|
def collect(self, incoming_input, key_id, unique_id):
|
|
global ASYNC_OUTPUT_STORAGE_DATA
|
|
|
|
if key_id == "":
|
|
raise Exception("ERROR: key_id property not set.")
|
|
|
|
if key_id not in ASYNC_OUTPUT_STORAGE_DATA:
|
|
ASYNC_OUTPUT_STORAGE_DATA[key_id] = []
|
|
|
|
ASYNC_OUTPUT_STORAGE_DATA[key_id].append(incoming_input)
|
|
|
|
return (incoming_input,)
|
|
|
|
@classmethod
|
|
def IS_CHANGED(s, incoming_input, key_id, unique_id):
|
|
return float('nan')
|
|
```
|
|
|
|
## Intro
|
|
|
|
Simple collect all batch output, then convert to a string list
|
|
|
|
Like ECMAScript Promise.all
|
|
|
|
```ts
|
|
const tasks_queue: Array<Promise<string>> = [];
|
|
for (let i = 0; i < n; i++) {
|
|
const task = new Promise<string>((resolve, reject) => {
|
|
/* Your jobs, just a mock, */
|
|
});
|
|
tasks_queue.push(task);
|
|
}
|
|
|
|
/*
|
|
results will be an Array<string>
|
|
*/
|
|
Promise.all(tasks_queue).then((results) => {
|
|
const ffmpeg_concat_input_str = results.join("\n");
|
|
// others
|
|
})
|
|
|
|
```
|
|
|
|
## Parmeters
|
|
|
|
- key_id: persistence memory dict key
|
|
|
|
## Node
|
|
|
|
- String
|
|
- AsyncOutputCollect(Collection)
|
|
- Receive other node 'string' output, persistence memory
|
|
- Output is 'string', passthrough your input
|
|
- AsyncOutputEmitter(Conditions)
|
|
- If conditions is true, Output Boolean, else always false.
|
|
- AsyncOutputCallback(Output)
|
|
- Receive Emitter Output, If true, will output dict\[key_id\], then delete dict\[key_id\]
|
|
- If the received value is false, then the subsequent downstream process will be blocked directly.
|
|
- (comfy_execution.graph.ExecutionBlocker(None), )
|
|
- Utils
|
|
- String List To String
|
|
- Convert String List to String
|
|
|
|
## Others (use JS illustrate)
|
|
|
|
String List to String
|
|
|
|
```ts
|
|
const string_list = ["abc", "edf", "jqk"];
|
|
const str = string_list.join("<your_input>");
|
|
```
|
|
|
|
AsyncOutputCollect(Collection)
|
|
|
|
```ts
|
|
const collect_list = [];
|
|
|
|
for (let i = 0; i < n; i++) {
|
|
const task = new Promise();
|
|
collect_list.push(task);
|
|
}
|
|
|
|
```
|
|
|
|
AsyncOutputEmitter(Conditions)
|
|
|
|
```ts
|
|
const collect_list = [];
|
|
const spec_task_n = 10;
|
|
const mode = "exact";
|
|
const e = new EventEmitter();
|
|
|
|
function* collect_task(collect_list) {
|
|
for (let i = 0; i < n; i++) {
|
|
const task = new Promise();
|
|
collect_list.push(task);
|
|
yield i;
|
|
}
|
|
}
|
|
|
|
current_exec = collect_task(collect_list);
|
|
|
|
let it = current_exec.next();
|
|
|
|
|
|
if (mode === "exact") { // exact mode
|
|
while (it.done == false && it.value != spec_task_n) {
|
|
it = current_exec.next();
|
|
e.emit("trigger_result", false);
|
|
}
|
|
} else if (mode === "greater_than_or_equal") { // greater_than_or_equal mode
|
|
while (it.done == false && it.value <= spec_task_n) {
|
|
it = current_exec.next();
|
|
e.emit("trigger_result", false);
|
|
}
|
|
}
|
|
|
|
if (it.value == spec_tack_n) {
|
|
e.emit("trigger_result", true);
|
|
}
|
|
|
|
|
|
```
|
|
|
|
AsyncOutputCallback(Output)
|
|
|
|
```ts
|
|
|
|
const comfy_eventloop_emitter = new EventEmitter();
|
|
|
|
e.on("trigger_result", (trigger_signal) => {
|
|
if (trigger_signal === true) {
|
|
const str_list = callback();
|
|
comfy_eventloop_emitter.emit("next", str_list);
|
|
}
|
|
});
|
|
```
|