Skip to content

Commit 41ab134

Browse files
committed
update
1 parent 1e9a32b commit 41ab134

File tree

15 files changed

+382
-87
lines changed

15 files changed

+382
-87
lines changed

MyApp.ServiceInterface/AppConfig.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public class AppConfig
2626

2727
public string? GoogleClientId { get; set; }
2828
public string? GoogleClientSecret { get; set; }
29+
public string? BunExePath { get; set; }
2930

3031
public VueAppConfig ToVueAppConfig() => new() {
3132
AppName = AppName,

MyApp.ServiceInterface/AppData.cs

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,11 @@ public async Task<string> SaveUploadedArtifactAsync(IHttpFile uploadedFile)
9797
public Stream OpenArtifactStream(string fileName) => File.OpenRead(GetArtifactPath(fileName));
9898
public string GetArtifactPath(string fileName) => appConfig.ArtifactsPath.CombineWith(fileName[..2], fileName);
9999

100+
public string GetDeviceObjectInfoPath(string deviceId) =>
101+
GetDevicePath(deviceId).CombineWith("object_info.json");
102+
public string GetDevicePath(string deviceId) =>
103+
appConfig.ArtifactsPath.CombineWith(deviceId.GetDevicePath());
104+
100105
ServerEvent RegisterEvent = new() { Event = "register" };
101106
ServerEvent HeartbeatEvent = new() { Event = "heartbeat", Data = "pulse" };
102107

@@ -147,11 +152,16 @@ public void Reload(IDbConnection db)
147152
}
148153

149154
public string OverridesPath => Path.GetFullPath(Path.Combine(appConfig.AppDataPath, "/overrides"));
155+
156+
public string DefaultObjectInfoPath { get; set; }
150157

