public void TestEvaluateTimeOut() { _chatBot = new ChatBot(); ConfigurationManager.AppSettings["timeoutMax"] = "10"; _node = new Node(); _request = new Request("Test 1", new User("1", _chatBot), _chatBot); var path = "Test 1 <that> that <topic> topic"; var template = "<srai>TEST</srai>"; _node = new Node(); _node.AddCategory(path, template); var pathAlt = "Alt Test <that> that <topic> topic"; var templateAlt = "<srai>TEST ALT</srai>"; _node.AddCategory(pathAlt, templateAlt); _subQuery = new SubQuery(path); Thread.Sleep(20); var result = _node.Evaluate("Test 1 <that> that <topic> topic", _subQuery, _request, MatchState.UserInput, new StringBuilder()); Assert.AreEqual(string.Empty, result); Assert.AreEqual(true, _request.HasTimedOut); }
/// <summary> /// Ctor /// </summary> /// <param name="chatBot">The ChatBot involved in this request</param> /// <param name="user">The user making the request</param> /// <param name="query">The query that originated this node</param> /// <param name="request">The request inputted into the system</param> /// <param name="template">The node to be processed</param> public Sr(ChatBot chatBot, User user, SubQuery query, Request request, XmlNode template) : base(template) { ChatBot = chatBot; User = user; Query = query; Request = request; }
public void Setup() { _request = new Request("This is a test", new User()); _query = new SubQuery(); _query.InputStar.Insert(0, "first star"); _query.InputStar.Insert(0, "second star"); }
public void Setup() { _chatBot = new ChatBot(); ConfigurationManager.AppSettings["timeoutMax"] = Int32.MaxValue.ToString(); _node = new Node(); _request = new Request("Test 1", new User("1", _chatBot), _chatBot); _subQuery = new SubQuery("Test 1 <that> * <topic> *"); }
public void Setup() { _chatBot = new ChatBot(); var filePath = $@"{Environment.CurrentDirectory}\AIML\Srai.aiml"; _chatBot.LoadAIML(filePath); _user = new User(); _request = new Request("This is a test", _user); _query = new SubQuery(); _query.InputStar.Insert(0, "first star"); _query.InputStar.Insert(0, "second star"); }
/// <summary> /// Navigates this node (and recusively into child nodes) for a match to the path passed as an argument /// whilst processing the referenced request /// </summary> /// <param name="path">The normalized path derived from the user's input</param> /// <param name="query">The query that this search is for</param> /// <param name="request">An encapsulation of the request from the user</param> /// <param name="matchstate">The part of the input path the node represents</param> /// <param name="wildcard">The contents of the user input absorbed by the AIML wildcards "_" and "*"</param> /// <returns>The template to process to generate the output</returns> public string evaluate(string path, SubQuery query, Request request, MatchState matchstate, StringBuilder wildcard) { // check for timeout if (request.StartedOn.AddMilliseconds(request.bot.TimeOut) < DateTime.Now) { request.bot.writeToLog("WARNING! Request timeout. User: "******" raw input: \"" + request.rawInput + "\""); request.hasTimedOut = true; return(string.Empty); } // so we still have time! path = path.Trim(); // check if this is the end of a branch in the GraphMaster // return the cCategory for this node if (children.Count == 0) { if (path.Length > 0) { // if we get here it means that there is a wildcard in the user input part of the // path. storeWildCard(path, wildcard); } return(template); } // if we've matched all the words in the input sentence and this is the end // of the line then return the cCategory for this node if (path.Length == 0) { return(template); } // otherwise split the input into it's component words string[] splitPath = path.Split(" \r\n\t".ToCharArray()); // get the first word of the sentence string firstWord = Normalize.MakeCaseInsensitive.TransformInput(splitPath[0]); // and concatenate the rest of the input into a new path for child nodes string newPath = path.Substring(firstWord.Length, path.Length - firstWord.Length); // first option is to see if this node has a child denoted by the "_" // wildcard. "_" comes first in precedence in the AIML alphabet if (children.ContainsKey("_")) { Node childNode = children["_"]; // add the next word to the wildcard match StringBuilder newWildcard = new StringBuilder(); storeWildCard(splitPath[0], newWildcard); // move down into the identified branch of the GraphMaster structure string result = childNode.evaluate(newPath, query, request, matchstate, newWildcard); // and if we get a result from the branch process the wildcard matches and return // the result if (result.Length > 0) { if (newWildcard.Length > 0) { // capture and push the star content appropriate to the current matchstate switch (matchstate) { case MatchState.UserInput: query.InputStar.Add(newWildcard.ToString()); // added due to this match being the end of the line newWildcard.Remove(0, newWildcard.Length); break; case MatchState.That: query.ThatStar.Add(newWildcard.ToString()); break; case MatchState.Topic: query.TopicStar.Add(newWildcard.ToString()); break; } } return(result); } } // second option - the nodemapper may have contained a "_" child, but led to no match // or it didn't contain a "_" child at all. So get the child nodemapper from this // nodemapper that matches the first word of the input sentence. if (children.ContainsKey(firstWord)) { // process the matchstate - this might not make sense but the matchstate is working // with a "backwards" path: "topic <topic> that <that> user input" // the "classic" path looks like this: "user input <that> that <topic> topic" // but having it backwards is more efficient for searching purposes MatchState newMatchstate = matchstate; if (firstWord == "<THAT>") { newMatchstate = MatchState.That; } else if (firstWord == "<TOPIC>") { newMatchstate = MatchState.Topic; } Node childNode = children[firstWord]; // move down into the identified branch of the GraphMaster structure using the new // matchstate StringBuilder newWildcard = new StringBuilder(); string result = childNode.evaluate(newPath, query, request, newMatchstate, newWildcard); // and if we get a result from the child return it if (result.Length > 0) { if (newWildcard.Length > 0) { // capture and push the star content appropriate to the matchstate if it exists // and then clear it for subsequent wildcards switch (matchstate) { case MatchState.UserInput: query.InputStar.Add(newWildcard.ToString()); newWildcard.Remove(0, newWildcard.Length); break; case MatchState.That: query.ThatStar.Add(newWildcard.ToString()); newWildcard.Remove(0, newWildcard.Length); break; case MatchState.Topic: query.TopicStar.Add(newWildcard.ToString()); newWildcard.Remove(0, newWildcard.Length); break; } } return(result); } } // third option - the input part of the path might have been matched so far but hasn't // returned a match, so check to see it contains the "*" wildcard. "*" comes last in // precedence in the AIML alphabet. if (children.ContainsKey("*")) { // o.k. look for the path in the child node denoted by "*" Node childNode = children["*"]; // add the next word to the wildcard match StringBuilder newWildcard = new StringBuilder(); storeWildCard(splitPath[0], newWildcard); string result = childNode.evaluate(newPath, query, request, matchstate, newWildcard); // and if we get a result from the branch process and return it if (result.Length > 0) { if (newWildcard.Length > 0) { // capture and push the star content appropriate to the current matchstate switch (matchstate) { case MatchState.UserInput: query.InputStar.Add(newWildcard.ToString()); // added due to this match being the end of the line newWildcard.Remove(0, newWildcard.Length); break; case MatchState.That: query.ThatStar.Add(newWildcard.ToString()); break; case MatchState.Topic: query.TopicStar.Add(newWildcard.ToString()); break; } } return(result); } } // o.k. if the nodemapper has failed to match at all: the input contains neither // a "_", the sFirstWord text, or "*" as a means of denoting a child node. However, // if this node is itself representing a wildcard then the search continues to be // valid if we proceed with the tail. if ((word == "_") || (word == "*")) { storeWildCard(splitPath[0], wildcard); return(evaluate(newPath, query, request, matchstate, wildcard)); } // If we get here then we're at a dead end so return an empty string. Hopefully, if the // AIML files have been set up to include a "* <that> * <topic> *" catch-all this // state won't be reached. Remember to empty the surplus to requirements wildcard matches wildcard = new StringBuilder(); return(string.Empty); }
/// <summary> /// Searches the CustomTag collection and processes the AIML if an appropriate tag handler is found /// </summary> /// <param name="user">the user who originated the request</param> /// <param name="query">the query that produced this node</param> /// <param name="request">the request from the user</param> /// <param name="result">the result to be sent to the user</param> /// <param name="node">the node to evaluate</param> /// <returns>the output string</returns> public AIMLTagHandler getBespokeTags(User user, SubQuery query, Request request, Result result, XmlNode node) { if (this.CustomTags.ContainsKey(node.Name.ToLower())) { TagHandler customTagHandler = (TagHandler)this.CustomTags[node.Name.ToLower()]; AIMLTagHandler newCustomTag = customTagHandler.Instantiate(this.LateBindingAssemblies); if(object.Equals(null,newCustomTag)) { return null; } else { newCustomTag.user = user; newCustomTag.query = query; newCustomTag.request = request; newCustomTag.result = result; newCustomTag.templateNode = node; newCustomTag.bot = this; return newCustomTag; } } else { return null; } }
/// <summary> /// Ctor /// </summary> /// <param name="query">The query that originated this node</param> /// <param name="request">The request inputted into the system</param> /// <param name="template">The node to be processed</param> public ThatStar(SubQuery query, Request request, XmlNode template) : base(template) { Query = query; Request = request; }
/// <summary> /// Given a request containing user input, produces a result from the bot /// </summary> /// <param name="request">the request from the user</param> /// <returns>the result to be output to the user</returns> public Result Chat(Request request) { Result result = new Result(request.user, this, request); if (this.isAcceptingUserInput) { // Normalize the input AIMLLoader loader = new AIMLLoader(this); AIMLbot.Normalize.SplitIntoSentences splitter = new AIMLbot.Normalize.SplitIntoSentences(this); string[] rawSentences = splitter.Transform(request.rawInput); foreach (string sentence in rawSentences) { result.InputSentences.Add(sentence); string path = loader.generatePath(sentence, request.user.getLastBotOutput(), request.user.Topic, true); result.NormalizedPaths.Add(path); } // grab the templates for the various sentences from the graphmaster foreach (string path in result.NormalizedPaths) { Utils.SubQuery query = new SubQuery(path); query.Template = this.Graphmaster.evaluate(path, query, request, MatchState.UserInput, new StringBuilder()); result.SubQueries.Add(query); } // process the templates into appropriate output foreach (SubQuery query in result.SubQueries) { if (query.Template.Length > 0) { try { XmlNode templateNode = AIMLTagHandler.getNode(query.Template); string outputSentence = this.processNode(templateNode, query, request, result, request.user); if (outputSentence.Length > 0) { result.OutputSentences.Add(outputSentence); } } catch (Exception e) { if (this.WillCallHome) { this.phoneHome(e.Message, request); } this.writeToLog("WARNING! A problem was encountered when trying to process the input: " + request.rawInput + " with the template: \"" + query.Template + "\""); } } } } else { result.OutputSentences.Add(this.NotAcceptingUserInputMessage); } // populate the Result object result.Duration = DateTime.Now - request.StartedOn; request.user.addResult(result); return result; }
/// <summary> /// Recursively evaluates the template nodes returned from the bot /// </summary> /// <param name="node">the node to evaluate</param> /// <param name="query">the query that produced this node</param> /// <param name="request">the request from the user</param> /// <param name="result">the result to be sent to the user</param> /// <param name="user">the user who originated the request</param> /// <returns>the output string</returns> private string processNode(XmlNode node, SubQuery query, Request request, Result result, User user) { // check for timeout (to avoid infinite loops) if (request.StartedOn.AddMilliseconds(request.bot.TimeOut) < DateTime.Now) { request.bot.writeToLog("WARNING! Request timeout. User: "******" raw input: \"" + request.rawInput + "\" processing template: \""+query.Template+"\""); request.hasTimedOut = true; return string.Empty; } // process the node string tagName = node.Name.ToLower(); if (tagName == "template") { StringBuilder templateResult = new StringBuilder(); if (node.HasChildNodes) { // recursively check foreach (XmlNode childNode in node.ChildNodes) { templateResult.Append(this.processNode(childNode, query, request, result, user)); } } return templateResult.ToString(); } else { AIMLTagHandler tagHandler = null; tagHandler = this.getBespokeTags(user, query, request, result, node); if (object.Equals(null, tagHandler)) { switch (tagName) { case "bot": tagHandler = new AIMLTagHandlers.bot(this, user, query, request, result, node); break; case "condition": tagHandler = new AIMLTagHandlers.Condition(this, user, query, request, result, node); break; case "date": tagHandler = new AIMLTagHandlers.date(this, user, query, request, result, node); break; case "formal": tagHandler = new AIMLTagHandlers.formal(this, user, query, request, result, node); break; case "gender": tagHandler = new AIMLTagHandlers.gender(this, user, query, request, result, node); break; case "get": tagHandler = new AIMLTagHandlers.get(this, user, query, request, result, node); break; case "gossip": tagHandler = new AIMLTagHandlers.gossip(this, user, query, request, result, node); break; case "id": tagHandler = new AIMLTagHandlers.id(this, user, query, request, result, node); break; case "input": tagHandler = new AIMLTagHandlers.input(this, user, query, request, result, node); break; case "javascript": tagHandler = new AIMLTagHandlers.javascript(this, user, query, request, result, node); break; case "learn": tagHandler = new AIMLTagHandlers.learn(this, user, query, request, result, node); break; case "lowercase": tagHandler = new AIMLTagHandlers.lowercase(this, user, query, request, result, node); break; case "person": tagHandler = new AIMLTagHandlers.person(this, user, query, request, result, node); break; case "person2": tagHandler = new AIMLTagHandlers.person2(this, user, query, request, result, node); break; case "random": tagHandler = new AIMLTagHandlers.random(this, user, query, request, result, node); break; case "sentence": tagHandler = new AIMLTagHandlers.sentence(this, user, query, request, result, node); break; case "set": tagHandler = new AIMLTagHandlers.set(this, user, query, request, result, node); break; case "size": tagHandler = new AIMLTagHandlers.size(this, user, query, request, result, node); break; case "sr": tagHandler = new AIMLTagHandlers.sr(this, user, query, request, result, node); break; case "srai": tagHandler = new AIMLTagHandlers.srai(this, user, query, request, result, node); break; case "star": tagHandler = new AIMLTagHandlers.star(this, user, query, request, result, node); break; case "system": tagHandler = new AIMLTagHandlers.system(this, user, query, request, result, node); break; case "that": tagHandler = new AIMLTagHandlers.that(this, user, query, request, result, node); break; case "thatstar": tagHandler = new AIMLTagHandlers.thatstar(this, user, query, request, result, node); break; case "think": tagHandler = new AIMLTagHandlers.think(this, user, query, request, result, node); break; case "topicstar": tagHandler = new AIMLTagHandlers.topicstar(this, user, query, request, result, node); break; case "uppercase": tagHandler = new AIMLTagHandlers.uppercase(this, user, query, request, result, node); break; case "version": tagHandler = new AIMLTagHandlers.version(this, user, query, request, result, node); break; default: tagHandler = null; break; } } if (object.Equals(null, tagHandler)) { return node.InnerText; } else { if (tagHandler.isRecursive) { if (node.HasChildNodes) { // recursively check foreach (XmlNode childNode in node.ChildNodes) { if (childNode.NodeType != XmlNodeType.Text) { childNode.InnerXml = this.processNode(childNode, query, request, result, user); } } } return tagHandler.Transform(); } else { string resultNodeInnerXML = tagHandler.Transform(); XmlNode resultNode = AIMLTagHandler.getNode("<node>" + resultNodeInnerXML + "</node>"); if (resultNode.HasChildNodes) { StringBuilder recursiveResult = new StringBuilder(); // recursively check foreach (XmlNode childNode in resultNode.ChildNodes) { recursiveResult.Append(this.processNode(childNode, query, request, result, user)); } return recursiveResult.ToString(); } else { return resultNode.InnerXml; } } } } }
/// <summary> /// Used to navigate the graph. /// </summary> public NodeSearcher() { Query = new SubQuery(); }
public void TestEvaluateWithStarWildCardUserInputNotMatched() { var path = "Test * 1 <that> that <topic> topic>"; var template = "<srai>TEST</srai>"; _node = new Node(); _node.AddCategory(path, template); var pathAlt = "Alt Test <that> that <topic> topic"; var templateAlt = "<srai>TEST ALT</srai>"; _node.AddCategory(pathAlt, templateAlt); _request = new Request("Test 1", new User("1", _chatBot), _chatBot); _subQuery = new SubQuery(path); Assert.AreEqual("<srai>TEST ALT</srai>", _node.Evaluate("Alt Test <that> that <topic> topic", _subQuery, _request, MatchState.UserInput, new StringBuilder())); }
/// <summary> /// Ctor /// </summary> /// <param name="query">The query that originated this node</param> /// <param name="request">The request inputted into the system</param> /// <param name="template">The node to be processed</param> public Person2(SubQuery query, Request request, XmlNode template) : base(template) { Query = query; Request = request; }
public void Setup() { var user = new User(); _request = new Request("This is a test", user); _query = new SubQuery(); }
public void TestEvaluateWithEmptyNode() { _chatBot = new ChatBot(); _node = new Node(); _request = new Request("Test 1", new User("1", _chatBot), _chatBot); _subQuery = new SubQuery("Test 1 <that> that <topic> topic"); Assert.AreEqual(string.Empty, _node.Evaluate("Test 1 <that> that <topic> topic", _subQuery, _request, MatchState.UserInput, new StringBuilder())); }
/// <summary> /// Searches the CustomTag collection and processes the AIML if an appropriate tag handler is found /// </summary> /// <param name="user">the user who originated the request</param> /// <param name="query">the query that produced this node</param> /// <param name="request">the request from the user</param> /// <param name="result">the result to be sent to the user</param> /// <param name="node">the node to evaluate</param> /// <returns>the output string</returns> private AIMLTagHandler getBespokeTags(User user, SubQuery query, Request request, Result result, XmlNode node) { if (this.CustomTags.ContainsKey(node.Name.ToLower())) { AIMLTagHandler customTagHandler = (AIMLTagHandler)this.CustomTags[node.Name.ToLower()]; customTagHandler.user = user; customTagHandler.query = query; customTagHandler.request = request; customTagHandler.result = result; customTagHandler.templateNode = node; customTagHandler.bot = this; return customTagHandler; } else { return null; } }
public void testEvaluateWith_WildCardThat() { var path = "Test 1 <that> _ <topic> topic"; var template = "<srai>TEST</srai>"; _node = new Node(); _node.AddCategory(path, template); var pathAlt = "Alt Test <that> that <topic> topic"; var templateAlt = "<srai>TEST ALT</srai>"; _node.AddCategory(pathAlt, templateAlt); _request = new Request("Test 1", new User("1", _chatBot), _chatBot); _subQuery = new SubQuery(path); var result = _node.Evaluate("Test 1 <that> WILDCARD WORDS <topic> topic", _subQuery, _request, MatchState.UserInput, new StringBuilder()); Assert.AreEqual("<srai>TEST</srai>", result); Assert.AreEqual("WILDCARD WORDS", _subQuery.ThatStar[0]); }
public void TestEvaluateWithInternationalCharset() { var path = "中 文 <that> * <topic> *"; var template = "中文 (Chinese)"; _node = new Node(); _node.AddCategory(path, template); var path2 = "日 本 語 <that> * <topic> *"; var template2 = "日 本 語 (Japanese)"; _node.AddCategory(path2, template2); var path3 = "Русский язык <that> * <topic> *"; var template3 = "Русский язык (Russian)"; _node.AddCategory(path3, template3); _request = new Request("中 文", new User("1", _chatBot), _chatBot); _subQuery = new SubQuery(path); Assert.AreEqual("中文 (Chinese)", _node.Evaluate("中 文 <that> * <topic> *", _subQuery, _request, MatchState.UserInput, new StringBuilder())); _request = new Request("日 本 語", new User("1", _chatBot), _chatBot); _subQuery = new SubQuery(path); Assert.AreEqual("日 本 語 (Japanese)", _node.Evaluate("日 本 語 <that> * <topic> *", _subQuery, _request, MatchState.UserInput, new StringBuilder())); _request = new Request("Русский язык", new User("1", _chatBot), _chatBot); _subQuery = new SubQuery(path); Assert.AreEqual("Русский язык (Russian)", _node.Evaluate("Русский язык <that> * <topic> *", _subQuery, _request, MatchState.UserInput, new StringBuilder())); }
public void TestEvaluateWithWildcardsInDifferentPartsOfPath() { var path = "Test * 1 <that> Test * 1 <topic> Test * 1"; var template = "<srai>TEST</srai>"; _node = new Node(); _node.AddCategory(path, template); var pathAlt = "Alt Test <that> that <topic> topic"; var templateAlt = "<srai>TEST ALT</srai>"; _node.AddCategory(pathAlt, templateAlt); _request = new Request("Test 1", new User("1", _chatBot), _chatBot); _subQuery = new SubQuery(path); Assert.AreEqual("<srai>TEST</srai>", _node.Evaluate( "Test WILDCARD USER WORDS 1 <that> Test WILDCARD THAT WORDS 1 <topic> Test WILDCARD TOPIC WORDS 1", _subQuery, _request, MatchState.UserInput, new StringBuilder())); Assert.AreEqual("WILDCARD USER WORDS", _subQuery.InputStar[0]); Assert.AreEqual("WILDCARD THAT WORDS", _subQuery.ThatStar[0]); Assert.AreEqual("WILDCARD TOPIC WORDS", _subQuery.TopicStar[0]); }
/// <summary> /// Ctor /// </summary> /// <param name="bot">The bot involved in this request</param> /// <param name="user">The user making the request</param> /// <param name="query">The query that originated this node</param> /// <param name="request">The request inputted into the system</param> /// <param name="result">The result to be passed to the user</param> /// <param name="templateNode">The node to be processed</param> public Condition(Bot bot, User user, SubQuery query, Request request, Result result, XmlNode templateNode) : base(bot, user, query, request, result, templateNode) { isRecursive = false; }
public void Setup() { _request = new Request("This is a test", new User()); _query = new SubQuery(); }
/// <summary> /// Ctor /// </summary> /// <param name="query">The query that originated this node</param> /// <param name="request">The request inputted into the system</param> /// <param name="template">The node to be processed</param> public Sentence(SubQuery query, Request request, XmlNode template) : base(template) { Query = query; Request = request; }
/// <summary> /// Navigates this node (and recusively into child nodes) for a match to the path passed as an argument /// whilst processing the referenced request /// </summary> /// <param name="path">The normalized path derived from the user's input</param> /// <param name="query">The query that this search is for</param> /// <param name="request">An encapsulation of the request from the user</param> /// <param name="matchstate">The part of the input path the node represents</param> /// <param name="wildcard">The contents of the user input absorbed by the AIML wildcards "_" and "*"</param> /// <returns>The template to process to generate the output</returns> public string evaluate(string path, SubQuery query, Request request, MatchState matchstate, StringBuilder wildcard) { if (request.StartedOn.AddMilliseconds(request.bot.TimeOut) < DateTime.Now) { request.bot.writeToLog("文件读取超时. 用户ID: " + request.user.UserID + ",输入内容: \"" + request.rawInput + "\""); request.hasTimedOut = true; return(string.Empty); } path = path.Trim(); if (this.children.Count == 0) { if (path.Length > 0) { this.storeWildCard(path, wildcard); } return(this.template); } if (path.Length == 0) { return(this.template); } List <string> splitPath = new List <string>(); string w = ""; foreach (char c in path.ToCharArray()) { if (Regex.IsMatch(c.ToString(), @"[\u4e00-\u9fa5]+")) { if (w != "") { splitPath.Add(w.ToString()); } w = ""; splitPath.Add(c.ToString()); } else if (c.ToString() == "*") { w = ""; splitPath.Add(c.ToString()); } else { if (!Regex.IsMatch(c.ToString(), @"[ \r\n\t]+")) { w += c.ToString(); } else if (w != "") { splitPath.Add(w.ToString()); w = ""; } } } if (w != "") { splitPath.Add(w.ToString()); } string firstWord = Normalize.MakeCaseInsensitive.TransformInput(splitPath[0]); string newPath = path.Substring(firstWord.Length, path.Length - firstWord.Length); if (this.children.ContainsKey("_")) { Node childNode = (Node)this.children["_"]; StringBuilder newWildcard = new StringBuilder(); this.storeWildCard(splitPath[0], newWildcard); string result = childNode.evaluate(newPath, query, request, matchstate, newWildcard); if (result.Length > 0) { if (newWildcard.Length > 0) { switch (matchstate) { case MatchState.UserInput: query.InputStar.Add(newWildcard.ToString()); newWildcard.Remove(0, newWildcard.Length); break; case MatchState.That: query.ThatStar.Add(newWildcard.ToString()); break; case MatchState.Topic: query.TopicStar.Add(newWildcard.ToString()); break; } } return(result); } } if (this.children.ContainsKey(firstWord)) { MatchState newMatchstate = matchstate; if (firstWord == "<THAT>") { newMatchstate = MatchState.That; } else if (firstWord == "<TOPIC>") { newMatchstate = MatchState.Topic; } Node childNode = (Node)this.children[firstWord]; StringBuilder newWildcard = new StringBuilder(); string result = childNode.evaluate(newPath, query, request, newMatchstate, newWildcard); if (result.Length > 0) { if (newWildcard.Length > 0) { switch (matchstate) { case MatchState.UserInput: query.InputStar.Add(newWildcard.ToString()); newWildcard.Remove(0, newWildcard.Length); break; case MatchState.That: query.ThatStar.Add(newWildcard.ToString()); newWildcard.Remove(0, newWildcard.Length); break; case MatchState.Topic: query.TopicStar.Add(newWildcard.ToString()); newWildcard.Remove(0, newWildcard.Length); break; } } return(result); } } if (this.children.ContainsKey("*")) { Node childNode = (Node)this.children["*"]; StringBuilder newWildcard = new StringBuilder(); this.storeWildCard(splitPath[0], newWildcard); string result = childNode.evaluate(newPath, query, request, matchstate, newWildcard); if (result.Length > 0) { if (newWildcard.Length > 0) { switch (matchstate) { case MatchState.UserInput: query.InputStar.Add(newWildcard.ToString()); newWildcard.Remove(0, newWildcard.Length); break; case MatchState.That: query.ThatStar.Add(newWildcard.ToString()); break; case MatchState.Topic: query.TopicStar.Add(newWildcard.ToString()); break; } } return(result); } } if ((this.word == "_") || (this.word == "*")) { this.storeWildCard(splitPath[0], wildcard); return(this.evaluate(newPath, query, request, matchstate, wildcard)); } wildcard = new StringBuilder(); return(string.Empty); }
/// <summary> /// Navigates this node (and recusively into child nodes) for a match to the path passed as an argument /// whilst processing the referenced request /// </summary> /// <param name="path">The normalized path derived from the user's input</param> /// <param name="query">The query that this search is for</param> /// <param name="request">An encapsulation of the request from the user</param> /// <param name="matchstate">The part of the input path the node represents</param> /// <param name="wildcard">The contents of the user input absorbed by the AIML wildcards "_" and "*"</param> /// <returns>The template to process to generate the output</returns> public string evaluate(string path, SubQuery query, Request request, MatchState matchstate, StringBuilder wildcard) { // check for timeout if (request.StartedOn.AddMilliseconds(request.bot.TimeOut) < DateTime.Now) { request.bot.writeToLog("WARNING! Request timeout. User: "******" raw input: \"" + request.rawInput + "\""); request.hasTimedOut = true; return string.Empty; } // so we still have time! path = path.Trim(); // check if this is the end of a branch in the GraphMaster // return the cCategory for this node if (this.children.Count==0) { if (path.Length > 0) { // if we get here it means that there is a wildcard in the user input part of the // path. this.storeWildCard(path, wildcard); } return this.template; } // if we've matched all the words in the input sentence and this is the end // of the line then return the cCategory for this node if (path.Length == 0) { return this.template; } // otherwise split the input into it's component words string[] splitPath = path.Split(" \r\n\t".ToCharArray()); // get the first word of the sentence string firstWord = Normalize.MakeCaseInsensitive.TransformInput(splitPath[0]); // and concatenate the rest of the input into a new path for child nodes string newPath = path.Substring(firstWord.Length, path.Length - firstWord.Length); // first option is to see if this node has a child denoted by the "_" // wildcard. "_" comes first in precedence in the AIML alphabet if (this.children.ContainsKey("_")) { Node childNode = (Node)this.children["_"]; // add the next word to the wildcard match StringBuilder newWildcard = new StringBuilder(); this.storeWildCard(splitPath[0],newWildcard); // move down into the identified branch of the GraphMaster structure string result = childNode.evaluate(newPath, query, request, matchstate, newWildcard); // and if we get a result from the branch process the wildcard matches and return // the result if (result.Length>0) { if (newWildcard.Length > 0) { // capture and push the star content appropriate to the current matchstate switch (matchstate) { case MatchState.UserInput: query.InputStar.Add(newWildcard.ToString()); // added due to this match being the end of the line newWildcard.Remove(0, newWildcard.Length); break; case MatchState.That: query.ThatStar.Add(newWildcard.ToString()); break; case MatchState.Topic: query.TopicStar.Add(newWildcard.ToString()); break; } } return result; } } // second option - the nodemapper may have contained a "_" child, but led to no match // or it didn't contain a "_" child at all. So get the child nodemapper from this // nodemapper that matches the first word of the input sentence. if (this.children.ContainsKey(firstWord)) { // process the matchstate - this might not make sense but the matchstate is working // with a "backwards" path: "topic <topic> that <that> user input" // the "classic" path looks like this: "user input <that> that <topic> topic" // but having it backwards is more efficient for searching purposes MatchState newMatchstate = matchstate; if (firstWord == "<THAT>") { newMatchstate = MatchState.That; } else if (firstWord == "<TOPIC>") { newMatchstate = MatchState.Topic; } Node childNode = (Node)this.children[firstWord]; // move down into the identified branch of the GraphMaster structure using the new // matchstate StringBuilder newWildcard = new StringBuilder(); string result = childNode.evaluate(newPath, query, request, newMatchstate,newWildcard); // and if we get a result from the child return it if (result.Length > 0) { if (newWildcard.Length > 0) { // capture and push the star content appropriate to the matchstate if it exists // and then clear it for subsequent wildcards switch (matchstate) { case MatchState.UserInput: query.InputStar.Add(newWildcard.ToString()); newWildcard.Remove(0, newWildcard.Length); break; case MatchState.That: query.ThatStar.Add(newWildcard.ToString()); newWildcard.Remove(0, newWildcard.Length); break; case MatchState.Topic: query.TopicStar.Add(newWildcard.ToString()); newWildcard.Remove(0, newWildcard.Length); break; } } return result; } } // third option - the input part of the path might have been matched so far but hasn't // returned a match, so check to see it contains the "*" wildcard. "*" comes last in // precedence in the AIML alphabet. if (this.children.ContainsKey("*")) { // o.k. look for the path in the child node denoted by "*" Node childNode = (Node)this.children["*"]; // add the next word to the wildcard match StringBuilder newWildcard = new StringBuilder(); this.storeWildCard(splitPath[0], newWildcard); string result = childNode.evaluate(newPath, query, request, matchstate, newWildcard); // and if we get a result from the branch process and return it if (result.Length > 0) { if (newWildcard.Length > 0) { // capture and push the star content appropriate to the current matchstate switch (matchstate) { case MatchState.UserInput: query.InputStar.Add(newWildcard.ToString()); // added due to this match being the end of the line newWildcard.Remove(0, newWildcard.Length); break; case MatchState.That: query.ThatStar.Add(newWildcard.ToString()); break; case MatchState.Topic: query.TopicStar.Add(newWildcard.ToString()); break; } } return result; } } // o.k. if the nodemapper has failed to match at all: the input contains neither // a "_", the sFirstWord text, or "*" as a means of denoting a child node. However, // if this node is itself representing a wildcard then the search continues to be // valid if we proceed with the tail. if ((this.word == "_") || (this.word == "*")) { this.storeWildCard(splitPath[0], wildcard); return this.evaluate(newPath, query, request, matchstate, wildcard); } // If we get here then we're at a dead end so return an empty string. Hopefully, if the // AIML files have been set up to include a "* <that> * <topic> *" catch-all this // state won't be reached. Remember to empty the surplus to requirements wildcard matches wildcard = new StringBuilder(); return string.Empty; }
public void TestEvaluateWithMultipleWildcardsSwitched() { var path = "Test * 1 _ <that> Test * 1 _ <topic> Test _ 1 *"; var template = "<srai>TEST</srai>"; _node = new Node(); _node.AddCategory(path, template); var pathAlt = "Alt Test <that> that <topic> topic"; var templateAlt = "<srai>TEST ALT</srai>"; _node.AddCategory(pathAlt, templateAlt); _request = new Request("Test 1", new User("1", _chatBot), _chatBot); _subQuery = new SubQuery(path); Assert.AreEqual("<srai>TEST</srai>", _node.Evaluate( "Test FIRST USER 1 SECOND USER <that> Test FIRST THAT 1 SECOND THAT <topic> Test FIRST TOPIC 1 SECOND TOPIC", _subQuery, _request, MatchState.UserInput, new StringBuilder())); Assert.AreEqual(2, _subQuery.InputStar.Count); Assert.AreEqual("SECOND USER", _subQuery.InputStar[0]); Assert.AreEqual("FIRST USER", _subQuery.InputStar[1]); Assert.AreEqual(2, _subQuery.ThatStar.Count); Assert.AreEqual("SECOND THAT", _subQuery.ThatStar[0]); Assert.AreEqual("FIRST THAT", _subQuery.ThatStar[1]); Assert.AreEqual(2, _subQuery.TopicStar.Count); Assert.AreEqual("SECOND TOPIC", _subQuery.TopicStar[0]); Assert.AreEqual("FIRST TOPIC", _subQuery.TopicStar[1]); }
// Token: 0x0600001D RID: 29 RVA: 0x000028E0 File Offset: 0x000018E0 public string evaluate(string path, SubQuery query, Request request, MatchState matchstate, StringBuilder wildcard) { if (request.StartedOn.AddMilliseconds(request.bot.TimeOut) < DateTime.Now) { request.bot.writeToLog(string.Concat(new string[] { "WARNING! Request timeout. User: "******" raw input: \"", request.rawInput, "\"" })); request.hasTimedOut = true; return(string.Empty); } path = path.Trim(); if (this.children.Count == 0) { if (path.Length > 0) { this.storeWildCard(path, wildcard); } return(this.template); } if (path.Length == 0) { return(this.template); } string[] array = path.Split(" \r\n\t".ToCharArray()); string text = MakeCaseInsensitive.TransformInput(array[0]); string path2 = path.Substring(text.Length, path.Length - text.Length); if (this.children.ContainsKey("_")) { Node node = this.children["_"]; StringBuilder stringBuilder = new StringBuilder(); this.storeWildCard(array[0], stringBuilder); string text2 = node.evaluate(path2, query, request, matchstate, stringBuilder); if (text2.Length > 0) { if (stringBuilder.Length > 0) { switch (matchstate) { case MatchState.UserInput: query.InputStar.Add(stringBuilder.ToString()); stringBuilder.Remove(0, stringBuilder.Length); break; case MatchState.That: query.ThatStar.Add(stringBuilder.ToString()); break; case MatchState.Topic: query.TopicStar.Add(stringBuilder.ToString()); break; } } return(text2); } } if (this.children.ContainsKey(text)) { MatchState matchstate2 = matchstate; if (text == "<THAT>") { matchstate2 = MatchState.That; } else if (text == "<TOPIC>") { matchstate2 = MatchState.Topic; } Node node2 = this.children[text]; StringBuilder stringBuilder2 = new StringBuilder(); string text3 = node2.evaluate(path2, query, request, matchstate2, stringBuilder2); if (text3.Length > 0) { if (stringBuilder2.Length > 0) { switch (matchstate) { case MatchState.UserInput: query.InputStar.Add(stringBuilder2.ToString()); stringBuilder2.Remove(0, stringBuilder2.Length); break; case MatchState.That: query.ThatStar.Add(stringBuilder2.ToString()); stringBuilder2.Remove(0, stringBuilder2.Length); break; case MatchState.Topic: query.TopicStar.Add(stringBuilder2.ToString()); stringBuilder2.Remove(0, stringBuilder2.Length); break; } } return(text3); } } if (this.children.ContainsKey("*")) { Node node3 = this.children["*"]; StringBuilder stringBuilder3 = new StringBuilder(); this.storeWildCard(array[0], stringBuilder3); string text4 = node3.evaluate(path2, query, request, matchstate, stringBuilder3); if (text4.Length > 0) { if (stringBuilder3.Length > 0) { switch (matchstate) { case MatchState.UserInput: query.InputStar.Add(stringBuilder3.ToString()); stringBuilder3.Remove(0, stringBuilder3.Length); break; case MatchState.That: query.ThatStar.Add(stringBuilder3.ToString()); break; case MatchState.Topic: query.TopicStar.Add(stringBuilder3.ToString()); break; } } return(text4); } } if (this.word == "_" || this.word == "*") { this.storeWildCard(array[0], wildcard); return(this.evaluate(path2, query, request, matchstate, wildcard)); } wildcard = new StringBuilder(); return(string.Empty); }
/// <summary> /// Recursively evaluates the template nodes returned from the ChatBot /// </summary> /// <param name="node">the node to evaluate</param> /// <param name="query">the query that produced this node</param> /// <param name="request">the request from the user</param> /// <param name="user">the user who originated the request</param> /// <returns>the output string</returns> private string ProcessNode(XmlNode node, SubQuery query, Request request, User user) { // process the node var tagName = node.Name.ToLower(); if (tagName == "template") { var templateResult = new StringBuilder(); if (node.HasChildNodes) { // recursively check foreach (XmlNode childNode in node.ChildNodes) { templateResult.Append(ProcessNode(childNode, query, request, user)); } } return templateResult.ToString(); } AIMLTagHandler tagHandler = null; switch (tagName) { case "bot": tagHandler = new Bot(node); break; case "condition": tagHandler = new Condition(user, node); break; case "date": tagHandler = new Date(node); break; case "formal": tagHandler = new Formal(node); break; case "gender": tagHandler = new AIMLTagHandlers.Gender(query, request, node); break; case "get": tagHandler = new Get(user, node); break; case "gossip": tagHandler = new Gossip(user, node); break; case "id": tagHandler = new Id(user, node); break; case "input": tagHandler = new Input(user, request, node); break; case "javascript": tagHandler = new Javascript(node); break; case "learn": tagHandler = new Learn(node); break; case "lowercase": tagHandler = new Lowercase(node); break; case "person": tagHandler = new Person(query, request, node); break; case "person2": tagHandler = new Person2(query, request, node); break; case "random": tagHandler = new Random(node); break; case "sentence": tagHandler = new Sentence(query, request, node); break; case "set": tagHandler = new Set(user, node); break; case "size": tagHandler = new Size(node); break; case "sr": tagHandler = new Sr(this, user, query, request, node); break; case "srai": tagHandler = new Srai(this, user, request, node); break; case "star": tagHandler = new Star(query, request, node); break; case "system": tagHandler = new SystemTag(node); break; case "that": tagHandler = new That(user, request, node); break; case "thatstar": tagHandler = new ThatStar(query, request, node); break; case "think": tagHandler = new Think(node); break; case "topicstar": tagHandler = new Topicstar(query, request, node); break; case "uppercase": tagHandler = new Uppercase(node); break; case "version": tagHandler = new Version(node); break; default: Log.ErrorFormat("Unknown AIML tag: {0}", tagName); break; } if (Equals(null, tagHandler)) { return node.InnerText; } if (tagHandler.IsRecursive) { if (node.HasChildNodes) { // recursively check foreach (XmlNode childNode in node.ChildNodes) { if (childNode.NodeType != XmlNodeType.Text) { childNode.InnerXml = ProcessNode(childNode, query, request, user); } } } return tagHandler.ProcessChange(); } var resultNodeInnerXML = tagHandler.ProcessChange(); var resultNode = AIMLTagHandler.GetNode("<node>" + resultNodeInnerXML + "</node>"); if (resultNode.HasChildNodes) { var recursiveResult = new StringBuilder(); // recursively check foreach (XmlNode childNode in resultNode.ChildNodes) { recursiveResult.Append(ProcessNode(childNode, query, request, user)); } return recursiveResult.ToString(); } return resultNode.InnerXml; }