人工智能:用AIML寫一個機器人

最近搞了一把人工智能,感覺AIML(Artificial Intelligence Mark-up Language)確實是個好東西,特筆記之。
AIML OVERVIEW:
http://www.pandorabots.com/pandora/pics/wallaceaimltutorial.html

AIML的一個java引擎:
http://www.geocities.com/phelio/chatterbean/?200931#BOTS

1: AIML OVERVIEW
首先看看AIML到底長啥樣:

<aiml>
<category><pattern>WHO WANTS TO KNOW</pattern><template>ALICE wants to know.</template></category>     
<category><pattern>WHY ARE YOU CALLED</pattern><template>   <srai>WHAT DOES ALICE STAND FOR</srai>    </template></category>     
<category><pattern>WHY ARE YOU NAMED *</pattern><template>   <srai>WHAT DOES ALICE STAND FOR</srai>    </template></category>     
<category><pattern>WHY DO YOU DREAM *</pattern><template>I dream about adding new code to ALICE.</template></category>     
<category><pattern>WHY SILVER</pattern><template>ALICE is competing for the Loebner Silver Medal.</template></category>     
<category><pattern>WHY WERE YOU NAMED ALICE</pattern><template><srai>WHAT DOES ALICE STAND FOR</srai></template></category>      
<category><pattern>WHY WERE YOU NAMED</pattern><template><srai>WHAT DOES ALICE STAND FOR</srai></template></category>      
<category><pattern>WHY</pattern><that>I AM SMARTER *</that><template>ALICE won an award for being the "most human" robot.</template></category>     
<category><pattern>WOULD ALICE *</pattern><template><srai>WOULD YOU <star/> </srai> </template></category>
</aiml>
 


簡單說明一下AIML的常用標籤:
1:pattern tag:支持模式匹配(正則表達式,模糊匹配),及基於template的返回
2:random tag:支持隨機回答(一對多)
4:think,system tag: 支持簡單邏輯記憶及自定義函數(本來打算擴展一下AIML, 搞一個支持Groovy語言的標籤, 結果看到了它的<system>標籤, 遂作罷)
5:javascript tag: 支持嵌入js腳本(適用於web chat開發,比如根據情緒改變表情等)。
6:srai tag: 支持多對一回答.
詳細內容請參加AIML的官方文檔:
http://alicebot.org/TR/2005/WD-aiml/WD-aiml-1.0.1-008.html


2:按照AIML, 鄙人整理了一個簡單的DEMO,擴展了AIML的DATE標籤,支持了java的時間掩碼,並有自學習功能.

機器人Alice表現如下,可見其多麼聰明:

Alice>Hi ya! Welcome!
you say>what's your name
Alice>sorry, what?
you say>this is not a good answer  //開始學習功能
Alice>Sorry. What would be a good answer?
you say>my name is Alice
Alice>Alright! You can ask me again to see if I got it.
you say>what's your name
Alice>my name is Alice
you say>what is your name
Alice>my name is Alice
you say>my name is Lichunlei
Alice>hello, Lichunlei.
you say>do you remember me?
Alice>Your name is Lichunlei, seeker.  //Alice的記憶功能
you say>what's time now?
Alice>It is 10:59 A.M.
you say>what date is today?
Alice>Monday.
 



如果感覺機器人Alice的答案不滿意, 只需輸入包含not和good answer的句子,在你的指導下,Alice就可以開始學習新知識。

讓它如此智慧的原因就是AIML文件, 此爲機器人的大腦.
下爲Alice的AIML文件:

<?xml version="1.0" encoding="ISO-8859-1"?>
<aiml>
<!-- Copyright (c) 2007 ALICE A.I. Foundation, Inc. -->
<!-- Last modified Seo 21, 2009, by Lichunlei -->

