Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,8 @@ public partial class NavMenu
SubMenu = new List<MenuItem>
{
new MenuItem { Text = "Smart MindMap", Href = "diagram/mindmap" },
new MenuItem { Text = "Smart FlowChart", Href = "diagram/flowchart" }
new MenuItem { Text = "Smart FlowChart", Href = "diagram/flowchart" },
new MenuItem { Text = "Smart Sequence", Href = "/diagram/sequence" }
}
},
new MenuItem
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@using Syncfusion.Blazor.Buttons
@using Syncfusion.Blazor.Popups
@using Syncfusion.Blazor.Inputs
@inject AzureAIService ChatGptService
@namespace TextToSequenceDiagram

<SfFab IconCss="e-icons e-ai-chat" Content="AI Assist" OnClick="OnFabClicked" Target="#diagram-area"></SfFab>
<SfDialog Width="570px" IsModal="true" ShowCloseIcon="true" CssClass="custom-dialog" Visible="@ShowAIAssistDialog">
<DialogTemplates>
<Header> <span class="e-icons e-ai-chat" style="color: black; font-size: 16px;"></span> AI Assist</Header>
<Content>
<p style="margin-bottom: 10px;">Suggested Prompts</p>
<SfButton style="flex: 1; overflow: visible; border-radius: 8px;margin-bottom: 10px;" @onclick="()=>GenerateSequence(ATMPrompt)">Sequence Diagram for ATM Transaction Process</SfButton>
<SfButton style="flex: 1; overflow: visible; border-radius: 8px;margin-bottom: 10px;" @onclick="()=>GenerateSequence(UserAuthendicationPrompt)">Sequence Diagram for User Authentication and Authorization</SfButton>
<SfButton style="flex: 1; overflow: visible; border-radius: 8px;margin-bottom: 10px;" @onclick="()=>GenerateSequence(MedicalAppointementPrompt)">Sequence Diagram for Medical Appointment Scheduling</SfButton>

<div style="display: flex; flex: 95%; margin-top:20px;">
<SfTextBox @bind-Value="@OpenAIPrompt" CssClass="db-openai-textbox" Height="32px" Placeholder="Please enter your prompt for generating a sequence diagram..." autofocus style="font-size: 14px;"></SfTextBox>
<SfButton @onclick="@GenerateDiagramFromAI" CssClass="e-icons e-flat e-send" IsPrimary="true" style="height: 38px; width: 38px; margin-left: 5px; padding: 0;"></SfButton>
</div>
</Content>
</DialogTemplates>
<DialogEvents Closed="@DialogClose"></DialogEvents>
</SfDialog>

Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace TextToSequenceDiagram
{
public partial class SequenceDiagramOpenAI
{
#pragma warning disable CS8618
public bool ShowAIAssistDialog = false;
public string OpenAIPrompt;
public TextToSequence Parent;
string ATMPrompt = "ATM Transaction Process";
string UserAuthendicationPrompt = "User Authentication and Authorization";
string MedicalAppointementPrompt = "Medical Appointment Scheduling";
#pragma warning restore CS8618
public void OnFabClicked()
{
ShowAIAssistDialog = !ShowAIAssistDialog;
}
private void DialogClose(Object args)
{
ShowAIAssistDialog = false;
}
public async void GenerateSequence(string value)
{
OpenAIPrompt = value;
await GenerateDiagramFromAI();
StateHasChanged();
}
public async Task GenerateDiagramFromAI()
{
ShowAIAssistDialog = false;
Parent.IsGeneratingFromAI = true;
if (!string.IsNullOrWhiteSpace(OpenAIPrompt))
{
await Parent.SpinnerRef!.ShowAsync();
string result = string.Empty;
string systemRole = "You are an expert assistant skilled in generating Mermaid sequence diagram data based on user queries.";

string userRole = $@"You are an assistant tasked with generating structured sequence diagram Mermaid data for the scenario {OpenAIPrompt} based on the guidelines below. The output should strictly adhere to these rules and must not include any markdown code fences or the string '```mermaid' at the beginning.

1. Start with sequenceDiagram.
2. Declare all participants with actor or participant; user types must be actor.
3. Use specific arrows only: ->>, -), --), and for self-messages also ->>.
4. Mark activations (activate) and deactivations (deactivate) for all interactions.
5. Include at least one alt, opt, or loop block.
6. Add at least one create and destroy message.
7. Include at least 10 interaction steps, building a complex flow.
8. Follow proper indentation and do not add extra comments or markdown syntax.

Basic simple examples for your context, but you try to create a complex diagram with all the given elements:

Example 1: All Types of Messages
sequenceDiagram
actor Client
participant Server
Client ->> Server: Sync Request
Server -) Client: Async Notification
Client -->> Server: Reply Message
Client ->> Client: Self Check
Server ->> Client: Delete Record

Example 2: With Activations
sequenceDiagram
participant User
participant Service
User ->> Service: Start Process
activate Service
Service -->> User: Process Acknowledged
deactivate Service

Example 3: With Fragments
sequenceDiagram
participant User
participant System
alt Successful Login
User ->> System: Enter Credentials
activate System
System -->> User: Login Successful
deactivate System
else Failed Login
loop Retry up to 3 times
User ->> System: Re-enter Credentials
end
end

Example 4: With Create/Destroy Messages
sequenceDiagram
actor Admin
create participant Worker as DataProcessor
Admin -) Worker: Initialize Service
activate Worker
Worker ->> Admin: Service Ready
deactivate Worker
destroy Worker

