/// <summary> /// deals with the "get" tag /// </summary> /// <param name="thisNode">the "get" node in question</param> /// <param name="thisCat">the current category</param> /// <param name="myBot">the bot whose graphmaster returned the "template"</param> /// <param name="sUserID">the user who requires a reply</param> /// <returns>the string that results in the processing of this node</returns> private static string getTag(XmlNode thisNode, cCategory thisCat, cBot myBot, string sUserID) { // get the attributes for this tag XmlAttributeCollection myAttributes = thisNode.Attributes; // no attributes? then just return a blank if (myAttributes.Count == 0) { return(""); } // o.k. we have an attribute to process // get the value associated with the "name" attribute string sName = thisNode.Attributes["name"].Value; cUser myUser = (cUser)cUsers.users[sUserID]; string sValue = (string)myUser.Predicates[sName]; if (sValue == null) { sValue = ""; } return(sValue.Trim()); }
/// <summary> /// Takes the user's raw input and returns a cResponse object for this bot /// </summary> /// <param name="sRawInput">the user's raw input</param> /// <param name="sUserID">the user's id</param> /// <returns>the cResponse object containing information about the reply from the bot</returns> public cResponse chat(string sRawInput, string sUserID) { // process the user cUser myUser; if (cUsers.users.ContainsKey(sUserID)) { myUser = (cUser)cUsers.users[sUserID]; } else { myUser = new cUser(sUserID); cUsers.users.Add(sUserID, myUser); } // get the "that" and "topic" fields string sNewThat = cNormalizer.substitute(cGlobals.getSubstitutions(), myUser.getThat()); string sThat = cNormalizer.patternfit(sNewThat); if (sThat.Length == 0) { sThat = "*"; } string sTopic = myUser.sTopic; // do some normalisation on the raw input string sSubstitutedInput = cNormalizer.substitute(Substitutions, sRawInput); ArrayList sSplitInput = cNormalizer.sentencesplit(Splitters, sSubstitutedInput); // to hold the bot's reply string[] sRawOutput = { "", "" }; ArrayList alReply = new ArrayList(); for (int i = 0; i < sSplitInput.Count; i++) { string sFullInput = cNormalizer.patternfit((string)sSplitInput[i]) + " <that> " + sThat + " <topic> " + sTopic; sRawOutput = GraphMaster.evaluate(sFullInput, this, sUserID); string sReply = (string)sRawOutput[1]; // make sure everything is spaced out properly string[] sWords = sReply.Split(" \r\n\t".ToCharArray()); sReply = ""; foreach (string sThisWord in sWords) { string sWord = sThisWord.Trim(); if ((sWord == ".") || (sWord == ",") || (sWord == "!") || (sWord == "?")) { sReply += sWord; } else if (sWord == "") { } else { sReply += " " + sWord; } } string sProcessedReply = sReply.Trim(); alReply.Add(sProcessedReply); } // The following should never happen if you have your AIML sorted out properly! // Hint: try having a '*' pattern to catch all unknown input with responses like "Huh?", // "I'm sorry I didn't understand that..." or "I'm afraid I don't understand" if (alReply.Count == 0) { if (cGlobals.isDebug) { alReply.Add("WARNING! No reply generated by Graphmaster algorithm. Please contact the administrator of this software."); cGlobals.writeLog("WARNING! The Graphmaster algorithm failed to generate a reply under the following conditions.\r\nRawInput: " + sRawInput + "\r\n'that': " + sThat + "\r\n'topic': " + sTopic + "\r\n'UserID': " + sUserID + "\r\nPlease check your AIML files to make sure this input can be processed."); } else { alReply.Add("Hmmm, I'm not sure I understand what you mean. I think parts of my brain are missing. Please make sure I have access to a large set of AIML files. See http://www.alicebot.org/ for more information."); } } // Create the response object that is to be returned cResponse ReplyObject = new cResponse(sRawInput, sThat, sTopic, sUserID, "Default", alReply, sRawOutput[0]); // store the new <that> setting myUser.alThat.Insert(0, ReplyObject.getThat()); // store the user's input into the "Input" arraylist myUser.alInput.Insert(0, cNormalizer.sentencesplit(this.Splitters, ReplyObject.sInput)); return(ReplyObject); }
/// <summary> /// deals with the "set" tag /// </summary> /// <param name="thisNode">the "set" node in question</param> /// <param name="thisCat">the current category</param> /// <param name="myBot">the bot whose graphmaster returned the "template"</param> /// <param name="sUserID">the user who requires a reply</param> /// <returns>the string that results in the processing of this node</returns> private static string setTag(XmlNode thisNode, cCategory thisCat, cBot myBot, string sUserID) { // get the attributes for this tag XmlAttributeCollection myAttributes = thisNode.Attributes; // no attributes? then just return a blank if (myAttributes.Count == 0) { return(""); } // o.k. we have an attribute to process // get the value(s) associated with the "name" attribute string sName = thisNode.Attributes["name"].Value; string sContent = thisNode.InnerText; string sStarXML = thisNode.InnerXml; // ultimately holds the processed value for this predicate string sValue = ""; // check for further processing if (sStarXML.StartsWith("<star")) { XmlDocument starXML = new XmlDocument(); starXML.LoadXml(sStarXML); // get the node that we need XmlNode starnode = starXML.SelectSingleNode("descendant::star"); sValue = star(starnode, thisCat, myBot, sUserID); } else { sValue = sContent; } // make sure any names are stored correctly if (sName.ToUpper() == "NAME") { string sNewValue = formal(sValue); sValue = sNewValue; thisNode.InnerText = " " + sValue; } cUser myUser = (cUser)cUsers.users[sUserID]; // handle the topic predicate otherwise it is a generic predicate if (sName.ToUpper() == "TOPIC") { if ((sValue.Length == 0) || (sValue == "") || (sValue == " ") || (sValue == null)) { sValue = "*"; } myUser.sTopic = sValue; } else { if (myUser.Predicates.Contains(sName)) { myUser.Predicates.Remove(sName); } myUser.Predicates.Add(sName, sValue); } return(thisNode.InnerText); }
/// <summary> /// deals with the "input" tag /// </summary> /// <param name="thisNode">the "input" node in question</param> /// <param name="thisCat">the current category</param> /// <param name="myBot">the bot whose graphmaster returned the "template"</param> /// <param name="sUserID">the user who requires a reply</param> /// <returns>the string that results in the processing of this node</returns> private static string input(XmlNode thisNode, cCategory thisCat, cBot myBot, string sUserID) { // the conversation histories are stored in the cUser object for the user cUser thisUser = (cUser)cUsers.users[sUserID]; // o.k. lets check that we actually have some "That"s (there is a small possibility that this // might happen if the AIML code is flunky) if (thisUser.alInput.Count > 0) { // get the attributes for this tag XmlAttributeCollection myAttributes = thisNode.Attributes; // no attributes? then just return the last That if (myAttributes.Count == 0) { ArrayList alLastInput = (ArrayList)thisUser.alInput[0]; return((string)alLastInput[0]); } // o.k. we have some attributes to process and, // yeah I know upper case attributes are naff but I've seen // some AIML with them in so I'm including this kludge just in case else { string sIndex; // get the value associated with the "index" attribute sIndex = thisNode.Attributes["index"].Value; if (sIndex == null) { // get the value associated with the "INDEX" attribute sIndex = thisNode.Attributes["INDEX"].Value; } if (sIndex != null) { // o.k. if we're here then there is an index to a particular "that" statement // the index can be either in one or two dimensions string sFirstDimension, sSecondDimension; int iFirst, iSecond; // extract the first dimension sFirstDimension = (string)sIndex[0].ToString(); iFirst = Convert.ToInt32(sFirstDimension); iFirst -= 1; // check the first dimension is in range if ((iFirst > thisUser.alInput.Count - 1) || (iFirst < 0)) { // write a warning message to the bot log cGlobals.writeLog("The user " + sUserID + " caused a reference to a <that> that was out of range. Check AIML for path:" + thisCat.sPath + "\n"); // for safety's sake return the default value for <that> ArrayList alLastInput = (ArrayList)thisUser.alInput[0]; return((string)alLastInput[0]); } // now check if we have a second dimension if (sIndex.Length == 3) // sIndex will be something like "1,2" { sSecondDimension = (string)sIndex[2].ToString(); iSecond = Convert.ToInt32(sSecondDimension); iSecond -= 1; } else { iSecond = 0; } // get the appropriate arraylist of sentences ArrayList alLastInputSentences = (ArrayList)thisUser.alInput[iFirst]; // check the second dimension is in range if ((iSecond > alLastInputSentences.Count - 1) || (iSecond < 0)) { // write a warning message to the bot log cGlobals.writeLog("The user " + sUserID + " caused a reference to a two dimensional <that> that was out of range. Check AIML for path:" + thisCat.sPath + "\n"); // for safety's sake return the default value for <that> ArrayList alLastInput = (ArrayList)thisUser.alInput[0]; return((string)alLastInput[0]); } // okay, we have two dimensions and they're in range so return the correct result! return((string)alLastInputSentences[iSecond]); } else { // index is not one of the attributes so just return the default ArrayList alLastInput = (ArrayList)thisUser.alInput[0]; return((string)alLastInput[0]); } } } else { // if we get here it means the AIML is FUBAR cGlobals.writeLog("The user " + sUserID + " caused the return of a blank INPUT. CHECK THE AIML path: " + thisCat.sPath + "\n"); return(""); } }
/// <summary> /// Takes the user's raw input and returns a cResponse object for this bot /// </summary> /// <param name="sRawInput">the user's raw input</param> /// <param name="sUserID">the user's id</param> /// <returns>the cResponse object containing information about the reply from the bot</returns> public cResponse chat(string sRawInput, string sUserID) { // process the user cUser myUser; if(cUsers.users.ContainsKey(sUserID)) { myUser=(cUser)cUsers.users[sUserID]; } else { myUser=new cUser(sUserID); cUsers.users.Add(sUserID,myUser); } // get the "that" and "topic" fields string sNewThat=cNormalizer.substitute(cGlobals.getSubstitutions(), myUser.getThat()); string sThat=cNormalizer.patternfit(sNewThat); if (sThat.Length==0) sThat="*"; string sTopic=myUser.sTopic; // do some normalisation on the raw input string sSubstitutedInput = cNormalizer.substitute(Substitutions,sRawInput); ArrayList sSplitInput = cNormalizer.sentencesplit(Splitters,sSubstitutedInput); // to hold the bot's reply string[] sRawOutput={"",""}; ArrayList alReply=new ArrayList(); for (int i=0; i<sSplitInput.Count; i++) { string sFullInput=cNormalizer.patternfit((string)sSplitInput[i])+" <that> "+sThat+" <topic> "+sTopic; sRawOutput = GraphMaster.evaluate(sFullInput,this, sUserID); string sReply = (string)sRawOutput[1]; // make sure everything is spaced out properly string[] sWords=sReply.Split(" \r\n\t".ToCharArray()); sReply=""; foreach(string sThisWord in sWords) { string sWord=sThisWord.Trim(); if((sWord==".")||(sWord==",")||(sWord=="!")||(sWord=="?")) { sReply+=sWord; } else if (sWord=="") { } else { sReply+=" "+sWord; } } string sProcessedReply=sReply.Trim(); alReply.Add(sProcessedReply); } // The following should never happen if you have your AIML sorted out properly! // Hint: try having a '*' pattern to catch all unknown input with responses like "Huh?", // "I'm sorry I didn't understand that..." or "I'm afraid I don't understand" if (alReply.Count==0) { if(cGlobals.isDebug) { alReply.Add("WARNING! No reply generated by Graphmaster algorithm. Please contact the administrator of this software."); cGlobals.writeLog("WARNING! The Graphmaster algorithm failed to generate a reply under the following conditions.\r\nRawInput: "+sRawInput+"\r\n'that': "+sThat+"\r\n'topic': "+sTopic+"\r\n'UserID': "+sUserID+"\r\nPlease check your AIML files to make sure this input can be processed."); } else { alReply.Add("Hmmm, I'm not sure I understand what you mean. I think parts of my brain are missing. Please make sure I have access to a large set of AIML files. See http://www.alicebot.org/ for more information."); } } // Create the response object that is to be returned cResponse ReplyObject = new cResponse ( sRawInput,sThat,sTopic, sUserID, "Default", alReply, sRawOutput[0]); // store the new <that> setting myUser.alThat.Insert(0,ReplyObject.getThat()); // store the user's input into the "Input" arraylist myUser.alInput.Insert(0,cNormalizer.sentencesplit(this.Splitters,ReplyObject.sInput)); return ReplyObject; }