/// <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..."));
            }
        }
Beispiel #3
0
        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);
        }
Beispiel #8
0
        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);
        }
Beispiel #9
0
        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);
        }