Skip to content
This repository was archived by the owner on Jun 30, 2022. It is now read-only.

Commit 2ccc211

Browse files
KayMKMdarrenj
authored andcommitted
[Skills] convert location to timezone (#2301)
* convert location to timezone * remove useless field * update function name
1 parent cf065ba commit 2ccc211

File tree

10 files changed

+300
-17
lines changed

10 files changed

+300
-17
lines changed

skills/src/csharp/calendarskill/calendarskill/Dialogs/MainDialog.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using CalendarSkill.Responses.Main;
1111
using CalendarSkill.Responses.Shared;
1212
using CalendarSkill.Services;
13+
using CalendarSkill.Services.AzureMapsAPI;
1314
using CalendarSkill.Utilities;
1415
using Luis;
1516
using Microsoft.Bot.Builder;
@@ -22,6 +23,7 @@
2223
using Microsoft.Bot.Builder.Solutions.Responses;
2324
using Microsoft.Bot.Connector;
2425
using Microsoft.Bot.Schema;
26+
using Microsoft.EntityFrameworkCore.Diagnostics;
2527

2628
namespace CalendarSkill.Dialogs
2729
{
@@ -305,6 +307,28 @@ private async Task PopulateStateFromSemanticAction(ITurnContext context)
305307
// we have a timezone
306308
state.UserInfo.Timezone = timezoneObj;
307309
}
310+
311+
if (semanticAction != null && semanticAction.Entities.ContainsKey("location"))
312+
{
313+
var location = semanticAction.Entities["location"];
314+
var locationString = location.Properties["location"].ToString();
315+
var state = await _stateAccessor.GetAsync(context, () => new CalendarSkillState());
316+
317+
var coords = locationString.Split(',');
318+
if (coords.Length == 2)
319+
{
320+
if (double.TryParse(coords[0], out var lat) && double.TryParse(coords[1], out var lng))
321+
{
322+
state.UserInfo.Latitude = lat;
323+
state.UserInfo.Longitude = lng;
324+
}
325+
}
326+
327+
var azureMapsClient = new AzureMapsClient(_settings);
328+
var timezone = await azureMapsClient.GetTimeZoneInfoByCoordinates(locationString);
329+
330+
state.UserInfo.Timezone = timezone;
331+
}
308332
}
309333

310334
private async Task<InterruptionAction> OnCancel(DialogContext dc)
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
6+
namespace CalendarSkill.Models
7+
{
8+
public class TimeZoneResponse
9+
{
10+
public string Version { get; set; }
11+
12+
public DateTime ReferenceUtcTimestamp { get; set; }
13+
14+
public Timezone[] TimeZones { get; set; }
15+
16+
public class Timezone
17+
{
18+
public string Id { get; set; }
19+
20+
public string[] Aliases { get; set; }
21+
22+
public Names Names { get; set; }
23+
24+
public Referencetime ReferenceTime { get; set; }
25+
26+
public Representativepoint RepresentativePoint { get; set; }
27+
28+
public Timetransition[] TimeTransitions { get; set; }
29+
}
30+
31+
public class Names
32+
{
33+
public string ISO6391LanguageCode { get; set; }
34+
35+
public string Generic { get; set; }
36+
37+
public string Standard { get; set; }
38+
39+
public string Daylight { get; set; }
40+
}
41+
42+
public class Referencetime
43+
{
44+
public string Tag { get; set; }
45+
46+
public string StandardOffset { get; set; }
47+
48+
public string DaylightSavings { get; set; }
49+
50+
public DateTime WallTime { get; set; }
51+
52+
public int PosixTzValidYear { get; set; }
53+
54+
public string PosixTz { get; set; }
55+
56+
public DateTime Sunrise { get; set; }
57+
58+
public DateTime Sunset { get; set; }
59+
}
60+
61+
public class Representativepoint
62+
{
63+
public float Latitude { get; set; }
64+
65+
public float Longitude { get; set; }
66+
}
67+
68+
public class Timetransition
69+
{
70+
public string Tag { get; set; }
71+
72+
public string StandardOffset { get; set; }
73+
74+
public string DaylightSavings { get; set; }
75+
76+
public DateTime UtcStart { get; set; }
77+
78+
public DateTime UtcEnd { get; set; }
79+
}
80+
}
81+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System;
2+
using System.Net.Http;
3+
using System.Threading.Tasks;
4+
using CalendarSkill.Models;
5+
using Newtonsoft.Json;
6+
7+
namespace CalendarSkill.Services.AzureMapsAPI
8+
{
9+
public class AzureMapsClient
10+
{
11+
private static HttpClient _httpClient;
12+
private string _apiKey;
13+
private string _byCoordinatesUrl = "https://atlas.microsoft.com/timezone/byCoordinates/json?subscription-key={0}&api-version=1.0&options=all&query={1}";
14+
15+
public AzureMapsClient(BotSettings settings)
16+
{
17+
GetApiKey(settings);
18+
_httpClient = new HttpClient();
19+
}
20+
21+
public async Task<TimeZoneInfo> GetTimeZoneInfoByCoordinates(string query)
22+
{
23+
try
24+
{
25+
var url = string.Format(_byCoordinatesUrl, _apiKey, query);
26+
var response = await _httpClient.GetStringAsync(url);
27+
var apiResponse = JsonConvert.DeserializeObject<TimeZoneResponse>(response);
28+
return TimeZoneInfo.FindSystemTimeZoneById(apiResponse.TimeZones[0].Names.Standard);
29+
}
30+
catch
31+
{
32+
return null;
33+
}
34+
}
35+
36+
private void GetApiKey(BotSettings settings)
37+
{
38+
_apiKey = settings.AzureMapsKey ?? throw new Exception("Could not get the required AzureMapsKey API key. Please make sure your settings are correctly configured.");
39+
}
40+
}
41+
}

skills/src/csharp/calendarskill/calendarskill/Services/BotSettings.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,7 @@ public class SlotFillingConfigItem
3030
public string DefaultValue { get; set; }
3131
}
3232
}
33+
34+
public string AzureMapsKey { get; set; }
3335
}
3436
}

