diff --git a/CS/DevExpress.AI.Samples.WPFBlazor/App.config b/CS/DevExpress.AI.Samples.WPFBlazor/App.config new file mode 100644 index 0000000..1b99773 --- /dev/null +++ b/CS/DevExpress.AI.Samples.WPFBlazor/App.config @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/CS/DevExpress.AI.Samples.WPFBlazor/App.xaml b/CS/DevExpress.AI.Samples.WPFBlazor/App.xaml index c2757af..797fc58 100644 --- a/CS/DevExpress.AI.Samples.WPFBlazor/App.xaml +++ b/CS/DevExpress.AI.Samples.WPFBlazor/App.xaml @@ -1,9 +1,23 @@ - - + diff --git a/CS/DevExpress.AI.Samples.WPFBlazor/App.xaml.cs b/CS/DevExpress.AI.Samples.WPFBlazor/App.xaml.cs index d6ff120..815ff6e 100644 --- a/CS/DevExpress.AI.Samples.WPFBlazor/App.xaml.cs +++ b/CS/DevExpress.AI.Samples.WPFBlazor/App.xaml.cs @@ -1,14 +1,36 @@ -using System.Configuration; -using System.Data; +using System; using System.Windows; +using DevExpress.AIIntegration; +using Azure.AI.OpenAI; +using DevExpress.Data.Utils; +using DevExpress.Xpf.Core; +using Microsoft.Extensions.AI; -namespace DevExpress.AI.Samples.WPFBlazor -{ +namespace WPF_AIChatControl { /// /// Interaction logic for App.xaml /// - public partial class App : System.Windows.Application - { + public partial class App : Application { + static App() { + CompatibilitySettings.UseLightweightThemes = true; + ApplicationThemeHelper.ApplicationThemeName = Theme.Win11Light.Name; + + SetupAzureOpenAI(); + } + static void SetupAzureOpenAI() { + + string azureOpenAIEndpoint = SafeEnvironment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT"); + string azureOpenAIKey = SafeEnvironment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY"); + string deployment = "gpt-4o-mini"; + + var openAIClient = new AzureOpenAIClient( + new Uri(azureOpenAIEndpoint), + new System.ClientModel.ApiKeyCredential(azureOpenAIKey) + ); + var container = AIExtensionsContainerDesktop.Default; + container.RegisterChatClient(openAIClient.AsChatClient(deployment)); + container.RegisterOpenAIAssistants(openAIClient, deployment); + } } } diff --git a/CS/DevExpress.AI.Samples.WPFBlazor/Controls/AIChatControl.cs b/CS/DevExpress.AI.Samples.WPFBlazor/Controls/AIChatControl.cs new file mode 100644 index 0000000..30b3bd8 --- /dev/null +++ b/CS/DevExpress.AI.Samples.WPFBlazor/Controls/AIChatControl.cs @@ -0,0 +1,265 @@ +using System; +using System.Windows; +using System.Windows.Controls; +using System.ComponentModel; +using DevExpress.Blazor.Internal; +using Microsoft.AspNetCore.Components.WebView.Wpf; +using DevExpress.AIIntegration.Blazor.Chat; +using DevExpress.AIIntegration.Services.Assistant; +using Microsoft.AspNetCore.Components; +using Microsoft.Extensions.DependencyInjection; +using DevExpress.AIIntegration.Blazor.Chat.WebView; +using DevExpress.Utils; +using System.Collections.Generic; +using System.Drawing; +using DevExpress.AIIntegration; +using Microsoft.Extensions.AI; +using System.Threading.Tasks; +using DevExpress.Xpf.Printing.Native; + +namespace WPF_AIChatControl { + public class AIChatControl : Control { + + public static readonly DependencyProperty UseStreamingProperty; + public static readonly DependencyProperty ContentFormatProperty; + public static readonly DependencyProperty EmptyStateTextProperty; + public static readonly DependencyProperty TemperatureProperty; + public static readonly DependencyProperty MaxTokensProperty; + public static readonly DependencyProperty FrequencyPenaltyProperty; + public static readonly DependencyProperty ControlBackgroundProperty; + public static readonly DependencyProperty ItemBackgroundProperty; + + static AIChatControl() { + var ownerType = typeof(AIChatControl); + UseStreamingProperty = DependencyProperty.Register(nameof(UseStreaming), typeof(bool), ownerType, + new PropertyMetadata(false, (d, e) => ((AIChatControl)d).OnUseStreamingChanged())); + ContentFormatProperty = DependencyProperty.Register(nameof(ContentFormat), typeof(ResponseContentFormat), ownerType, + new PropertyMetadata(ResponseContentFormat.PlainText, (d, e) => ((AIChatControl)d).OnContentFormatChanged())); + EmptyStateTextProperty = DependencyProperty.Register(nameof(EmptyStateText), typeof(string), ownerType, + new PropertyMetadata(string.Empty, (d, e) => ((AIChatControl)d).OnEmptyStateTextChanged())); + TemperatureProperty = DependencyProperty.Register(nameof(Temperature), typeof(float?), ownerType, + new PropertyMetadata(null, (d, e) => ((AIChatControl)d).OnTemperatureChanged())); + MaxTokensProperty = DependencyProperty.Register(nameof(MaxTokens), typeof(int?), ownerType, + new PropertyMetadata(null, (d, e) => ((AIChatControl)d).OnMaxTokensChanged())); + FrequencyPenaltyProperty = DependencyProperty.Register(nameof(FrequencyPenalty), typeof(float?), ownerType, + new PropertyMetadata(null, (d, e) => ((AIChatControl)d).OnFrequencyPenaltyChanged())); + ControlBackgroundProperty = DependencyProperty.Register(nameof(ControlBackground), typeof(System.Windows.Media.Brush), ownerType, + new PropertyMetadata(null, (d, e) => ((AIChatControl)d).OnControlBackgroundChanged())); + ItemBackgroundProperty = DependencyProperty.Register(nameof(ItemBackground), typeof(System.Windows.Media.Brush), ownerType, + new PropertyMetadata(null, (d, e) => ((AIChatControl)d).OnItemBackgroundChanged())); + } + + DxChatIncapsulationService incapsulationService; + RootComponent blazorChatComponent; + ChatBlazorWebView chatWebView; + + public bool UseStreaming { + get => (bool)GetValue(UseStreamingProperty); + set => SetValue(UseStreamingProperty, value); + } + public ResponseContentFormat ContentFormat { + get => (ResponseContentFormat)GetValue(ContentFormatProperty); + set => SetValue(ContentFormatProperty, value); + } + public string EmptyStateText { + get => (string)GetValue(EmptyStateTextProperty); + set => SetValue(EmptyStateTextProperty, value); + } + public float? Temperature { + get => (float?)GetValue(TemperatureProperty); + set => SetValue(TemperatureProperty, value); + } + public int? MaxTokens { + get => (int?)GetValue(MaxTokensProperty); + set => SetValue(MaxTokensProperty, value); + } + public float? FrequencyPenalty { + get => (float?)GetValue(FrequencyPenaltyProperty); + set => SetValue(FrequencyPenaltyProperty, value); + } + public System.Windows.Media.Brush ControlBackground { + get => (System.Windows.Media.Brush)GetValue(ControlBackgroundProperty); + set => SetValue(ControlBackgroundProperty, value); + } + public System.Windows.Media.Brush ItemBackground { + get => (System.Windows.Media.Brush)GetValue(ItemBackgroundProperty); + set => SetValue(ItemBackgroundProperty, value); + } + + IChatUIWrapper Chat => incapsulationService?.DxChatUI; + + EventHandler markdownConvert; + public event EventHandler MarkdownConvert { + add => markdownConvert += value; + remove => markdownConvert -= value; + } + EventHandler messageSent; + public event EventHandler MessageSent { + add { + if(messageSent == null && Chat != null) + Chat.SetMessageSentCallback(RaiseMessageSent); + messageSent += value; + } + remove { + messageSent -= value; + if(messageSent == null && Chat != null) + Chat.SetMessageSentCallback(null); + } + } + + public async Task SendMessage(string text, ChatRole role) { + if (Chat != null) { + await Chat.SendMessage(text, role); + Chat.Update(); + } + } + public IEnumerable SaveMessages() { + return Chat?.SaveMessages() ?? []; + } + public void LoadMessages(IEnumerable messages) { + if (Chat != null) { + Chat.LoadMessages(messages); + Chat.Update(); + } + } + public override void OnApplyTemplate() { + base.OnApplyTemplate(); + this.chatWebView = GetTemplateChild("PART_ChatWebView") as ChatBlazorWebView; + ConfigureBlazorWebView(); + } + + void RaiseMessageSent(MessageSentEventArgs args) { + messageSent?.Invoke(this, new AIChatControlMessageSentEventArgs(Chat, args.Content)); + } + MarkupString RaiseMarkdownConvert(string text) { + if(markdownConvert != null) { + var e = new AIChatControlMarkdownConvertEventArgs(text); + markdownConvert(this, e); + return e.HtmlText ?? new MarkupString(); + } + return new MarkupString(); + } + void OnUseStreamingChanged() { + if(Chat != null) { + Chat.UseStreaming = UseStreaming; + Chat.Update(); + } + } + void OnContentFormatChanged() { + if(Chat != null) { + Chat.ResponseContentFormat = ContentFormat; + Chat.SetMarkdownConvertCallback(ContentFormat == ResponseContentFormat.Markdown ? RaiseMarkdownConvert : null); + Chat.Update(); + } + } + void OnEmptyStateTextChanged() { + if(Chat != null) { + Chat.SetEmptyStateText(EmptyStateText); + Chat.Update(); + } + } + void OnTemperatureChanged() { + if(Chat != null) + Chat.Temperature = Temperature; + } + void OnMaxTokensChanged() { + if(Chat != null) + Chat.MaxTokens = MaxTokens; + } + void OnFrequencyPenaltyChanged() { + if(Chat != null) + Chat.FrequencyPenalty = FrequencyPenalty; + } + void OnItemBackgroundChanged() { + if(Chat == null) + return; + Chat.Colors[ChatUIColor.UserMessageBackground] = ItemBackground.ToColor(); + } + void OnControlBackgroundChanged() { + if(Chat == null) + return; + var controlBackground = ControlBackground.ToColor(); + Chat.Colors[ChatUIColor.SubmitAreaBackground] = controlBackground; + Chat.Colors[ChatUIColor.InputBackground] = controlBackground; + Chat.Colors[ChatUIColor.AssistantMessageBackground] = controlBackground; + Chat.Colors[ChatUIColor.ButtonNormalBackground] = controlBackground; + Chat.Colors[ChatUIColor.ButtonDisabledBackground] = controlBackground; + + } + void OnBackgroundChanged() { + if(Chat == null) + return; + var background = Background.ToColor(); + Chat.Colors[ChatUIColor.Background] = background; + Chat.Colors[ChatUIColor.ButtonHoverBackground] = background; + + } + void OnForegroundChanged() { + if(Chat == null) + return; + var foreground = Foreground.ToColor(); + Chat.Colors[ChatUIColor.EmptyForeground] = foreground; + Chat.Colors[ChatUIColor.ScrollViewer] = foreground; + Chat.Colors[ChatUIColor.InputForeground] = foreground; + Chat.Colors[ChatUIColor.InputBorder] = Color.FromArgb((int)(255 * 0.25), foreground); + Chat.Colors[ChatUIColor.InputFocusShadow] = Color.FromArgb((int)(255 * 0.1), foreground); + Chat.Colors[ChatUIColor.MessageBorder] = Color.FromArgb((int)(255 * 0.25), foreground); + Chat.Colors[ChatUIColor.UserMessageForeground] = foreground; + Chat.Colors[ChatUIColor.AssistantMessageForeground] = foreground; + + } + protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e) { + base.OnPropertyChanged(e); + if(e.Property == BackgroundProperty) + OnBackgroundChanged(); + if(e.Property == ForegroundProperty) + OnForegroundChanged(); + } + void ConfigureBlazorWebView() { + incapsulationService = new DxChatIncapsulationService(); + chatWebView.HostPage = StaticResourceIdentifiers.HostPageFilePath; + chatWebView.Services = GetServiceProvider(incapsulationService); + chatWebView.RootComponents.Add(new RootComponent() { + Selector = StaticResourceIdentifiers.AppDivId, + ComponentType = typeof(ChatUIWrapper), + Parameters = new Dictionary() { + { nameof(DxAIChat.Initialized), new EventCallback(null, OnChatInitialized)} + } + }); + blazorChatComponent = chatWebView.RootComponents[0]; + } + ServiceProvider GetServiceProvider(DxChatIncapsulationService incapsulationService) { + var chatClientAIService = AIExtensionsContainerDesktop.Default.GetService(); + if(chatClientAIService == null) + throw new InvalidOperationException("There is no registered service of type Microsoft.Extensions.AI.IChatClient"); + var aiAssistantFactory = AIExtensionsContainerDesktop.Default.GetService(); + return ServiceProviderBuildHelper.BuildServiceProvider(incapsulationService, + s => s.AddWpfBlazorWebView(), + chatClientAIService, aiAssistantFactory); + } + void OnChatInitialized(IAIChat chat) { + var chatWrapper = chat as IChatUIWrapper; + if(chatWrapper == null) + return; + chatWrapper.UseStreaming = UseStreaming; + chatWrapper.ResponseContentFormat = ContentFormat; + chatWrapper.SetEmptyStateText(EmptyStateText); + chatWrapper.Temperature = Temperature; + chatWrapper.FrequencyPenalty = FrequencyPenalty; + chatWrapper.MaxTokens = MaxTokens; + if(messageSent != null) + chatWrapper.SetMessageSentCallback(RaiseMessageSent); + if(ContentFormat == ResponseContentFormat.Markdown) + chatWrapper.SetMarkdownConvertCallback(RaiseMarkdownConvert); + OnBackgroundChanged(); + OnForegroundChanged(); + OnControlBackgroundChanged(); + OnItemBackgroundChanged(); + } + } + static class ColorExtensions { + public static Color ToColor(this System.Windows.Media.Brush brush) { + return (brush as System.Windows.Media.SolidColorBrush)?.Color.ToColor() ?? Color.Black; + } + } +} diff --git a/CS/DevExpress.AI.Samples.WPFBlazor/Controls/ChatBlazorWebView.cs b/CS/DevExpress.AI.Samples.WPFBlazor/Controls/ChatBlazorWebView.cs new file mode 100644 index 0000000..021ae10 --- /dev/null +++ b/CS/DevExpress.AI.Samples.WPFBlazor/Controls/ChatBlazorWebView.cs @@ -0,0 +1,13 @@ +using DevExpress.AIIntegration.Blazor.Chat.WebView; +using Microsoft.AspNetCore.Components.WebView.Wpf; +using Microsoft.Extensions.FileProviders; + +namespace WPF_AIChatControl { + internal class ChatBlazorWebView : BlazorWebView { + public override IFileProvider CreateFileProvider(string contentRootDir) { + return new EmbeddedFileProvider( + typeof(IChatUIWrapper).Assembly, + typeof(ChatUIWrapper).Namespace); + } + } +} diff --git a/CS/DevExpress.AI.Samples.WPFBlazor/DevExpress.AI.Samples.WPFBlazor.csproj b/CS/DevExpress.AI.Samples.WPFBlazor/DevExpress.AI.Samples.WPFBlazor.csproj deleted file mode 100644 index 80a0bc8..0000000 --- a/CS/DevExpress.AI.Samples.WPFBlazor/DevExpress.AI.Samples.WPFBlazor.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - WinExe - net8.0-windows - enable - enable - true - WPFBlazor - true - - - - - - - - - - - - - diff --git a/CS/DevExpress.AI.Samples.WPFBlazor/MainViewModel.cs b/CS/DevExpress.AI.Samples.WPFBlazor/MainViewModel.cs deleted file mode 100644 index 0aa4d5f..0000000 --- a/CS/DevExpress.AI.Samples.WPFBlazor/MainViewModel.cs +++ /dev/null @@ -1,65 +0,0 @@ -using System.Windows.Input; -using Microsoft.Extensions.DependencyInjection; -using Azure; -using Azure.AI.OpenAI; -using DevExpress.Mvvm; -using DevExpress.AIIntegration; -using System.ClientModel; -using Microsoft.Extensions.AI; - -namespace DevExpress.AI.Samples.WPFBlazor { - class MainViewModel : BindableBase { - readonly DxChatEncapsulationService service = new DxChatEncapsulationService(); - - public MainViewModel() - { - InitializeCommand = new DelegateCommand(Initialize); - SendMessageCommand = new DelegateCommand(SendMesssage, CanSendMessage); - } - - public ServiceProvider ServiceProvider { - get { return GetValue(); } - private set { SetValue(value); } - } - - public string Message - { - get { return GetValue(); } - set { SetValue(value); } - } - - public ICommand InitializeCommand { get; } - - public ICommand SendMessageCommand { get; } - - void Initialize() - { - var services = new ServiceCollection(); - - string azureOpenAIEndpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT"); - string azureOpenAIKey = Environment.GetEnvironmentVariable("AZURE_OPENAI_API_KEY"); - - var chatClient = new AzureOpenAIClient( - new Uri(azureOpenAIEndpoint), - new ApiKeyCredential(azureOpenAIKey)).AsChatClient("gpt4o"); - - services.AddWpfBlazorWebView(); - services.AddDevExpressBlazor(); - services.AddSingleton(chatClient); - services.AddDevExpressAI((config) => {}); - services.AddSingleton(service); - - ServiceProvider = services.BuildServiceProvider(); - } - - void SendMesssage() - { - service.DxChatUI?.SendMessage(Message, ChatRole.User); - } - - bool CanSendMessage() - { - return !string.IsNullOrEmpty(Message); - } - } -} diff --git a/CS/DevExpress.AI.Samples.WPFBlazor/MainWindow.xaml b/CS/DevExpress.AI.Samples.WPFBlazor/MainWindow.xaml index e5d571e..28d8e4f 100644 --- a/CS/DevExpress.AI.Samples.WPFBlazor/MainWindow.xaml +++ b/CS/DevExpress.AI.Samples.WPFBlazor/MainWindow.xaml @@ -1,52 +1,13 @@ - - - - - - - + - - - - - - - - - - - - - - True - - - - - - - + - - + \ No newline at end of file diff --git a/CS/DevExpress.AI.Samples.WPFBlazor/MainWindow.xaml.cs b/CS/DevExpress.AI.Samples.WPFBlazor/MainWindow.xaml.cs index 32374ed..2de2789 100644 --- a/CS/DevExpress.AI.Samples.WPFBlazor/MainWindow.xaml.cs +++ b/CS/DevExpress.AI.Samples.WPFBlazor/MainWindow.xaml.cs @@ -1,18 +1,16 @@ -using System.Windows.Input; +using Microsoft.AspNetCore.Components; -namespace DevExpress.AI.Samples.WPFBlazor -{ - public partial class MainWindow - { - public MainWindow() - { +namespace WPF_AIChatControl { + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : DevExpress.Xpf.Core.ThemedWindow { + public MainWindow() { InitializeComponent(); } - private void OnKeyDown(object sender, System.Windows.Input.KeyEventArgs e) - { - if (e.Key == Key.Enter) - SendMessageButton.Command?.Execute(null); + void AIChatControl_MarkdownConvert(object sender, DevExpress.AIIntegration.Blazor.Chat.WebView.AIChatControlMarkdownConvertEventArgs e) { + e.HtmlText = (MarkupString)Markdig.Markdown.ToHtml(e.MarkdownText); } } } \ No newline at end of file diff --git a/CS/DevExpress.AI.Samples.WPFBlazor/WPF_AIChatControl.csproj b/CS/DevExpress.AI.Samples.WPFBlazor/WPF_AIChatControl.csproj new file mode 100644 index 0000000..3ab8717 --- /dev/null +++ b/CS/DevExpress.AI.Samples.WPFBlazor/WPF_AIChatControl.csproj @@ -0,0 +1,21 @@ + + + + WinExe + net8.0-windows + true + + + + + + + + + + + + + + + diff --git a/CS/DevExpress.AI.Samples.WPFBlazor/WPF_AIChatControl.sln b/CS/DevExpress.AI.Samples.WPFBlazor/WPF_AIChatControl.sln new file mode 100644 index 0000000..623be63 --- /dev/null +++ b/CS/DevExpress.AI.Samples.WPFBlazor/WPF_AIChatControl.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.11.35312.102 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WPF_AIChatControl", "WPF_AIChatControl.csproj", "{09B887C2-D54E-4802-B61F-ADF31FC10501}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {09B887C2-D54E-4802-B61F-ADF31FC10501}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {09B887C2-D54E-4802-B61F-ADF31FC10501}.Debug|Any CPU.Build.0 = Debug|Any CPU + {09B887C2-D54E-4802-B61F-ADF31FC10501}.Release|Any CPU.ActiveCfg = Release|Any CPU + {09B887C2-D54E-4802-B61F-ADF31FC10501}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {72D64EF2-4696-4B86-84B1-B85C9C372974} + EndGlobalSection +EndGlobal diff --git a/CS/DevExpress.AI.Samples.WPFBlazor/WpfChatUIWrapper.cs b/CS/DevExpress.AI.Samples.WPFBlazor/WpfChatUIWrapper.cs deleted file mode 100644 index f1edcdf..0000000 --- a/CS/DevExpress.AI.Samples.WPFBlazor/WpfChatUIWrapper.cs +++ /dev/null @@ -1,41 +0,0 @@ -using Microsoft.AspNetCore.Components.Rendering; -using Microsoft.AspNetCore.Components; -using DevExpress.Blazor; -using DevExpress.AIIntegration.Blazor.Chat; - -namespace DevExpress.AI.Samples.WPFBlazor -{ - public interface ISelfEncapsulationService - { - void Initialize(WpfChatUIWrapper dxChatUI); - } - - class DxChatEncapsulationService : ISelfEncapsulationService - { - public WpfChatUIWrapper? DxChatUI { get; set; } - public void Initialize(WpfChatUIWrapper dxChatUI) - { - this.DxChatUI = dxChatUI; - } - } - - public class WpfChatUIWrapper: DxAIChat - { - [Inject] ISelfEncapsulationService SelfIncapsulationService { get; set; } = default!; - protected override void OnInitialized() - { - SelfIncapsulationService.Initialize(this); - base.OnInitialized(); - } - - protected override void BuildRenderTree(RenderTreeBuilder builder) - { - DxResourceManager.RegisterScripts()(builder); - base.BuildRenderTree(builder); - } - } - - public class MyDictionary : Dictionary - { - } -} \ No newline at end of file diff --git a/CS/DevExpress.AI.Samples.WPFBlazor/_Imports.razor b/CS/DevExpress.AI.Samples.WPFBlazor/_Imports.razor deleted file mode 100644 index 9083bba..0000000 --- a/CS/DevExpress.AI.Samples.WPFBlazor/_Imports.razor +++ /dev/null @@ -1,5 +0,0 @@ -@using Microsoft.AspNetCore.Components.Web - -@* @code { - -} *@ diff --git a/CS/DevExpress.AI.Samples.WPFBlazor/wwwroot/index.html b/CS/DevExpress.AI.Samples.WPFBlazor/wwwroot/index.html deleted file mode 100644 index 39b8aed..0000000 --- a/CS/DevExpress.AI.Samples.WPFBlazor/wwwroot/index.html +++ /dev/null @@ -1,37 +0,0 @@ - - - - - - - - - - - - -
Loading...
- - - - \ No newline at end of file diff --git a/README.md b/README.md index bf54fcd..327e60b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ -![](https://img.shields.io/endpoint?url=https://codecentral.devexpress.com/api/v1/VersionRange/851207927/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/T1251539) [![](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) @@ -161,7 +160,7 @@ Add the following code to the _Program.cs_ file to register AI Assistant service ```cs builder.Services.AddDevExpressAI((config) => { - //Reference the DevExpress.AIIntegration.OpenAI NuGet package to use Open AI Asisstants + //Reference the DevExpress.AIIntegration.OpenAI NuGet package to use Open AI Assistants config.RegisterOpenAIAssistants(azureClient, "gpt4o"); }); ``` @@ -204,6 +203,7 @@ Keys to implementation are as follows: * Custom CSS classes hide the built-in input field and the Send button (see _index.html_). Folders to review: [DevExpress.AI.Samples.MAUIBlazor](./CS/DevExpress.AI.Samples.MAUIBlazor/), [DevExpress.AI.Samples.WPFBlazor](./CS/DevExpress.AI.Samples.WPFBlazor/) +For more information on how to use AI extensions in WPF apps, refer to the following help topic: [AI-powered Extensions for WPF](https://docs.devexpress.com/WPF/405223/ai-powered-extensions?v=24.2) For WinForms apps, use the built-in `AIChatControl` component. Refer to the following help topic to learn more about the integration steps: [AI Chat Control Documentation](https://docs.devexpress.com/WindowsForms/405218/ai-powered-extensions/ai-chat-control?v=24.2)