Return only the structured Mermaid sequence diagram syntax.
";

result = await ChatGptService.GetCompletionAsync(userRole, false, false, systemRole);
if (result != null)
{
List<string> lines = result.Split(new[] { "\n", "\r\n" }, StringSplitOptions.RemoveEmptyEntries).ToList();
lines = lines.Where(line => !line.Contains("```")).ToList();
int startIndex = lines.FindIndex(line => line.Trim().StartsWith("sequenceDiagram"));
if (startIndex != -1)
{
List<string> validMermaidData = lines.Skip(startIndex).ToList();
result = string.Join(Environment.NewLine, validMermaidData);
await Parent.Diagram!.LoadDiagramFromMermaidAsync(result);
}
else
await GenerateDiagramFromAI();
StateHasChanged();
}
await Parent.SpinnerRef.HideAsync();
}
Parent.IsGeneratingFromAI = false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
@using Syncfusion.Blazor.Navigations
@using Syncfusion.Blazor.DropDowns
@using Syncfusion.Blazor.Diagram
@using Syncfusion.Blazor.Inputs
@using Syncfusion.Blazor.SplitButtons
@namespace TextToSequenceDiagram

<div style="border: 1px solid #ccc;">
<SfToolbar>
<ToolbarEvents Clicked="@ToolbarEditorClick"></ToolbarEvents>
<ToolbarItems>
<ToolbarItem TooltipText="New Diagram" PrefixIcon="e-icons e-circle-add"></ToolbarItem>
<ToolbarItem TooltipText="Open Diagram" PrefixIcon="e-icons e-folder-open"></ToolbarItem>
<ToolbarItem TooltipText="Save Diagram" PrefixIcon="e-icons e-save"></ToolbarItem>
<ToolbarItem TooltipText="Print Diagram" PrefixIcon="e-icons e-print"></ToolbarItem>
<ToolbarItem>
<Template>
<SfDropDownButton IconCss="e-icons e-export">
<DropDownButtonEvents ItemSelected="@SelectedItem"></DropDownButtonEvents>
<DropDownMenuItems>
<DropDownMenuItem Text="JPG"></DropDownMenuItem>
<DropDownMenuItem Text="PNG"></DropDownMenuItem>
<DropDownMenuItem Text="SVG"></DropDownMenuItem>
</DropDownMenuItems>
</SfDropDownButton>
</Template>
</ToolbarItem>
<ToolbarItem Type="ItemType.Separator"></ToolbarItem>
<ToolbarItem PrefixIcon="e-icons e-pan" TooltipText="Pan"> </ToolbarItem>
<ToolbarItem PrefixIcon="e-icons e-mouse-pointer" TooltipText="Select"></ToolbarItem>
<ToolbarItem Type="@ItemType.Separator"></ToolbarItem>
<ToolbarItem>
<Template>
<SfDropDownButton Content="@ZoomItemDropdownContent">
<DropDownButtonEvents ItemSelected="@SelectedZoomItem"></DropDownButtonEvents>
<DropDownMenuItems>
<DropDownMenuItem Text="Zoom In"></DropDownMenuItem>
<DropDownMenuItem Text="Zoom Out"></DropDownMenuItem>
<DropDownMenuItem Text="Zoom to Fit"></DropDownMenuItem>
<DropDownMenuItem Text="Zoom to 50%"></DropDownMenuItem>
<DropDownMenuItem Text="Zoom to 100%"></DropDownMenuItem>
<DropDownMenuItem Text="Zoom to 200%"></DropDownMenuItem>
</DropDownMenuItems>
</SfDropDownButton>
</Template>
</ToolbarItem>
</ToolbarItems>
</SfToolbar>
</div>



Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using Syncfusion.Blazor.Diagram;
using System;
using System.Threading.Tasks;
using SyncfusionAISamples.Models;