skills/src/csharp/calendarskill/calendarskill/appsettings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,6 @@
5555
"isSkipByDefault": false
5656
}
5757
]
58-
}
58+
},
59+
"azureMapsKey": ""
5960
}

skills/src/csharp/emailskill/emailskill/Dialogs/MainDialog.cs

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
using EmailSkill.Responses.Main;
1111
using EmailSkill.Responses.Shared;
1212
using EmailSkill.Services;
13+
using EmailSkill.Services.AzureMapsAPI;
1314
using Luis;
1415
using Microsoft.Bot.Builder;
1516
using Microsoft.Bot.Builder.Dialogs;
@@ -79,7 +80,7 @@ public MainDialog(
7980
var locale = CultureInfo.CurrentUICulture.TwoLetterISOLanguageName;
8081
var localeConfig = _services.CognitiveModelSets[locale];
8182

82-
await PopulateStateFromSkillContext(dc.Context);
83+
await PopulateStateFromSemanticAction(dc.Context);
8384

8485
// If dispatch result is general luis model
8586
localeConfig.LuisServices.TryGetValue("Email", out var luisService);
@@ -162,23 +163,31 @@ public MainDialog(
162163
}
163164
}
164165

165-
private async Task PopulateStateFromSkillContext(ITurnContext context)
166+
private async Task PopulateStateFromSemanticAction(ITurnContext context)
166167
{
167-
// If we have a SkillContext object populated from the SkillMiddleware we can retrieve requests slot (parameter) data
168-
// and make available in local state as appropriate.
169-
var accessor = _userState.CreateProperty<SkillContext>(nameof(SkillContext));
170-
var skillContext = await accessor.GetAsync(context, () => new SkillContext());
171-
if (skillContext != null)
168+
var activity = context.Activity;
169+
var semanticAction = activity.SemanticAction;
170+
if (semanticAction != null && semanticAction.Entities.ContainsKey("timezone"))
172171
{
173-
if (skillContext.ContainsKey("timezone"))
174-
{
175-
var timezone = skillContext["timezone"];
176-
var state = await _stateAccessor.GetAsync(context, () => new EmailSkillState());
177-
var timezoneJson = timezone as Newtonsoft.Json.Linq.JObject;
172+
var timezone = semanticAction.Entities["timezone"];
173+
var timezoneObj = timezone.Properties["timezone"].ToObject<TimeZoneInfo>();
178174

179-
// we have a timezone
180-
state.UserInfo.Timezone = timezoneJson.ToObject<TimeZoneInfo>();
181-
}
175+
var state = await _stateAccessor.GetAsync(context, () => new EmailSkillState());
176+
177+
// we have a timezone
178+
state.UserInfo.Timezone = timezoneObj;
179+
}
180+
181+
if (semanticAction != null && semanticAction.Entities.ContainsKey("location"))
182+
{
183+
var location = semanticAction.Entities["location"];
184+
var locationString = location.Properties["location"].ToString();
185+
var state = await _stateAccessor.GetAsync(context, () => new EmailSkillState());
186+
187+
var azureMapsClient = new AzureMapsClient(_settings);
188+
var timezone = await azureMapsClient.GetTimeZoneInfoByCoordinates(locationString);
189+
190+
state.UserInfo.Timezone = timezone;
182191
}
183192
}
184193

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
6+
namespace EmailSkill.Models
7+
{
8+
public class TimeZoneResponse
9+
{
10+
public string Version { get; set; }
11+
12+
public DateTime ReferenceUtcTimestamp { get; set; }
13+
14+
public Timezone[] TimeZones { get; set; }
15+
16+
public class Timezone
17+
{
18+
public string Id { get; set; }
19+
20+
public string[] Aliases { get; set; }
21+
22+
public Names Names { get; set; }
23+
24+
public Referencetime ReferenceTime { get; set; }
25+
26+
public Representativepoint RepresentativePoint { get; set; }
27+
28+
public Timetransition[] TimeTransitions { get; set; }
29+
}
30+
31+
public class Names
32+
{
33+
public string ISO6391LanguageCode { get; set; }
34+
35+
public string Generic { get; set; }
36+
37+
public string Standard { get; set; }
38+
39+
public string Daylight { get; set; }
40+
}
41+
42+
public class Referencetime
43+
{
44+
public string Tag { get; set; }
45+
46+
public string StandardOffset { get; set; }
47+
48+
public string DaylightSavings { get; set; }
49+
50+
public DateTime WallTime { get; set; }
51+
52+
public int PosixTzValidYear { get; set; }
53+
54+
public string PosixTz { get; set; }
55+
56+
public DateTime Sunrise { get; set; }
57+
58+
public DateTime Sunset { get; set; }
59+
}
60+
61+
public class Representativepoint
62+
{
63+
public float Latitude { get; set; }
64+
65+
public float Longitude { get; set; }
66+
}
67+
68+
public class Timetransition
69+
{
70+
public string Tag { get; set; }
71+
72+
public string StandardOffset { get; set; }
73+
74+
public string DaylightSavings { get; set; }
75+
76+
public DateTime UtcStart { get; set; }
77+
78+
public DateTime UtcEnd { get; set; }
79+
}
80+
}
81+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
using System;
2+
using System.Net.Http;
3+
using System.Threading.Tasks;
4+
using EmailSkill.Models;
5+
using Newtonsoft.Json;
6+
7+
namespace EmailSkill.Services.AzureMapsAPI
8+
{
9+
public class AzureMapsClient
10+
{
11+
private static HttpClient _httpClient;
12+
private string _apiKey;
13+
private string _byCoordinatesUrl = "https://atlas.microsoft.com/timezone/byCoordinates/json?subscription-key={0}&api-version=1.0&options=all&query={1}";
14+
15+
public AzureMapsClient(BotSettings settings)
16+
{
17+
GetApiKey(settings);
18+
_httpClient = new HttpClient();
19+
}
20+
21+
public async Task<TimeZoneInfo> GetTimeZoneInfoByCoordinates(string query)
22+
{
23+
try
24+
{
25+
var url = string.Format(_byCoordinatesUrl, _apiKey, query);
26+
var response = await _httpClient.GetStringAsync(url);
27+
var apiResponse = JsonConvert.DeserializeObject<TimeZoneResponse>(response);
28+
return TimeZoneInfo.FindSystemTimeZoneById(apiResponse.TimeZones[0].Names.Standard);
29+
}
30+
catch
31+
{
32+
return null;
33+
}
34+
}
35+
36+
private void GetApiKey(BotSettings settings)
37+
{
38+
_apiKey = settings.AzureMapsKey ?? throw new Exception("Could not get the required AzureMapsKey API key. Please make sure your settings are correctly configured.");
39+
}
40+
}
41+
}

skills/src/csharp/emailskill/emailskill/Services/BotSettings.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,7 @@ public class SlotFillingConfigItem
2828
public bool IsSkipByDefault { get; set; }
2929
}
3030
}
31+
32+
public string AzureMapsKey { get; set; }
3133
}
3234
}

skills/src/csharp/emailskill/emailskill/appsettings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,6 @@
3636
"googleClientId": "",
3737
"googleClientSecret": "",
3838
"googleScopes": "https://mail.google.com/ https://www.googleapis.com/auth/contacts",
39-
"displaySize": 3
39+
"displaySize": 3,
40+
"azureMapsKey": ""
4041
}

0 commit comments

Comments
 (0)