Saturday, October 18, 2014

Building Your ChatBot via AIML

This postings is pretty much for the person who would like to implement your own ChatBot via AIML (Artificial Intelligence Markup Language) 2.x. I wouldn't talk about the basic concept or logic too much but you can find them from the share links as below.

Preparation:

Before we start to talk about the aiml, you need to set up your environment, here are the preparation tasks:
  1. Knowing AIML Concept and Basic Logic
  2. Download the ProgramAB Source Code and Import into Eclipse or other IDE. 
  3. Make sure your ProgramAB run / debug without error message.
  4. I will make a new bots aiml files a copy from /bots/alice2 to the new location such as e.g: /bots/HelPer
  5. I usually prepare two copies in case I mess around the aiml files. Then I will update the run.sh (you can use run.bat for windows) in one of the copies as below example in blue.(the reason why I would like to have two copies is I always use action=aiml2csv cli to make sure the aiml file format correct which follows syntax format. This is just personal preference.) 
  6. I modified the programAB to change the botname to HelPer, adding a UI for easier testing and logging for tracing purpose. I will share it out on gitHub after I figure out these opensource license stuff.

run.sh eg:

java#
    java -cp lib/Ab.jar Main bot=HelPer action=aiml2csv trace=true morph=false
      cp ./bots/HelPer/aimlif/*.aiml.csv ../Users/xxx/workspace/LUNA/ProgramAB/bots/HelPer/aimlif/ -f

      I decide the ChatBot aiml separate into couple sessions as below. I would like to use my way to explain how's AIML can be written like a programming language. Hopefully it will help you easier to picture it from programmer point of view.
      1. Basic Concept.
      2. Default Folders and Preparation.
      3. Wildcard
      4. Memory + Echo + Think
      5. Recursion(goto)
      6. if then else with set/map
      7. Condition (Select Case) + That (link with previous chat)
      8. loop
      9. grouping
      10. execution (non AIML features)

      1. Basic Concept.

      AIML is an extension of a language called XML. It's written using "tag" (code) and text. Some tags came from pair and with some contents (text or even include nest tag) in between. Some tags will "self-closing" and don't require a partner (pair) e.g: <get=name="age"/>. 

      Beside that, it's HTML markup, which means you can use HTML to markup your bot's responses (templates) with the appropriate formatting. It's allow you include images or hyperlink that lead to other site. However, the premise is it's wrapped by HTML such as web site.

      e.g:HTML Images

      <img src="w3schools.jpg" alt="W3Schools.com" width="104" height="142">
      e.g: HTML links: 
      <href="http://www.w3schools.com">This is a link</a>

      The AIML basic concept is composed by 4 major segments.

      a. <aiml></aiml> is basically tell the program it's aiml file.

      b. <category></category> is the basic unit of knowledge in AIML. A aiml file can only have a pair of <aiml></aiml> but underneath can have multiple categories tags. 

      c. <pattern></pattern> is inside of <category> and you can think it's input for the ChatBot. One category tag can only have one pattern tag. The content is usually ignore the punctuation and it's always upper case.

      d. <template></template> is inside of <category> as well and it's the output from the ChatBot.Same with pattern, one category is only allow on template.

      here is an example:
      <aiml>
          <category>
              <pattern>MATCHES WHAT THE USER SAYS</pattern>
              <template>What’s the bots replies</template>
          </category>
          <category>
              <pattern>Do you like Happy 123 ChatBot Blog</pattern>
              <template>Yes, I like it</template>
          </category>
      </aiml>

      2. Default Folders and Preparation

      The default folders might be different regarding the design. I used ProgramAB as example. It includes 

      a. aiml: aiml files

      b. aimlif: The AIMLIF (AIML Intermediate Format)in CSV. It translates each AIML category into a single line of text.

      c. config: This folder includes normalization, properties, default predicates and the required configuration files such as triples ... etc.

      d. sets: e.g color.txt and content includes red, yellow, blue ... etc. Each word is one line.

      e. maps: it's a pair e.g: state2capital.txt and content includes CALIFORNIA:Sacramento ... etc. Each pair is one line.

      Basically the default download aiml is pretty much cover general ChatBot, you can start from bot_profile.aiml to set up default bot inform, such as name, birthday, gender ... etc.

      Except profile.aiml, I usually start from udc.aiml ( ultimate default category ) since if bot can't find any match. It will be point to udc.aiml eventually. For me, it's the last-ditch for bot response. e.g: if bot can't find the match answer and you don't want your bot random pick up the answer, you can ask your bot to tell such as "I don't know this answer" or "Please talk to the real support folk" ... etc.

      There has some default aiml files we might need to care but if you would like to start to play your aiml, i think it's almost ready now.

      3. Wildcard

      Wildcard just like * in SQL command, allow you to capture the input.

      wild card aiml e.g: 

      <category>
      <pattern>_ JOHNNY BLOG</pattern>
      <template>http://chianingwang.blogspot.com/</template>
      </category>

      Chat Log e.g:

      [2014-10-17 21:57:46] Q: do you know Johnny blog
      [2014-10-17 21:57:46] A: http://chianingwang.blogspot.com/

      I sum the wildcard follow with priority as below.





      4. Memory + Think

      There memory feature in aiml I summarized into 5 types as below.

      a. Properties: Global Constants for a bot. Can only be changed by BotMaster.( check e.g: ProgramAB\bots\HelPer\config\properties.txt ; format e.g: name:HelPer )

      b. Predicates: Global Variables for the bot. Usually set by the client when a template is activated. ( check e.g: ProgramAB\bots\HelPer\config\predicate.txt ; format e.g: address:where )

      c. Local Variables: Which are just like predicates, except their scope is limited to one category.

      d. learn: Lean is pretty much remember the whole category(Q&A).

      e. learnf: Leanf is not only remember conversation but also you can write it out into learnf.aiml. PS when you finish the code type wq. It will write the learnf from memory to physical file under the bot folder.

      variable + think aiml e.g: ( think won't and doesn't need to show up )

      <!--Variable + think (won't appear)-->
      <category>
      <pattern>$THE HELPER IS *</pattern>
      <template><think><set var="robot"><star/></set></think>
      I like <get var="robot"/> HelPer.
      </template>
      </category>

      Chat Log e.g:

      [2014-10-17 22:23:30] Q: the helper is cool
      [2014-10-17 22:23:30] A: I like cool HelPer.


      Predicates aiml eg:

      <!--Echo-->
      <category>
      <pattern>$MY NAME IS *</pattern>
      <template>Nice to meet you, <set name="name"><star/></set></template>
      </category>

      <category>
      <pattern>$WHAT IS MY NAME</pattern>
      <template>Your name is, <get name="name"/>.</template>
      </category> 

      Chat Log e.g:

      [2014-10-17 22:15:16] Q: my name is Johnny
      [2014-10-17 22:15:16] A: Nice to meet you, Johnny
      [2014-10-17 22:15:22] Q: what's my name
      [2014-10-17 22:15:22] A: Your name is, Johnny.


      Learn aiml e.g:

      <!--Learn-->
      <category>
      <pattern>$THE APPLE IS RED</pattern>
      <template>I will remember that the apple is red
      <learn>
      <category>
      <pattern>WHAT COLOR IS THE APPLE</pattern>
      <template>The apple is red</template>
      </category>
      </learn>
      </template>
      </category>

      Chat Log e.g:

      [2014-10-17 22:23:37] Q: the apple is red
      [2014-10-17 22:23:37] A: I will remember that the apple is red
      [2014-10-17 22:23:44] Q: what color is the apple
      [2014-10-17 22:23:44] A: The apple is red

      How do we access variables defined in the outer category from the inner category (found within the learn tag) ? Anything found within the <eval> tags will be evaluated FIRST, before the new category is actually created. This allow us to use <star/> within the <learn> tags to access parts of the input matched by the outer category.

      Another Learn aiml with eval (nest category) e.g:

      <!--Learn + eval(outer category)-->
      <category>
      <pattern>$THE BEST ENGINEER IS IN *</pattern>
      <template>I will remember that <star/> has best engineer.
      <learnf>
      <category>
      <pattern>DOES <eval><star/></eval> HAS ENGINEER</pattern>
      <template>Of course they have! Actually, <eval><star/></eval> has best engineer !</template>
      </category>
      </learnf>
      </template>
      </category>

      Chat Log eg:

      [2014-10-18 08:43:36] Q: The Best Engineer is in SCU
      [2014-10-18 08:43:36] A: I will remember that SCU has best engineer.
      [2014-10-18 08:43:43] Q: does SCU has engineer ?
      [2014-10-18 08:43:43] A: Of course they have! Actually, SCU has best engineer !


      5. Recursion(goto)

      <srai> allows you to go to other categories as long as the pattern is matched.

      sria e.g.:

      <!--srai (Recursion or link or goto)-->
      <category>
      <pattern>YELLO</pattern>
      <template>Ya ! Hello</template>
      </category>

      <!--srai (Recursion or link or goto) YELLO-->
      <category>
      <pattern>$HI THERE</pattern>
      <template><srai>YELLO</srai> how are you doing !</template>
      </category>

      <!--srai (Recursion or link or goto) YELLO-->
      <category>
      <pattern>HOWDY</pattern>
      <template><srai>YELLO</srai> What's up !</template>
      </category>

      Chat Log e.g:

      [2014-10-18 08:53:06] Q: yello
      [2014-10-18 08:53:06] A: Ya ! Hello
      [2014-10-18 08:53:09] Q: hi there
      [2014-10-18 08:53:09] A: Ya ! Hello how are you doing !
      [2014-10-18 08:53:12] Q: howdy
      [2014-10-18 08:53:12] A: Ya ! Hello What's up !


      6. If then Else with set/map


      if then else with set e.g:

      <!--if then else with SET (list) answer: yes-->
      <category>
      <pattern>$IS <set>color</set> A COLOR</pattern>
      <template>Yup ! <star/> is a color. </template>
      </category>

      <!--if then else with SET (list) answer: No-->
      <category>
      <pattern>$IS * A COLOR</pattern>
      <template>Nah ! <star/> is not a color.</template>
      </category>

      Chat Log e.g:

      [2014-10-18 09:24:23] Q: is blue a color
      [2014-10-18 09:24:23] A: Yup ! blue is a color.
      [2014-10-18 09:24:27] Q: is sky a color
      [2014-10-18 09:24:27] A: Nah ! sky is not a color.


      if then else with map e.g:

      <!--if then else with MAP (pair: Q and A) answer: yes-->
      <category>
      <pattern>$DO YOU KNOW THE CAPITAL OF <set>state</set></pattern>
      <template>
      <map name="state2capital"><star/></map> is the capital of <star/>
      </template>
      </category>

      <!--if then else with MAP (pair: Q and A) answer: yes-->
      <category>
      <pattern>$DO YOU KNOW THE CAPITAL OF *</pattern>
      <template>
      I have no idea the capital of <star/>
      </template>
      </category>

      Chat Log e.g:

      [2014-10-18 09:24:58] Q: do you know the capital of california
      [2014-10-18 09:24:58] A: Sacramento is the capital of california
      [2014-10-18 09:25:12] Q: do you know the capital of Taiwan
      [2014-10-18 09:25:12] A: I have no idea the capital of Taiwan


      7. condition (Select Cases) + That (link with previous chat)

      Condition with li can make the aiml works like programming select cases. The example is at the <!--that (last sentence as condition) 4 + select case example via li and variables-->. Before that, it's using the <that> to lock the conversation to tie up together.

      Condistion with li aiml e.g:

      <!--that (last sentence as condition) 1-->
      <category>
      <pattern>^ HELPER ^</pattern>
      <template>Are you looking for HelPer ?</template>
      </category>

      <!--that (last sentence as condition) 2-->
      <category>
      <pattern>YES I AM LOOKING FOR HELPER</pattern>
      <that>ARE YOU LOOKING FOR HELPER</that>
      <template>Could you share with me which region you are first ?</template>
      </category>

      <!--that (last sentence as condition) 3-->
      <category>
      <pattern>$APJ</pattern>
      <that>COULD YOU SHARE WITH ME WHICH REGION YOU ARE FIRST</that>
      <template>Try http://chianingwang.blogspot.com/ Asia-Pacific and Japan Tab.</template>
      </category>

      <!--that (last sentence as condition) 4 + select case example via li and variables-->
      <category>
      <pattern>MY REGION IS *</pattern>
      <that>COULD YOU SHARE WITH ME WHICH REGION YOU ARE FIRST</that>
      <template>
      <think><set name="region"><star/></set></think>
      <condition name="region">
      <li value="apj">Try http://chianingwang.blogspot.com/ Asia-Pacific and Japan Tab.</li>
      <li value="emea">Try http://chianingwang.blogspot.com/ Europe Tab.</li>
      <li value="americas">Try http://chianingwang.blogspot.com/ Americas Tab.</li>
      <li value="*">I have no idea about <star/>.</li>
      </condition>
      </template>
      </category>

      Chat log e.g:

      [2014-10-18 10:21:58] Q: hey helper
      [2014-10-18 10:21:58] A: Are you looking for HelPer ?
      [2014-10-18 10:29:04] Q: yes i'm looking for helper
      [2014-10-18 10:29:04] A: Could you share with me which region you are first ?
      [2014-10-18 10:29:12] Q: my region is apj
      [2014-10-18 10:29:12] A: Try http://chianingwang.blogspot.com/ Asia-Pacific and Japan Tab.
      [2014-10-18 10:29:56] Q: hey helper
      [2014-10-18 10:29:56] A: Are you looking for HelPer ?
      [2014-10-18 10:30:02] Q: yes i'm looking for helper
      [2014-10-18 10:30:02] A: Could you share with me which region you are first ?
      [2014-10-18 10:30:06] Q: my region is sky
      [2014-10-18 10:30:06] A: I have no idea about sky.


      8. loop

      In AIML, we can loop over list elements in a condition until a certain value has been reached, at which point the loop will terminate and the bot will give a response. The example I made, I think I might need to explain it a little bit since it's not easy to get the loop in aiml.

      First, I set up the * in pattern to catch the number.

      Second, I used think to not show and get two variables. One for explode(var="letter"), which used for split words and phrases into individual character, another is the variable counter(var="count"), starts count at 0, as loop over list elements then this counter will change.

      Third, I need condition tag with two <li></li>. 1st <li></li> is using for the stopping point to make sure loop end when count word end.

      Fourth, in 2nd <li></li>, I used think to not show since it's internal loop. I will get the letters in word one by one via <srai> to REMAININGWORDS in another category. Then I increase the counter via <map><name>successor</name><get var="count"/></map>.

      PS: <map><name>successor</name><get var="count"/></map> for increase and <map><name>predecessor</name><get var="count"/></map> can be used for decrease the count.


      Here is loop e.g:

      <category>
      <pattern>COUNTLETTERS *</pattern>
      <template>
      <think>
      <set var="letters"><explode><star/></explode> end</set>
      <set var="count">0</set>
      </think>
      <condition>
      <li><var>letters</var><value>end</value> <get var="count"/></li>
      <li>
      <think>
      <set var="letters"><srai>REMAININGWORDS <get var="letters"/></srai></set>
      <set var="count"><map><name>successor</name><get var="count"/></map></set>
      </think> 
      <loop/>
      </li>
      </condition>
      </template>
      </category>

      <!-- temp category for caculate remaingwords -->
      <category>
      <pattern>REMAININGWORDS</pattern>
      <template>undefined</template>
      </category>

      <category>
      <pattern>REMAININGWORDS *</pattern>
      <template>undefined</template>
      </category>

      <category>
      <pattern>REMAININGWORDS * *</pattern>
      <template><star index="2"/></template>
      </category>

      Chat Log e.g:

      [2014-10-18 09:39:47] Q: countletters JOHNNY
      [2014-10-18 09:39:47] A: 6

      9. Grouping via <topic>

      In grouping actually you need to setup the topic. I would like to play more complicated conversation as example to simulate how's a ChatBot to guide a user to apply a server from such as Amazon AWS or OpenStack Cloud. The requirements from user is actually store in predicates(variables to remember cross the categories) and at the end ChatBot will double confirm with user whether those requirements is what's user want. 

      topic e.g:

      <!--CLOUD HELPER Demo-->
      <category>
       <pattern>_ CLOUD HELPER</pattern>
       <template>
       <think><set name = "topic">cloudtopicdemo</set></think>
       <random>
       <li>What's up ! what's I can do for you ?</li>
       <li>Hi, I'm Cloud Helper, do you need any help ?</li>
       <li>Yes, Would you like to a help for Cloud ?</li>
       </random>
       </template>
      </category>

      <topic name="cloudtopicdemo">
      <category>
       <pattern>I WOULD LIKE TO REQUEST CLOUD SERVERS</pattern>
       <template>
       <think><set name = "topic">cloudtopicdemo</set></think>
       What's kinds of OS want ? Linux or Windows ?
       </template>
      </category>
      </topic>

      <topic name="cloudtopicdemo">
      <category>
       <pattern>_ LINUX</pattern>
       <template>
       <think><set name = "topic">cloudtopicdemo</set><set name="os">Linux</set></think>
       No problem ! What's kinds of drive size you like, we got Small(80GB), Medium(160GB) and Large(256GB) ?
       </template>
      </category>
      </topic>

      <category>
       <pattern>_ WINDOWS</pattern>
       <template>
       <think><set name = "topic">cloudtopicdemo</set></think>
       Sorry Windows is not ready yet
       </template>
      </category>

      <topic name="cloudtopicdemo">
      <category>
       <pattern>_ SMALL</pattern>
       <template>
       <think><set name = "topic">cloudtopicdemo</set><set name="size">Small</set></think>
       Perfect, How many server you need ?
       </template>
      </category>
      </topic>

      <topic name="cloudtopicdemo">
      <category>
       <pattern>_ MEDIUM</pattern>
       <template>
       <think><set name = "topic">cloudtopicdemo</set><set name="size">Medium</set></think>
       Perfect, How many server you need ?
       </template>
      </category>
      </topic>

      <topic name="cloudtopicdemo">
      <category>
       <pattern>_ LARGE</pattern>
       <template>
       <think><set name = "topic">cloudtopicdemo</set><set name="size">Large</set></think>
       Perfect, How many server you need ?
       </template>
      </category>
      </topic>

      <topic name="cloudtopicdemo">
      <category>
       <pattern>I NEED * SERVERS</pattern>
       <template>
       Got it, you need <set name="number"><star/></set>. Anything else ?
       <think><set name = "topic">cloudtopicdemo</set></think>
       </template>
      </category>
      </topic>

      <topic name="cloudtopicdemo">
      <category>
       <pattern>_ JAVA _</pattern>
       <template>
       <think><set name = "topic">cloudtopicdemo</set><set name="addon">Java</set></think>
       Sure. Let me recap for your request. You need <get name="number"/> <get name="size"/> <get name="addon"/> <get name="os"/> servers. correct ?
       </template>
      </category>
      </topic>

      <topic name="cloudtopicdemo">
      <category>
       <pattern>YES</pattern>
       <template>
       <think><set name = "topic">cloudtopicdemo</set></think>
       RUN xxx.sh -create -n <get name="number"/> -s <get name="size"/> -a <get name="addon"/> -o <get name="os"/> 
       </template>
      </category>  
      </topic> 

      <topic name="cloudtopicdemo">
      <category>
       <pattern>$THANK YOU VERY MUCH</pattern>
       <template>
       <think><set name = "topic">cloudtopicdemo</set></think>
       Cloud Helper is happy to help you.
       </template>
      </category>  
      </topic>

      Chat Log e.g:

      [2014-10-18 10:33:36] Q: hey cloud helper
      [2014-10-18 10:33:36] A: Yes, Would you like to a help for Cloud ?
      [2014-10-18 10:33:48] Q: i would like to request cloud servers
      [2014-10-18 10:33:48] A: What's kinds of OS want ? Linux or Windows
      [2014-10-18 10:33:52] Q: i want linux
      [2014-10-18 10:33:52] A: No problem ! What's kinds of drive size you like, we got Small(80GB), Medium(160GB) and Large(256GB) ?
      [2014-10-18 10:34:13] Q: i prefer large 
      [2014-10-18 10:34:13] A: Perfect, How many server you need ?
      [2014-10-18 10:34:23] Q: I need 7 servers
      [2014-10-18 10:34:23] A: Got it, you need 7. Anything else ?
      [2014-10-18 10:34:29] Q: they are java servers
      [2014-10-18 10:34:29] A: Sure. Let me recap for your request. You need 7 Large Java Linux servers. correct ?
      [2014-10-18 10:34:32] Q: yes
      [2014-10-18 10:34:32] A: RUN xxx.sh -create -n 7 -s Large -a Java -o Linux
      [2014-10-18 10:34:37] Q: thank you very much
      [2014-10-18 10:34:37] A: Cloud Helper is happy to help you.

      10. execution (non AIML features)

      Here is the feature I added for run or execute a script or cli. I think it will be very useful when the ChatBot can actually help you "Do" something. However the logic is very simple, it's just a trick in code.


      execution aiml e.g:

      <!--Execute, Trigger and Run -->
      <category>
      <pattern>RUN *</pattern>
      <template>run <star/></template>
      </category>

      <!--Execute, Trigger and Run -->
      <category>
      <pattern>EXECUTE *</pattern>
      <template>run <star/></template>
      </category>

      <!--Execute, Trigger and Run -->
      <category>
      <pattern>TRIGGER *</pattern>
      <template>run <star/></template>
      </category>

      Java Code Example:

      String question = txtInput.getText().toString();
      String reply = TestAB.testChatBot(chatSession, bot, question);

      if ((reply.length()>=3) && reply.substring(0, 3).equals("run")){
      try{    
      Runtime.getRuntime().exec(reply.substring(3).replace("slash ", "/").replace("dash ", "-").trim());    
      reply = reply + " OK !";  
      }catch( IOException ex ){
      //Validate the case the file can't be accesed (not enought permissions)
      System.out.println(ex.getMessage());
      reply = ex.getMessage();
      }
      }

      e.g: I try to check my vagrant version












      Chat Log eg:

      [2014-10-17 22:25:39] Q: run cmd /c start vagrant -v
      [2014-10-17 22:25:39] A: run cmd slash c start vagrant dash v OK !

      I can image there might be lots of automation or what's we call "robot" to provide the helping to people in the future. In the "Cloud" era, the "robot" can be virtual assistant like iphone siri. I believe it's not only provides you the answers from search but also provides you the execution capability for the operations. 

      Thus, I'm always thinking, as long as the machine learning getting more matured, maybe one day the human might be "replaced" by "robot"(Actually, it's happening)? Like movie Prometheus, the Alien told the human, the reason why the human being extinct is not because Alien need resource from Earth then kill us all. It's because machine will be better than human in one day by self-evolution and simply replace mankind follow Darwin's evolutionism. 

      PS: "Replace Mankind" might be a little bit terrify, but I think machine is just easier to survive than mankind in the future crucial environment and human being is just can't get through it at that moment. Check this movie (Autómata), it has interest statement regarding the machine evolution.

      Share the quote: “Everyone creates the thing they dread." - (The Avengers: Age of Ultron), 2015

      2 comments:

      1. sir thank you for writing this blog and i feel that i will use this information given very precisely.
        i am in final year of my b.tech course in computer science in andhra pradesh india.
        Sir i have understood the basic comcepts of aiml and i am making a "COLLEGE ENQUIRY CHATBOT SYSTEM" as my final year project so i need a guide to make the chatbot and i need your help i wish you will help me so i am asking as student
        1-i need to execute the aiml files i have done it via programAB but still i dont know how to execute a .aiml file from my linux
        2ndly do i need to write aiml.csv file for all modules and how to link those files and execute together

        ReplyDelete
      2. sir will you please check the content and reply cause its time for me to make the project and i will be very thankful if you guide me

        ReplyDelete