<category><pattern>WHAT IS TIME *</pattern><template>It is <date format="h:mm a"/>.</template></category>                         
<category><pattern>WHAT DAY IS TODAY</pattern><template><date format="E"/>.</template></category>
<category><pattern>WHAT IS TODAY *</pattern><template><date format="EEE"/>.</template></category>
<category><pattern>MY NAME IS *</pattern><template><think><set name="name"><star/></set></think>hello, <get name="name"/>.</template></category>   
<category><pattern>DO YOU REMEMBER ME</pattern><template>Your name is <get name="name"/>, seeker.</template></category>
<category><pattern>I CAN NOT *</pattern><template>Why can't you do <set name="it"><person/></set>?</template></category>
<category><pattern>MY INPUT</pattern> <template> 1:<input index="1"/> 2:<input index="2"/> 3:<input index="3"/></template></category>
<category><pattern>*</pattern><template>sorry, what?</template></category>                                         

  <!-- Greeting categories. -->
  <category>
    <pattern>WELCOME</pattern>
    <template>
      <think>
        <system> <!-- Defines a method to create new categories from user input at run-time. -->
          import bitoflife.chatterbean.AliceBot;
          import bitoflife.chatterbean.Context;
          import bitoflife.chatterbean.Graphmaster;
          import bitoflife.chatterbean.aiml.Category;
          import bitoflife.chatterbean.text.Transformations;
         
          void learn(String pattern, String template)
          {
            /* The "match" variable represents the current matching context. */
            AliceBot bot = match.getCallback();
            Context context = bot.getContext();
            Transformations transformations = context.getTransformations();
   
            pattern = transformations.normalization(pattern);
            Category category = new Category(pattern, new String[] {template});
            Graphmaster brain = bot.getGraphmaster();
            brain.append(category);
          }
        </system>
      </think>
      Hi ya! Welcome!
    </template>
  </category>

  <!-- A category set to learn simple user-fed categories. -->
  <category>
    <pattern>* NOT *  GOOD ANSWER</pattern>
    <template>
      Sorry. What would be a good answer?
    </template>
  </category>
  <category>
    <pattern>_</pattern>
    <that>WHAT WOULD BE A GOOD ANSWER</that>
    <template>
      <system>learn("<input index="3"/>", "<input index="1"/>")</system>
      Alright! You can ask me again to see if I got it.
    </template>
  </category>
</aiml>
 



之所以Alice可以學習, 重要的一點是<input/>標籤,此標籤記住了之前對方的聊天記錄, 通過index可以得到(倒序索引)

程序相對簡單,兩個class:
Alice工廠: AliceBotMother

package co.aiml;

import java.io.FileInputStream;
import java.io.ByteArrayOutputStream;

import bitoflife.chatterbean.AliceBot;
import bitoflife.chatterbean.Context;
import bitoflife.chatterbean.parser.AliceBotParser;
import bitoflife.chatterbean.util.Searcher;

public class AliceBotMother
{
 
  private ByteArrayOutputStream gossip;
 
 
  public void setUp()
  {
    gossip = new ByteArrayOutputStream();
  }
 
  public String gossip()
  {
    return gossip.toString();
  }

  public AliceBot newInstance() throws Exception
  {
    Searcher searcher = new Searcher();
    AliceBotParser parser = new AliceBotParser();
    AliceBot bot = parser.parse(new FileInputStream("Bots/context.xml"),
                                new FileInputStream("Bots/splitters.xml"),
                                new FileInputStream("Bots/substitutions.xml"),
                                searcher.search("Bots/mydomain", ".*\\.aiml"));

    Context context = bot.getContext();
    context.outputStream(gossip);
    return bot;
  }
}
 



命令行聊天程序:

package co.aiml;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

import bitoflife.chatterbean.AliceBot;

public class Chat
{
public static final String END = "bye";

public static String input()
{
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
System.out.println("you say>");
String input = "";
try
{
input = in.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return input;
}

public static void main(String[] args) throws Exception
{
     AliceBotMother mother = new AliceBotMother();  
     mother.setUp();
     AliceBot bot = mother.newInstance();
     System.err.println("Alice>" + bot.respond("welcome"));
while(true)
{
String input = Chat.input();
if(Chat.END.equalsIgnoreCase(input))
break;

System.err.println("Alice>" + bot.respond(input));
}

}
}
 



需要說明的是:

