|
|
|
@ -35,14 +35,19 @@ public class ComfyClient : InferenceClientBase
|
|
|
|
|
public Uri BaseAddress { get; } |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
/// Optional local path to output images. |
|
|
|
|
/// If available, the local path to the server root directory. |
|
|
|
|
/// </summary> |
|
|
|
|
public DirectoryPath? OutputImagesDir { get; set; } |
|
|
|
|
public DirectoryPath? LocalServerPath { get; set; } |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
/// Optional local path to input images. |
|
|
|
|
/// Path to the "output" folder from LocalServerPath |
|
|
|
|
/// </summary> |
|
|
|
|
public DirectoryPath? InputImagesDir { get; set; } |
|
|
|
|
public DirectoryPath? OutputImagesDir => LocalServerPath?.JoinDir("output"); |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
/// Path to the "input" folder from LocalServerPath |
|
|
|
|
/// </summary> |
|
|
|
|
public DirectoryPath? InputImagesDir => LocalServerPath?.JoinDir("input"); |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
/// Dictionary of ongoing prompt execution tasks |
|
|
|
@ -144,9 +149,7 @@ public class ComfyClient : InferenceClientBase
|
|
|
|
|
|
|
|
|
|
if (json.Type == ComfyWebSocketResponseType.Executing) |
|
|
|
|
{ |
|
|
|
|
var executingData = json.GetDataAsType<ComfyWebSocketExecutingData>( |
|
|
|
|
jsonSerializerOptions |
|
|
|
|
); |
|
|
|
|
var executingData = json.GetDataAsType<ComfyWebSocketExecutingData>(jsonSerializerOptions); |
|
|
|
|
if (executingData?.PromptId is null) |
|
|
|
|
{ |
|
|
|
|
Logger.Warn($"Could not parse executing data {json.Data}, skipping"); |
|
|
|
@ -165,9 +168,7 @@ public class ComfyClient : InferenceClientBase
|
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
Logger.Warn( |
|
|
|
|
$"Could not find task for prompt {executingData.PromptId}, skipping" |
|
|
|
|
); |
|
|
|
|
Logger.Warn($"Could not find task for prompt {executingData.PromptId}, skipping"); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Otherwise set the task's active node to the one received |
|
|
|
@ -194,9 +195,7 @@ public class ComfyClient : InferenceClientBase
|
|
|
|
|
} |
|
|
|
|
else if (json.Type == ComfyWebSocketResponseType.Progress) |
|
|
|
|
{ |
|
|
|
|
var progressData = json.GetDataAsType<ComfyWebSocketProgressData>( |
|
|
|
|
jsonSerializerOptions |
|
|
|
|
); |
|
|
|
|
var progressData = json.GetDataAsType<ComfyWebSocketProgressData>(jsonSerializerOptions); |
|
|
|
|
if (progressData is null) |
|
|
|
|
{ |
|
|
|
|
Logger.Warn($"Could not parse progress data {json.Data}, skipping"); |
|
|
|
@ -224,11 +223,7 @@ public class ComfyClient : InferenceClientBase
|
|
|
|
|
{ |
|
|
|
|
task.RunningNode = null; |
|
|
|
|
task.SetException( |
|
|
|
|
new ComfyNodeException |
|
|
|
|
{ |
|
|
|
|
ErrorData = errorData, |
|
|
|
|
JsonData = json.Data.ToString() |
|
|
|
|
} |
|
|
|
|
new ComfyNodeException { ErrorData = errorData, JsonData = json.Data.ToString() } |
|
|
|
|
); |
|
|
|
|
currentPromptTask = null; |
|
|
|
|
} |
|
|
|
@ -306,9 +301,7 @@ public class ComfyClient : InferenceClientBase
|
|
|
|
|
|
|
|
|
|
public override async Task CloseAsync(CancellationToken cancellationToken = default) |
|
|
|
|
{ |
|
|
|
|
await webSocketClient |
|
|
|
|
.Stop(WebSocketCloseStatus.NormalClosure, string.Empty) |
|
|
|
|
.ConfigureAwait(false); |
|
|
|
|
await webSocketClient.Stop(WebSocketCloseStatus.NormalClosure, string.Empty).ConfigureAwait(false); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public async Task<ComfyTask> QueuePromptAsync( |
|
|
|
@ -349,13 +342,39 @@ public class ComfyClient : InferenceClientBase
|
|
|
|
|
) |
|
|
|
|
{ |
|
|
|
|
var streamPart = new StreamPart(image, fileName); |
|
|
|
|
return comfyApi.PostUploadImage( |
|
|
|
|
streamPart, |
|
|
|
|
"true", |
|
|
|
|
"input", |
|
|
|
|
"Inference", |
|
|
|
|
cancellationToken |
|
|
|
|
); |
|
|
|
|
return comfyApi.PostUploadImage(streamPart, "true", "input", "Inference", cancellationToken); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/// <summary> |
|
|
|
|
/// Upload a file to the server at the given relative path from server's root |
|
|
|
|
/// </summary> |
|
|
|
|
public async Task UploadFileAsync( |
|
|
|
|
string sourcePath, |
|
|
|
|
string destinationRelativePath, |
|
|
|
|
CancellationToken cancellationToken = default |
|
|
|
|
) |
|
|
|
|
{ |
|
|
|
|
cancellationToken.ThrowIfCancellationRequested(); |
|
|
|
|
|
|
|
|
|
// Currently there is no api, so we do a local file copy |
|
|
|
|
if (LocalServerPath is null) |
|
|
|
|
{ |
|
|
|
|
throw new InvalidOperationException("LocalServerPath is not set"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var sourceFile = new FilePath(sourcePath); |
|
|
|
|
var destFile = LocalServerPath.JoinFile(destinationRelativePath); |
|
|
|
|
|
|
|
|
|
Logger.Info("Copying file from {Source} to {Dest}", sourcePath, destFile); |
|
|
|
|
|
|
|
|
|
if (!sourceFile.Exists) |
|
|
|
|
{ |
|
|
|
|
throw new FileNotFoundException("Source file does not exist", sourcePath); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
destFile.Directory?.Create(); |
|
|
|
|
|
|
|
|
|
await sourceFile.CopyToAsync(destFile, true).ConfigureAwait(false); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
public async Task<Dictionary<string, List<ComfyImage>?>> GetImagesForExecutedPromptAsync( |
|
|
|
@ -413,9 +432,7 @@ public class ComfyClient : InferenceClientBase
|
|
|
|
|
CancellationToken cancellationToken = default |
|
|
|
|
) |
|
|
|
|
{ |
|
|
|
|
var response = await comfyApi |
|
|
|
|
.GetObjectInfo(nodeName, cancellationToken) |
|
|
|
|
.ConfigureAwait(false); |
|
|
|
|
var response = await comfyApi.GetObjectInfo(nodeName, cancellationToken).ConfigureAwait(false); |
|
|
|
|
|
|
|
|
|
var info = response[nodeName]; |
|
|
|
|
return info.Input.GetRequiredValueAsNestedList(optionName); |
|
|
|
|