Add logger dependency and implement PromptBuilder for workflow management
This commit is contained in:
@@ -2,8 +2,8 @@ import 'dart:async';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import 'package:logger/logger.dart';
|
||||
import 'models/websocket_event.dart';
|
||||
import 'models/progress_event.dart';
|
||||
import 'models/execution_event.dart';
|
||||
@@ -22,14 +22,17 @@ class ComfyUiApi {
|
||||
final String clientId;
|
||||
final http.Client _httpClient;
|
||||
final WebSocketManager _webSocketManager;
|
||||
final Logger logger;
|
||||
|
||||
/// Creates a new ComfyUI API client
|
||||
ComfyUiApi({
|
||||
required this.host,
|
||||
required this.clientId,
|
||||
Logger? logger,
|
||||
http.Client? httpClient,
|
||||
}) : _httpClient = httpClient ?? http.Client(),
|
||||
_webSocketManager = WebSocketManager(host: host, clientId: clientId);
|
||||
_webSocketManager = WebSocketManager(host: host, clientId: clientId),
|
||||
logger = logger ?? Logger();
|
||||
|
||||
/// Expose WebSocketManager streams and methods
|
||||
Stream<WebSocketEvent> get events => _webSocketManager.events;
|
||||
|
89
lib/src/prompt_builder.dart
Normal file
89
lib/src/prompt_builder.dart
Normal file
@@ -0,0 +1,89 @@
|
||||
class PromptBuilder {
|
||||
final String clientId;
|
||||
final Map<String, dynamic> _nodes = {};
|
||||
final Map<String, Map<String, String>> _outputToNode =
|
||||
{}; // Maps output tags to node IDs
|
||||
int _nodeIdCounter = 1;
|
||||
|
||||
PromptBuilder({required this.clientId});
|
||||
|
||||
/// Adds a node to the workflow
|
||||
void addNode(String classType, Map<String, dynamic> inputs,
|
||||
{String? title, Map<String, String>? outputTags}) {
|
||||
final nodeId = _nodeIdCounter.toString();
|
||||
|
||||
// Resolve dependencies for inputs
|
||||
inputs.forEach((key, value) {
|
||||
if (value is List && value.length == 2 && value[1] is int) {
|
||||
final outputTag = value[0];
|
||||
if (_outputToNode.containsKey(outputTag)) {
|
||||
inputs[key] = [_outputToNode[outputTag]!["nodeId"], value[1]];
|
||||
} else {
|
||||
throw Exception(
|
||||
"Unresolved dependency: No node provides output tag '$outputTag'");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_nodes[nodeId] = {
|
||||
"inputs": inputs,
|
||||
"class_type": classType,
|
||||
"_meta": {"title": title ?? classType}
|
||||
};
|
||||
|
||||
// Register outputs of this node with optional tags
|
||||
final defaultOutputs = _getDefaultOutputs(classType);
|
||||
for (var i = 0; i < defaultOutputs.length; i++) {
|
||||
final outputTag = outputTags?[defaultOutputs[i]] ?? defaultOutputs[i];
|
||||
_outputToNode[outputTag] = {
|
||||
"nodeId": nodeId,
|
||||
"outputIndex": i.toString()
|
||||
};
|
||||
}
|
||||
|
||||
_nodeIdCounter++;
|
||||
}
|
||||
|
||||
/// Generates the final workflow map
|
||||
Map<String, dynamic> build() {
|
||||
return {
|
||||
"client_id": clientId,
|
||||
"prompt": _nodes,
|
||||
};
|
||||
}
|
||||
|
||||
/// Validates the workflow against object info (optional)
|
||||
void validate(Map<String, dynamic> objectInfo) {
|
||||
for (var nodeId in _nodes.keys) {
|
||||
final node = _nodes[nodeId];
|
||||
final classType = node["class_type"];
|
||||
if (!objectInfo.containsKey(classType)) {
|
||||
throw Exception("Invalid node class type: $classType");
|
||||
}
|
||||
final requiredInputs = objectInfo[classType]["input"]["required"];
|
||||
for (var inputKey in requiredInputs.keys) {
|
||||
if (!node["inputs"].containsKey(inputKey)) {
|
||||
throw Exception(
|
||||
"Missing required input '$inputKey' for node $nodeId");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper method to get default outputs for a class type
|
||||
List<String> _getDefaultOutputs(String classType) {
|
||||
if (classType == "CheckpointLoaderSimple") {
|
||||
return ["MODEL", "CLIP", "VAE"];
|
||||
} else if (classType == "CLIPTextEncode") {
|
||||
return ["CONDITIONING"];
|
||||
} else if (classType == "EmptyLatentImage" ||
|
||||
classType == "KSampler" ||
|
||||
classType == "LatentUpscale" ||
|
||||
classType == "LatentUpscaleBy") {
|
||||
return ["LATENT"];
|
||||
} else if (classType == "VAEDecode") {
|
||||
return ["IMAGE"];
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user