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

Multi-Locale support for Manifest generation #1183

Merged
merged 1 commit into from
Apr 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
Expand Down Expand Up @@ -47,6 +48,8 @@ public void TestInitialize()

cogModelConfig.LanguageModels.Add(luisModel);
_botSettings.CognitiveModels.Add("en", cogModelConfig);
_botSettings.CognitiveModels.Add("de", cogModelConfig);
_botSettings.CognitiveModels.Add("fr", cogModelConfig);

_services = new ServiceCollection();

Expand Down Expand Up @@ -180,6 +183,15 @@ public async Task SkillControllerManifestRequestInlineTriggerUtterances()
Assert.IsTrue(
skillManifest.Actions[i].Definition.Triggers.Utterances[0].Text.Length > 0,
$"The {skillManifest.Actions[i].Id} action has no LUIS utterances added as part of manifest generation.");

// Validate DE, FR has been added too.
Assert.IsTrue(
skillManifest.Actions[i].Definition.Triggers.Utterances.Exists(u => u.Locale.ToLower() == "de"),
$"The {skillManifest.Actions[i].Id} action has no LUIS utterances added as part of manifest generation for the DE locale.");

Assert.IsTrue(
skillManifest.Actions[i].Definition.Triggers.Utterances.Exists(u => u.Locale.ToLower() == "fr"),
$"The {skillManifest.Actions[i].Id} action has no LUIS utterances added as part of manifest generation for the FR locale.");
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,20 @@
"Calendar#CreateCalendarEntry",
"Calendar#FindMeetingRoom"
]
},
{
"locale": "de",
"source": [
"Calendar#CreateCalendarEntry",
"Calendar#FindMeetingRoom"
]
},
{
"locale": "fr",
"source": [
"Calendar#CreateCalendarEntry",
"Calendar#FindMeetingRoom"
]
}
]
}
Expand Down Expand Up @@ -85,6 +99,20 @@
"Calendar#AcceptEventEntry",
"Calendar#DeleteCalendarEntry"
]
},
{
"locale": "de",
"source": [
"Calendar#AcceptEventEntry",
"Calendar#DeleteCalendarEntry"
]
},
{
"locale": "fr",
"source": [
"Calendar#AcceptEventEntry",
"Calendar#DeleteCalendarEntry"
]
}
]
}
Expand All @@ -102,6 +130,18 @@
"source": [
"Calendar#ConnectToMeeting"
]
},
{
"locale": "de",
"source": [
"Calendar#ConnectToMeeting"
]
},
{
"locale": "fr",
"source": [
"Calendar#ConnectToMeeting"
]
}
]
}
Expand Down Expand Up @@ -133,6 +173,18 @@
"source": [
"Calendar#TimeRemaining"
]
},
{
"locale": "de",
"source": [
"Calendar#TimeRemaining"
]
},
{
"locale": "fr",
"source": [
"Calendar#TimeRemaining"
]
}
]
}
Expand Down Expand Up @@ -172,6 +224,28 @@
"Calendar#FindCalendarWho",
"Calendar#FindDuration"
]
},
{
"locale": "de",
"source": [
"Calendar#FindCalendarDetail",
"Calendar#FindCalendarEntry",
"Calendar#FindCalendarWhen",
"Calendar#FindCalendarWhere",
"Calendar#FindCalendarWho",
"Calendar#FindDuration"
]
},
{
"locale": "fr",
"source": [
"Calendar#FindCalendarDetail",
"Calendar#FindCalendarEntry",
"Calendar#FindCalendarWhen",
"Calendar#FindCalendarWhere",
"Calendar#FindCalendarWho",
"Calendar#FindDuration"
]
}
]
}
Expand Down Expand Up @@ -214,6 +288,18 @@
"source": [
"Calendar#ChangeCalendarEntry"
]
},
{
"locale": "de",
"source": [
"Calendar#ChangeCalendarEntry"
]
},
{
"locale": "fr",
"source": [
"Calendar#ChangeCalendarEntry"
]
}
]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,15 @@ public async Task<SkillManifest> GenerateManifest(string manifestFile, string ap
// If the developer has requested inline, we need to go through all utteranceSource references and retrieve the utterances and insert inline
if (inlineTriggerUtterances)
{
// Retrieve all of the LUIS model definitions deployed and configured for the skill
// These are used to match the model name and intent so we can retrieve the utterances
Dictionary<string, dynamic> localeLuisModels = new Dictionary<string, dynamic>();

// TODO - Multi-locale support
var modelCache = await PreFetchLuisModelContents(cognitiveModels["en"].LanguageModels);
// Retrieve all of the LUIS model definitions deployed and configured for the skill which could have multiple locales
// These are used to match the model name and intent so we can retrieve the utterances
foreach (var localeSet in cognitiveModels)
{
// Download/cache all the LUIS models configured for this locale (key is the locale name)
await PreFetchLuisModelContents(localeLuisModels, localeSet.Key, localeSet.Value.LanguageModels);
}

foreach (var action in skillManifest.Actions)
{
Expand Down Expand Up @@ -105,12 +109,11 @@ public async Task<SkillManifest> GenerateManifest(string manifestFile, string ap
var modelName = source.Substring(0, intentIndex);
string intentToMatch = source.Substring(intentIndex + 1);

// Find the LUIS model from our cache by matching on the luis model ID
var model = modelCache.SingleOrDefault(m => string.Equals(m.Key, modelName, StringComparison.CurrentCultureIgnoreCase)).Value;

// Find the LUIS model from our cache by matching on the locale/modelname
var model = localeLuisModels.SingleOrDefault(m => string.Equals(m.Key, $"{utteranceSource.Locale}_{modelName}", StringComparison.CurrentCultureIgnoreCase)).Value;
if (model == null)
{
throw new Exception($"Utterance source for action: '{action.Id}' references the '{modelName}' model which cannot be found in the currently deployed configuration.");
throw new Exception($"Utterance source (locale: {utteranceSource.Locale}) for action: '{action.Id}' references the '{modelName}' model which cannot be found in the currently deployed configuration.");
}

// Validate that the intent in the manifest exists in this LUIS model
Expand Down Expand Up @@ -151,10 +154,8 @@ public async Task<SkillManifest> GenerateManifest(string manifestFile, string ap
/// </summary>
/// <param name="luisServices">List of LuisServices.</param>
/// <returns>Collection of LUIS model definitions grouped by model name.</returns>
private async Task<Dictionary<string, dynamic>> PreFetchLuisModelContents(List<LuisService> luisServices)
private async Task PreFetchLuisModelContents(Dictionary<string, dynamic> localeModelUtteranceCache, string locale, List<LuisService> luisServices)
{
Dictionary<string, dynamic> utteranceCache = new Dictionary<string, dynamic>();

// For each luisSource we identify the Intent and match with available luisServices to identify the LuisAppId which we update
foreach (LuisService luisService in luisServices)
{
Expand All @@ -167,11 +168,9 @@ private async Task<Dictionary<string, dynamic>> PreFetchLuisModelContents(List<L
string json = await httpResponse.Content.ReadAsStringAsync();
var luisApp = JsonConvert.DeserializeObject<dynamic>(json);

utteranceCache.Add(luisService.Id, luisApp);
localeModelUtteranceCache.Add($"{locale}_{luisService.Id}", luisApp);
}
}

return utteranceCache;
}
}
}