151158
public void LoadDefaultObjectInfo()
152159
{
153-
var json = ReadTextFile(Path.Combine(OverridesPath, "object_info.gateway.json"))
154-
?? ReadTextFile("wwwroot/data/object_info.gateway.json")
160+
DefaultObjectInfoPath = Path.Combine(OverridesPath, "object_info.gateway.json");
161+
if (!File.Exists(DefaultObjectInfoPath))
162+
DefaultObjectInfoPath = WebRootPath.CombineWith("data/object_info.gateway.json");
163+
164+
var json = ReadTextFile(DefaultObjectInfoPath)
155165
?? throw new Exception("object_info.gateway.json not found");
156166
Metadata.LoadObjectInfo(json);
157167
DefaultGatewayNodes = Metadata.DefaultNodeDefinitions.Keys.ToSet();
@@ -253,17 +263,18 @@ void AddModel(Asset model)
253263
? null
254264
: Workflows.FirstOrDefault(x => x.Id == workflowId);
255265

256-
public ParsedWorkflow ParseWorkflow(string workflowJson, string workflowName, string baseModel) =>
257-
_ParseWorkflow(workflowJson, workflowName, baseModel, rethrow: true)!;
266+
public ParsedWorkflow ParseWorkflow(string workflowJson, string workflowName, string baseModel, string version) =>
267+
_ParseWorkflow(workflowJson, workflowName, baseModel, version, rethrow: true)!;
258268

259-
public ParsedWorkflow? TryParseWorkflow(string workflowJson, string workflowName, string baseModel) =>
260-
_ParseWorkflow(workflowJson, workflowName, baseModel, rethrow: false);
269+
public ParsedWorkflow? TryParseWorkflow(string workflowJson, string workflowName, string baseModel, string version) =>
270+
_ParseWorkflow(workflowJson, workflowName, baseModel, version, rethrow: false);
261271

262-
public ParsedWorkflow? _ParseWorkflow(string workflowJson, string workflowName, string baseModel, bool rethrow)
272+
public ParsedWorkflow? _ParseWorkflow(string workflowJson, string workflowName, string baseModel, string version, bool rethrow)
263273
{
264274
var ret = new ParsedWorkflow
265275
{
266-
BaseModel = baseModel
276+
BaseModel = baseModel,
277+
Version = version,
267278
};
268279
try
269280
{
@@ -314,7 +325,7 @@ public void LoadWorkflows(IDbConnection db)
314325
{
315326
var workflows = db.Select<Workflow>();
316327
var workflowVersions = db.Select<WorkflowVersion>();
317-
var workflowPaths = workflows.ToDictionary(x => x.Path);
328+
var workflowPaths = workflowVersions.ToDictionary(x => x.Path);
318329

319330
var files = Directory.GetFiles(WorkflowsPath, "*.json", SearchOption.AllDirectories);
320331
var allWorkflows = files.Map(x => x[WorkflowsPath.Length..].TrimStart('/'));
@@ -327,25 +338,35 @@ public void LoadWorkflows(IDbConnection db)
327338
var parts = workflowPath.Split('/');
328339
if (parts.Length != 3)
329340
{
330-
log.LogWarning("Invalid Workflow Path: {WorkflowPath}, should be <category>/<group>/<filename>.json", workflowPath);
341+
log.LogWarning("Invalid Workflow Path: {WorkflowPath}, should be <category>/<group>/<name>.<version>.json", workflowPath);
331342
continue;
332343
}
344+
345+
var fileName = workflowPath.LastRightPart('/');
346+
var nameAndVersion = fileName.WithoutExtension();
347+
if (nameAndVersion.IndexOf('.') == -1)
348+
{
349+
log.LogWarning("Invalid Workflow Filename: {FileName}, should be <name>.<version>.json", fileName);
350+
continue;
351+
}
352+
353+
var name = nameAndVersion.LastLeftPart('.');
354+
var version = nameAndVersion.LastRightPart('.');
333355

334356
var userId = AppConfig.Instance.DefaultUserId;
335357
var workflowJson = ReadTextFile(WorkflowsPath.CombineWith(workflowPath))
336-
?? throw new Exception($"Workflow not found: {workflowPath}");
358+
?? throw new Exception($"Workflow not found: {workflowPath}");
337359

338-
var name = parts[2].WithoutExtension();
339360
var baseModel = parts[1];
340-
var workflowName = StringFormatters.FormatName(workflowPath.LastRightPart('/').WithoutExtension());
341-
var parsedWorkflow = TryParseWorkflow(workflowJson, workflowName, baseModel);
361+
var workflowName = StringFormatters.FormatName(name);
362+
var parsedWorkflow = TryParseWorkflow(workflowJson, workflowName, baseModel, version);
342363
if (parsedWorkflow == null)
343364
continue;
344365

345366
var (workflow, workflowVersion) = CreateWorkflowAndVersion(db, parsedWorkflow, userId);
346367

347368
workflowVersions.Add(workflowVersion);
348-
workflowPaths[workflow.Path] = workflow;
369+
workflowPaths[workflowVersion.Path] = workflowVersion;
349370
workflows.Add(workflow);
350371
}
351372
Workflows = workflows;
@@ -355,7 +376,6 @@ public static (Workflow,WorkflowVersion) CreateWorkflowAndVersion(IDbConnection
355376
{
356377
var workflow = new Workflow
357378
{
358-
Path = parsedWorkflow.Path,
359379
Name = parsedWorkflow.Name,
360380
Category = parsedWorkflow.Category,
361381
Base = parsedWorkflow.BaseModel,
@@ -370,8 +390,9 @@ public static (Workflow,WorkflowVersion) CreateWorkflowAndVersion(IDbConnection
370390
var workflowVersion = new WorkflowVersion
371391
{
372392
ParentId = workflow.Id,
373-
Version = "v1",
374393
Name = parsedWorkflow.Name,
394+
Version = parsedWorkflow.Version,
395+
Path = parsedWorkflow.Path,
375396
Workflow = parsedWorkflow.Workflow,
376397
Info = parsedWorkflow.Info,
377398
Nodes = parsedWorkflow.Nodes,
@@ -889,6 +910,16 @@ public bool AgentCanRunWorkflow(ComfyAgent agent, HashSet<string> RequiredNodes,
889910
return true;
890911
}
891912

913+
public ComfyAgent? GetSupportedAgent(HashSet<string> requiredNodes, HashSet<string> requiredAssets)
914+
{
915+
foreach (var agent in ComfyAgents.Values)
916+
{
917+
if (AgentCanRunWorkflow(agent, requiredNodes, requiredAssets))
918+
return agent;
919+
}
920+
return null;
921+
}
922+
892923
public Dictionary<string, NodeInfo> GetSupportedNodeDefinitions(HashSet<string> requiredNodes, HashSet<string> requiredAssets)
893924
{
894925
foreach (var agent in ComfyAgents.Values)

MyApp.ServiceInterface/ComfyProvider.cs

Whitespace-only changes.

MyApp.ServiceInterface/ComfyServices.cs

Lines changed: 35 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ public class ComfyServices(ILogger<ComfyServices> log,
1919
ComfyGateway comfyGateway,
2020
IBackgroundJobs jobs,
2121
IDbConnectionFactory dbFactory,
22-
AgentEventsManager agentManager)
22+
AgentEventsManager agentManager,
23+
IComfyWorkflowConverter comfyConverter)
2324
: Service
2425
{
2526
public const string ComfyBaseUrl = "http://localhost:7860/api";
@@ -313,7 +314,7 @@ public async Task<WorkflowInfo> GetWorkflowInfoAsync(string path)
313314
// return apiPrompt;
314315
// }
315316

316-
public object Post(RequeueGeneration request)
317+
public async Task<object> Post(RequeueGeneration request)
317318
{
318319
var userId = Request.GetClaimsPrincipal().GetUserId();
319320
log.LogInformation("Received RequeueGeneration from '{UserId}' to execute Generation '{Id}'",
@@ -339,21 +340,13 @@ public object Post(RequeueGeneration request)
339340
}
340341

341342
var workflowVersion = GetWorkflowVersion(Db, gen.WorkflowId, gen.VersionId);
342-
var workflow = workflowVersion.Workflow;
343-
var workflowInfo = workflowVersion.Info;
344-
var result = ComfyWorkflowParser.MergeWorkflow(workflow, gen.Args!, workflowInfo);
345-
gen.Workflow = result.Result;
346-
347-
var requiredNodes = ComfyWorkflowParser.ExtractNodeTypes(workflow, log);
348-
var requiredAssets = ComfyWorkflowParser.ExtractAssetPaths(workflow, log);
349-
var nodeDefs = appData.GetSupportedNodeDefinitions(requiredNodes, requiredAssets);
350-
gen.ApiPrompt = ComfyConverters.ConvertWorkflowToApiPrompt(workflow, nodeDefs, gen.Id, log:log);
343+
var (apiPrompt, newWorkflow) = await comfyConverter.CreateApiPromptAsync(workflowVersion, gen.Args, gen.Id);
351344

352345
Db.UpdateOnly(() => new WorkflowGeneration
353346
{
354347
Args = gen.Args,
355-
Workflow = gen.Workflow,
356-
ApiPrompt = gen.ApiPrompt,
348+
Workflow = newWorkflow,
349+
ApiPrompt = apiPrompt,
357350
DeviceId = null,
358351
PromptId = null,
359352
Error = null,
@@ -403,32 +396,23 @@ private static WorkflowVersion GetWorkflowVersion(IDbConnection db, int workflow
403396
return workflowVersion;
404397
}
405398

406-
public object Post(QueueWorkflow request)
399+
public async Task<object> Post(QueueWorkflow request)
407400
{
408401
using var db = Db;
409402
var userId = Request.GetClaimsPrincipal().GetUserId();
410403
log.LogInformation("Received QueueComfyWorkflow from '{UserId}' to execute workflow '{Workflow}'",
411404
userId, request.WorkflowId);
412405

413-
var workflowVersion = GetWorkflowVersion(db, request.WorkflowId, request.VersionId);
414-
var workflow = workflowVersion.Workflow;
415-
var workflowInfo = workflowVersion.Info;
416-
if (request.Args?.Count > 0)
417-
{
418-
var result = ComfyWorkflowParser.MergeWorkflow(workflow, request.Args!, workflowInfo);
419-
workflow = result.Result;
420-
}
421-
422-
var requiredNodes = ComfyWorkflowParser.ExtractNodeTypes(workflow, log);
423-
var requiredAssets = ComfyWorkflowParser.ExtractAssetPaths(workflow, log);
424-
var nodeDefs = appData.GetSupportedNodeDefinitions(requiredNodes,requiredAssets);
425-
426406
var clientId = Guid.NewGuid().ToString("N");
427-
var apiPrompt = ComfyConverters.ConvertWorkflowToApiPrompt(workflow, nodeDefs, clientId, log:log);
407+
var workflowVersion = GetWorkflowVersion(db, request.WorkflowId, request.VersionId);
408+
var (apiPrompt, workflow) = await comfyConverter.CreateApiPromptAsync(workflowVersion, request.Args!, clientId);
428409

429410
log.LogInformation("Queueing ComfyUI Workflow for {ClientId}: {ApiPromptJson}",
430411
apiPrompt.ClientId, ClientConfig.ToSystemJson(apiPrompt.Prompt));
431412

413+
var requiredNodes = ComfyWorkflowParser.ExtractNodeTypes(workflowVersion.Workflow, log);
414+
var requiredAssets = ComfyWorkflowParser.ExtractAssetPaths(workflowVersion.Workflow, log);
415+
432416
var checkpoint = requiredAssets.FirstOrDefault(x =>
433417
x.StartsWith("checkpoints/") || x.StartsWith("diffusion_models/") || x.StartsWith("unet/") ||
434418
x.StartsWith("Stable-diffusion/", StringComparison.OrdinalIgnoreCase));
@@ -870,10 +854,10 @@ public async Task<object> Post(UpdateWorkflowVersion request)
870854
var workflowJson = await Request.Files[0].InputStream.ReadToEndAsync();
871855
var workflow = db.SingleById<Workflow>(workflowVersion.ParentId);
872856

873-
var parsedWorkflow = appData.TryParseWorkflow(workflowJson, workflowVersion.Name, workflow.Base)
857+
var parsedWorkflow = appData.TryParseWorkflow(workflowJson, workflowVersion.Name, workflow.Base, workflowVersion.Version)
874858
?? throw HttpError.BadRequest("Failed to parse workflow");
875859

876-
var saveToPath = appData.WorkflowsPath.CombineWith(workflow.Path);
860+
var saveToPath = appData.WorkflowsPath.CombineWith(workflowVersion.Path);
877861
Path.GetDirectoryName(saveToPath).AssertDir();
878862
await File.WriteAllTextAsync(saveToPath, workflowJson);
879863

@@ -914,25 +898,28 @@ public async Task<object> Post(ParseWorkflowVersions request)
914898
foreach (var version in allVersions)
915899
{
916900
var workflow = allWorkflows.Find(x => x.Id == version.ParentId);
917-
if (workflow?.Path == null)
901+
if (workflow == null)
918902
{
919903
ret.Results.Add($"Workflow not found for version {version.Id}");
920904
continue;
921905
}
922906

923907
try
924908
{
925-
var workflowJson = await File.ReadAllTextAsync(appData.WorkflowsPath.CombineWith(workflow.Path));
909+
var workflowJson = await File.ReadAllTextAsync(appData.WorkflowsPath.CombineWith(version.Path));
926910

927-
var parsedWorkflow = appData.ParseWorkflow(workflowJson, version.Name, workflow.Base);
911+
var parsedWorkflow = appData.ParseWorkflow(workflowJson, version.Name, workflow.Base, version.Version);
928912

929-
// if (parsedWorkflow.Nodes.SequenceEqual(version.Nodes) &&
930-
// parsedWorkflow.Assets.SequenceEqual(version.Assets))
931-
// continue;
913+
var clientId = version.Workflow.TryGetValue("Id", out var oId) && oId is string id
914+
? id
915+
: Guid.NewGuid().ToString("N");
916+
var (apiPrompt, _) = await comfyConverter.CreateApiPromptAsync(version, new(), clientId);
917+
version.ApiPrompt = apiPrompt.Prompt;
932918

933919
await db.UpdateOnlyAsync(() => new WorkflowVersion {
934920
Workflow = parsedWorkflow.Workflow,
935921
Info = parsedWorkflow.Info,
922+
ApiPrompt = version.ApiPrompt,
936923
Nodes = parsedWorkflow.Nodes,
937924
Assets = parsedWorkflow.Assets,
938925
ModifiedBy = userId,
@@ -943,7 +930,7 @@ public async Task<object> Post(ParseWorkflowVersions request)
943930
}
944931
catch (Exception e)
945932
{
946-
ret.Results.Add($"Failed to parse {workflow.Path}");
933+
ret.Results.Add($"Failed to parse {version.Path}");
947934
}
948935
}
949936

@@ -967,7 +954,7 @@ public async Task<object> Post(ParseWorkflow request)
967954

968955
workflowName = StringFormatters.FormatName(workflowName);
969956
var workflow = workflowJson.ParseAsObjectDictionary();
970-
var parsedWorkflow = appData.TryParseWorkflow(workflowJson, workflowName, "SDXL")
957+
var parsedWorkflow = appData.TryParseWorkflow(workflowJson, workflowName, "SDXL", "v1")
971958
?? throw HttpError.BadRequest("Failed to parse workflow");
972959
return parsedWorkflow;
973960
}
@@ -982,19 +969,25 @@ public async Task<object> Post(UploadNewWorkflow request)
982969
throw HttpError.BadRequest("No file uploaded");
983970

984971
var name = request.WorkflowName ?? Request.Files[0].FileName.LastRightPart('/').LastLeftPart('.');
985-
var fileName = name + ".json";
986972
// Check for invalid filename chars
987-
if (fileName.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0 ||
988-
fileName.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
973+
if (name.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0 ||
974+
name.IndexOfAny(Path.GetInvalidPathChars()) >= 0)
989975
throw HttpError.BadRequest("Invalid Name");
990976

977+
var version = "v1";
978+
if (name.IndexOf('.') >= 0)
979+
{
980+
version = name.LastRightPart('.');
981+
name = name.LastLeftPart('.');
982+
}
983+
991984
if (db.Exists<Workflow>(x => x.Name == name))
992985
throw new ArgumentNullException(nameof(request.WorkflowName), $"Workflow '{name}' already exists");
993986

994987
var workflowJson = await Request.Files[0].InputStream.ReadToEndAsync();
995988

996989
var baseModel = request.BaseModel.ToJsv(); // Use EnumMember Value if exists
997-
var parsedWorkflow = appData.ParseWorkflow(workflowJson, name, baseModel);
990+
var parsedWorkflow = appData.ParseWorkflow(workflowJson, name, baseModel, version);
998991
var saveToFullPath = appData.WorkflowsPath.CombineWith(parsedWorkflow.Path);
999992
Path.GetDirectoryName(saveToFullPath).AssertDir();
1000993
await File.WriteAllTextAsync(saveToFullPath, workflowJson);

0 commit comments

Comments
 (0)