In this blog post, we will explore the process of developing a .NET MAUI application that leverages OpenAI’s ChatGPT APIs to deliver place recommendations based on the user’s location. The application will feature a user-friendly interface where users can input their geographical location, and in return, they will receive information about popular landmarks and attractions nearby.
To get started with developing the application, there are a few prerequisites that need to be fulfilled:
Next, I’ll detail how to meet these prerequisites.
Note: To access OpenAI’s APIs in your .NET MAUI application, you need the API key, which is not free. If you are considering a paid account, this blog will give you an idea of how you might utilize it, even if you can’t follow along. Check the pricing page for more details.
To create an OpenAI account, follow these steps:
By following these steps, you can create an OpenAI account and gain access to their services.
To obtain an OpenAI API key:
Please create a .NET MAUI application and follow the instructions within the project.
To integrate the ChatGPT library and call its APIs in your .NET MAUI project, follow these steps:
Install-Package ChatGptNet
builder.Services.AddChatGpt(options => { options.ApiKey = ""; // Your API Key Here; options.Organization = null; // Optional options.DefaultModel = ChatGptModels.Gpt35Turbo; // Default: ChatGptModels.Gpt35Turbo options.MessageLimit = 10; // Default: 10 options.MessageExpiration = TimeSpan.FromMinutes(5); // Default: 1 hour });
In this application, I will utilize the Syncfusion .NET MAUI controls, specifically the Maps, Busy Indicator, and Popup controls. These controls will play crucial roles in enhancing the functionality and user experience of the app.
The Maps control will be the centerpiece of the application, allowing users to select a specific location by picking the latitude and longitude. With the Maps control, users will have an interactive and visually appealing interface to navigate and explore different areas.
To provide a seamless user experience, I will incorporate the Busy Indicator control. This control will be activated when the application communicates with the ChatGPT API to retrieve recommendations based on the selected location. The Busy Indicator will display an animated loading indicator, assuring users that the app is working in the background to fetch the desired information.
I will utilize the Popup control to present the output corresponding to the selected location. This control will enable me to display relevant information and recommendations in an organized and visually appealing manner.
Syncfusion .NET MAUI components are available on NuGet.org. To add SfMaps to your project, open the NuGet package manager in Visual Studio, search for Syncfusion.Maui.Maps, and then install it. Similarly, SfBusyIndicator is available in the Syncfusion.Maui.Core NuGet package and SfPopup is available in the Syncfusion.Maui.Popup NuGet package.
Syncfusion.Maui.Core NuGet is a dependent package for all Syncfusion .NET MAUI controls. In the MauiProgram.cs file, register the handler for Syncfusion core.
using ChatGptNet; using ChatGptNet.Models; using Microsoft.Extensions.Logging; using Syncfusion.Maui.Core.Hosting; namespace ChatGPTinMAUI; public static class MauiProgram { public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder.UseMauiApp<App>() builder.ConfigureSyncfusionCore(); builder.Services.AddChatGpt(options => { options.ApiKey = ""; // Your API key here; options.Organization = null; // Optional options.DefaultModel = ChatGptModels.Gpt35Turbo; // Default: ChatGptModels.Gpt35Turbo options.MessageLimit = 10; // Default: 10 options.MessageExpiration = TimeSpan.FromMinutes(5); // Default: 1 hour }); #if DEBUG builder.Logging.AddDebug(); #endif return builder.Build(); } }
Create the required UI:
The XAML code begins with declaring the necessary namespaces using the xmlns attribute. The required namespaces are:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:maps="clr-namespace:Syncfusion.Maui.Maps;assembly=Syncfusion.Maui.Maps" xmlns:busy="clr-namespace:Syncfusion.Maui.Core;assembly=Syncfusion.Maui.Core" xmlns:syncfusion="clr-namespace:Syncfusion.Maui.Popup;assembly=Syncfusion.Maui.Popup" x:Class="ChatGPTinMAUI.MainPage"> </ContentPage>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:maps="clr-namespace:Syncfusion.Maui.Maps;assembly=Syncfusion.Maui.Maps" xmlns:busy="clr-namespace:Syncfusion.Maui.Core;assembly=Syncfusion.Maui.Core" xmlns:syncfusion="clr-namespace:Syncfusion.Maui.Popup;assembly=Syncfusion.Maui.Popup" x:Class="ChatGPTinMAUI.MainPage"> <busy:SfBusyIndicator x:Name="busyIndicator"> </busy:SfBusyIndicator> </ContentPage>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:maps="clr-namespace:Syncfusion.Maui.Maps;assembly=Syncfusion.Maui.Maps" xmlns:busy="clr-namespace:Syncfusion.Maui.Core;assembly=Syncfusion.Maui.Core" xmlns:syncfusion="clr-namespace:Syncfusion.Maui.Popup;assembly=Syncfusion.Maui.Popup" x:Class="ChatGPTinMAUI.MainPage"> <busy:SfBusyIndicator x:Name="busyIndicator"> <ScrollView> <Grid> </Grid> </ScrollView> </busy:SfBusyIndicator> </ContentPage>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:maps="clr-namespace:Syncfusion.Maui.Maps;assembly=Syncfusion.Maui.Maps" xmlns:busy="clr-namespace:Syncfusion.Maui.Core;assembly=Syncfusion.Maui.Core" xmlns:syncfusion="clr-namespace:Syncfusion.Maui.Popup;assembly=Syncfusion.Maui.Popup" x:Class="ChatGPTinMAUI.MainPage"> <busy:SfBusyIndicator x:Name="busyIndicator"> <ScrollView> <Grid > <maps:SfMaps x:Name="maps"> <maps:SfMaps.Layer> <maps:MapTileLayer UrlTemplate="https://tile.openstreetmap.org/{z}/{x}/{y}.png"> <maps:MapTileLayer.ZoomPanBehavior> <maps:MapZoomPanBehavior MinZoomLevel="3" MaxZoomLevel="10" EnableDoubleTapZooming="True" ZoomLevel="3"> </maps:MapZoomPanBehavior> </maps:MapTileLayer.ZoomPanBehavior> </maps:MapTileLayer> </maps:SfMaps.Layer> </maps:SfMaps> </Grid> </ScrollView> </busy:SfBusyIndicator> </ContentPage>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:maps="clr-namespace:Syncfusion.Maui.Maps;assembly=Syncfusion.Maui.Maps" xmlns:busy="clr-namespace:Syncfusion.Maui.Core;assembly=Syncfusion.Maui.Core" xmlns:syncfusion="clr-namespace:Syncfusion.Maui.Popup;assembly=Syncfusion.Maui.Popup" x:Class="ChatGPTinMAUI.MainPage"> <busy:SfBusyIndicator x:Name="busyIndicator"> <ScrollView> <Grid > <maps:SfMaps x:Name="maps"> <maps:SfMaps.Layer> <maps:MapTileLayer UrlTemplate="https://tile.openstreetmap.org/{z}/{x}/{y}.png"> <maps:MapTileLayer.ZoomPanBehavior> <maps:MapZoomPanBehavior MinZoomLevel="3" MaxZoomLevel="10" EnableDoubleTapZooming="True" ZoomLevel="3"> </maps:MapZoomPanBehavior> </maps:MapTileLayer.ZoomPanBehavior> </maps:MapTileLayer> </maps:SfMaps.Layer> </maps:SfMaps> <syncfusion:SfPopup x:Name="popupDisplay" IsOpen="false" ShowHeader="False" WidthRequest="500" HeightRequest="300"> <syncfusion:SfPopup.ContentTemplate> <DataTemplate> <Grid RowDefinitions="20,*"> <Label Text="5 places to visit in this location :" FontSize="14" FontAttributes="Bold" /> <ScrollView Grid.Row="1" > <Label Text="{Binding ContentText}" Margin="0,10,0,10" /> </ScrollView> </Grid> </DataTemplate> </syncfusion:SfPopup.ContentTemplate> </syncfusion:SfPopup> </Grid> </ScrollView> </busy:SfBusyIndicator> </ContentPage>
Overall, the XAML code creates a content page with a Busy Indicator control, a scroll view, a Maps control, and a Popup control.
using ChatGptNet; using ChatGptNet.Models; using Syncfusion.Maui.Maps;
The code is within the ChatGPTinMAUI namespace, and the MainPage class is defined as a partial class extending the ContentPage class.
using ChatGptNet; using ChatGptNet.Models; using Syncfusion.Maui.Maps; namespace ChatGPTinMAUI;
public partial class MainPage : ContentPage { }
using ChatGptNet; using ChatGptNet.Models; using Syncfusion.Maui.Maps; namespace ChatGPTinMAUI; public partial class MainPage : ContentPage { public String Title { get { return (String)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } public static readonly BindableProperty TitleProperty = BindableProperty.Create("Title", typeof(String), typeof(MainPage), String.Empty); public String ContentText { get { return (String)GetValue(ContentTextProperty); } set { SetValue(ContentTextProperty, value); } } public static readonly BindableProperty ContentTextProperty = BindableProperty.Create("ContentText", typeof(String), typeof(MainPage), String.Empty); }
using ChatGptNet; using ChatGptNet.Models; using Syncfusion.Maui.Maps; namespace ChatGPTinMAUI; public partial class MainPage : ContentPage { public String Title { get { return (String)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } public static readonly BindableProperty TitleProperty = BindableProperty.Create("Title", typeof(String), typeof(MainPage), String.Empty); public String ContentText { get { return (String)GetValue(ContentTextProperty); } set { SetValue(ContentTextProperty, value); } } public static readonly BindableProperty ContentTextProperty = BindableProperty.Create("ContentText", typeof(String), typeof(MainPage), String.Empty); private IChatGptClient _chatGptClient; private Guid _sessionGuid = Guid.Empty; MapMarkerCollection mapMarkers = new MapMarkerCollection(); MapMarker mapMarker = new MapMarker(); public MainPage() { InitializeComponent(); this.Loaded += MainPage_Loaded; mapMarkers.Add(mapMarker); this.BindingContext = this; } }
using ChatGptNet; using ChatGptNet.Models; using Syncfusion.Maui.Maps; namespace ChatGPTinMAUI; public partial class MainPage : ContentPage { public String Title { get { return (String)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } public static readonly BindableProperty TitleProperty = BindableProperty.Create("Title", typeof(String), typeof(MainPage), String.Empty); public String ContentText { get { return (String)GetValue(ContentTextProperty); } set { SetValue(ContentTextProperty, value); } } public static readonly BindableProperty ContentTextProperty = BindableProperty.Create("ContentText", typeof(String), typeof(MainPage), String.Empty); private IChatGptClient _chatGptClient; private Guid _sessionGuid = Guid.Empty; MapMarkerCollection mapMarkers = new MapMarkerCollection(); MapMarker mapMarker = new MapMarker(); public MainPage() { InitializeComponent(); this.Loaded += MainPage_Loaded; mapMarkers.Add(mapMarker); this.BindingContext = this; } private void MainPage_Loaded(object sender, EventArgs e) { _chatGptClient = Handler.MauiContext.Services.GetService<IChatGptClient>(); } }
using ChatGptNet; using ChatGptNet.Models; using Syncfusion.Maui.Maps; namespace ChatGPTinMAUI; public partial class MainPage : ContentPage { public String Title { get { return (String)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } public static readonly BindableProperty TitleProperty = BindableProperty.Create("Title", typeof(String), typeof(MainPage), String.Empty); public String ContentText { get { return (String)GetValue(ContentTextProperty); } set { SetValue(ContentTextProperty, value); } } public static readonly BindableProperty ContentTextProperty = BindableProperty.Create("ContentText", typeof(String), typeof(MainPage), String.Empty); private IChatGptClient _chatGptClient; private Guid _sessionGuid = Guid.Empty; MapMarkerCollection mapMarkers = new MapMarkerCollection(); MapMarker mapMarker = new MapMarker(); public MainPage() { InitializeComponent(); this.Loaded += MainPage_Loaded; mapMarkers.Add(mapMarker); this.BindingContext = this; } private void MainPage_Loaded(object sender, EventArgs e) { _chatGptClient = Handler.MauiContext.Services.GetService<IChatGptClient>(); } private async void MainPage_Tapped(object sender, Syncfusion.Maui.Maps.TappedEventArgs e) { var latlong = (this.maps.Layer as MapTileLayer).GetLatLngFromPoint(e.Position); var geoLocation = "Latitude:"+ latlong.Latitude.ToString() + ",Longitude:" + latlong.Longitude.ToString(); await GetNearByTouristAttraction(geoLocation); this.popupDisplay.Show(e.Position.X, e.Position.Y); this.popupDisplay.Show(e.Position.X, e.Position.Y); } }
The GetNearByTouristAttraction method is an asynchronous method that fetches nearby tourist attractions based on the provided geolocation. It displays a loading indicator while the request is being processed. It makes a request to the ChatGPT Client to get recommendations for tourist attractions and then updates the ContentText property with the response.
using ChatGptNet; using ChatGptNet.Models; using Syncfusion.Maui.Maps; namespace ChatGPTinMAUI; public partial class MainPage : ContentPage { public String Title { get { return (String)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } public static readonly BindableProperty TitleProperty = BindableProperty.Create("Title", typeof(String), typeof(MainPage), String.Empty); public String ContentText { get { return (String)GetValue(ContentTextProperty); } set { SetValue(ContentTextProperty, value); } } public static readonly BindableProperty ContentTextProperty = BindableProperty.Create("ContentText", typeof(String), typeof(MainPage), String.Empty); private IChatGptClient _chatGptClient; private Guid _sessionGuid = Guid.Empty; MapMarkerCollection mapMarkers = new MapMarkerCollection(); MapMarker mapMarker = new MapMarker(); public MainPage() { InitializeComponent(); this.Loaded += MainPage_Loaded; mapMarkers.Add(mapMarker); this.BindingContext = this; } private void MainPage_Loaded(object sender, EventArgs e) { _chatGptClient = Handler.MauiContext.Services.GetService<IChatGptClient>(); } private async void MainPage_Tapped(object sender, Syncfusion.Maui.Maps.TappedEventArgs e) { var latlong = (this.maps.Layer as MapTileLayer).GetLatLngFromPoint(e.Position); var geoLocation = "Latitude:"+ latlong.Latitude.ToString() + ",Longitude:" + latlong.Longitude.ToString(); await GetNearByTouristAttraction(geoLocation); this.popupDisplay.Show(e.Position.X, e.Position.Y); this.popupDisplay.Show(e.Position.X, e.Position.Y); } private async Task GetNearByTouristAttraction(string geoLocation) { this.busyIndicator.IsRunning = true; if (string.IsNullOrWhiteSpace(geoLocation)) { await DisplayAlert("Empty location", "No Suggestions", "OK"); return; } if (_sessionGuid == Guid.Empty) { _sessionGuid = Guid.NewGuid(); } var query = "Tell me 5 places near the following location (Each with 20 words) " + geoLocation; ChatGptResponse response = await _chatGptClient.AskAsync(_sessionGuid, query); this.ContentText = response.GetMessage(); this.busyIndicator.IsRunning = false; } }
For more details, refer to the project on GitHub.
This blog guided you in creating a .NET MAUI application that leverages the power of the OpenAI ChatGPT API to deliver tourist recommendations based on the user’s location.
Feel free to experiment by modifying the prompts to enhance the quality of the suggestions. Additionally, you can explore the option of changing the ChatGptModels enum value within the AddChatGpt method in MauiProgram.cs to observe if different models yield improved outcomes.
Syncfusion’s collection of .NET MAUI controls offers a comprehensive suite of tools that enable developers to create robust and feature-rich applications. With their extensive customization options and intuitive APIs, Syncfusion controls provide seamless integration into the .NET MAUI framework, making building cross-platform applications with enhanced functionality easier.
Please try out the steps in this blog and share your feedback in the comment section below. You can also reach us through our support forum, support portal, or feedback portal. We are always happy to assist you!
Disclaimer: You will need to use professional skill and judgment when doing any implementation. This provides only a sample. Syncfusion is not affiliated with ChatGPT and is not responsible for any results.