Implement example file to showcase how the library works

This commit is contained in:
Menno van Leeuwen 2025-03-21 11:51:57 +01:00
parent 8dad2b57b3
commit 2bbbd38b93
Signed by: vleeuwenmenno
SSH Key Fingerprint: SHA256:OJFmjANpakwD3F2Rsws4GLtbdz1TJ5tkQF0RZmF0TRE

231
example/example.dart Normal file
View File

@ -0,0 +1,231 @@
import 'dart:io';
import 'package:comfyui_api_sdk/comfyui_api_sdk.dart';
import 'package:uuid/uuid.dart';
import 'package:comfyui_api_sdk/src/prompt_builder.dart';
bool jobFinished = false;
void main() async {
// Create the API client
final clientId = Uuid().v4().replaceAll('-', '');
final api = ComfyUiApi(host: 'http://mennos-server:7860', clientId: clientId);
// Connect to the WebSocket for progress updates
await api.connectWebSocket();
// Listen for progress updates
api.onProgressChanged((progress) {
print(
'⏱️ Progress: ${progress.value} / ${progress.max} for ${progress.promptId}');
});
// Register for prompt start events
api.onPromptStart((promptId) {
print('🚀 Prompt started: $promptId');
});
// Register for prompt finished events
api.onPromptFinished((promptId) async {
print('✅ Prompt finished: $promptId');
// Fetch the history when a prompt finishes
try {
final history = await api.getHistory(maxItems: 5);
print('Recent history:');
history.items.forEach((promptId, item) {
print(' - $promptId: ${item.status.statusStr}');
});
final prompt = history.items[promptId];
if (prompt != null) {
print('🖼 Prompt $promptId: ${prompt.status.statusStr}');
if (prompt.outputs.nodes.isNotEmpty) {
for (var node in prompt.outputs.nodes.values) {
for (var image in node.images) {
print(
' - Image: ${image.filename} URL: ${api.host}/api/view?filename=${image.filename}');
// Write image to disk using image.fetchImageBytes(api.host)
final bytes = await image.fetchImageBytes(api.host);
// Ensure pwd/images exists
Directory('images').createSync();
// We can save this to the disk under $pwd/images/${image.filename}
final file = File('images/${image.filename}');
await file.writeAsBytes(bytes);
}
}
}
}
} catch (e) {
print('Error fetching history: $e');
}
jobFinished = true;
});
// Let's get a list of available checkpoints
try {
final checkpoints = await api.getCheckpoints();
print('📦 Checkpoints: ${checkpoints.length}');
for (var checkpoint in checkpoints) {
print(' - ${checkpoint.name}');
}
} catch (e) {
print('❌ Error fetching checkpoints: $e');
}
// Let's get a list of vaes
try {
final vaes = await api.getVaes();
print('🧠 VAES: ${vaes.length}');
for (var vae in vaes) {
print(' - ${vae.name}');
}
} catch (e) {
print('❌ Error fetching vaes: $e');
}
// Let's get a list of Loras
try {
final loras = await api.getLoras();
print('📡 Loras: ${loras.length}');
for (var lora in loras) {
print(' - ${lora.name}');
}
} catch (e) {
print('❌ Error fetching loras: $e');
}
// Let's get a list of possible samplers to use
try {
final samplers = await api.getKSamplers();
print('🎲 Samplers: ${samplers.length}');
for (var sampler in samplers) {
print(' - ${sampler}');
}
} catch (e) {
print('❌ Error fetching samplers: $e');
}
// Let's get a list of possible schedulers to use
try {
final schedulers = await api.getSchedulers();
print('📅 Schedulers: ${schedulers.length}');
for (var scheduler in schedulers) {
print(' - ${scheduler}');
}
} catch (e) {
print('❌ Error fetching schedulers: $e');
}
var randomSeed = DateTime.now().millisecondsSinceEpoch;
// Fetch object info for validation (optional)
Map<String, dynamic> objectInfo = {};
try {
objectInfo = await api.getObjectInfo();
} catch (e) {
print('❌ Error fetching object info: $e');
}
// Use PromptBuilder to create a workflow
final promptBuilder = PromptBuilder(clientId: api.clientId)
..addNode(
"CheckpointLoaderSimple",
{"ckpt_name": "Anime/prefectPonyXL_v50.safetensors"},
title: "Load Checkpoint",
outputTags: {"MODEL": "model", "CLIP": "clip", "VAE": "vae"},
)
..addNode(
"EmptyLatentImage",
{"width": 512, "height": 512, "batch_size": 1},
title: "Empty Latent Image",
outputTags: {"LATENT": "latent_image"},
)
..addNode(
"CLIPTextEncode",
{
"text": "beautiful scenery nature glass bottle landscape",
"clip": ["clip", 1] // Explicitly use the "clip" output
},
title: "CLIP Text Encode (Positive Prompt)",
outputTags: {"CONDITIONING": "positive_conditioning"},
)
..addNode(
"CLIPTextEncode",
{
"text": "negative, dark, scary, horror, spooky",
"clip": ["clip", 1] // Explicitly use the "clip" output
},
title: "CLIP Text Encode (Negative Prompt)",
outputTags: {"CONDITIONING": "negative_conditioning"},
)
..addNode(
"KSampler",
{
"seed": randomSeed,
"steps": 25,
"cfg": 4,
"sampler_name": "euler",
"scheduler": "normal",
"denoise": 1,
"model": ["model", 0], // Explicitly use the "model" output
"positive": [
"positive_conditioning",
0
], // Explicitly use the positive conditioning
"negative": [
"negative_conditioning",
0
], // Explicitly use the negative conditioning
"latent_image": ["latent_image", 0] // Explicitly use the latent image
},
title: "KSampler",
outputTags: {"LATENT": "denoised_latent"},
)
..addNode(
"VAEDecode",
{
"samples": ["denoised_latent", 0], // Explicitly use the denoised latent
"vae": ["vae", 2] // Explicitly use the "vae" output
},
title: "VAE Decode",
outputTags: {"IMAGE": "final_image"},
)
..addNode(
"SaveImage",
{
"filename_prefix": "ComfyUI",
"images": ["final_image", 0] // Explicitly use the final image
},
title: "Save Image",
);
// Validate the workflow (optional)
try {
promptBuilder.validate(objectInfo);
} catch (e) {
print('❌ Validation error: $e');
return;
}
// Submit the workflow
try {
final result = await api.submitPrompt(promptBuilder.build());
print('💼 Prompt submitted: ${result.promptId}');
} catch (e) {
print('❌ Error submitting prompt: $e');
}
// Wait until job is finished
while (!jobFinished) {
await Future.delayed(Duration(seconds: 1));
}
// Clean up
api.dispose();
}