TL;DR: Learn how to generate impressive charts using AI and Syncfusion® in .NET MAUI by simply describing your data needs in natural language. Streamline your workflow with automatic JSON configurations and real-time updates.
Imagine describing your data visualization needs in plain English and instantly receiving a stunning chart without any coding required! This is now a reality, thanks to the integration of AI with Syncfusion® robust .NET MAUI Charts control.
In this blog, we’ll explore how you can effortlessly generate charts in .NET MAUI using natural language input. For an introduction to our JSON-based auto-chart generation process, feel free to check out our previous blog to understand the foundation of this feature.
To implement this feature, we leverage the Microsoft.SemanticKernel package. Install the package using the following command.
> dotnet add package Microsoft.SemanticKernel --version 1.32.0
The ChartAIService class handles Azure OpenAI credentials, validates them, and fetches AI responses.
Key features
Refer to the following code example.
internal class ChartAIService { #region Fields private const string Endpoint = "https://YOUR_ACCOUNT.openai.azure.com/"; private const string DeploymentName = "deployment name"; private const string Key = "Your_API_key"; private IChatCompletionService? chatCompletions; private Kernel? kernel; private ChatHistory? chatHistory; private static bool isCredentialValid; private static bool isAlreadyValidated; private Uri? uriResult; #endregion public ChartAIService() { ValidateCredential(); } #region Properties public static bool IsCredentialValid { get; set; } public ChatHistory? ChatHistory { get; set; } public IChatCompletionService? ChatCompletions { get; set; } public Kernel? Kernel { get; set; } #endregion #region Private Methods /// <summary> /// Validate Azure Credentials /// </summary> private async void ValidateCredential() { #region Azure OpenAI this.GetAzureOpenAIKernal(); #endregion if (isAlreadyValidated) { return; } bool isValidUri = Uri.TryCreate(endpoint, UriKind.Absolute, out uriResult) && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps); if (!isValidUri || !endpoint.Contains("http") || string.IsNullOrEmpty(key) || key.Contains("API key") || string.IsNullOrEmpty(deploymentName) || deploymentName.Contains("deployment name") || string.IsNullOrEmpty(imageDeploymentName)) { ShowAlertAsync(); return; } try { if (ChatHistory != null && chatCompletions != null) { ChatHistory.AddSystemMessage("Hello, Test Check"); await chatCompletions.GetChatMessageContentAsync(chatHistory: ChatHistory, kernel: kernel); } } catch (Exception) { // Handle any exceptions that indicate the credentials or endpoint are invalid. ShowAlertAsync(); return; } IsCredentialValid = true; isAlreadyValidated = true; } #region Azure OpenAI /// <summary> /// To get the Azure open ai kernal method /// </summary> private void GetAzureOpenAIKernal() { // Create the chat history chatHistory = new ChatHistory(); var builder = Kernel.CreateBuilder().AddAzureOpenAIChatCompletion(deploymentName, endpoint, key); // Get the kernal from build kernel = builder.Build(); // Get the chat completions from kernal chatCompletions = kernel.GetRequiredService<IChatCompletionService>(); } #endregion /// <summary> /// Show Alert Popup /// </summary> private async void ShowAlertAsync() { #pragma warning disable CS0618 // Type or member is obsolete if (Application.Current?.MainPage != null && !IsCredentialValid) { isAlreadyValidated = true; await Application.Current.MainPage.DisplayAlert("Alert", "The Azure API key or endpoint is missing or incorrect. Please verify your credentials. You can also continue with the offline data.", "OK"); } #pragma warning restore CS0618 // Type or member is obsolete } #endregion }
Then, replace the placeholders, such as YOUR_ACCOUNT and Your_API_key with your actual Azure OpenAI credentials.
/// <summary> /// Retrieves an answer from the deployment name model using the provided user prompt. /// </summary> /// <param name="userPrompt">The user prompt.</param> /// <returns>The AI response.</returns> internal async Task<string> GetAnswerFromGPT(string userPrompt) { if (IsCredentialValid && ChatCompletions != null && ChatHistory != null) { ChatHistory.Clear(); // Add the user's prompt as a user message to the conversation. ChatHistory.AddUserMessage(userPrompt); try { // Send the chat completion request to the OpenAI API and await the response. var response = await ChatCompletions.GetChatMessageContentAsync(chatHistory: ChatHistory, kernel: Kernel); return response.ToString(); } catch { // If an exception occurs (e.g., network issues, API errors), return an empty string. return ""; } } return ""; }
To ensure accurate and cost-effective responses, we request JSON configurations instead of direct chart logic.
public async Task<string> GetAIResponse(string query) { string prompt = "Create a JSON configuration for a cartesian chart using the ChartConfig and SeriesConfig classes, " + $"based on the following query: {query}. The JSON should include: " + "1. The chart type (cartesian or circular). " + "2. Title of the chart. " + "3. X-axis and Y-axis specifications (for cartesian charts). " + "4. Series configurations, including type and data source. " + "5. A setting for whether tooltips are enabled. " + "Use exemplary data relevant to the query to fill in the values. " + "Example JSON Structure: " + "{ " + " chartType: cartesian, // or circular" + " title: {Chart Title}, // Replace with an appropriate title" + " ShowLegend: true, " + " series: [ " + " { " + " type: line, // Specify type: line, area, column, pie, doughnut, or radialbar etc." + " xpath: xvalue, " + " dataSource: [ " + " { xvalue: {X1}, yvalue: {Y1} }, // Sample data points" + " { xvalue: {X2}, yvalue: {Y2} }, // Keys should always be xvalue and yvalue. All other keys are not allowed." + " { xvalue: {X3}, yvalue: {Y3} } // Real-world data is preferred over sample data" + " ], " + " tooltip: true " + " } " + " ], " + " xAxis: { " + " type: category, // For cartesian charts" + " title: {X Axis Title} // Optional: Replace with an appropriate title" + " }, " + " yAxis: { " + " title: {Y Axis Title}, // Optional: Replace with an appropriate title" + " type: numerical, // For cartesian charts" + " min: {Min Value}, // Optional: set minimum value if relevant" + " max: {Max Value} // Optional: set maximum value if relevant" + " }, " + "} " + "Instructions: " + "- Replace placeholders such as `{query}`, `{Chart Title}`, `{X1}`, `{Y1}`, `{X Axis Title}`, and `{Y Axis Title}` with actual data relevant to the query. " + "- Choose the appropriate chart and series types based on the data. " + "- Ensure the data format matches the requirements for cartesian charts. " + "- Only plain text should be used; no need to specify 'json' above the data. " + "- No additional content other than json data should be included!"; // Call the method to get the AI response var response = await semanticKernalService.GetAnswerFromGPT(prompt); // Convert the response to a string (assuming the response has a ToString method) return response.ToString(); }
The AI-generated JSON integrates seamlessly with the JSON-to-chart logic discussed in our previous blog. This modular approach leverages existing functionality, thus avoiding duplication.
The .NET MAUI AI AssistView enables real-time interaction with the AI service, allowing for dynamic chart updates. To use this feature, install the package using the following command.
> dotnet add package Syncfusion.Maui.AIAssistView --version 28.1.37
ViewModel setup
C#
public ICommand RequestCommand { get; } public ObservableCollection<IAssistItem> Messages { get; set; }
XAML
xmlns:aiassistview="clr-namespace:Syncfusion.Maui.AIAssistView;assembly=Syncfusion.Maui.AIAssistView" ... <aiassistview:SfAIAssistView IsVisible="{Binding ShowAssistView, Mode=TwoWay}" x:Name="aiAssistView" RequestCommand="{Binding RequestCommand}" ShowHeader="{Binding ShowHeader}" AssistItems="{Binding Messages}"> <aiassistview:SfAIAssistView.HeaderTemplate> <DataTemplate> <VerticalStackLayout Spacing="12"> <Label Text="How can I assist with generated chart?" Padding="0,20,0,0" LineBreakMode="WordWrap" FontSize="Subtitle" HorizontalOptions="Center" /> <HorizontalStackLayout x:Name="listView" HeightRequest="{OnPlatform WinUI=140, Android=160, MacCatalyst=180, iOS=150}" WidthRequest="{OnPlatform MacCatalyst=430, Android=335, iOS=310}" HorizontalOptions="Center" BindableLayout.ItemsSource="{Binding Path=ModelPrompts}"> </HorizontalStackLayout> </VerticalStackLayout> </DataTemplate> </aiassistview:SfAIAssistView.HeaderTemplate> <aiassistview:SfAIAssistView.Shadow> <Shadow Brush="Black" Offset="0,0" Radius="1" Opacity="0.5" /> </aiassistview:SfAIAssistView.Shadow> </aiassistview:SfAIAssistView>
Now, refer to the following code example to configure the message service with AI AssistView.
RequestCommand = new Command<object>(OnRequest); ... internal async void OnRequest(object requestText) { var value = ((RequestEventArgs)requestText).RequestItem.Text; OnRequest(value); } internal async void OnRequest(string requestText) { if (!string.IsNullOrEmpty(requestText)) { newJson = await ProcessUserRequest(requestText); } if (!string.IsNullOrEmpty(newJson) && newJson != oldJson) { DecryptJSON(newJson, true); oldJson = newJson; } else { AssistItem assistItem = new() { Text = "Invalid request. Please try again!", ShowAssistItemFooter = false }; Messages.Add(assistItem); } } public async Task<string> ProcessUserRequest(string request) { string prompt = $"Given the user's request: {request}, modify the following json data." + $"json data: {oldJson}" + "Instructions: " + "- Accept only the possible modifications that can be made to the current json data; return empty string for unintended requests like changing the entire chart type or etc." + "- Only plain text should be used; no need to specify 'json' above the data." + "- No additional content other than json data should be included!"; var response = await semanticKernalService.GetAnswerFromGPT(prompt); return response.ToString(); }
Refer to the following output GIF image.
Also, refer to transforming natural language inputs into charts using the AI-powered chart creator GitHub demo.
Thanks for reading the blog! We have explored how to effortlessly create stunning charts using AI and Syncfusion® robust .NET MAUI tools, all with natural language input. No coding is needed for dynamic chart visuals! Try it out and experience the convenience of auto-generating stunning charts with AI!
If you need assistance, please do not hesitate to contact us via our support forum, support portal, or feedback portal. We are always eager to help you!