/// <summary> /// Gets a result for paper requirements /// </summary> /// <param name="response">The response from RASA</param> /// <returns>A user-friendly response based on the RASA response</returns> private JsonResult GetPaperRequirementResult(RasaResponse response) { // Get the entities that match 'paper' var paperEntities = response.Entities.Where(entity => entity.Entity == RasaResponse.ENTITY_PAPER); if (paperEntities.Count() > 0) { // Get the first entity, then find it in our paper data var paper = paperEntities.First(); var matchingPaper = papers.FindPaperByKeyword(paper.Value); if (matchingPaper != null) // If we have a matching paper { var requirementsString = string.Join(" or ", matchingPaper.RequiredPapers); // Respond with the requirements for the paper return(QueryResponse.Result($"{matchingPaper.FullName} ({matchingPaper.PaperCode}) requires that you have completed {requirementsString}")); } else // If we don't have the paper in our data, inform the user. { return(QueryResponse.Result("I'm sorry, I don't have any information regarding that as of yet.")); } } else { return(QueryResponse.Result("I'm sorry, could you ask that again?")); } }
/// <summary> /// Gets a result for paper suggestions /// </summary> /// <param name="response">The response from RASA</param> /// <returns>A user-friendly response based on the RASA response</returns> private JsonResult GetPaperSuggestionResult(RasaResponse response) { // get the entities that match a job var jobs = response.Entities.Where(entity => entity.Entity == RasaResponse.ENTITY_JOB); if (jobs.Count() > 0) { var matchingPapers = papers.FindPapersMatchingJob(jobs.First().Value); if (matchingPapers.Count() > 0) { string str = $"Papers matching '{jobs.First().Value}'"; foreach (var paper in matchingPapers) { str += $"\n{paper.FullName} ({paper.PaperCode})"; } return(QueryResponse.Result(str)); } else { return(QueryResponse.Result("No papers in my database match that job.")); } } else { return(QueryResponse.Result("I'm sorry, I didn't quite get that...")); } }
public AIResponse TextRequest(AIRequest request) { AIResponse aiResponse = new AIResponse(); string model = RasaRequestExtension.GetModelPerContexts(agent, AiConfig, request, dc); var result = CallRasa(agent.Id, request.Query.First(), model); result.Content.Log(); RasaResponse response = result.Data; aiResponse.Id = Guid.NewGuid().ToString(); aiResponse.Lang = agent.Language; aiResponse.Status = new AIResponseStatus { }; aiResponse.SessionId = AiConfig.SessionId; aiResponse.Timestamp = DateTime.UtcNow; var intentResponse = RasaRequestExtension.HandleIntentPerContextIn(agent, AiConfig, request, result.Data, dc); RasaRequestExtension.HandleParameter(agent, intentResponse, response, request); RasaRequestExtension.HandleMessage(intentResponse); aiResponse.Result = new AIResponseResult { Source = "agent", ResolvedQuery = request.Query.First(), Action = intentResponse?.Action, Parameters = intentResponse?.Parameters?.ToDictionary(x => x.Name, x => (object)x.Value), Score = response.Intent.Confidence, Metadata = new AIResponseMetadata { IntentId = intentResponse?.IntentId, IntentName = intentResponse?.IntentName }, Fulfillment = new AIResponseFulfillment { Messages = intentResponse?.Messages?.Select(x => { if (x.Type == AIResponseMessageType.Custom) { return((new { x.Type, Payload = JsonConvert.DeserializeObject(x.PayloadJson) }) as Object); } else { return((new { x.Type, x.Speech }) as Object); } }).ToList() } }; RasaRequestExtension.HandleContext(dc, AiConfig, intentResponse, aiResponse); Console.WriteLine(JsonConvert.SerializeObject(aiResponse.Result)); return(aiResponse); }
public JsonResult Ask([FromBody] QueryArguments query) { if (query.UserInput.StartsWith("@")) // Enable us to debug the bot in case it's displaying incorrect messages { RasaQuery rasaQuery = new RasaQuery(query.UserInput.Substring(1)); RasaResponse rasaResponse = rasaQuery.GetResponse(); return(QueryResponse.Result(rasaResponse.GetDebug())); } else // Regular messages { RasaQuery rasaQuery = new RasaQuery(query.UserInput); RasaResponse rasaResponse = rasaQuery.GetResponse(); if (rasaResponse.Intent == null) // If for some reason our bot decides there's no intent, we respond gracefully. { return(QueryResponse.Result("I'm only able to answer questions in relations to papers at AUT.")); } RasaIntent intent = rasaResponse.Intent; if (intent?.Name == RasaResponse.INTENT_REQUIREMENTS) // Check if our intent is paper_requirements { return(GetPaperRequirementResult(rasaResponse)); } else if (intent?.Name == RasaResponse.INTENT_SUGGESTION) // Else if our intent is a paper suggestion { return(GetPaperSuggestionResult(rasaResponse)); } else // If our intent isn't supported we need to let the user know { return(QueryResponse.Result("I do not yet have the capability to answer that question.")); } } }
public static IntentResponse HandleIntentPerContextIn(Agent agent, AIConfiguration aiConfig, AIRequest request, RasaResponse response, Database dc) { // Merge input contexts var contexts = dc.Table <ConversationContext>() .Where(x => x.ConversationId == aiConfig.SessionId && x.Lifespan > 0) .ToList() .Select(x => new AIContext { Name = x.Context.ToLower(), Lifespan = x.Lifespan }) .ToList(); contexts.AddRange(request.Contexts.Select(x => new AIContext { Name = x.Name.ToLower(), Lifespan = x.Lifespan })); contexts = contexts.OrderBy(x => x.Name).ToList(); // search all potential intents which input context included in contexts var intents = agent.Intents.Where(it => { if (contexts.Count == 0) { return(it.Contexts.Count() == 0); } else { return(it.Contexts.Count() == 0 || it.Contexts.Count(x => contexts.Select(ctx => ctx.Name).Contains(x.Name.ToLower())) == it.Contexts.Count); } }).OrderByDescending(x => x.Contexts.Count).ToList(); if (response.IntentRanking == null) { response.IntentRanking = new List <RasaResponseIntent> { response.Intent }; } response.IntentRanking = response.IntentRanking.Where(x => x.Confidence > agent.MlConfig.MinConfidence).ToList(); response.IntentRanking = response.IntentRanking.Where(x => intents.Select(i => i.Name).Contains(x.Name)).ToList(); // add Default Fallback Intent if (response.IntentRanking.Count == 0) { var defaultFallbackIntent = agent.Intents.FirstOrDefault(x => x.Name == "Default Fallback Intent"); response.IntentRanking.Add(new RasaResponseIntent { Name = defaultFallbackIntent.Name, Confidence = decimal.Parse("0.8") }); } response.Intent = response.IntentRanking.First(); var intent = (dc.Table <Intent>().Where(x => x.AgentId == agent.Id && x.Name == response.Intent.Name) .Include(x => x.Responses).ThenInclude(x => x.Contexts) .Include(x => x.Responses).ThenInclude(x => x.Parameters).ThenInclude(x => x.Prompts) .Include(x => x.Responses).ThenInclude(x => x.Messages)).First(); var intentResponse = ArrayHelper.GetRandom(intent.Responses); intentResponse.IntentName = intent.Name; return(intentResponse); }
/// <summary> /// /// </summary> /// <param name="agent"></param> /// <param name="intentResponse"></param> /// <param name="response"></param> /// <param name="request"></param> /// <returns>Required field is missed</returns> public static void HandleParameter(Agent agent, IntentResponse intentResponse, RasaResponse response, AIRequest request) { if (intentResponse == null) { return; } intentResponse.Parameters.ForEach(p => { string query = request.Query.First(); var entity = response.Entities.FirstOrDefault(x => x.Entity == p.Name || x.Entity.Split(":").Contains(p.Name)); if (entity != null) { p.Value = query.Substring(entity.Start, entity.End - entity.Start); } // convert to Standard entity value if (!String.IsNullOrEmpty(p.Value) && !p.DataType.StartsWith("sys.")) { p.Value = agent.Entities .FirstOrDefault(x => x.Name == p.DataType) .Entries .FirstOrDefault((entry) => { return(entry.Value.ToLower() == p.Value.ToLower() || entry.Synonyms.Select(synonym => synonym.Synonym.ToLower()).Contains(p.Value.ToLower())); })?.Value; } // fixed entity per request if (request.Entities != null) { var fixedEntity = request.Entities.FirstOrDefault(x => x.Name == p.Name); if (fixedEntity != null) { if (query.ToLower().Contains(fixedEntity.Entries.First().Value.ToLower())) { p.Value = fixedEntity.Entries.First().Value; } } } }); }
public ActionResult <RasaResponse> Parse(RasaRequestModel request) { var config = new AIConfiguration("", SupportedLanguage.English); config.SessionId = "rasa nlu"; string body = ""; using (var reader = new StreamReader(Request.Body)) { body = reader.ReadToEnd(); } Console.WriteLine($"Got message from {Request.Host}: {body}", Color.Green); if (request.Project == null && !String.IsNullOrEmpty(body)) { request = JsonConvert.DeserializeObject <RasaRequestModel>(body); } // Load agent var projectPath = Path.Combine(AppDomain.CurrentDomain.GetData("DataPath").ToString(), "Projects", request.Project); if (String.IsNullOrEmpty(request.Model)) { request.Model = Directory.GetDirectories(projectPath).Where(x => x.Contains("model_")).Last().Split(Path.DirectorySeparatorChar).Last(); } var modelPath = Path.Combine(projectPath, request.Model); var agent = _platform.LoadAgentFromFile(modelPath); var aIResponse = _platform.TextRequest(new AIRequest { AgentDir = projectPath, Model = request.Model, Query = new String[] { request.Text } }); var rasaResponse = new RasaResponse { Intent = new RasaResponseIntent { Name = aIResponse.Result.Metadata.IntentName, Confidence = aIResponse.Result.Score }, Entities = aIResponse.Result.Entities.Select(x => new RasaResponseEntity { Extractor = x.Extrator, Start = x.Start, Entity = x.Entity, Value = x.Value }).ToList(), Text = request.Text, Model = request.Model, Project = agent.Name, IntentRanking = new List <RasaResponseIntent> { new RasaResponseIntent { Name = aIResponse.Result.Metadata.IntentName, Confidence = aIResponse.Result.Score } }, Fullfillment = aIResponse.Result.Fulfillment }; return(rasaResponse); }
public static AIResponse TextRequest(this RasaAi rasa, AIRequest request) { AIResponse aiResponse = new AIResponse(); RasaResponse response = null; Database dc = rasa.dc; // Merge input contexts var contexts = dc.Table <SessionContext>() .Where(x => x.SessionId == rasa.AiConfig.SessionId && x.Lifespan > 0) .ToList() .Select(x => new AIContext { Name = x.Context.ToLower(), Lifespan = x.Lifespan }) .ToList(); contexts.AddRange(request.Contexts.Select(x => new AIContext { Name = x.Name.ToLower(), Lifespan = x.Lifespan })); contexts = contexts.OrderBy(x => x.Name).ToList(); // search all potential intents which input context included in contexts var intents = rasa.agent.Intents.Where(it => { if (contexts.Count == 0) { return(it.Contexts.Count() == 0); } else { return(it.Contexts.Count() > 0 && it.Contexts.Count(x => contexts.Select(ctx => ctx.Name).Contains(x.Name.ToLower())) == it.Contexts.Count); } }).OrderByDescending(x => x.Contexts.Count).ToList(); var result = CallRasa(rasa.agent.Id, request.Query.First(), rasa.agent.Id); if (result.Data.IntentRanking == null) { result.Data.IntentRanking = new List <RasaResponseIntent> { result.Data.Intent }; } result.Data.IntentRanking = result.Data.IntentRanking.Where(x => intents.Select(i => i.Name).Contains(x.Name)).ToList(); result.Data.Intent = result.Data.IntentRanking.First(); response = result.Data; var intent = (dc.Table <Intent>().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(); var intentResponse = ArrayHelper.GetRandom(intent.Responses); aiResponse.Id = Guid.NewGuid().ToString(); aiResponse.Lang = rasa.agent.Language; aiResponse.Status = new AIResponseStatus { }; aiResponse.SessionId = rasa.AiConfig.SessionId; aiResponse.Timestamp = DateTime.UtcNow; intentResponse.Parameters.ForEach(p => { string query = request.Query.First(); var entity = response.Entities.FirstOrDefault(x => x.Entity == p.Name); if (entity != null) { p.Value = query.Substring(entity.Start, entity.End - entity.Start); } // fixed entity per request if (request.Entities != null) { var fixedEntity = request.Entities.FirstOrDefault(x => x.Name == p.Name); if (fixedEntity != null) { if (query.ToLower().Contains(fixedEntity.Entries.First().Value.ToLower())) { p.Value = fixedEntity.Entries.First().Value; } } } }); intentResponse.Messages = intentResponse.Messages.OrderBy(x => x.UpdatedTime).ToList(); intentResponse.Messages.ToList() .ForEach(msg => { if (msg.Type == AIResponseMessageType.Custom) { } else { msg.Speech = msg.Speech.StartsWith("[") ? ArrayHelper.GetRandom(msg.Speech.Substring(2, msg.Speech.Length - 4).Split("\",\"").ToList()) : msg.Speech; } }); aiResponse.Result = new AIResponseResult { Source = "agent", ResolvedQuery = request.Query.First(), Action = intentResponse.Action, Parameters = intentResponse.Parameters.ToDictionary(x => x.Name, x => x.Value), Score = response.Intent.Confidence, Metadata = new AIResponseMetadata { IntentId = intent.Id, IntentName = intent.Name }, Fulfillment = new AIResponseFulfillment { Messages = intentResponse.Messages.Select(x => { if (x.Type == AIResponseMessageType.Custom) { return((new { x.Type, Payload = JObject.Parse(x.Payload) }) as Object); } else { return((new { x.Type, x.Speech }) as Object); } }).ToList() } }; // Merge context lifespan // override if exists, otherwise add, delete if lifespan is zero dc.DbTran(() => { var sessionContexts = dc.Table <SessionContext>().Where(x => x.SessionId == rasa.AiConfig.SessionId).ToList(); // minus 1 round sessionContexts.Where(x => !intentResponse.Contexts.Select(ctx => ctx.Name).Contains(x.Context)) .ToList() .ForEach(ctx => ctx.Lifespan = ctx.Lifespan - 1); intentResponse.Contexts.ForEach(ctx => { var session1 = sessionContexts.FirstOrDefault(x => x.Context == ctx.Name); if (session1 != null) { if (ctx.Lifespan == 0) { dc.Table <SessionContext>().Remove(session1); } else { session1.Lifespan = ctx.Lifespan; } } else { dc.Table <SessionContext>().Add(new SessionContext { SessionId = rasa.AiConfig.SessionId, Context = ctx.Name, Lifespan = ctx.Lifespan }); } }); }); aiResponse.Result.Contexts = dc.Table <SessionContext>() .Where(x => x.SessionId == rasa.AiConfig.SessionId) .Select(x => new AIContext { Name = x.Context.ToLower(), Lifespan = x.Lifespan }) .ToArray(); return(aiResponse); }
public static AIResponse TextRequestPerContexts(this RasaAi rasa, AIRequest request) { AIResponse aiResponse = new AIResponse(); RasaResponse response = null; Database dc = rasa.dc; // Merge input contexts var contexts = dc.Table <SessionContext>() .Where(x => x.SessionId == rasa.AiConfig.SessionId && x.Lifespan > 0) .ToList() .Select(x => new AIContext { Name = x.Context.ToLower(), Lifespan = x.Lifespan }) .ToList(); contexts.AddRange(request.Contexts.Select(x => new AIContext { Name = x.Name.ToLower(), Lifespan = x.Lifespan })); contexts = contexts.OrderBy(x => x.Name).ToList(); // search all potential intents which input context included in contexts var intents = rasa.agent.Intents.Where(it => { if (contexts.Count == 0) { return(it.Contexts.Count() == 0); } else { return(it.Contexts.Count() > 0 && it.Contexts.Count(x => contexts.Select(ctx => ctx.Name).Contains(x.Name.ToLower())) == it.Contexts.Count); } }).OrderByDescending(x => x.Contexts.Count).ToList(); // training per request contexts { string contextId = $"{String.Join(',', contexts.Select(x => x.Name))}".GetMd5Hash(); string modelName = dc.Table <ContextModelMapping>().FirstOrDefault(x => x.ContextId == contextId)?.ModelName; // need training if (String.IsNullOrEmpty(modelName)) { request.Contexts = contexts.Select(x => new AIContext { Name = x.Name.ToLower() }) .OrderBy(x => x.Name) .ToList(); dc.DbTran(() => { modelName = TrainWithContexts(rasa, dc, request, contextId); }); } var result = CallRasa(rasa.agent.Id, request.Query.First(), modelName); if (result.Data.Intent != null) { response = result.Data; } } // Max contexts match if (response == null) { foreach (var it in intents) { request.Contexts = it.Contexts.Select(x => new AIContext { Name = x.Name.ToLower() }) .OrderBy(x => x.Name) .ToList(); string contextId = $"{String.Join(',', request.Contexts.Select(x => x.Name))}".GetMd5Hash(); string modelName = dc.Table <ContextModelMapping>().FirstOrDefault(x => x.ContextId == contextId)?.ModelName; // need training if (String.IsNullOrEmpty(modelName)) { dc.DbTran(() => { modelName = TrainWithContexts(rasa, dc, request, contextId); }); } var result = CallRasa(rasa.agent.Id, request.Query.First(), modelName); if (result.Data.Intent != null) { response = result.Data; break; } } ; } var intent = (dc.Table <Intent>().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(); var intentResponse = ArrayHelper.GetRandom(intent.Responses); aiResponse.Id = Guid.NewGuid().ToString(); aiResponse.Lang = rasa.agent.Language; aiResponse.Status = new AIResponseStatus { }; aiResponse.SessionId = rasa.AiConfig.SessionId; aiResponse.Timestamp = DateTime.UtcNow; intentResponse.Messages = intentResponse.Messages.OrderBy(x => x.UpdatedTime).ToList(); intentResponse.Messages.ToList() .ForEach(msg => { if (msg.Type == AIResponseMessageType.Custom) { } else { msg.Speech = msg.Speech.StartsWith("[") ? ArrayHelper.GetRandom(msg.Speech.Substring(2, msg.Speech.Length - 4).Split("\",\"").ToList()) : msg.Speech; } }); aiResponse.Result = new AIResponseResult { Source = "agent", ResolvedQuery = request.Query.First(), Action = intentResponse.Action, Parameters = new Dictionary <string, string>(), Score = response.Intent.Confidence, Metadata = new AIResponseMetadata { IntentId = intent.Id, IntentName = intent.Name }, Fulfillment = new AIResponseFulfillment { Messages = intentResponse.Messages.Select(x => { if (x.Type == AIResponseMessageType.Custom) { return((new { x.Type, Payload = JObject.Parse(x.Payload) }) as Object); } else { return((new { x.Type, x.Speech }) as Object); } }).ToList() } }; // Merge context lifespan // override if exists, otherwise add, delete if lifespan is zero dc.DbTran(() => { var sessionContexts = dc.Table <SessionContext>().Where(x => x.SessionId == rasa.AiConfig.SessionId).ToList(); // minus 1 round sessionContexts.Where(x => !intentResponse.Contexts.Select(ctx => ctx.Name).Contains(x.Context)) .ToList() .ForEach(ctx => ctx.Lifespan = ctx.Lifespan - 1); intentResponse.Contexts.ForEach(ctx => { var session1 = sessionContexts.FirstOrDefault(x => x.Context == ctx.Name); if (session1 != null) { if (ctx.Lifespan == 0) { dc.Table <SessionContext>().Remove(session1); } else { session1.Lifespan = ctx.Lifespan; } } else { dc.Table <SessionContext>().Add(new SessionContext { SessionId = rasa.AiConfig.SessionId, Context = ctx.Name, Lifespan = ctx.Lifespan }); } }); }); aiResponse.Result.Contexts = dc.Table <SessionContext>() .Where(x => x.SessionId == rasa.AiConfig.SessionId) .Select(x => new AIContext { Name = x.Context.ToLower(), Lifespan = x.Lifespan }) .ToArray(); return(aiResponse); }