diff --git a/CODEOWNERS b/CODEOWNERS new file mode 100644 index 0000000..a88e69e --- /dev/null +++ b/CODEOWNERS @@ -0,0 +1 @@ +* @DevExpressExampleBot \ No newline at end of file diff --git a/CS/DevExpress.AI.Samples.Blazor.Editors/Components/AdditionalItems/ShakespeareAIContextMenuItem.cs b/CS/DevExpress.AI.Samples.Blazor.Editors/Components/AdditionalItems/ShakespeareAIContextMenuItem.cs new file mode 100644 index 0000000..6d84aab --- /dev/null +++ b/CS/DevExpress.AI.Samples.Blazor.Editors/Components/AdditionalItems/ShakespeareAIContextMenuItem.cs @@ -0,0 +1,17 @@ +using DevExpress.AIIntegration; +using DevExpress.AIIntegration.Blazor.RichEdit; +using DevExpress.AIIntegration.Extensions; +using Microsoft.AspNetCore.Components; + +namespace DevExpress.AI.Samples.Blazor.Editors.Components.AdditionalItems { + public class ShakespeareAIContextMenuItem : BaseAIContextMenuItem { + [Inject] IAIExtensionsContainer? aIExtensionsContainer { get; set; } + + protected override string DefaultItemText => "Rewrite like Shakespeare"; + + protected override Task GetCommandTextResult(string text) { + var customExtension = aIExtensionsContainer.CreateCustomPromptExtension(); + return customExtension.ExecuteAsync(new CustomPromptRequest("Rewrite the following text in William Shakespeare style.", text)); + } + } +} \ No newline at end of file diff --git a/CS/DevExpress.AI.Samples.Blazor.Editors/Components/AdditionalItems/ShakespeareAIToolbarItem.cs b/CS/DevExpress.AI.Samples.Blazor.Editors/Components/AdditionalItems/ShakespeareAIToolbarItem.cs new file mode 100644 index 0000000..de93d97 --- /dev/null +++ b/CS/DevExpress.AI.Samples.Blazor.Editors/Components/AdditionalItems/ShakespeareAIToolbarItem.cs @@ -0,0 +1,17 @@ +using DevExpress.AIIntegration; +using DevExpress.AIIntegration.Blazor.HtmlEditor; +using DevExpress.AIIntegration.Extensions; +using Microsoft.AspNetCore.Components; + +namespace DevExpress.AI.Samples.Blazor.Editors.Components.AdditionalItems { + public class ShakespeareAIToolbarItem: BaseAIToolbarItem { + [Inject] IAIExtensionsContainer? aIExtensionsContainer { get; set; } + + protected override string DefaultItemText => "Rewrite like Shakespeare"; + + protected override Task GetCommandTextResult(string text) { + var customExtension = aIExtensionsContainer.CreateCustomPromptExtension(); + return customExtension.ExecuteAsync(new CustomPromptRequest("Rewrite the following text in William Shakespeare style.", text)); + } + } +} \ No newline at end of file diff --git a/CS/DevExpress.AI.Samples.Blazor.Editors/Components/App.razor b/CS/DevExpress.AI.Samples.Blazor.Editors/Components/App.razor index bd5fbc0..ef1a08c 100644 --- a/CS/DevExpress.AI.Samples.Blazor.Editors/Components/App.razor +++ b/CS/DevExpress.AI.Samples.Blazor.Editors/Components/App.razor @@ -12,8 +12,8 @@ - - + + - + \ No newline at end of file diff --git a/CS/DevExpress.AI.Samples.Blazor.Editors/Components/Pages/HtmlEditor.razor b/CS/DevExpress.AI.Samples.Blazor.Editors/Components/Pages/HtmlEditor.razor index 70f62e5..9b27a61 100644 --- a/CS/DevExpress.AI.Samples.Blazor.Editors/Components/Pages/HtmlEditor.razor +++ b/CS/DevExpress.AI.Samples.Blazor.Editors/Components/Pages/HtmlEditor.razor @@ -1,73 +1,74 @@ -@page "/htmleditor" -@using DevExpress.AIIntegration.Blazor.HtmlEditor -@using System.Reflection - - - - - - - - - - - - - - - -@code { - public string Value { get; set; } = @"

- HTML Editor -


-

The HTML Editor component for Blazor is a WYSIWYG (what you see is what you get) text editor that allows users to format text and add graphics. The document can use HTML or Markdown format.

-

Supported features:

-
    -
  • Inline formats: -
      -
    • Bold, italic, strikethrough text formatting
    • -
    • Font, size, color changes (HTML only)
    • -
    -
  • -
  • Block formats: -
      -
    • Headings
    • -
    • Text alignment
    • -
    • Lists (bullet and numbered)
    • -
    • Code blocks
    • -
    • Quotes
    • -
    -
  • -
  • HTML and Markdown support
  • -
  • Variable support: produce documents based on templates
  • -
  • Toolbar with adaptive layout support
  • -
  • Insert images: specify a URL or upload from the local file system
  • -
  • Table support
  • -
-

Supported browsers: - - - - - - - - - - - - - - - - - - - - - - - -
Google Chrome (including Android)Latest
Apple Safari (including iOS)Latest
Mozilla FirefoxLatest
Microsoft EdgeLatest
Microsoft Edge LegacyNot supported
-
"; +@page "/htmleditor" +@using DevExpress.AI.Samples.Blazor.Editors.Components.AdditionalItems +@using DevExpress.AIIntegration.Blazor.HtmlEditor + + + + + + + + + + + + + + + + +@code { +public string Value { get; set; } = @"

+ HTML Editor +


+

The HTML Editor component for Blazor is a WYSIWYG (what you see is what you get) text editor that allows users to format text and add graphics. The document can use HTML or Markdown format.

+

Supported features:

+
    +
  • Inline formats: +
      +
    • Bold, italic, strikethrough text formatting
    • +
    • Font, size, color changes (HTML only)
    • +
    +
  • +
  • Block formats: +
      +
    • Headings
    • +
    • Text alignment
    • +
    • Lists (bullet and numbered)
    • +
    • Code blocks
    • +
    • Quotes
    • +
    +
  • +
  • HTML and Markdown support
  • +
  • Variable support: produce documents based on templates
  • +
  • Toolbar with adaptive layout support
  • +
  • Insert images: specify a URL or upload from the local file system
  • +
  • Table support
  • +
+

Supported browsers: + + + + + + + + + + + + + + + + + + + + + + + +
Google Chrome (including Android)Latest
Apple Safari (including iOS)Latest
Mozilla FirefoxLatest
Microsoft EdgeLatest
Microsoft Edge LegacyNot supported
+
"; } \ No newline at end of file diff --git a/CS/DevExpress.AI.Samples.Blazor.Editors/Components/Pages/RichEdit.razor b/CS/DevExpress.AI.Samples.Blazor.Editors/Components/Pages/RichEdit.razor index c2dc01e..a42413f 100644 --- a/CS/DevExpress.AI.Samples.Blazor.Editors/Components/Pages/RichEdit.razor +++ b/CS/DevExpress.AI.Samples.Blazor.Editors/Components/Pages/RichEdit.razor @@ -1,31 +1,36 @@ @page "/" @using DevExpress.AIIntegration.Blazor.RichEdit +@using DevExpress.AI.Samples.Blazor.Editors.Components.AdditionalItems @using DevExpress.Blazor.RichEdit @using System.Reflection - - - - - - - - - - - + + + + + + + + + + + + @code { const string DocumentResourceName = "DevExpress.AI.Samples.Blazor.Editors.Docs.Example.docx"; byte[] DocumentContent { get; set; } - protected override void OnInitialized() { - using(MemoryStream ms = new MemoryStream()) { + protected override void OnInitialized() + { + using (var ms = new MemoryStream()) + { var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(DocumentResourceName); - stream.CopyTo(ms); + stream?.CopyTo(ms); DocumentContent = ms.ToArray(); } + base.OnInitialized(); } } \ No newline at end of file diff --git a/CS/DevExpress.AI.Samples.Blazor.Editors/Components/_Imports.razor b/CS/DevExpress.AI.Samples.Blazor.Editors/Components/_Imports.razor index 916051e..dfc969d 100644 --- a/CS/DevExpress.AI.Samples.Blazor.Editors/Components/_Imports.razor +++ b/CS/DevExpress.AI.Samples.Blazor.Editors/Components/_Imports.razor @@ -9,4 +9,4 @@ @using DevExpress.AI.Samples.Blazor.Editors @using DevExpress.AI.Samples.Blazor.Editors.Components @using DevExpress.Blazor -@* @using DevExpress.AIIntegration.Blazor.Components.ChatUI.Models *@ \ No newline at end of file +@using DevExpress.Blazor.Office \ No newline at end of file diff --git a/CS/DevExpress.AI.Samples.Blazor.Editors/DevExpress.AI.Samples.Blazor.Editors.csproj b/CS/DevExpress.AI.Samples.Blazor.Editors/DevExpress.AI.Samples.Blazor.Editors.csproj index 3e43406..5f68c7c 100644 --- a/CS/DevExpress.AI.Samples.Blazor.Editors/DevExpress.AI.Samples.Blazor.Editors.csproj +++ b/CS/DevExpress.AI.Samples.Blazor.Editors/DevExpress.AI.Samples.Blazor.Editors.csproj @@ -6,19 +6,21 @@ enable - - + + - - + + - - - - + + + + + + diff --git a/CS/DevExpress.AI.Samples.Blazor.Editors/Program.cs b/CS/DevExpress.AI.Samples.Blazor.Editors/Program.cs index e5f6225..f5f9ecb 100644 --- a/CS/DevExpress.AI.Samples.Blazor.Editors/Program.cs +++ b/CS/DevExpress.AI.Samples.Blazor.Editors/Program.cs @@ -1,25 +1,25 @@ -using Azure.AI.OpenAI; -using Azure; +using Azure; +using Azure.AI.OpenAI; using DevExpress.AI.Samples.Blazor.Editors.Components; -using DevExpress.AIIntegration; +using Microsoft.Extensions.AI; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddRazorComponents() -.AddInteractiveServerComponents(); + .AddInteractiveServerComponents(); -string azureOpenAIEndpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT"); +string azureOpenAIEndpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT"); string azureOpenAIKey = Environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY"); +string deploymentName = string.Empty; + +IChatClient chatClient = new AzureOpenAIClient( + new Uri(azureOpenAIEndpoint), + new AzureKeyCredential(azureOpenAIKey)).AsChatClient(deploymentName); builder.Services.AddDevExpressBlazor(); -builder.Services.AddDevExpressAI((config) => { - var client = new AzureOpenAIClient( - new Uri(azureOpenAIEndpoint), - new AzureKeyCredential(azureOpenAIKey)); - config.RegisterChatClientOpenAIService(client, "gpt4o"); - config.RegisterOpenAIAssistants(client, "gpt4o"); -}); +builder.Services.AddChatClient(config => config.Use(chatClient)); +builder.Services.AddDevExpressAI(); var app = builder.Build(); // Configure the HTTP request pipeline. @@ -37,4 +37,4 @@ app.MapRazorComponents() .AddInteractiveServerRenderMode(); -app.Run(); +app.Run(); \ No newline at end of file diff --git a/README.md b/README.md index 99b4cc8..207fbf7 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -![](https://img.shields.io/endpoint?url=https://codecentral.devexpress.com/api/v1/VersionRange/851771053/24.2.1%2B) [![](https://img.shields.io/badge/Open_in_DevExpress_Support_Center-FF7200?style=flat-square&logo=DevExpress&logoColor=white)](https://supportcenter.devexpress.com/ticket/details/T1251646) [![](https://img.shields.io/badge/📖_How_to_use_DevExpress_Examples-e9f6fc?style=flat-square)](https://docs.devexpress.com/GeneralInformation/403183) [![](https://img.shields.io/badge/💬_Leave_Feedback-feecdd?style=flat-square)](#does-this-example-address-your-development-requirementsobjectives) @@ -10,85 +9,125 @@ This example enables AI-powered extensions for both the DevExpress Blazor Rich T ## Implementation Details -Both the DevExpress Blazor Rich Text Editor ([DxRichEdit](https://docs.devexpress.com/Blazor/DevExpress.Blazor.RichEdit.DxRichEdit)) and Blazor HTML Editor ([DxHtmlEditor](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxHtmlEditor)) ship with an `AdditionalSettings` property. You can populate this property with commands and allow users to process editor text as needs dictate. Available commands for both editors are as follows: +Both the DevExpress Blazor Rich Text Editor ([DxRichEdit](https://docs.devexpress.com/Blazor/DevExpress.Blazor.RichEdit.DxRichEdit)) and Blazor HTML Editor ([DxHtmlEditor](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxHtmlEditor)) ship with an `AdditionalItems` property. You can populate this property with commands and allow users to process editor text as needs dictate. Available commands for both editors are as follows: -* `CustomAISettings` allows user to process text according to a custom prompt. -* `ExpandAISettings` expands the text. -* `ExplainAISettings` explains the text. -* `ProofreadAISettings` proofreads the text. -* `RewriteAISettings` rewrite text using a specified style. -* `ShortenAISettings` shortens the text. -* `SummaryAISettings` summarizes the text. -* `ToneAISettings` rewrite text using a specified tone. -* `TranslateAISettings` translates the text into the specified language. +* **Ask AI Assistant** allows user to process text based on a custom prompt. +* **Change Style** rewrite text using a specified style. +* **Change Tone** rewrite text using a specified tone. +* **Describe Picture** generates the description for an image (for Rich Text Editor only). +* **Expand** expands text. +* **Explain** explains text. +* **Proofread** proofreads text. +* **Shorten** shortens text. +* **Summarize** summarizes text. +* **Translate** translates text into the specified language. ### Register AI Services +> [!NOTE] +> DevExpress AI-powered extensions follow the "bring your own key" principle. DevExpress does not offer a REST API and does not ship any built-in LLMs/SLMs. You need an active Azure/Open AI subscription to obtain the REST API endpoint, key, and model deployment name. These variables must be specified at application startup to register AI clients and enable DevExpress AI-powered Extensions in your application. + Add the following code to the _Program.cs_ file to register AI services in the application: ```cs -using DevExpress.AIIntegration; - +using Azure; +using Azure.AI.OpenAI; +using Microsoft.Extensions.AI; +... string azureOpenAIEndpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT"); string azureOpenAIKey = Environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY"); -... -builder.Services.AddDevExpressAI((config) => { - var client = new AzureOpenAIClient( - new Uri(azureOpenAIEndpoint), - new AzureKeyCredential(azureOpenAIKey)); - config.RegisterChatClientOpenAIService(client, "gpt4o"); - config.RegisterOpenAIAssistants(client, "gpt4o"); -}); +string deploymentName = string.Empty; + +IChatClient chatClient = new AzureOpenAIClient( + new Uri(azureOpenAIEndpoint), + new AzureKeyCredential(azureOpenAIKey)).AsChatClient(deploymentName); + +builder.Services.AddDevExpressBlazor(); +builder.Services.AddChatClient(config => config.Use(chatClient)); +builder.Services.AddDevExpressAI(); ``` -### Enable AI-powered extension for the DevExpress Rich Text Editor +### Enable AI-powered extension for the DevExpress Blazor Rich Text Editor + +AI-powered extension for our Blazor Rich Text Editor adds AI-related commands to the editor's context menu. + +You can add [predefined commands](https://docs.devexpress.com/Blazor/DevExpress.AIIntegration.Blazor.RichEdit?v=24.2) or implement custom commands as necessary. This example introduces a **Rewrite like Shakespeare** context menu item. + +```csharp +public class ShakespeareAIContextMenuItem : BaseAIContextMenuItem { + [Inject] IAIExtensionsContainer? aIExtensionsContainer { get; set; } -AI-powered extension for Rich Text Editor adds AI-related commands to the editor's context menu. + protected override string DefaultItemText => "Rewrite like Shakespeare"; -Declare DxRichEdit's `AdditionalSettings` and populate it with commands in the following manner: + protected override Task GetCommandTextResult(string text) { + var customExtension = aIExtensionsContainer.CreateCustomPromptExtension(); + return customExtension.ExecuteAsync(new CustomPromptRequest("Rewrite the following text in William Shakespeare style.", text)); + } +} +``` + +Declare DxRichEdit's [AdditionalItems](https://docs.devexpress.com/Blazor/DevExpress.Blazor.RichEdit.DxRichEdit.AdditionalItems?v=24.2) and populate it with commands in the following manner: ```razor @using DevExpress.AIIntegration.Blazor.RichEdit @using DevExpress.Blazor.RichEdit - - - - - - - - - - - + + + + + + + + + + + + ``` ![](richedit.png) -### Enable AI-powered extension for the DevExpress HTML Editor +### Enable AI-powered extension for the DevExpress Blazor HTML Editor + +The AI-powered extension for our Blazor HTML Editor adds AI-related commands to the editor's toolbar. + +You can add [predefined commands](https://docs.devexpress.com/Blazor/DevExpress.AIIntegration.Blazor.HtmlEditor?v=24.2) or implement custom commands as necessary. This example introduces a **Rewrite like Shakespeare** toolbar item. -The AI-powered extension for our HTML Editor adds AI-related commands to the editor's toolbar. +```csharp +public class ShakespeareAIToolbarItem: BaseAIToolbarItem { + [Inject] IAIExtensionsContainer? aIExtensionsContainer { get; set; } + + protected override string DefaultItemText => "Rewrite like Shakespeare"; + + protected override Task GetCommandTextResult(string text) { + var customExtension = aIExtensionsContainer.CreateCustomPromptExtension(); + return customExtension.ExecuteAsync(new CustomPromptRequest("Rewrite the following text in William Shakespeare style.", text)); + } +} +``` -Declare DxHtmlEditor's `AdditionalSettings` and populate it with commands in the following manner: +Declare DxHtmlEditor's [AdditionalItems](https://docs.devexpress.com/Blazor/DevExpress.Blazor.DxHtmlEditor.AdditionalItems?v=24.2) and populate it with commands in the following manner: ```razor +@using DevExpress.AI.Samples.Blazor.Editors.Components.AdditionalItems @using DevExpress.AIIntegration.Blazor.HtmlEditor - - - - - - - - - - - + + + + + + + + + + + + ``` @@ -98,14 +137,15 @@ Declare DxHtmlEditor's `AdditionalSettings` and populate it with commands in the * [RichEdit.razor](./CS/DevExpress.AI.Samples.Blazor.Editors/Components/Pages/RichEdit.razor) * [HtmlEditor.razor](./CS/DevExpress.AI.Samples.Blazor.Editors/Components/Pages/HtmlEditor.razor) +* [ShakespeareAIContextMenuItem.cs](./CS/DevExpress.AI.Samples.Blazor.Editors/Components/AdditionalItems/ShakespeareAIContextMenuItem.cs) +* [ShakespeareAIToolbarItem.cs](./CS/DevExpress.AI.Samples.Blazor.Editors/Components/AdditionalItems/ShakespeareAIToolbarItem.cs) * [Program.cs](./CS/DevExpress.AI.Samples.Blazor.Editors/Program.cs) - +* [DevExpress AI-powered Extensions for Blazor](https://docs.devexpress.com/Blazor/405228/ai-powered-extensions?v=24.2) +* [AI-powered Extension for Blazor Rich Text Editor](https://docs.devexpress.com/Blazor/405193/components/rich-edit/ai-integration?v=24.2) +* [AI-powered Extension for Blazor HTML Editor](https://docs.devexpress.com/Blazor/405187/components/html-editor/ai-integration?v=24.2) ## More Examples diff --git a/htmleditor.png b/htmleditor.png index 55bf3eb..110dca0 100644 Binary files a/htmleditor.png and b/htmleditor.png differ diff --git a/richedit.png b/richedit.png index 2ca3697..e139917 100644 Binary files a/richedit.png and b/richedit.png differ