    AliceBot bot = parser.parse(new FileInputStream("Bots/context.xml"),
                                new FileInputStream("Bots/splitters.xml"),
                                new FileInputStream("Bots/substitutions.xml"),
                                searcher.search("Bots/mydomain", ".*\\.aiml"));
 



context.xml:設置application的屬性, 及時間格式等可變屬性

<context>
<!-- The id is a unique string that identifies this context. -->
<bot name="id" value="test_cases" />

<!-- Bot predicates are set at load time, and cannot be changed at runtime. -->
<bot name="output" value="Logs/gossip.txt" />
<bot name="randomSeed" value="1" />
<bot name="series" value="Alpha" />
<bot name="version" value="0.7.5 Alpha" />
<bot name="location" value="Atlanta" />
<bot name="name" value="Alice" />

<!-- Default values for predicates, can be changed later at runtime. -->
<set name="dateFormat" value="yyyy-MM-dd HH:mm:ss" />
<set name="name" value="dear friend" />
<set name="me" value="Alice" />
<set name="engine" value="ChatterBean" />
<set name="topic" value="*" />
</context>
 



如上屬性,都可以用AIML的<bot>標籤及<get>標籤訪問得到。

splitters.xml:定義什麼是句子,即句子的結束符。

<splitters>
  <splitter value="..." type="sentence"/>
  <splitter value="." type="sentence"/>
  <splitter value="!" type="sentence"/>
  <splitter value="?" type="sentence"/>
  <splitter value=";" type="sentence"/>
  <splitter value="," type="word"/>
  <splitter value=":" type="word"/>
</splitters>
 

substitutions.xml:定義容錯規則及特殊字符映射等。

<substitutions>
  <!-- Input substitutions correct spelling mistakes and convert "sentence"-ending characters into characters that will not be identified as sentence enders. -->
  <input>
    <correction><!--sentence correction-->
      <substitute find="=reply" replace=""/>
      <substitute find="name=reset" replace=""/>
      <substitute find=":-)" replace=" smile "/>
      <substitute find=":)" replace=" smile "/>
      <substitute find=",)" replace=" smile "/>
      <substitute find=";)" replace=" smile "/>
      <substitute find=";-)" replace=" smile "/>
      <substitute find="&quot;" replace=""/>
      <substitute find="/" replace=" "/>
      <substitute find="&gt;" replace=" gt "/>
      <substitute find="&lt;" replace=" lt "/>
      <substitute find="(" replace=" "/>
      <substitute find=")" replace=" "/>
      <substitute find=" u " replace=" you "/>
      <substitute find=" ur " replace=" your "/>
      <substitute find=" you'd " replace=" you would "/>
      <substitute find=" you're " replace=" you are "/>
      <substitute find=" you re " replace=" you are "/>
      <substitute find=" you've " replace=" you have "/>
      <substitute find=" you ve " replace=" you have "/>
     <substitute find=" what's " replace=" what is "/>
     ...
    </correction>
    <protection><!-- sentence protection -->
      <substitute find=",what " replace=".  what "/>
      <substitute find=", do " replace=".  do "/>
      <substitute find=",do " replace=".  do "/>
      ...
    </protection>
  </input>
  <gender>
    <substitute find=" on her " replace="on him"/>
    <substitute find=" in her " replace="in him"/>
    <substitute find=" his " replace="her"/>
    <substitute find=" her " replace="his"/>
    <substitute find=" him " replace="her"/>
    ...
  </gender>
  <person>
    <substitute find=" I was " replace="he or she was"/>
    <substitute find=" mine " replace="his or hers"/>
  </person>
  <person2>
    ...
    <substitute find=" your " replace="my"/>
  </person2>
</substitutions>
 



比如在上面的聊天DEMO中, 我輸入what's your name, 和輸入what is your name, 都能得到正確的回答,這是因爲:
在substitutions.xml文件中有如下設置;

<substitute find=" what's " replace=" what is "/>
 


3:擴展AIML標籤(基於AIML的java引擎:chatterbean):
package bitoflife.chatterbean.aiml是chatterbean對於AIML標籤的實現包。目前爲止,實現了大多數常用AIML標籤.
而對date標籤只有一個最簡單的實現, 也不支持java時間掩碼.
鄙人理想中的date標籤應該是:

<category><pattern>WHAT IS TIME *</pattern><template>It is <date format="h:mm a"/>.</template></category>
 


標籤類只需擴展TemplateElement即可。
所以, 修改之:

public class Date extends TemplateElement
{

  private final SimpleDateFormat format = new SimpleDateFormat();

  /**date tag format value, add by lcl**/
  private String formatStr = "";

  public Date()
  {
  }

  public Date(Attributes attributes)
  {
  //得到時間掩碼
  formatStr = attributes.getValue(0);
  }

  public String process(Match match)
  {  
    try
    {
    format.applyPattern(formatStr);
    return format.format(new java.util.Date());
    }
    catch (Exception e)
    {
    return defaultDate(match);
    }
  }
 
  private String defaultDate(Match match)
  {
    try
    {
      format.applyPattern((String) match.getCallback().getContext().property("predicate.dateFormat"));
      return format.format(new java.util.Date());
    }
    catch (NullPointerException e)
    {
      return "";
    }
  }
 
}
 




4:要想讓Alice足夠聰明, 必須要有足夠多的AIML, 如下地址是其所有的資料庫:
http://www.alicebot.org/downloads/sets.html
加入到程序中, Alice幾乎無所不知了。

5:如果需要做一個某領域的機器人專家, 基於AIML來實現,是一個不錯的選擇。

6:附件是Alice源碼,及其上面的DEMO,eclipse工程.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章