namespace TextToSequenceDiagram
{
public partial class SequenceDiagramToolbar
{
#pragma warning disable CS8618
public TextToSequence Parent;
public string ZoomItemDropdownContent = "100%";
[Inject]
protected IJSRuntime jsRuntime { get; set; }
#pragma warning restore CS8618
private async Task ToolbarEditorClick(Syncfusion.Blazor.Navigations.ClickEventArgs args)
{
var value = args.Item.TooltipText;
switch (value)
{
case "New Diagram":
Parent.Diagram!.Clear();
SetElements();
break;
case "Open Diagram":
await LoadDiagram();
break;
case "Save Diagram":
string fileName = "Sequence Diagram";
await Download(fileName);
break;
case "Print Diagram":
DiagramPrintSettings print = new DiagramPrintSettings();
await Parent.Diagram!.PrintAsync(print);
break;
case "Pan":
Parent.DiagramTool = DiagramInteractions.ZoomPan;
break;
case "Select":
Parent.DiagramTool = DiagramInteractions.SingleSelect | DiagramInteractions.MultipleSelect;
break;
}
Parent.StateChanged();
}

private async void SelectedItem(Syncfusion.Blazor.SplitButtons.MenuEventArgs args)
{
var value = args.Item.Text;
switch (value)
{
case "JPG":
case "PNG":
case "SVG":
await Export(value);
break;
}
}

private void SelectedZoomItem(Syncfusion.Blazor.SplitButtons.MenuEventArgs args)
{
var value = args.Item.Text;
var currentZoom = Parent.Diagram!.ScrollSettings!.CurrentZoom;
switch (value)
{
case "Zoom In":
case "Zoom Out":
var ZoomFactor = 0.2;
ZoomFactor = value == "Zoom Out" ? 1 / (1 + ZoomFactor) : (1 + ZoomFactor);
Parent.Diagram.Zoom(ZoomFactor, null);
break;
case "Zoom to Fit":
FitOptions fitoption = new FitOptions()
{
Mode = FitMode.Both,
Region = DiagramRegion.Content,
};
Parent.Diagram.FitToPage(fitoption);
break;
case "Zoom to 50%":
ZoomFactor = 0.5 / currentZoom;
Parent.Diagram.Zoom(ZoomFactor, null);
break;
case "Zoom to 100%":
ZoomFactor = 1 / currentZoom;
Parent.Diagram.Zoom(ZoomFactor, null);
break;
case "Zoom to 200%":
ZoomFactor = 2 / currentZoom;
Parent.Diagram.Zoom(ZoomFactor, null);
break;
}
ZoomItemDropdownContent = FormattableString.Invariant($"{Math.Round(Parent.Diagram.ScrollSettings.CurrentZoom * 100)}") + "%";
}

public void RefreshToolbar()
{
StateHasChanged();
}
public void SetElements()
{
Parent.Diagram!.ClearHistory();
Parent.Diagram.ResetZoom();
StateHasChanged();
}

public async Task LoadDiagram()
{
Parent.Diagram!.BeginUpdate();
Parent.ExtensionType = ".json";
await FileUtil.Click(jsRuntime);
await Parent.Diagram.EndUpdateAsync();
}

public async Task Download(string fileName)
{
string data = Parent.Diagram!.SaveDiagram();
await FileUtil.SaveAs(jsRuntime, data, fileName);
}

private async Task Export(string value)
{
DiagramExportSettings export = new DiagramExportSettings();
export.FitToPage = true;
if (value == "JPG")
await Parent.Diagram!.ExportAsync("Diagram", DiagramExportFormat.JPEG, export);
else if (value == "PNG")
await Parent.Diagram!.ExportAsync("Diagram", DiagramExportFormat.PNG, export);
else if (value == "SVG")
await Parent.Diagram!.ExportAsync("Diagram", DiagramExportFormat.SVG, export);
}
}
}
Loading