diff --git a/BotSharp.Core/Adapters/Dialogflow/DialogflowIntentResponseParameter.cs b/BotSharp.Core/Adapters/Dialogflow/DialogflowIntentResponseParameter.cs index 153c8650..6b3d8103 100644 --- a/BotSharp.Core/Adapters/Dialogflow/DialogflowIntentResponseParameter.cs +++ b/BotSharp.Core/Adapters/Dialogflow/DialogflowIntentResponseParameter.cs @@ -6,11 +6,18 @@ namespace BotSharp.Core.Adapters.Dialogflow { public class DialogflowIntentResponseParameter { + public DialogflowIntentResponseParameter() + { + PromptList = new List(); + } public string Id { get; set; } public bool Required { get; set; } public string DataType { get; set; } + public string DefaultValue { get; set; } public string Name { get; set; } public string Value { get; set; } public bool IsList { get; set; } + + public List PromptList { get; set; } } } diff --git a/BotSharp.Core/Adapters/Dialogflow/DialogflowIntentResponseParameterPrompt.cs b/BotSharp.Core/Adapters/Dialogflow/DialogflowIntentResponseParameterPrompt.cs new file mode 100644 index 00000000..9c403a19 --- /dev/null +++ b/BotSharp.Core/Adapters/Dialogflow/DialogflowIntentResponseParameterPrompt.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace BotSharp.Core.Adapters.Dialogflow +{ + public class DialogflowIntentResponseParameterPrompt + { + public string Lang { get; set; } + + public string Value { get; set; } + } +} diff --git a/BotSharp.Core/Agents/AgentDriver.cs b/BotSharp.Core/Agents/AgentDriver.cs index fa24e1c5..0c72ca82 100644 --- a/BotSharp.Core/Agents/AgentDriver.cs +++ b/BotSharp.Core/Agents/AgentDriver.cs @@ -1,7 +1,6 @@ using BotSharp.Core.Adapters.Rasa; using BotSharp.Core.Engines; using BotSharp.Core.Entities; -using BotSharp.Core.Expressions; using BotSharp.Core.Intents; using BotSharp.Core.Models; using EntityFrameworkCore.BootKit; @@ -83,7 +82,7 @@ namespace BotSharp.Core.Agents var intents = dc.Table() .Include(x => x.Contexts) .Include(x => x.UserSays).ThenInclude(say => say.Data) - .Where(x => x.UserSays.Count > 0) + .Where(x => x.AgentId == agent.Id && x.UserSays.Count > 0) .ToList(); intents.ForEach(intent => diff --git a/BotSharp.Core/Engines/AgentImporterInDialogflow.cs b/BotSharp.Core/Engines/AgentImporterInDialogflow.cs index eac9f77a..4cbb312d 100644 --- a/BotSharp.Core/Engines/AgentImporterInDialogflow.cs +++ b/BotSharp.Core/Engines/AgentImporterInDialogflow.cs @@ -72,23 +72,43 @@ namespace BotSharp.Core.Engines .ToList() .ForEach(fileName => { - if (!fileName.Contains("_usersays_" + agent.Language)) + if (!fileName.Contains("_usersays_" + agent.Language) + || fileName.Contains("Default Fallback Intent")) { string intentJson = File.ReadAllText($"{fileName}"); // avoid confict data structure intentJson = intentJson.Replace("\"contexts\":", "\"contextList\":"); intentJson = intentJson.Replace("\"messages\":", "\"messageList\":"); + intentJson = intentJson.Replace("\"prompts\":", "\"promptList\":"); var intent = JsonConvert.DeserializeObject(intentJson); intent.Name = intent.Name.Replace("/","_"); // load user expressions - string expressionFileName = fileName.Replace(intent.Name, $"{intent.Name}_usersays_{agent.Language}"); - if (File.Exists(expressionFileName)) + if (fileName.Contains("Default Fallback Intent")) { - string expressionJson = File.ReadAllText($"{expressionFileName}"); - intent.UserSays = JsonConvert.DeserializeObject>(expressionJson); + intent.UserSays = (intent.Responses[0].MessageList[0].Speech as JArray) + .Select(x => new DialogflowIntentExpression + { + Data = new List + { + new DialogflowIntentExpressionPart + { + Text = x.ToString() + } + } + }).ToList(); } + else + { + string expressionFileName = fileName.Replace(intent.Name, $"{intent.Name}_usersays_{agent.Language}"); + if (File.Exists(expressionFileName)) + { + string expressionJson = File.ReadAllText($"{expressionFileName}"); + intent.UserSays = JsonConvert.DeserializeObject>(expressionJson); + } + } + var newIntent = intent.ToObject(); intent.Responses.ForEach(res => @@ -124,6 +144,13 @@ namespace BotSharp.Core.Engines } }).ToList(); + + newResponse.Parameters = res.Parameters.Select(p => + { + var rp = p.ToObject(); + rp.Prompts = p.PromptList.Select(pl => new ResponseParameterPrompt { Prompt = pl.Value }).ToList(); + return rp; + }).ToList(); }); newIntent.Contexts = intent.ContextList.Select(x => new IntentInputContext { Name = x }).ToList(); diff --git a/BotSharp.Core/Engines/RequestExtension.cs b/BotSharp.Core/Engines/RequestExtension.cs index c21c657e..7c11981d 100644 --- a/BotSharp.Core/Engines/RequestExtension.cs +++ b/BotSharp.Core/Engines/RequestExtension.cs @@ -39,7 +39,7 @@ namespace BotSharp.Core.Engines aiResponse.Timestamp = DateTime.UtcNow; var intentResponse = HandleIntentPerContextIn(rasa, request, result.Data); - HandleParameter(rasa.agent, intentResponse, response, request); + bool missedRequiredField = HandleParameter(rasa.agent, intentResponse, response, request); HandleMessage(intentResponse); @@ -113,31 +113,45 @@ namespace BotSharp.Core.Engines response.Intent }; } - response.IntentRanking = response.IntentRanking.Where(x => intents.Select(i => i.Name).Contains(x.Name)).ToList(); + response.IntentRanking = response.IntentRanking + .Where(x => x.Confidence > decimal.Parse("0.2") && intents.Select(i => i.Name).Contains(x.Name)).ToList(); + // add Default Fallback Intent if (response.IntentRanking.Count == 0) { - return null; + var defaultFallbackIntent = rasa.agent.Intents.FirstOrDefault(x => x.Name == "Default Fallback Intent"); + response.IntentRanking.Add(new RasaResponseIntent + { + Name = defaultFallbackIntent.Name, + Confidence = decimal.Parse("0.8") + }); } - else - { - response.Intent = response.IntentRanking.First(); - var intent = (dc.Table().Where(x => x.Name == response.Intent.Name) - .Include(x => x.Responses).ThenInclude(x => x.Contexts) - .Include(x => x.Responses).ThenInclude(x => x.Parameters) - .Include(x => x.Responses).ThenInclude(x => x.Messages)).First(); + response.Intent = response.IntentRanking.First(); - var intentResponse = ArrayHelper.GetRandom(intent.Responses); - intentResponse.IntentName = intent.Name; + var intent = (dc.Table().Where(x => x.AgentId == rasa.agent.Id && x.Name == response.Intent.Name) + .Include(x => x.Responses).ThenInclude(x => x.Contexts) + .Include(x => x.Responses).ThenInclude(x => x.Parameters) + .Include(x => x.Responses).ThenInclude(x => x.Messages)).First(); + + var intentResponse = ArrayHelper.GetRandom(intent.Responses); + intentResponse.IntentName = intent.Name; + + return intentResponse; - return intentResponse; - } } - private static void HandleParameter(Agent agent, IntentResponse intentResponse, RasaResponse response, AIRequest request) + /// + /// + /// + /// + /// + /// + /// + /// Required field is missed + private static bool HandleParameter(Agent agent, IntentResponse intentResponse, RasaResponse response, AIRequest request) { - if (intentResponse == null) return; + if (intentResponse == null) return false; intentResponse.Parameters.ForEach(p => { string query = request.Query.First(); @@ -169,6 +183,8 @@ namespace BotSharp.Core.Engines } } }); + + return intentResponse.Parameters.Any(x => x.Required && String.IsNullOrEmpty(x.Value)); } private static void HandleMessage(IntentResponse intentResponse) @@ -463,6 +479,9 @@ namespace BotSharp.Core.Engines var corpus = console.agent.GrabCorpus(dc); + // remove Default Fallback Intent + corpus.UserSays = corpus.UserSays.Where(x => x.Intent != "Default Fallback Intent").ToList(); + string json = JsonConvert.SerializeObject(new { rasa_nlu_data = corpus }, new JsonSerializerSettings { @@ -473,7 +492,7 @@ namespace BotSharp.Core.Engines #if RASA_NLU_0_11 rest.AddParameter("application/json", json, ParameterType.RequestBody); #else - string trainingConfig = console.agent.Language == "zh" ? "config_jieba_mitie_sklearn.yml" : "config_spacy.yml"; + string trainingConfig = console.agent.Language == "zh" ? "config_jieba_mitie_sklearn.yml" : "config_mitie_sklearn.yml"; string body = File.ReadAllText($"{Database.ContentRootPath}{Path.DirectorySeparatorChar}Settings{Path.DirectorySeparatorChar}{trainingConfig}"); body = $"{body}\r\ndata: {json}"; rest.AddParameter("application/x-yml", body, ParameterType.RequestBody); diff --git a/BotSharp.Core/Intents/IntentDriver.cs b/BotSharp.Core/Intents/IntentDriver.cs index 68e3c12b..48e9b780 100644 --- a/BotSharp.Core/Intents/IntentDriver.cs +++ b/BotSharp.Core/Intents/IntentDriver.cs @@ -13,13 +13,18 @@ namespace BotSharp.Core.Intents { public static Intent GetIntent(this IBotEngine bot, Database dc, string intentId) { - return dc.Table() + var intent = dc.Table() .Include(x => x.Contexts) .Include(x => x.Responses).ThenInclude(x => x.Contexts) - .Include(x => x.Responses).ThenInclude(x => x.Parameters) + .Include(x => x.Responses).ThenInclude(x => x.Parameters).ThenInclude(x => x.Prompts) .Include(x => x.Responses).ThenInclude(x => x.Messages) .Include(x => x.UserSays).ThenInclude(x => x.Data) .FirstOrDefault(x => x.Id == intentId); + + // order parts by time + intent.UserSays.ForEach(x => x.Data = x.Data.OrderBy(d => d.UpdatedTime).ToList()); + + return intent; } public static String CreateIntent(this Agent agent, Database dc, Intent intent) diff --git a/BotSharp.Core/Intents/IntentExpression.cs b/BotSharp.Core/Intents/IntentExpression.cs index 538d86b6..c75d62a6 100644 --- a/BotSharp.Core/Intents/IntentExpression.cs +++ b/BotSharp.Core/Intents/IntentExpression.cs @@ -1,5 +1,4 @@ -using BotSharp.Core.Expressions; -using EntityFrameworkCore.BootKit; +using EntityFrameworkCore.BootKit; using Newtonsoft.Json; using System; using System.Collections.Generic; diff --git a/BotSharp.Core/Expressions/IntentExpressionPart.cs b/BotSharp.Core/Intents/IntentExpressionPart.cs similarity index 94% rename from BotSharp.Core/Expressions/IntentExpressionPart.cs rename to BotSharp.Core/Intents/IntentExpressionPart.cs index 3d4d93c5..e6e23668 100644 --- a/BotSharp.Core/Expressions/IntentExpressionPart.cs +++ b/BotSharp.Core/Intents/IntentExpressionPart.cs @@ -5,7 +5,7 @@ using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; using System.Text; -namespace BotSharp.Core.Expressions +namespace BotSharp.Core.Intents { [Table("Bot_IntentExpressionPart")] public class IntentExpressionPart : DbRecord, IDbRecord diff --git a/BotSharp.Core/Intents/IntentResponseParameter.cs b/BotSharp.Core/Intents/IntentResponseParameter.cs index 07165476..05cb1a3c 100644 --- a/BotSharp.Core/Intents/IntentResponseParameter.cs +++ b/BotSharp.Core/Intents/IntentResponseParameter.cs @@ -19,6 +19,9 @@ namespace BotSharp.Core.Intents [MaxLength(32)] public string DataType { get; set; } + [MaxLength(128)] + public string DefaultValue { get; set; } + [MaxLength(64)] public string Name { get; set; } @@ -26,5 +29,8 @@ namespace BotSharp.Core.Intents public string Value { get; set; } public bool IsList { get; set; } + + [ForeignKey("ResponseParameterId")] + public List Prompts { get; set; } } } diff --git a/BotSharp.Core/Intents/ResponseParameterPrompt.cs b/BotSharp.Core/Intents/ResponseParameterPrompt.cs new file mode 100644 index 00000000..6142b8db --- /dev/null +++ b/BotSharp.Core/Intents/ResponseParameterPrompt.cs @@ -0,0 +1,20 @@ +using EntityFrameworkCore.BootKit; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.ComponentModel.DataAnnotations.Schema; +using System.Text; + +namespace BotSharp.Core.Intents +{ + [Table("Bot_ResponseParameterPrompt")] + public class ResponseParameterPrompt : DbRecord, IDbRecord + { + [Required] + [StringLength(36)] + public String ResponseParameterId { get; set; } + + [MaxLength(256)] + public string Prompt { get; set; } + } +} diff --git a/BotSharp.Core/Models/RasaIntentExpression.cs b/BotSharp.Core/Models/RasaIntentExpression.cs index 480e711c..b7562340 100644 --- a/BotSharp.Core/Models/RasaIntentExpression.cs +++ b/BotSharp.Core/Models/RasaIntentExpression.cs @@ -1,5 +1,4 @@ -using BotSharp.Core.Expressions; -using System; +using System; using System.Collections.Generic; using System.Text; diff --git a/BotSharp.UnitTest/BotSharp.UnitTest.csproj b/BotSharp.UnitTest/BotSharp.UnitTest.csproj index 4b239e00..44a9776a 100644 --- a/BotSharp.UnitTest/BotSharp.UnitTest.csproj +++ b/BotSharp.UnitTest/BotSharp.UnitTest.csproj @@ -224,8 +224,8 @@ - - + + diff --git a/BotSharp.UnitTest/TestEssential.cs b/BotSharp.UnitTest/TestEssential.cs index 6a48021a..eff7a16e 100644 --- a/BotSharp.UnitTest/TestEssential.cs +++ b/BotSharp.UnitTest/TestEssential.cs @@ -13,7 +13,7 @@ namespace BotSharp.UnitTest public static String BOT_ID = "fd9f1b29-fed8-4c68-8fda-69ab463da126"; public static String BOT_CLIENT_TOKEN = "23a53c46d6244840bbb10c89c171d299"; public static String BOT_DEVELOPER_TOKEN = "d86103f446d049ff8d5f506e8dfe5f3f"; - public static String BOT_NAME = "VirtualAssistant"; + public static String BOT_NAME = "Voicebot"; protected Database dc { get; set; } protected string contentRoot;