Skip to content

Commit

Permalink
Merge pull request #1 from SyncfusionExamples/Maps_AISample
Browse files Browse the repository at this point in the history
Maps AI sample added
Jeyasri-Murugan authored Sep 4, 2024
2 parents f1945e1 + 981a4e5 commit 93c9456
Showing 56 changed files with 1,660 additions and 1 deletion.
27 changes: 27 additions & 0 deletions MAUIMaps/MAUIMaps.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.8.34309.116
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MAUIMaps", "MAUIMaps\MAUIMaps.csproj", "{4F6A4296-B0BC-45E4-BA18-E658172E0C3A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4F6A4296-B0BC-45E4-BA18-E658172E0C3A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4F6A4296-B0BC-45E4-BA18-E658172E0C3A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4F6A4296-B0BC-45E4-BA18-E658172E0C3A}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
{4F6A4296-B0BC-45E4-BA18-E658172E0C3A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4F6A4296-B0BC-45E4-BA18-E658172E0C3A}.Release|Any CPU.Build.0 = Release|Any CPU
{4F6A4296-B0BC-45E4-BA18-E658172E0C3A}.Release|Any CPU.Deploy.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {56271685-1BDE-449C-B414-AFE0958FFBC8}
EndGlobalSection
EndGlobal
14 changes: 14 additions & 0 deletions MAUIMaps/MAUIMaps/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?xml version = "1.0" encoding = "UTF-8" ?>
<Application xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MAUIMaps"
x:Class="MAUIMaps.App">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources/Styles/Colors.xaml" />
<ResourceDictionary Source="Resources/Styles/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
12 changes: 12 additions & 0 deletions MAUIMaps/MAUIMaps/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
namespace MAUIMaps
{
public partial class App : Application
{
public App()
{
InitializeComponent();

MainPage = new MainPage();
}
}
}
301 changes: 301 additions & 0 deletions MAUIMaps/MAUIMaps/Behavior/MapsGettingStartedBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,301 @@
namespace MAUIMaps
{
using Newtonsoft.Json.Linq;
using Syncfusion.Maui.Core;
using Syncfusion.Maui.Inputs;
using Syncfusion.Maui.Maps;
using System.Collections.ObjectModel;
using System.Text.RegularExpressions;
public class MapsGettingStartedBehavior : Behavior<ContentPage>
{
/// <summary>
/// Holds the map tile layer.
/// </summary>
private MapTileLayer? mapTileLayer;

/// <summary>
/// Holds the map zoompanbehaviour instance.
/// </summary>
private MapZoomPanBehavior? zoomPanBehavior;

/// <summary>
/// Holds the autocomplete instance.
/// </summary>
private SfAutocomplete? autoComplete;

/// <summary>
/// Holds the button instance.
/// </summary>
private Button? button;

/// <summary>
/// Holds the busy indicator instance.
/// </summary>
private SfBusyIndicator? busyIndicator;

/// <summary>
/// Holds the azure ai helper instance.
/// </summary>
private AzureOpenAIService azureAIHelper = new AzureOpenAIService();

/// <summary>
/// Holds the maps data helper instance.
/// </summary>
private MapsDataHelper dataHelper = new MapsDataHelper();

/// <summary>
/// Holds the custom marker view model instance.
/// </summary>
private ObservableCollection<CustomMarker>? customMarkers = new ObservableCollection<CustomMarker>();

/// <summary>
/// Begins when the behavior attached to the view.
/// </summary>
/// <param name="bindable"></param>
protected override void OnAttachedTo(ContentPage bindable)
{
base.OnAttachedTo(bindable);
this.mapTileLayer = bindable.Content.FindByName<MapTileLayer>("layer");
this.zoomPanBehavior = bindable.Content.FindByName<MapZoomPanBehavior>("zoomPanBehavior");
this.autoComplete = bindable.Content.FindByName<SfAutocomplete>("autoComplete");
this.button = bindable.Content.FindByName<Button>("button");
this.busyIndicator = bindable.Content.FindByName<SfBusyIndicator>("busyIndicator");
if (this.autoComplete != null)
{
if (this.azureAIHelper.Client != null)
{
this.autoComplete.NoResultsFoundText = string.Empty;
}
else
{
this.autoComplete.ItemsSource = new ObservableCollection<string>()
{
"Hospitals in New York", "Hotels in Denver"
};
}
}

if (this.button != null)
{
this.button.Clicked += SearchButtonClicked;
}
}

/// <summary>
/// Method to button click changed.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private async void SearchButtonClicked(object? sender, EventArgs e)
{
if (this.autoComplete == null)
{
return;
}

await GetRecommendationAsync(this.autoComplete.Text);
if (this.busyIndicator != null)
{
this.busyIndicator.IsVisible = false;
this.busyIndicator.IsRunning = false;
}
}

/// <summary>
/// Method to contain AI respose and updates.
/// </summary>
/// <param name="userQuery"></param>
/// <returns></returns>
private async Task GetRecommendationAsync(string userQuery)
{
if (this.autoComplete == null || this.mapTileLayer == null || this.zoomPanBehavior == null)
{
return;
}
if (string.IsNullOrWhiteSpace(this.autoComplete.Text))
{
return;
}
if (this.busyIndicator != null)
{
this.busyIndicator.IsVisible = true;
this.busyIndicator.IsRunning = true;
}

string prompt = $"Given location name: {userQuery}" +
$"\nSome conditions need to follow:" +
$"\nCheck the location name is just a state, city, capital or region, then retrieve the following fields: location name, detail, latitude, longitude, and set address value as null" +
$"\nOtherwise, retrieve minimum 5 to 6 entries with following fields: location's name, details, latitude, longitude, address." +
$"\nThe return format should be the following JSON format: markercollections[Name, Details, Latitude, Longitude, Address]" +
$"\nRemove ```json and remove ``` if it is there in the code." +
$"\nProvide JSON format details only, No need any explanation.";

var returnMessage = await azureAIHelper.GetResultsFromAI(prompt);
try
{
var jsonObj = new JObject();
if (returnMessage == string.Empty)
{
if (this.autoComplete.Text == "Hospitals in New York")
{
jsonObj = JObject.Parse(dataHelper.hospitalsData);
this.zoomPanBehavior.ZoomLevel = 10;
}
else if (this.autoComplete.Text == "Hotels in Denver")
{
jsonObj = JObject.Parse(dataHelper.hotelsData);
this.zoomPanBehavior.ZoomLevel = 12;
}
else
{
return;
}
}
else
{
jsonObj = JObject.Parse(returnMessage);
}

this.customMarkers?.Clear();
foreach (var marker in jsonObj["markercollections"]!)
{
CustomMarker customMarker = new CustomMarker();
customMarker.Name = marker["Name"]?.ToString();
customMarker.Details = marker["Details"]?.ToString();
customMarker.Address = marker["Address"]?.ToString();
customMarker.Latitude = StringToDoubleConverter(marker["Latitude"]?.ToString());
customMarker.Longitude = StringToDoubleConverter(marker["Longitude"]?.ToString());
if (this.azureAIHelper.Client != null)
{
customMarker.Image = await azureAIHelper.GetImageFromAI(customMarker.Name);
customMarker.ImageName = string.Empty;
}
else
{
customMarker.Image = null;
customMarker.ImageName = this.UpdateOfflineImage(customMarker.Name);
}

this.customMarkers?.Add(customMarker);
}

this.mapTileLayer.Markers = this.customMarkers!;
this.mapTileLayer.EnableCenterAnimation = true;
if (this.customMarkers != null && this.customMarkers.Count > 0)
{
var firstMarker = this.customMarkers[0];
this.mapTileLayer.Center = new MapLatLng
{
Latitude = firstMarker.Latitude,
Longitude = firstMarker.Longitude,
};

if (this.azureAIHelper.Client != null)
{
this.zoomPanBehavior.ZoomLevel = 10;
}
}
}
catch
{
}
}

/// <summary>
/// Remove the unwanted string value for latitude and longitude, and change its to double.
/// </summary>
/// <param name="input"></param>
/// <returns></returns>
private double StringToDoubleConverter(string? input)
{
if (input == null)
{
return 0;
}

string cleanedInput = Regex.Replace(input, @"\s*[°NSEW]\s*", string.Empty);
return double.Parse(cleanedInput);
}

/// <summary>
/// Return the image name based on offline datas.
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
private string UpdateOfflineImage(string? name)
{
string imageName = string.Empty;
if (name == "NewYork-Presbyterian Hospital" || name == "Hospital for Special Surgery" || name == "Kings County Hospital Center")
{
imageName = "hospital1.jpg";
}
else if (name == "Mount Sinai Hospital" || name == "Memorial Sloan Kettering Cancer Center")
{
imageName = "hospital2.jpg";
}
else if (name == "NYU Langone Health" || name == "New York Eye and Ear Infirmary of Mount Sinai")
{
imageName = "hospital3.jpg";
}
else if (name == "Lenox Hill Hospital" || name == "St. Luke's Roosevelt Hospital Center")
{
imageName = "hospital4.jpg";
}
else if (name == "Bellevue Hospital Center" || name == "Bronx-Lebanon Hospital Center")
{
imageName = "hospital5.jpg";
}
else if (name == "Mount Sinai West" || name == "Jamaica Hospital Medical Center")
{
imageName = "hospital6.jpg";
}
else if (name == "Mount Sinai Beth Israel" || name == "Flushing Hospital Medical Center")
{
imageName = "hospital7.jpg";
}
else if (name == "The Brown Palace Hotel and Spa" || name == "Le Méridien Denver Downtown" || name == "The Maven Hotel at Dairy Block")
{
imageName = "hotel1.jpg";
}
else if (name == "Hyatt Regency Denver at Colorado Convention Center" || name == "JW Marriott Denver Cherry Creek")
{
imageName = "hotel2.jpg";
}
else if (name == "The Ritz-Carlton, Denver" || name == "Halcyon, a hotel in Cherry Creek")
{
imageName = "hotel3.jpg";
}
else if (name == "Kimpton Hotel Born" || name == "The Art Hotel Denver, Curio Collection by Hilton")
{
imageName = "hotel4.jpg";
}
else if (name == "Grand Hyatt Denver" || name == "Kimpton Hotel Monaco Denver")
{
imageName = "hotel5.jpg";
}
else if (name == "The Oxford Hotel" || name == "Four Seasons Hotel Denver")
{
imageName = "hotel6.jpg";
}
else if (name == "Hotel Teatro" || name == "The Crawford Hotel")
{
imageName = "hotel7.jpg";
}

return imageName;
}

/// <summary>
/// Begins when the behavior attached to the view.
/// </summary>
/// <param name="bindable"></param>
protected override void OnDetachingFrom(ContentPage bindable)
{
base.OnDetachingFrom(bindable);
if (this.button != null)
{
this.button.Clicked -= SearchButtonClicked;
}
}
}
}
Loading

0 comments on commit 93c9456

Please sign in to comment.