| | | 1 | | using System.Text.Json.Nodes; |
| | | 2 | | using Elsa.AI.Abstractions.Models; |
| | | 3 | | using Elsa.Workflows.Management.Entities; |
| | | 4 | | using Elsa.Workflows.Management.Models; |
| | | 5 | | |
| | | 6 | | namespace Elsa.AI.Host.Services; |
| | | 7 | | |
| | | 8 | | public class WorkflowGroundingMapper |
| | | 9 | | { |
| | | 10 | | public WorkflowGroundingSummary Map(WorkflowDefinitionSummary summary) => |
| | | 11 | | new() |
| | | 12 | | { |
| | | 13 | | Id = summary.Id, |
| | | 14 | | DefinitionId = summary.DefinitionId, |
| | | 15 | | Name = summary.Name, |
| | | 16 | | Description = summary.Description, |
| | | 17 | | Version = summary.Version, |
| | | 18 | | IsLatest = summary.IsLatest, |
| | | 19 | | IsPublished = summary.IsPublished, |
| | | 20 | | IsReadonly = summary.IsReadonly, |
| | | 21 | | MaterializerName = summary.MaterializerName, |
| | | 22 | | ProviderName = summary.ProviderName, |
| | | 23 | | CreatedAt = summary.CreatedAt |
| | | 24 | | }; |
| | | 25 | | |
| | | 26 | | public WorkflowGroundingSummary Map(WorkflowDefinition definition) |
| | | 27 | | { |
| | | 28 | | var graph = GetGraph(definition); |
| | | 29 | | return new WorkflowGroundingSummary |
| | | 30 | | { |
| | | 31 | | Id = definition.Id, |
| | | 32 | | DefinitionId = definition.DefinitionId, |
| | | 33 | | Name = definition.Name, |
| | | 34 | | Description = definition.Description, |
| | | 35 | | Version = definition.Version, |
| | | 36 | | IsLatest = definition.IsLatest, |
| | | 37 | | IsPublished = definition.IsPublished, |
| | | 38 | | IsReadonly = definition.IsReadonly, |
| | | 39 | | MaterializerName = definition.MaterializerName, |
| | | 40 | | ProviderName = definition.ProviderName, |
| | | 41 | | CreatedAt = definition.CreatedAt, |
| | | 42 | | ActivityTypes = graph.ActivityTypes, |
| | | 43 | | Variables = definition.Variables.Select(x => x.Name).Where(x => !string.IsNullOrWhiteSpace(x)).Distinct(Stri |
| | | 44 | | Inputs = definition.Inputs.Select(x => x.Name).Where(x => !string.IsNullOrWhiteSpace(x)).Distinct(StringComp |
| | | 45 | | Outputs = definition.Outputs.Select(x => x.Name).Where(x => !string.IsNullOrWhiteSpace(x)).Distinct(StringCo |
| | | 46 | | }; |
| | | 47 | | } |
| | | 48 | | |
| | | 49 | | public JsonObject MapGraph(WorkflowDefinition definition) |
| | | 50 | | { |
| | | 51 | | var graph = GetGraph(definition); |
| | | 52 | | return new JsonObject |
| | | 53 | | { |
| | | 54 | | ["definitionId"] = definition.DefinitionId, |
| | | 55 | | ["versionId"] = definition.Id, |
| | | 56 | | ["version"] = definition.Version, |
| | | 57 | | ["activityTypes"] = AIGroundingJson.ToJsonArray(graph.ActivityTypes), |
| | | 58 | | ["activityCount"] = graph.ActivityCount, |
| | | 59 | | ["activities"] = AIGroundingJson.ToJsonArray(graph.Activities), |
| | | 60 | | ["variables"] = AIGroundingJson.ToJsonArray(definition.Variables.Select(x => x.Name).Where(x => !string.IsNu |
| | | 61 | | ["inputs"] = AIGroundingJson.ToJsonArray(definition.Inputs.Select(x => x.Name).Where(x => !string.IsNullOrWh |
| | | 62 | | ["outputs"] = AIGroundingJson.ToJsonArray(definition.Outputs.Select(x => x.Name).Where(x => !string.IsNullOr |
| | | 63 | | }; |
| | | 64 | | } |
| | | 65 | | |
| | | 66 | | public WorkflowGraphSummary GetGraph(WorkflowDefinition definition) |
| | | 67 | | { |
| | | 68 | | var root = TryParseWorkflowJson(definition); |
| | | 69 | | var activities = root == null ? [] : FindActivities(root).Take(200).ToList(); |
| | | 70 | | var activityTypes = activities |
| | | 71 | | .Select(x => x.Type) |
| | | 72 | | .Where(x => !string.IsNullOrWhiteSpace(x)) |
| | | 73 | | .Distinct(StringComparer.OrdinalIgnoreCase) |
| | | 74 | | .Order(StringComparer.OrdinalIgnoreCase) |
| | | 75 | | .ToList(); |
| | | 76 | | |
| | | 77 | | return new WorkflowGraphSummary(activities, activityTypes, activities.Count); |
| | | 78 | | } |
| | | 79 | | |
| | | 80 | | private static JsonNode? TryParseWorkflowJson(WorkflowDefinition definition) |
| | | 81 | | { |
| | | 82 | | var json = !string.IsNullOrWhiteSpace(definition.OriginalSource) ? definition.OriginalSource : definition.String |
| | | 83 | | if (string.IsNullOrWhiteSpace(json)) |
| | | 84 | | return null; |
| | | 85 | | |
| | | 86 | | try |
| | | 87 | | { |
| | | 88 | | return JsonNode.Parse(json); |
| | | 89 | | } |
| | | 90 | | catch |
| | | 91 | | { |
| | | 92 | | return null; |
| | | 93 | | } |
| | | 94 | | } |
| | | 95 | | |
| | | 96 | | private static IEnumerable<WorkflowActivitySummary> FindActivities(JsonNode node) |
| | | 97 | | { |
| | | 98 | | if (node is JsonObject jsonObject) |
| | | 99 | | { |
| | | 100 | | var type = ReadString(jsonObject, "type") ?? ReadString(jsonObject, "typeName") ?? ReadString(jsonObject, "a |
| | | 101 | | var id = ReadString(jsonObject, "id") ?? ReadString(jsonObject, "activityId") ?? ReadString(jsonObject, "nod |
| | | 102 | | if (!string.IsNullOrWhiteSpace(type)) |
| | | 103 | | yield return new WorkflowActivitySummary(id, type, ReadString(jsonObject, "name") ?? ReadString(jsonObje |
| | | 104 | | |
| | | 105 | | foreach (var child in jsonObject.Select(x => x.Value).OfType<JsonNode>()) |
| | | 106 | | { |
| | | 107 | | foreach (var activity in FindActivities(child)) |
| | | 108 | | yield return activity; |
| | | 109 | | } |
| | | 110 | | } |
| | | 111 | | else if (node is JsonArray jsonArray) |
| | | 112 | | { |
| | | 113 | | foreach (var child in jsonArray.OfType<JsonNode>()) |
| | | 114 | | { |
| | | 115 | | foreach (var activity in FindActivities(child)) |
| | | 116 | | yield return activity; |
| | | 117 | | } |
| | | 118 | | } |
| | | 119 | | } |
| | | 120 | | |
| | | 121 | | private static string? ReadString(JsonObject jsonObject, string name) => |
| | | 122 | | jsonObject.TryGetPropertyValue(name, out var node) && node is JsonValue value && value.TryGetValue<string>(out v |
| | | 123 | | } |
| | | 124 | | |
| | 10 | 125 | | public record WorkflowGraphSummary(IReadOnlyCollection<WorkflowActivitySummary> Activities, IReadOnlyCollection<string> |
| | | 126 | | |
| | | 127 | | public record WorkflowActivitySummary(string? Id, string Type, string? Name); |