diff --git a/blazor-toc.html b/blazor-toc.html index 6789609612..6c884531ca 100644 --- a/blazor-toc.html +++ b/blazor-toc.html @@ -5000,9 +5000,9 @@
  • 31.1.18
  • -
  • 31.2.9 Service Pack Release
  • +
  • 31.2.12 Service Pack Release
  • 31.2.2 Service Pack Release
  • -
  • 31.1.17 Main Release
  • +
  • 31.2.12 Service Pack Release
  • 31.1.17 Main Release
  • 2025 Volume 2 - 30.*
  • 2025 Volume 1 - 29.*
  • 2024 Volume 4 - 28.*
  • 2024 Volume 3 - 27.*
  • 2024 Volume 2 - 26.*
  • 2024 Volume 1 - 25.*
  • 2023 Volume 4 - 24.*
  • 2023 Volume 3 - 23.*
  • 2023 Volume 2 - 22.*
  • 2023 Volume 1 - 21.*
  • 2022 Volume 4 - 20.4.*
  • 2022 Volume 3 - 20.3.*
  • 2022 volume 2 - 20.2.*
  • 2022 volume 1 - 20.1.*
  • 2021 Volume 4 - 19.4.*
  • 2021 volume 3 - 19.3.*
  • 2021 Volume 2 - 19.2.*
  • 2021 volume 1 - 19.1.*
  • 2020 volume 4 - 18.4.*
  • diff --git a/blazor/Release-Notes/31.2.12.md b/blazor/Release-Notes/31.2.12.md new file mode 100644 index 0000000000..3bcb0f5000 --- /dev/null +++ b/blazor/Release-Notes/31.2.12.md @@ -0,0 +1,94 @@ +--- +title: Essential Studio for Blazor Release Notes +description: Learn here about the controls in the Essential Studio for Blazor 2025 Volume 3 SP Release - Release Notes +platform: blazor +documentation: ug +--- + +# Essential Studio for Blazor - v31.2.12 Release Notes + +{% include release-info.html date="November 18, 2025" version="v31.2.12" passed="71954" failed="0" %} + +{% directory path: _includes/release-notes/v31.2.12 %} + +{% include {{file.url}} %} + +{% enddirectory %} + +## Test Results + +| Component Name | Test Cases | Passed | Failed | Remarks | +|---------------|------------|--------|--------|---------| +| 3DChart | 198 | 198 | 0 | All Passed | +| Accordion | 232 | 232 | 0 | All Passed | +| AiAssistView | 297 | 297 | 0 | All Passed | +| Appbar | 102 | 102 | 0 | All Passed | +| Autocomplete | 444 | 444 | 0 | All Passed | +| BarcodeGenerator | 440 | 440 | 0 | All Passed | +| Breadcrumb | 137 | 137 | 0 | All Passed | +| Bulletchart | 237 | 237 | 0 | All Passed | +| Button | 255 | 255 | 0 | All Passed | +| Calendar | 146 | 146 | 0 | All Passed | +| Carousel | 174 | 174 | 0 | All Passed | +| Charts | 4175 | 4175 | 0 | All Passed | +| ChatUI | 102 | 102 | 0 | All Passed | +| Chips | 196 | 196 | 0 | All Passed | +| CircularGauge | 928 | 928 | 0 | All Passed | +| ColorPicker | 113 | 113 | 0 | All Passed | +| ComboBox | 248 | 248 | 0 | All Passed | +| DashboardLayout | 253 | 253 | 0 | All Passed | +| DataForm | 547 | 547 | 0 | All Passed | +| DataGrid | 5951 | 5951 | 0 | All Passed | +| DatePicker | 576 | 576 | 0 | All Passed | +| DateRangePicker | 366 | 366 | 0 | All Passed | +| DateTimePicker | 474 | 474 | 0 | All Passed | +| Diagram | 15316 | 15316 | 0 | All Passed | +| Dialog | 481 | 481 | 0 | All Passed | +| DropdownList | 584 | 584 | 0 | All Passed | +| Dropdowntree | 164 | 164 | 0 | All Passed | +| FileManager | 3108 | 3108 | 0 | All Passed | +| FileUpload | 330 | 330 | 0 | All Passed | +| FloatingActionButton | 128 | 128 | 0 | All Passed | +| Gantt | 4800 | 4800 | 0 | All Passed | +| HeatMap | 339 | 339 | 0 | All Passed | +| ImageEditor | 3561 | 3561 | 0 | All Passed | +| InPlaceEditor | 764 | 764 | 0 | All Passed | +| InputMask | 168 | 168 | 0 | All Passed | +| Kanban | 380 | 380 | 0 | All Passed | +| LinearGauge | 799 | 799 | 0 | All Passed | +| ListBox | 138 | 138 | 0 | All Passed | +| ListView | 441 | 441 | 0 | All Passed | +| Maps | 1570 | 1570 | 0 | All Passed | +| Mention | 152 | 152 | 0 | All Passed | +| Menu | 398 | 398 | 0 | All Passed | +| Message | 211 | 211 | 0 | All Passed | +| MultiselectDropdown | 386 | 386 | 0 | All Passed | +| NumericTextbox | 442 | 442 | 0 | All Passed | +| OtpInput | 123 | 123 | 0 | All Passed | +| PivotTable | 1378 | 1378 | 0 | All Passed | +| ProgressBar | 199 | 199 | 0 | All Passed | +| progressbutton | 101 | 101 | 0 | All Passed | +| QueryBuilder | 584 | 584 | 0 | All Passed | +| RangeNavigator | 196 | 196 | 0 | All Passed | +| Rating | 106 | 106 | 0 | All Passed | +| Ribbon | 451 | 451 | 0 | All Passed | +| RichTextEditor | 2768 | 2768 | 0 | All Passed | +| Scheduler | 5623 | 5623 | 0 | All Passed | +| Sidebar | 144 | 144 | 0 | All Passed | +| Slider | 271 | 271 | 0 | All Passed | +| SmithChart | 259 | 259 | 0 | All Passed | +| SparklineChart | 150 | 150 | 0 | All Passed | +| SpeedDial | 353 | 353 | 0 | All Passed | +| Splitter | 190 | 190 | 0 | All Passed | +| Stepper | 218 | 218 | 0 | All Passed | +| StockChart | 335 | 335 | 0 | All Passed | +| Tabs | 936 | 936 | 0 | All Passed | +| TextArea | 126 | 126 | 0 | All Passed | +| Textbox | 653 | 653 | 0 | All Passed | +| Timeline | 182 | 182 | 0 | All Passed | +| TimePicker | 419 | 419 | 0 | All Passed | +| Toast | 233 | 233 | 0 | All Passed | +| Toolbar | 230 | 230 | 0 | All Passed | +| TreeGrid | 4943 | 4943 | 0 | All Passed | +| TreeMap | 704 | 704 | 0 | All Passed | +| TreeView | 1361 | 1361 | 0 | All Passed | \ No newline at end of file diff --git a/blazor/Release-Notes/31.2.9.md b/blazor/Release-Notes/31.2.9.md deleted file mode 100644 index dd89f63f11..0000000000 --- a/blazor/Release-Notes/31.2.9.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -title: Essential Studio for Blazor Release Notes -description: Learn here about the controls in the Essential Studio for Blazor 2025 Volume 3 SP2 Release - Release Notes -platform: blazor -documentation: ug ---- - -# Essential Studio for Blazor - v31.2.9 Release Notes - -{% include release-info.html date="November 12, 2025" version="v31.2.9" %} - -{% directory path: _includes/release-notes/v31.2.9 %} - -{% include {{file.url}} %} - -{% enddirectory %} \ No newline at end of file diff --git a/blazor/common/how-to/version-compatibility.md b/blazor/common/how-to/version-compatibility.md index 26638346bb..255dab8361 100644 --- a/blazor/common/how-to/version-compatibility.md +++ b/blazor/common/how-to/version-compatibility.md @@ -13,6 +13,7 @@ The following table shows the supported .NET and .NET Core versions for Syncfusi | Version | Syncfusion® Blazor Components Version | | ------------- | ------------- | +| [.NET 10.0](https://dotnet.microsoft.com/en-us/download/dotnet/10.0) | 31.2.10 and above | | [.NET 9.0](https://dotnet.microsoft.com/en-us/download/dotnet/9.0) | 27.2.2 and above | | [.NET 8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) | 23.1.36 and above | | [.NET 7.0](https://dotnet.microsoft.com/en-us/download/dotnet/7.0) | 20.4.0.38 to 28.2.12 | diff --git a/blazor/smart-ai-solutions/ai-samples/kanban/sentiment-analysis.md b/blazor/smart-ai-solutions/ai-samples/kanban/sentiment-analysis.md index d66c1982d1..ed365c4934 100644 --- a/blazor/smart-ai-solutions/ai-samples/kanban/sentiment-analysis.md +++ b/blazor/smart-ai-solutions/ai-samples/kanban/sentiment-analysis.md @@ -228,304 +228,233 @@ await builder.Build().RunAsync(); {% endhighlight %} {% endtabs %} -## Razor Component +## AI-powered Sentiment Analysis in Kanban -This section demonstrates how to implement sentiment analysis in the Syncfusion Blazor Kanban component using AI. The AI Assistant evaluates the emotional tone of each task description and displays a corresponding emoji (😊, 😐, 😞) to help teams quickly assess the mood or urgency of tasks. This can be especially useful in agile workflows where emotional context can influence task priority and team communication. +The AI-powered sentiment analysis feature in Blazor Kanban evaluates customer feedback for delivered tasks and displays emojis (😊, 😐, 😞) to indicate positive, neutral, or negative sentiment. This helps teams quickly assess satisfaction levels and prioritize follow-up actions, improving customer experience in service workflows. -(`Home.razor`) +### UI Structure -```csharp -@using Syncfusion.Blazor.Kanban -@using Syncfusion.Blazor.SplitButtons -@using Syncfusion.Blazor.Calendars -@using Syncfusion.Blazor.Inputs -@using Syncfusion.Blazor.DropDowns -@using AISamples.Components.Models -@using AISamples.Components.Service -@inject AzureAIService OpenAIService - -
    - - - -
    -
    -
    - - - @foreach (ColumnModel item in columnData) - { - - } - - - + + -``` +{% endhighlight %} +{% endtabs %} -`Home.razor.cs` +### Analyzing Sentiments with AI -```csharp +After the user clicks **Check Customer Sentiments** button, the `GetScore()` method runs. It serializes the Kanban data into JSON and builds a prompt for the AI service using the `GetCompletionAsync` method. The prompt instructs the AI to: + +- Provide a `SentimentScore` out of 5 based on the feedback. +- Skip scoring if feedback is null. +- Return the updated data strictly in JSON format with all fields included. -using System.Text.Json; -using AISamples.Components.Models; -using Syncfusion.Blazor.DropDowns; -using Syncfusion.Blazor.Inputs; -using Syncfusion.Blazor.Kanban; +The AI response is cleaned to remove extra formatting and deserialized into a list of PizzaDataModel objects. Each item’s `SentimentScore` is mapped to an emoji: -namespace AISamples.Components.Pages +- Score > 3 → 😊 smiling face +- Score = 3 → 😐 neutral face +- Score ≤ 2 → 😞 disappointed face + +Finally, `ShowScore` is set to `true`, and the Kanban board updates to display emojis for delivered items. + +```csharp +private async Task GetScore() { - public partial class Home + this.IsSpinner = true; + string result = ""; + string json = JsonSerializer.Serialize(Pizza, new JsonSerializerOptions { WriteIndented = true }); + var description = "Provide a SentimentScore out of 5 (whole numbers only) based on the Feedback. If the feedback is null, do not give a SentimentScore. Use the dataset provided below to make recommendations. NOTE: Return the data in JSON format with all fields included, and return only JSON data, no explanatory text." + json; + result = await OpenAIService.GetCompletionAsync(description); + string data = result.Replace("```json", "").Replace("```", "").Replace("\r", "").Replace("\n", "").Replace("\t", "").Trim(); + this.Pizza = JsonSerializer.Deserialize>(data); + this.IsSpinner = false; + foreach(var item in Pizza) { - SfDropDownList CategoryRef; - SfTextBox DescriptionRef; - private string SelectedAPI = "Open AI"; - private bool ShowScore = false; - private bool IsSpinner = false; - private List Pizza = new PizzaDataModel().GetPizzaData(); - public string Content = "Check Customer Sentiments"; - private async Task GetScore() + if(item.SentimentScore > 0 && item.SentimentScore <= 2) { - this.IsSpinner = true; - string result = ""; - string json = JsonSerializer.Serialize(Pizza, new JsonSerializerOptions { WriteIndented = true }); - var description = "Provide a SentimentScore out of 5 (whole numbers only) based on the Feedback. If the feedback is null, do not give a SentimentScore. Use the dataset provided below to make recommendations. NOTE: Return the data in JSON format with all fields included, and return only JSON data, no explanatory text." + json; - result = await OpenAIService.GetCompletionAsync(description); - string data = result.Replace("```json", "").Replace("```", "").Replace("\r", "").Replace("\n", "").Replace("\t", "").Trim(); - this.Pizza = JsonSerializer.Deserialize>(data); - this.IsSpinner = false; - foreach(var item in Pizza) - { - if(item.SentimentScore > 0 && item.SentimentScore <= 2) - { - item.Emoji = "😢"; - } - else if (item.SentimentScore > 3 && item.SentimentScore <= 5) - { - item.Emoji = "😀"; - } - else if (item.SentimentScore == 3) - { - item.Emoji = "😐"; - } - } - this.ShowScore = true; - StateHasChanged(); - } - private List CategoryData = new List() - { - new DropDownModel { Id = 0, Value = "Menu" }, - new DropDownModel { Id = 1, Value = "Order" }, - new DropDownModel { Id = 2, Value = "Ready to Serve" }, - new DropDownModel { Id = 3, Value = "Delivered"}, - new DropDownModel { Id = 3, Value = "Served"}, - }; - private class DropDownModel - { - public int Id { get; set; } - public string Value { get; set; } + item.Emoji = "😢"; } - private List columnData = new List() { - new ColumnModel(){ HeaderText= "Menu", KeyField= new List() { "Menu" } }, - new ColumnModel(){ HeaderText= "Order", KeyField= new List() { "Order" } }, - new ColumnModel(){ HeaderText= "Ready to Serve", KeyField= new List() { "Ready to Serve"} }, - new ColumnModel(){ HeaderText= "Delivered", KeyField=new List() { "Delivered", "Served" } } - }; - public void Begin(Syncfusion.Blazor.SplitButtons.ProgressEventArgs args) + else if (item.SentimentScore > 3 && item.SentimentScore <= 5) { - Content = "Analyzing..."; + item.Emoji = "😀"; } - public async Task End(Syncfusion.Blazor.SplitButtons.ProgressEventArgs args) + else if (item.SentimentScore == 3) { - while (this.IsSpinner) - { - await Task.Delay(1000); - } - Content = "Check Cusotomer Sentiments"; + item.Emoji = "😐"; } } + this.ShowScore = true; + StateHasChanged(); } + ``` -## Error Handling and Troubleshooting +### Displaying Sentiment Results on Kanban Cards -If the AI service fails to return a valid response, the Kanban will display an error message ("Oops! Please try again!"). Common issues include: +Once the AI response is processed and `ShowScore` is set to `true`, the Kanban board updates dynamically. For cards in the Delivered or Served categories: -- **Invalid API Key or Endpoint**: Verify that the `openAIApiKey`, `azureOpenAIKey`, or Ollama `Endpoint` is correct and the service is accessible. -- **Model Unavailable**: Ensure the specified `openAIModel`, `azureOpenAIModel`, or `ModelName` is deployed and supported. -- **Network Issues**: Check connectivity to the AI service endpoint, especially for self-hosted Ollama instances. -- **Large Prompts**: Processing large text inputs may cause timeouts. Consider reducing the prompt size or optimizing the request for efficiency. +- The Emoji field is shown alongside delivery details. +- Emojis represent the sentiment score: + - 😊 Smiling face for positive feedback (score > 3) + - 😐 Neutral face for average feedback (score = 3) + - 😞 Disappointed face for negative feedback (score ≤ 2) -## Performance Considerations +This is handled in the Kanban card template using conditional rendering: -When handling large text content, ensure the Ollama server has sufficient resources (CPU/GPU) to process requests efficiently. For long-form content or batch operations, consider splitting the input into smaller segments to avoid performance bottlenecks. Test the application with your specific use case to determine optimal performance. +{% tabs %} +{% highlight %} + +if (card.Category == "Delivered" || card.Category == "Served") +{ +
    Delivered
    + if (ShowScore) + { + +
    +
    +
    @card.Emoji
    +
    + + } +} + +{% endhighlight %} +{% endtabs %} ## Sample Code A complete working example is available in the [Syncfusion Blazor AI Samples GitHub repository](https://github.com/syncfusion/smart-ai-samples). -![Kanban AI Assistant - Output](../../ai/images/sentiment-analysis.png) \ No newline at end of file +![Kanban AI Assistant - Output](../../ai/images/sentiment-analysis.png) + +## Error Handling and Troubleshooting + +If the AI service fails to return a valid response, the Kanban will display an error message ("Oops! Please try again!"). Common issues include: + +- **Invalid API Key or Endpoint**: Verify that the `openAIApiKey`, `azureOpenAIKey`, or Ollama `Endpoint` is correct and the service is accessible. +- **Model Unavailable**: Ensure the specified `openAIModel`, `azureOpenAIModel`, or `ModelName` is deployed and supported. +- **Network Issues**: Check connectivity to the AI service endpoint, especially for self-hosted Ollama instances. +- **Large Prompts**: Processing large text inputs may cause timeouts. Consider reducing the prompt size or optimizing the request for efficiency. + diff --git a/blazor/smart-ai-solutions/ai-samples/kanban/smart-task-suggestion.md b/blazor/smart-ai-solutions/ai-samples/kanban/smart-task-suggestion.md index a8034ddae5..a4ad47896a 100644 --- a/blazor/smart-ai-solutions/ai-samples/kanban/smart-task-suggestion.md +++ b/blazor/smart-ai-solutions/ai-samples/kanban/smart-task-suggestion.md @@ -228,342 +228,215 @@ await builder.Build().RunAsync(); {% endhighlight %} {% endtabs %} -## Razor Component +## AI-powered Kanban Smart Card Generation -This section demonstrates how to implement the Syncfusion Blazor Kanban component with AI-powered task generation. The AI Assistant analyzes the provided project description and automatically suggests relevant tasks, which are then displayed in the Kanban board. +The AI-powered Kanban feature integrates Blazor Kanban with an AI service to automatically generate structured task cards based on user input. This functionality simplifies project planning by allowing users to enter basic project details and the desired number of tasks. The backend logic then uses AI to create well-defined tasks, including fields like **Title**, **Description**, **Status**, and **Story Points**, and dynamically updates the Kanban board. This approach ensures faster task creation, consistent formatting, and an interactive experience for managing projects. -(`Home.razor`) +### UI Structure + +The Kanban AI interface starts with a simple form where users provide **Project Details** and the **Number of Tasks** to generate. Below these inputs, a Progress Button labeled “Generate Tasks” triggers the AI process. This button shows a loading state during task generation for better user feedback. + +- **Project Details:** A multiline text box for describing the project. +- **Number of Tasks:** A numeric input for specifying how many tasks to generate. +- **Generate Button:** A progress-enabled button that calls `GenerateTasks()` to start AI-based task creation. + +{% tabs %} +{% highlight %} + +
    + +
    +
    + +
    +
    + +
    +
    + +
    +
    + + + +
    + +{% endhighlight %} +{% endtabs %} + +### Generating Tasks with AI + +After the user enters project details and the number of tasks, clicking Generate Tasks calls `GenerateTasks()`, which triggers `GenerateProjectTasks()` to build a detailed prompt for the AI service. This prompt includes the project description, task count, and strict instructions to return data in JSON format with fields like Id, Title, Description, Status, StoryPoints, and Color. + +The prompt is then sent to the AI using `GetCompletionAsync()`, which processes the request and returns a JSON response containing the generated tasks. The response is cleaned to remove unnecessary formatting and deserialized into a list of `SmartSuggestionDataModel` objects. These tasks are stored in `smartSuggestion` and displayed in the Kanban board or backlog view. ```csharp -@rendermode InteractiveServer -@inject AzureAIService OpenAIService -@using Syncfusion.Blazor.Kanban -@using Syncfusion.Blazor.Buttons -@using Syncfusion.Blazor.SplitButtons -@using Syncfusion.Blazor.Popups -@using Syncfusion.Blazor.Inputs -@using Syncfusion.Blazor.Notifications -@using BlazorApp4.Components.Models -@using BlazorApp4.Components.Service -@using Syncfusion.Blazor.Grids - -@if (isHomapage) +private async Task GenerateProjectTasks() { -
    -
    -
    -
    -

    AI Smart Task Suggestion

    -
    -
    -
    -
    -
    -
    - -
    -
    - -
    -
    - -
    -
    - -
    -
    - - - -
    -
    -
    -
    -
    -
    -
    -
    + try + { + if (!string.IsNullOrEmpty(TextBoxValue) && !string.IsNullOrEmpty(TasksValue)) + { + string result = ""; + var description = $"Generate {TasksValue} task recommendations for {TextBoxValue}. Each task should include the following fields: Id (like example: ID should be in project name simple 4char word - 1), Title, Status, Description, Assignee, StoryPoints, Color and Due Date, formatted according to the dataset. Assign each task to the Assignee: empty string, set the Status to 'Open', and use black for the Color. Use the dataset provided below to create your recommendations. IMPORTANT: Return the data strictly in JSON format with all the required fields. Only the JSON data is needed, no additional text.Return only the JSON array format without any explanations."; + result = await OpenAIService.GetCompletionAsync(description); + if (result != null) + { + string data = result.Replace("```json", "").Replace("```", "").Replace("\r", "").Replace("\n", "").Replace("\t", "").Trim(); + List modifiedData; + modifiedData = JsonSerializer.Deserialize>(data); + smartSuggestion = modifiedData != null ? smartSuggestion.Concat(modifiedData).ToList() : smartSuggestion; + this.isGeneratedProjectTasks = true; + } + ContentGenerateTask = "Generate Tasks"; + } + else + { + waringText = string.IsNullOrEmpty(TextBoxValue) && string.IsNullOrEmpty(TasksValue) ? "Enter the required task creation details" : !string.IsNullOrEmpty(TasksValue) ? "Enter the Project Details" : "Enter the number of tasks"; + } + } + catch + { + await this.ToastObj.ShowAsync(new ToastModel { ContentTemplate = @GetTemplate(), ShowCloseButton = true, Timeout = 0 }); + } } -else -{ -
    -
    -
    - @if (showBacklogs) - { -
    -

    Kanban Board

    -
    - Add New Projects -
    -
    - + +``` + +### Displaying AI-Generated Tasks in Kanban Cards + +Once the AI-generated tasks are processed and stored in `smartSuggestion`, they are displayed in two ways: + +1. Kanban Board View +2. Backlog Grid View + +#### Kanban Board View + +The Kanban board uses `SfKanban` to organize tasks into columns like **To Do**, **In Progress**, **Review**, and **Done**, based on the Status field. Each card shows the task title, description, and story points using a custom template for better readability. + +- **Kanban Columns:** Defined by KeyField values such as Open, InProgress, Review, and Close. +- **Card Template:** Displays Title, Description, and StoryPoints in a structured layout. +- **Dynamic Binding:** The [DataSource](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Kanban.SfKanban-1.html#Syncfusion_Blazor_Kanban_SfKanban_1_DataSource) property binds to `smartSuggestion`, ensuring that newly generated tasks appear instantly. + +{% tabs %} +{% highlight %} + + + + + + + + + + + + + +{% endhighlight %} +{% endtabs %} + +#### Backlog Grid View + +When users switch to **Backlog View**, tasks are displayed in a grid using `SfGrid`. This view allows adding, deleting, and editing tasks through a **dialog popup** for structured input. + +- **Dialog Editing:** Uses [GridEditSettings](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.SfGrid-1.html#Syncfusion_Blazor_Grids_SfGrid_1_EditSettings) with [Dialog](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.GridEditSettings.html#Syncfusion_Blazor_Grids_GridEditSettings_Dialog) mode for structured editing. +- **Validation:** Ensures required fields like Task ID, Title, and Status are filled. +- **Data Binding:** The [DataSource](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.Grids.SfGrid-1.html#Syncfusion_Blazor_Grids_SfGrid_1_DataSource) property binds to `smartSuggestion`, just like Kanban. + +{% tabs %} +{% highlight %} + + + + + + + + + + + + + + -``` +{% endhighlight %} +{% endtabs %} + +**View Toggle:** Users can switch between **Kanban** and **Grid** using the button below: + +{% tabs %} +{% highlight %} -`Home.razor.cs` + + +{% endhighlight %} +{% endtabs %} ```csharp -using System.Text.Json; -using AISamples.Components.Models; -using Microsoft.AspNetCore.Components; -using Syncfusion.Blazor.Grids; -using Syncfusion.Blazor.Kanban; -using Syncfusion.Blazor.Notifications; - -namespace AISamples.Components.Pages +private void GoToBacklogBoardView() { - public partial class Home + if (BacklogButtonViewContent == "View as Board") { - SfToast ToastObj; - public string[] SelectedAssignees { get; set; } = new string[] { }; - private string ToastTarget { get; set; } = "#toast-kanban-observable"; - SfKanban kanbanObj; - public string ContentGenerateTask = "Generate Tasks"; - public string BacklogButtonViewContent = "View as Backlog"; - private string TextBoxValue = string.Empty; - private string TasksValue = string.Empty; - private bool enableProjectDetailsDialog = false; - private bool isGeneratedProjectTasks = false; - private bool enableTaskEditing = false; - private bool isHomapage = true; - private bool showSprintBoard = false; - private bool showBacklogs = false; - private bool showBacklogBoard = true; - private List smartSuggestion = new List(); - private DialogSettings DialogParams = new DialogSettings { MinHeight = "400px", Width = "450px" }; - private string waringText = "Click \"Generate Tasks\" to preview"; - private void GoToBacklogBoardView() - { - if (BacklogButtonViewContent == "View as Board") - { - BacklogButtonViewContent = "View as Backlog"; - showBacklogBoard = true; - } - else - { - showBacklogBoard = false; - BacklogButtonViewContent = "View as Board"; - } - showSprintBoard = false; - } - private RenderFragment GetTemplate() => builder => - { - builder.OpenElement(0, "div"); - builder.AddContent(1, "An error occurred during the AI process, Please try again."); - builder.CloseElement(); - }; - public void BeginGenerateTasks(Syncfusion.Blazor.SplitButtons.ProgressEventArgs args) - { - ContentGenerateTask = "Generating..."; - } - public async Task EndGenerateTasks(Syncfusion.Blazor.SplitButtons.ProgressEventArgs args) - { - while (!isGeneratedProjectTasks) - { - await Task.Delay(1000); - } - this.isHomapage = false; - this.CloseDialog(); - showBacklogs = true; - } - private async Task GenerateProjectTasks() - { - try - { - if (!string.IsNullOrEmpty(TextBoxValue) && !string.IsNullOrEmpty(TasksValue)) - { - string result = ""; - var description = $"Generate {TasksValue} task recommendations for {TextBoxValue}. Each task should include the following fields: Id (like example: ID should be in project name simple 4char word - 1), Title, Status, Description, Assignee, StoryPoints, Color and Due Date, formatted according to the dataset. Assign each task to the Assignee: empty string, set the Status to 'Open', and use black for the Color. Use the dataset provided below to create your recommendations. IMPORTANT: Return the data strictly in JSON format with all the required fields. Only the JSON data is needed, no additional text.Return only the JSON array format without any explanations."; - result = await OpenAIService.GetCompletionAsync(description); - if (result != null) - { - string data = result.Replace("```json", "").Replace("```", "").Replace("\r", "").Replace("\n", "").Replace("\t", "").Trim(); - List modifiedData; - modifiedData = JsonSerializer.Deserialize>(data); - smartSuggestion = modifiedData != null ? smartSuggestion.Concat(modifiedData).ToList() : smartSuggestion; - this.isGeneratedProjectTasks = true; - } - ContentGenerateTask = "Generate Tasks"; - } - else - { - waringText = string.IsNullOrEmpty(TextBoxValue) && string.IsNullOrEmpty(TasksValue) ? "Enter the required task creation details" : !string.IsNullOrEmpty(TasksValue) ? "Enter the Project Details" : "Enter the number of tasks"; - } - } - catch - { - await this.ToastObj.ShowAsync(new ToastModel { ContentTemplate = @GetTemplate(), ShowCloseButton = true, Timeout = 0 }); - } - } - private void OpenProjectDetailsDialog() - { - this.enableProjectDetailsDialog = true; - } - private async Task GenerateTasks() - { - this.isGeneratedProjectTasks = false; - await this.GenerateProjectTasks(); - } - private void SaveTask() - { - this.enableProjectDetailsDialog = false; - this.TasksValue = string.Empty; - this.TextBoxValue = string.Empty; - this.isGeneratedProjectTasks = false; - StateHasChanged(); - } - private void CloseDialog() - { - this.enableProjectDetailsDialog = false; - this.TasksValue = string.Empty; - this.TextBoxValue = string.Empty; - this.isGeneratedProjectTasks = false; - StateHasChanged(); - } - public void TaskEditingHandler(Syncfusion.Blazor.Grids.ActionEventArgs args) - { - if (args.RequestType.ToString() == "Add") - { - enableTaskEditing = true; - } - else - { - enableTaskEditing = false; - } - } - public void RowCreatedHandler(RowCreatedEventArgs args) - { - args.Data.Status = "Open"; - args.Data.Color = "#000000"; - } + BacklogButtonViewContent = "View as Backlog"; + showBacklogBoard = true; + } + else + { + showBacklogBoard = false; + BacklogButtonViewContent = "View as Board"; } } - ``` +## Sample Code + +A complete working example is available in the [Syncfusion Blazor AI Samples GitHub repository](https://github.com/syncfusion/smart-ai-samples). + +![Kanban AI Assistant - Output](../../ai/images/smart-task-suggestion.png) + ## Error Handling and Troubleshooting If the AI service fails to return a valid response, the Kanban will display an error message ("Oops! Please try again!"). Common issues include: @@ -573,12 +446,3 @@ If the AI service fails to return a valid response, the Kanban will display an e - **Network Issues**: Check connectivity to the AI service endpoint, especially for self-hosted Ollama instances. - **Large Prompts**: Processing large text inputs may cause timeouts. Consider reducing the prompt size or optimizing the request for efficiency. -## Performance Considerations - -When handling large text content, ensure the Ollama server has sufficient resources (CPU/GPU) to process requests efficiently. For long-form content or batch operations, consider splitting the input into smaller segments to avoid performance bottlenecks. Test the application with your specific use case to determine optimal performance. - -## Sample Code - -A complete working example is available in the [Syncfusion Blazor AI Samples GitHub repository](https://github.com/syncfusion/smart-ai-samples). - -![Kanban AI Assistant - Output](../../ai/images/smart-task-suggestion.png) \ No newline at end of file diff --git a/blazor/smart-ai-solutions/ai-samples/rich-text-editor/writting-assistance.md b/blazor/smart-ai-solutions/ai-samples/rich-text-editor/writting-assistance.md index 3074d17360..f6c75df29c 100644 --- a/blazor/smart-ai-solutions/ai-samples/rich-text-editor/writting-assistance.md +++ b/blazor/smart-ai-solutions/ai-samples/rich-text-editor/writting-assistance.md @@ -228,432 +228,376 @@ await builder.Build().RunAsync(); {% endhighlight %} {% endtabs %} -## Razor Component +## AI-powered Rich Text Editor in Blazor -This section implements the Syncfusion Blazor Rich Text Editor with AI-powered content assistance features such as rephrase, correct grammar, summarize, elaborate, and translate. +This guide explains how to integrate a full-featured AI writing assistant into the Blazor Rich Text Editor using Azure OpenAI (via Semantic Kernel). The implementation supports **Rephrase**, **Correct Grammar**, **Summarize**, **Elaborate**, and **Translate** with live preview, dynamic tone and language controls, skeleton loading, and safe content replacement with undo support. -(`Home.razor`) +### How the Custom Toolbar is Rendered -```csharp -@inject AzureAIService semanticKernelAI -@inject IJSRuntime JSRuntime -@using AISamples.Components.Service -@using Syncfusion.Blazor.RichTextEditor -@using Syncfusion.Blazor.SplitButtons -@using Syncfusion.Blazor.Buttons -@using Syncfusion.Blazor.Popups -@using Syncfusion.Blazor.Notifications -@using Syncfusion.Blazor.DropDowns - -
    - - - - - - - - - - - - - -
    -
    - - -
    AI Assistant
    - -
    -
    -
    - - +The toolbar uses [RichTextEditorCustomToolbarItems](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.RichTextEditor.RichTextEditorCustomToolbarItems.html) to inject a custom item named AI. + +Inside the template, an `SfDropDownButton` is rendered with: + +- **Icon**: AI icon (e-icons e-ai-chat) +- **Dropdown Items**: Rephrase, Grammar, Summarize, Elaborate, Translate +- **Event Binding**: ItemSelected="AIQuerySelectedMenu" triggers the AI workflow when an option is selected. + +An additional `SfButton` for **Rephrase** is provided for quick access. + +{% tabs %} +{% highlight razor %} + + + + + + + + + + + + +{% endhighlight %} +{% endtabs %} + +### AI Assistant Dialog – Layout and Dynamic Controls + +The AI Assistant dialog provides a responsive, user-friendly interface for interacting with AI-generated content. It is designed as a modal dialog that overlays the editor and ensures proper z-index stacking for seamless integration. + +#### Dialog Structure + +The dialog is divided into two main rows: + +**Row 1:** Action Selection and Dynamic Controls + +- **Action Dropdown:** Allows users to switch between AI actions (Rephrase, Grammar, Summarize, Elaborate, Translate). +- **Dynamic Controls:** + - **Tone Chips** (Standard, Fluent, Professional) appear when the selected action is Rephrase. + - **Language Dropdown** (15+ languages) appears when the selected action is Translate. + +**Row 2:** Original Text vs AI Result + +- **Left Panel:** Displays the original selected text in a read-only Rich Text Editor. +- **Right Panel:** Shows AI-generated content in another Rich Text Editor. +- **Loading State:** While AI processes the request, a progressive skeleton loader animates from 100% to 10% width for visual feedback. +- **Fallback State:** If no result is returned, a “No results found” message with a warning icon is displayed. + +**Footer Actions** + +- **Regenerate:** Requests a new AI output for the same prompt. +- **Copy:** Copies the AI-generated content to the clipboard. +- **Replace:** Inserts the AI-generated content back into the original editor with undo support. + +{% tabs %} +{% highlight %} + + + + +
    + AI Assistant +
    + + + +
    +
    +
    + + + + + + +
    +
    + +
    + @if (this.enableRephraseChips) + { + + + + + + + + + + } + else if (this.enableLanguageList) + { +
    + Target Language +
    +
    + + - +
    -
    -
    - @if (this.enableRephraseChips) - { - - - - - - - - - } - else if (this.enableLanguageList) - { -
    - Target Language -
    -
    - - - - -
    - } -
    + }
    -
    -
    -
    - - - -
    +
    + +
    +
    +
    + + + +
    - @if (!isContentGenerating) +
    + + @if (!isContentGenerating) + { + @if (noResultsFound) { - @if (noResultsFound) - { -
    -
    -
    - -
    No results found
    -
    -
    -
    - } - else { -
    -
    - - - + +
    +
    +
    + +
    No results found
    - } - } else { +
    + } + else {
    -
    -
    -
    -
    -
    -
    - -
    + + + +
    } -
    - - -
    -
    + } else { +
    - Regenerate +
    + +
    +
    +
    +
    +
    + +
    -
    - @if (!string.IsNullOrEmpty(sentiment)) { - - } - Copy - Replace + } +
    + + + +
    +
    +
    + + Regenerate
    - - - - -
    - - - +
    + @if (!string.IsNullOrEmpty(sentiment)) { + + } + + Copy + Replace +
    +
    + + + + + +{% endhighlight %} +{% endtabs %} + +### Opening the AI Dialog and Preserving Selection + +The `DialogueOpen()` method opens the AI dialog when an action is selected and prepares the editor for processing. It first uses `GetSelectedHtmlAsync()` to capture the highlighted content with its formatting. If no text is selected, a toast message alerts the user to select content before proceeding. + +When valid text is found, the method makes the dialog visible, stores the selected HTML for AI processing, and calls `SaveSelectionAsync()` to preserve the cursor position so the AI output can replace only the selected text later. It then refreshes the dialog’s editor and updates AI suggestions based on the chosen action. + + +```csharp +private async Task Rephrase() +{ + // Directly open dialog for Rephrase action + await DialogueOpen("Rephrase"); +} +private async Task AIQuerySelectedMenu(MenuEventArgs args) +{ + // Open dialog based on selected dropdown item + await DialogueOpen(args.Item.Text); +} +private async Task DialogueOpen(string selectedQuery) +{ + // Get the selected text from the RichTextEditor + var selectionText = await rteObj.GetSelectedHtmlAsync(); + + if (!string.IsNullOrEmpty(selectionText)) + { + // Make the dialog visible + dialogVisible = true; + + // Identify the selected query and map it to its ID + + dropVal = QueryList.FirstOrDefault(q => q.Text.Equals(selectedQuery, StringComparison.OrdinalIgnoreCase))?.ID; + + // Store the selected text for AI processing + promptQuery = selectionText; + + // Save the current selection so AI output can be inserted later + await this.rteObj.SaveSelectionAsync(); + + // Refresh the left-side RichTextEditor in the dialog to show original text + await this.leftRteChildObj.RefreshUIAsync(); + + // Update AI suggestions based on the selected query + await UpdateAISuggestionsData(selectedQuery); + } + else + { + // Show a toast notification if no text is selected + await this.ToastObj.ShowAsync(new ToastModel { ContentTemplate = @GetTemplate(true), ShowCloseButton = true, Timeout = 0 }); + } +} ``` -`Home.razor.cs` +### Building and Sending the AI + +The AI prompt is built in two parts: **user intent** and **system instruction**. + +1. **User Intent (subQuery)** - Defines what the AI should do, such as summarizing, rephrasing with a specific tone, or translating into a target language. This makes the prompt context-aware and action-specific. + +2. **System Instruction (HTML preservation)** - Enforces formatting rules, for example: “Retain existing HTML structure. Modify content only.” This ensures that the AI preserves elements like bold text, lists, and links while updating the content. + +Both parts are combined and sent to `semanticKernelAI.GetCompletionAsync()` via Semantic Kernel, resulting in an AI-generated output that is accurate and safe to insert back into the editor. ```csharp -using Markdig; -using Microsoft.AspNetCore.Components; -using Microsoft.JSInterop; -using Syncfusion.Blazor.DropDowns; -using Syncfusion.Blazor.Inputs; -using Syncfusion.Blazor.Notifications; -using Syncfusion.Blazor.RichTextEditor; -using Syncfusion.Blazor.SplitButtons; - -namespace AISamples.Components.Pages + +private async Task UpdateAISuggestionsData(string selectedQuery) { - public partial class Home + enableRephraseChips = false; + enableLanguageList = false; + isSentimentCheck = false; + switch (selectedQuery) { - SfToast ToastObj; - private string ToastTarget { get; set; } = "#scroll-restricted"; - SfRichTextEditor rteObj; - SfRichTextEditor leftRteChildObj; - SfRichTextEditor rightRteChildObj; - private string Value { get; set; } = "
    Integrate AI with the Editor

    Integrate the AI assistant into the rich text editor by capturing the content from the editor, sending it to the AI service, and displaying the results or suggestions back in the editor.

    Summarize

    This function condenses the selected content into a brief summary, capturing the main points succinctly.

    Elaborate

    This function expands the selected content, adding additional details and context.

    Rephrase

    This function rewrites the selected content to convey the same meaning using different words or structures. It also enables rephrase options and disables language selection.

    Correct Grammar

    This function reviews and corrects the grammar of the selected content, ensuring it adheres to standard grammatical rules.

    Translate

    This function translates the selected content into the specified language, enabling language selection and disabling rephrase options.

    "; - private bool dialogVisible { get; set; } - private bool enabelAIAssitantButton { get; set; } = false; - private bool enabelRegenerateContentButton { get; set; } = false; - private bool enabelContentButton { get; set; } = true; - private string promptQuery = string.Empty; - private string subQuery = string.Empty; - private string[] chipValue = new[] { "Standard" }; - private string translatelanguage = "EN"; - private string dropVal { get; set; } = "Rephrase"; - private bool enableRephraseChips { get; set; } = true; - private bool enableLanguageList { get; set; } = false; - private bool noResultsFound { get; set; } = false; - public bool isContentGenerating { get; set; } = true; - private string AIResult { get; set; } = string.Empty; - private bool isSentimentCheck { get; set; } = false; - private MarkdownPipeline pipeline { get; set; } = new MarkdownPipelineBuilder().UseAdvancedExtensions().Build(); - private string sentiment = ""; - private string apiResultData = ""; - private string ButtonClass = "e-tbar-btn"; - private void UpdateStatus(Syncfusion.Blazor.RichTextEditor.ChangeEventArgs args) - { - Value = args.Value; - enabelAIAssitantButton = string.IsNullOrWhiteSpace(Value); - } - private void OnActionCompleteHandler(Syncfusion.Blazor.RichTextEditor.ActionCompleteEventArgs args) - { - if (args.RequestType == "SourceCode") - { - this.ButtonClass = "e-tbar-btn e-overlay"; - } - if (args.RequestType == "Preview") - { - this.ButtonClass = "e-tbar-btn"; - } - } - private void UpdateTextAreaStatus(InputEventArgs args) - { - Value = args.Value; - enabelRegenerateContentButton = string.IsNullOrWhiteSpace(Value); - } - private async Task AIQuerySelectedMenu(MenuEventArgs args) - { - await DialogueOpen(args.Item.Text); - } - private async Task Rephrase() - { - await DialogueOpen("Rephrase"); - } - private async Task DialogueOpen(string selectedQuery) - { - var selectionText = await rteObj.GetSelectedHtmlAsync(); - if (!string.IsNullOrEmpty(selectionText)) - { - dialogVisible = true; - dropVal = QueryList.FirstOrDefault(q => q.Text.Equals(selectedQuery, StringComparison.OrdinalIgnoreCase))?.ID; - promptQuery = selectionText; - await this.rteObj.SaveSelectionAsync(); - await this.leftRteChildObj.RefreshUIAsync(); - await UpdateAISuggestionsData(selectedQuery); - } - else - { - await this.ToastObj.ShowAsync(new ToastModel { ContentTemplate = @GetTemplate(true), ShowCloseButton = true, Timeout = 0 }); - } - } - private async Task SelectedChipsChanged(Syncfusion.Blazor.Buttons.SelectionChangedEventArgs args) - { - if (chipValue.Length == 0 && args != null && args.RemovedItems.Length > 0) - { - chipValue = new [] { args.RemovedItems[0] }; - } - await UpdateAISuggestionsData("Rephrase"); - } - private async Task AITranslateDropdownList(ChangeEventArgs args) - { - await UpdateAISuggestionsData("Translate"); - } - private async Task AIQuerySelectedDropdownList(ChangeEventArgs args) - { - if (!string.IsNullOrEmpty(dropVal)) - { - chipValue = new[] { "Standard" }; - translatelanguage = "EN"; - var selectedQuery = QueryList.FirstOrDefault(q => q.ID.Equals(dropVal, StringComparison.OrdinalIgnoreCase))?.Text; - await UpdateAISuggestionsData(selectedQuery); - } - } - private async Task UpdateAISuggestionsData(string selectedQuery) - { - enableRephraseChips = false; - enableLanguageList = false; - isSentimentCheck = false; - switch (selectedQuery) - { - case "Summarize": - subQuery = "Briefly summarize the following text in a short and concise manner."; - break; - case "Elaborate": - subQuery = "Elaborate/Expand on the following text, providing more detail and context."; - break; - case "Rephrase": - enableRephraseChips = true; - enableLanguageList = false; - subQuery = $"Rephrase the following text in a {chipValue[0]} [tone/style], ensuring clarity and maintaining the original meaning."; - break; - case "Correct Grammar": - subQuery = "Correct any grammatical errors in the following text, ensuring it is clear and well-structured."; - break; - case "Translate": - enableLanguageList = true; - enableRephraseChips = false; - subQuery = $"Translate the following text into {translatelanguage}, preserving the original meaning and tone."; - break; - } - UpdateAISuggestionsData(); - } - private async Task RegenerateContent() - { - UpdateAISuggestionsData(); - } - private async Task ReplaceContent() - { - ExecuteCommandOption executeCommandOption = new ExecuteCommandOption(); - executeCommandOption.Undo = true; - await this.rteObj.RestoreSelectionAsync(); - await this.rteObj.ExecuteCommandAsync(CommandName.InsertHTML, this.apiResultData, executeCommandOption); - await CloseDialog(); - } - private async Task CopyContent() - { - await JSRuntime.InvokeVoidAsync("copyToClipboard", Markdig.Markdown.ToPlainText(AIResult, pipeline)); - } - private async Task CloseDialog() - { - dialogVisible = false; - promptQuery = string.Empty; - AIResult = string.Empty; - chipValue = new[] { "Standard" }; - dropVal = "Query1"; + case "Summarize": + subQuery = "Briefly summarize the following text in a short and concise manner."; + break; + case "Elaborate": + subQuery = "Elaborate/Expand on the following text, providing more detail and context."; + break; + case "Rephrase": enableRephraseChips = true; enableLanguageList = false; - sentiment = ""; - apiResultData = ""; - } - private async Task UpdateAISuggestionsData() + subQuery = $"Rephrase the following text in a {chipValue[0]} [tone/style], ensuring clarity and maintaining the original meaning."; + break; + case "Correct Grammar": + subQuery = "Correct any grammatical errors in the following text, ensuring it is clear and well-structured."; + break; + case "Translate": + enableLanguageList = true; + enableRephraseChips = false; + subQuery = $"Translate the following text into {translatelanguage}, preserving the original meaning and tone."; + break; + } + UpdateAISuggestionsData(); +} + +private async Task UpdateAISuggestionsData() +{ + try + { + if (!string.IsNullOrEmpty(promptQuery)) { - try - { - if (!string.IsNullOrEmpty(promptQuery)) - { - enabelRegenerateContentButton = isContentGenerating = enabelContentButton = true; - string systemPrompt = subQuery.Contains("emoji followed by the sentiment in the format") ? "You are a helpful assistant. Please respond in string format." : "NOTE:Please retain the existing HTML structure and modify the content only. Ensure that the response adheres to the specified formatting."; - apiResultData = await semanticKernelAI.GetCompletionAsync(promptQuery, false, false, (subQuery + systemPrompt)); - if (apiResultData != null) - { - isContentGenerating = false; - sentiment = isSentimentCheck ? apiResultData.Replace("\"", "").Replace("'", "") : ""; - AIResult = isSentimentCheck ? promptQuery : apiResultData; - noResultsFound = string.IsNullOrEmpty(AIResult) || string.IsNullOrEmpty(promptQuery); - enabelRegenerateContentButton = enabelContentButton = noResultsFound; - await InvokeAsync(StateHasChanged); - } - else - { - isContentGenerating = false; - await InvokeAsync(StateHasChanged); - } - } - } - catch - { - await this.ToastObj.ShowAsync(new ToastModel { ContentTemplate = @GetTemplate(), ShowCloseButton = true, Timeout = 0 }); - } - } - private RenderFragment GetTemplate(bool hasTextSelection = false) => builder => - { - builder.OpenElement(0, "div"); - builder.AddContent(1, hasTextSelection ? "Please select the content to perform the AI operation." : "An error occurred during the AI process, Please try again."); - builder.CloseElement(); - }; - public class SubQuery + enabelRegenerateContentButton = isContentGenerating = enabelContentButton = true; + string systemPrompt = subQuery.Contains("emoji followed by the sentiment in the format") ? "You are a helpful assistant. Please respond in string format." : "NOTE:Please retain the existing HTML structure and modify the content only. Ensure that the response adheres to the specified formatting."; + apiResultData = await semanticKernelAI.GetCompletionAsync(promptQuery, false, false, (subQuery + systemPrompt)); + if (apiResultData != null) { - public string ID { get; set; } - public string Text { get; set; } + isContentGenerating = false; + sentiment = isSentimentCheck ? apiResultData.Replace("\"", "").Replace("'", "") : ""; + AIResult = isSentimentCheck ? promptQuery : apiResultData; + noResultsFound = string.IsNullOrEmpty(AIResult) || string.IsNullOrEmpty(promptQuery); + enabelRegenerateContentButton = enabelContentButton = noResultsFound; + await InvokeAsync(StateHasChanged); } - public class Languages + else { - public string ID { get; set; } - public string Text { get; set; } + isContentGenerating = false; + await InvokeAsync(StateHasChanged); } - public List QueryList = new List - { - new SubQuery { ID = "Rephrase", Text = "Rephrase" }, - new SubQuery { ID = "Grammar", Text = "Correct Grammar" }, - new SubQuery { ID = "Summarize", Text = "Summarize" }, - new SubQuery { ID = "Elaborate", Text = "Elaborate" }, - new SubQuery { ID = "Translate", Text = "Translate" } - }; - public List LanguageList = new List - { - new Languages { ID = "EN", Text = "English" }, - new Languages { ID = "ZH", Text = "Chinese (Simplified)" }, - new Languages { ID = "ZHT", Text = "Chinese (Traditional)" }, - new Languages { ID = "ES", Text = "Spanish" }, - new Languages { ID = "HI", Text = "Hindi" }, - new Languages { ID = "AR", Text = "Arabic" }, - new Languages { ID = "BN", Text = "Bengali" }, - new Languages { ID = "PT", Text = "Portuguese" }, - new Languages { ID = "RU", Text = "Russian" }, - new Languages { ID = "JA", Text = "Japanese" }, - new Languages { ID = "DE", Text = "German" }, - new Languages { ID = "KO", Text = "Korean" }, - new Languages { ID = "FR", Text = "French" }, - new Languages { ID = "IT", Text = "Italian" }, - new Languages { ID = "TR", Text = "Turkish" } - }; - private List Tools = new List() - { - new ToolbarItemModel() { Name = "AIAssistant", TooltipText = "AI Assistant" }, - new ToolbarItemModel() { Name = "Rephrase", TooltipText = "Rephrase" }, - new ToolbarItemModel() { Command = ToolbarCommand.Bold }, - new ToolbarItemModel() { Command = ToolbarCommand.Italic }, - new ToolbarItemModel() { Command = ToolbarCommand.Underline }, - new ToolbarItemModel() { Command = ToolbarCommand.Separator }, - new ToolbarItemModel() { Command = ToolbarCommand.FontName }, - new ToolbarItemModel() { Command = ToolbarCommand.FontSize }, - new ToolbarItemModel() { Command = ToolbarCommand.FontColor }, - new ToolbarItemModel() { Command = ToolbarCommand.Separator }, - new ToolbarItemModel() { Command = ToolbarCommand.BackgroundColor }, - new ToolbarItemModel() { Command = ToolbarCommand.Formats }, - new ToolbarItemModel() { Command = ToolbarCommand.Alignments }, - new ToolbarItemModel() { Command = ToolbarCommand.Separator }, - new ToolbarItemModel() { Command = ToolbarCommand.NumberFormatList }, - new ToolbarItemModel() { Command = ToolbarCommand.BulletFormatList }, - new ToolbarItemModel() { Command = ToolbarCommand.CreateLink }, - new ToolbarItemModel() { Command = ToolbarCommand.Image }, - new ToolbarItemModel() { Command = ToolbarCommand.Separator }, - new ToolbarItemModel() { Command = ToolbarCommand.CreateTable }, - new ToolbarItemModel() { Command = ToolbarCommand.SourceCode }, - new ToolbarItemModel() { Command = ToolbarCommand.Undo }, - new ToolbarItemModel() { Command = ToolbarCommand.Redo }, - }; + } + } + catch + { + await this.ToastObj.ShowAsync(new ToastModel { ContentTemplate = @GetTemplate(), ShowCloseButton = true, Timeout = 0 }); } } + +``` + +### Replacing AI Result Back into the Editor (with Undo Support) + +Once the AI-generated content is ready, it needs to be inserted exactly where the user originally selected text, without disturbing the rest of the document. This is achieved using the [ExecuteCommandAsync](https://help.syncfusion.com/cr/blazor/Syncfusion.Blazor.RichTextEditor.SfRichTextEditor.html#Syncfusion_Blazor_RichTextEditor_SfRichTextEditor_ExecuteCommandAsync_Syncfusion_Blazor_RichTextEditor_CommandName_System_String_Syncfusion_Blazor_RichTextEditor_ExecuteCommandOption_) method with the `InsertHTML` command. The `Undo` option is enabled to allow users to revert changes if needed. + +Additionally, users can copy the AI-generated content to the clipboard for use elsewhere. This is handled via a `JavaScript interop` function that copies plain text extracted from the AI result. + +{% tabs %} +{% highlight %} + + + Copy + Replace + + +{% endhighlight %} +{% endtabs %} + +```csharp + +private async Task ReplaceContent() +{ + ExecuteCommandOption executeCommandOption = new ExecuteCommandOption(); + executeCommandOption.Undo = true; + await this.rteObj.RestoreSelectionAsync(); // Return to original selection + await this.rteObj.ExecuteCommandAsync(CommandName.InsertHTML, this.apiResultData, executeCommandOption); + await CloseDialog(); +} +private async Task CopyContent() +{ + await JSRuntime.InvokeVoidAsync("copyToClipboard", Markdig.Markdown.ToPlainText(AIResult, pipeline)); +} + +``` + -``` +## Workflow Summary + +Select text → Choose AI action → Dialog opens → AI processes → Updated content displayed → User copies or replaces content. + +## Sample Code + +A complete working example is available in the [Syncfusion Blazor AI Samples GitHub repository](https://github.com/syncfusion/smart-ai-samples). + +![Rich Text Editor AI Assistant - Output](../../ai/images/richtexteditor-ai-assistant.png) ## Error Handling and Troubleshooting @@ -695,13 +647,3 @@ If the AI service fails to return a valid response, the Rich Text Editor will di - **Model Unavailable**: Ensure the specified `openAIModel`, `azureOpenAIModel`, or `ModelName` is deployed and supported. - **Network Issues**: Check connectivity to the AI service endpoint, especially for self-hosted Ollama instances. - **Large Prompts**: Processing large text inputs may cause timeouts. Consider reducing the prompt size or optimizing the request for efficiency. - -## Performance Considerations - -When handling large text content, ensure the Ollama server has sufficient resources (CPU/GPU) to process requests efficiently. For long-form content or batch operations, consider splitting the input into smaller segments to avoid performance bottlenecks. Test the application with your specific use case to determine optimal performance. - -## Sample Code - -A complete working example is available in the [Syncfusion Blazor AI Samples GitHub repository](https://github.com/syncfusion/smart-ai-samples). - -![Rich Text Editor AI Assistant - Output](../../ai/images/richtexteditor-ai-assistant.png) \ No newline at end of file diff --git a/blazor/visual-studio-code-integration/create-project.md b/blazor/visual-studio-code-integration/create-project.md index 91a06d0173..0fe9fd5a5b 100644 --- a/blazor/visual-studio-code-integration/create-project.md +++ b/blazor/visual-studio-code-integration/create-project.md @@ -29,8 +29,8 @@ Use the following steps to create Syncfusion®® Blazor Application Type | | ---------------- | -------------------------------------------- | - | [.NET 9.0](https://dotnet.microsoft.com/en-us/download/dotnet/9.0), [.NET 8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) | Syncfusion® Blazor Web App | - | [.NET 9.0](https://dotnet.microsoft.com/en-us/download/dotnet/9.0), [.NET 8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) | Syncfusion® Blazor WebAssembly App | + | [.NET 10.0](https://dotnet.microsoft.com/en-us/download/dotnet/10.0), [.NET 9.0](https://dotnet.microsoft.com/en-us/download/dotnet/9.0), [.NET 8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) | Syncfusion® Blazor Web App | + | [.NET 10.0](https://dotnet.microsoft.com/en-us/download/dotnet/10.0), [.NET 9.0](https://dotnet.microsoft.com/en-us/download/dotnet/9.0), [.NET 8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) | Syncfusion® Blazor WebAssembly App | In the **Syncfusion® Blazor Web App** application type, the following options are available: @@ -79,7 +79,7 @@ Use the following steps to create Syncfusion®® Blazor application type, the following authentication options are supported: @@ -150,3 +150,5 @@ The Syncfusion Blazor Calendar, Button, and DataGrid component render code is ad | `~/Pages/Home.razor or Index.razor` | ![Index page updated with Syncfusion components](images/IndexFileChange.png) | | `~/Pages/Counter.razor` | ![Counter page updated with Syncfusion components](images/CounterPageChange.png) | | `~/Pages/FetchData.razor` | ![FetchData page updated with Syncfusion DataGrid](images/FetchDataPageChange.png) | + + diff --git a/blazor/visual-studio-code-integration/download-and-installation.md b/blazor/visual-studio-code-integration/download-and-installation.md index 14f1be6e17..7d16253e56 100644 --- a/blazor/visual-studio-code-integration/download-and-installation.md +++ b/blazor/visual-studio-code-integration/download-and-installation.md @@ -17,7 +17,7 @@ Install the following prerequisites to install the Syncfusion® publishes the Visual Studio extension in the Visual Studio Marketplace. Install it directly from Visual Studio or download and install it from the Visual Studio Marketplace. -[Download the Visual Studio 2022 extension](https://marketplace.visualstudio.com/items?itemName=SyncfusionInc.BlazorVSExtension) +[Download the Visual Studio 2026 extension](https://marketplace.visualstudio.com/items?itemName=SyncfusionInc.BlazorVSExtension) ## Prerequisites The following software is required to install the Syncfusion® Blazor extension and to create projects, add snippets, convert, and upgrade Syncfusion® Blazor applications. -* [Visual Studio 2022](https://visualstudio.microsoft.com/downloads/). +* [Visual Studio 2026](https://visualstudio.microsoft.com/downloads/). + +* [.NET 10.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet). * [.NET 9.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet). @@ -28,7 +30,7 @@ The following software is required to install the Syncfusion® Blazor extension from **Manage Extensions** in Visual Studio. -1. Open Visual Studio 2022. +1. Open Visual Studio 2026. 2. Navigate to **Extensions -> Manage Extensions** to open the Manage Extensions window. @@ -56,7 +58,7 @@ The following steps illustrate how to download and install the Syncfusion® Blazor extension from the Visual Studio Marketplace. - [Download the Visual Studio 2022 extension](https://marketplace.visualstudio.com/items?itemName=SyncfusionInc.BlazorVSExtension) + [Download the Visual Studio 2026 extension](https://marketplace.visualstudio.com/items?itemName=SyncfusionInc.BlazorVSExtension) 2. Close all Visual Studio instances running, if any. @@ -68,4 +70,5 @@ The following steps illustrate how to download and install the Syncfusion® extensions are available under the **Extensions** menu. - ![SyncfusionMenu](images/SyncfusionMenu.png) \ No newline at end of file + + ![SyncfusionMenu](images/SyncfusionMenu.png) diff --git a/blazor/visual-studio-integration/overview.md b/blazor/visual-studio-integration/overview.md index 188cfecab2..d66e2d16e7 100644 --- a/blazor/visual-studio-integration/overview.md +++ b/blazor/visual-studio-integration/overview.md @@ -9,9 +9,9 @@ documentation: ug # Overview of Blazor extension for Visual Studio -The Syncfusion® Blazor extension for Visual Studio streamlines working with Syncfusion® Blazor components by configuring the required Syncfusion® NuGet packages and themes. Separate extensions are available for Visual Studio 2022. +The Syncfusion® Blazor extension for Visual Studio streamlines working with Syncfusion® Blazor components by configuring the required Syncfusion® NuGet packages and themes. Separate extensions are available for Visual Studio 2026. -[Download the Visual Studio 2022 extension](https://marketplace.visualstudio.com/items?itemName=SyncfusionInc.BlazorVSExtension) +[Download the Visual Studio 2026 extension](https://marketplace.visualstudio.com/items?itemName=SyncfusionInc.BlazorVSExtension) The Syncfusion® Blazor extension provides the following add-ins in Visual Studio: diff --git a/blazor/visual-studio-integration/template-studio.md b/blazor/visual-studio-integration/template-studio.md index a05fa0d82b..bc7b844fb9 100644 --- a/blazor/visual-studio-integration/template-studio.md +++ b/blazor/visual-studio-integration/template-studio.md @@ -1,7 +1,7 @@ --- layout: post title: Template Studio for Blazor | Syncfusion -description: Learn here about how to create a Blazor application using Syncfusion Blazor components with the Template Studio in Visual Studio 2022. Explore to more details. +description: Learn here about how to create a Blazor application using Syncfusion Blazor components with the Template Studio in Visual Studio 2026. Explore to more details. platform: Blazor control: Common documentation: ug @@ -11,13 +11,13 @@ documentation: ug Syncfusion® provides the Blazor Template Studio, which creates a Syncfusion® Blazor application preconfigured with the required Syncfusion® NuGet packages, namespaces, styles, and component render mode. The Template Studio offers an intuitive project wizard to guide creation of an application with Syncfusion® components. -The steps below will assist you to create your **Syncfusion Blazor Application** through **Visual Studio 2022**: +The steps below will assist you to create your **Syncfusion Blazor Application** through **Visual Studio 2026**: -> **Note:** The Syncfusion® Blazor extensions for Visual Studio 2022 are available only for Essential Studio® versions 20.3.0.56 and earlier. +> **Note:** The Syncfusion® Blazor extensions for Visual Studio 2026 are available only for Essential Studio® versions 20.3.0.56 and earlier. N> Before use the Syncfusion® Blazor Project Template, check whether the Syncfusion® Blazor Template Studio Extension installed or not in Visual Studio Extension Manager by clicking on the Extensions -> Manage Extensions -> Installed. If it is not installed, follow the steps in the [download and installation](https://blazor.syncfusion.com/documentation/visual-studio-integration/download-and-installation) topic. -1. Open Visual Studio 2022. +1. Open Visual Studio 2026. 2. To create a Syncfusion® Blazor application, use either one of the following options: @@ -47,8 +47,8 @@ N> Before use the Syncfusion® Blazor Project Template, check whether the Syncfu | .NET SDK version | Supported Syncfusion® Blazor application type | | ---------------- | -------------------------------------------- | - | [.NET 9.0](https://dotnet.microsoft.com/en-us/download/dotnet/9.0), [.NET 8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) | Syncfusion® Blazor Web App | - | [.NET 9.0](https://dotnet.microsoft.com/en-us/download/dotnet/9.0), [.NET 8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) | Syncfusion® Blazor WebAssembly App | + | [.NET 10.0](https://dotnet.microsoft.com/en-us/download/dotnet/10.0), [.NET 9.0](https://dotnet.microsoft.com/en-us/download/dotnet/9.0), [.NET 8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) | Syncfusion® Blazor Web App | + | [.NET 10.0](https://dotnet.microsoft.com/en-us/download/dotnet/10.0), [.NET 9.0](https://dotnet.microsoft.com/en-us/download/dotnet/9.0), [.NET 8.0](https://dotnet.microsoft.com/en-us/download/dotnet/8.0) | Syncfusion® Blazor WebAssembly App | In the **Syncfusion® Blazor Web App** application type, you can configure the following options: @@ -98,7 +98,7 @@ N> Before use the Syncfusion® Blazor Project Template, check whether the Syncfu 6. Click **Next** or select the **Features** tab to review and choose features for the selected controls. -7. Click **Next** or select the **Configuration** tab. Configure the target .NET version (.NET 9.0 or .NET 8.0), theme, HTTPS configuration, localization, authentication type, and options specific to Blazor Web App or Blazor WebAssembly Application types. +7. Click **Next** or select the **Configuration** tab. Configure the target .NET version (.NET10.0, .NET 9.0 or .NET 8.0), theme, HTTPS configuration, localization, authentication type, and options specific to Blazor Web App or Blazor WebAssembly Application types. Depending on your Syncfusion® Blazor Application Type, refer to the table below for supported authentication types. @@ -402,3 +402,4 @@ Open a command prompt in your project directory and execute the following comman 2. Accept permission request of your application. ![Accept permission](images/microsoftauthentication.png) +