Previous Section  < Day Day Up >  Next Section

Hack 62 An Artificial Intelligence Bot

figs/moderate.gif figs/hack62.gif

Use the JMegaHal package in a PircBot-based IRC bot that learns from and chats with other users.

I RC is not just a place where people hang out in channels, chatting with one another. It is also a valuable learning zone. Knowledgeable users populate certain channels. Interacting with these users makes it possible to learn new facts and share in a wealth of expert information on a particular subject. This is obviously useful to human users, but what about bots? Can they too learn from what they see on IRC? Is it possible to mimic the behavior of a human user?

From a learning point of view, one appealing thing about IRC is that you can join a channel and quietly observe real humans talking to one another. You can learn a lot while lurking—and so can a bot. One popular pastime is to try to make conversation bots that respond intelligently to what is being said by the humans around it. What better way could there be of teaching such bots than by leaving them in a busy channel, learning from what real users are saying?

9.6.1 Markov Modeling

One simple way of modeling each sentence generated by a human user is to break it down into tokens. In the simplest case, each word in the sentence is a token. After several sentences are "learned," an attempt can be made to create new sentences based on what has been observed. As humans generate more sentences, tokens that are used to start and end sentences become recognizable, as do which tokens are likely to precede or follow any particular token. All of these links form a graphlike structure that can be navigated from start to finish, with each random walk generating a different sentence that nearly makes logical sense. Due to the nature of this model, it is independent on the language spoken, although strange results may be observed when it learns more than one language at a time. Figure 9-5 shows the kind of data structures that form in a Markov chain.

Figure 9-5. The data structures present in a Markov chain
figs/irch_0905.gif


There is a simple Java Applet that demonstrates and visualizes the generation of these graphs at http://www.jibble.org/dynamicgraph.php.


9.6.2 JMegaHal

MegaHal is a more advanced model that improves the quality of the generated sentences by gathering tokens into sequences of four and remembering which tokens precede and follow these sequences. Tokens consist of words and punctuation between words. A full description of the model can be found at http://www.megahal.net.

JMegaHal is a simple Java implementation of MegaHal and can be found at http://www.jibble.org/jmegahal. This also generates a fourth-order Markov chain to generate sentences in response to user input. It is these higher orders that ensure the output makes more sense than simpler implementations, but, of course, this will also depend on where your bot is learning its sentences.

Because the token set can include the whitespace and punctuation between words, the model is likely to preserve punctuation styles. However, because IRC channels typically contain more than one user, you probably won't notice any recognizable style, as it will be learning from everybody.

As an example, given the following two sentences to learn from:

The dog sat on the mat.

There was a dog sat in the bushes.

JMegaHal could possibly come out with four different sentences:

The dog sat on the mat.

There was a dog sat in the bushes.

The dog sat in the bushes.

There was a dog sat on the mat.

9.6.3 The Code

In this hack, we use the JMegaHal package to learn sentences and generate replies. We will then combine it with the PircBot package [Hack #35] to create an IRC bot that can learn from other IRC users and hold wacky conversations with them.

9.6.3.1 A simple example

The JMegaHal package is supplied in a JAR file, so it is easy to integrate into any Java program, including an IRC bot. Make sure you import org.jibble.jmegahal.*; in any classes that will use it.

JMegaHal hal = new JMegaHal( );



// Teach it some sentences.

hal.add("Hello, my name is Paul.");

hal.add("This is a sentence.");

// Note that the more sentences you add, the more sense it will make...



// Make JMegaHal generate a sentence.

String sentence1 = hal.getSentence( );



// Get another sentence, with the word "jibble" in it (if possible).

String sentence2 = hal.getSentence("jibble");

Notice the getSentence method can take a String as an optional argument. If you want to generate random sentences all about pie, then you might want to call hal.getSentence("pie"). This ensures that all generated sentences include the word "pie" somewhere. If JMegaHal has not yet learned anything about pie, it will choose some other random token.

One thing to consider with a chat bot is telling it when to respond. If you make it respond to every message, the other users in the channel will very quickly get fed up with it and kick it out. One safe option is to make it respond only to messages that contain its nickname but to learn from all other messages.

9.6.3.2 Combining JMegaHal and PircBot

Combining JMegaHal and PircBot is very easy. If anybody utters the bot's nickname, it should respond with a randomly generated sentence from the JMegaHal object. All other messages that do not contain the bot's nickname will be used to teach it more sentences. In the following simple implementation, the bot is seeded with a starting sentence in the constructor, so it will always be able to respond with this if it has not learned anything else.

Create a file called JMegaHalBot.java:

import org.jibble.pircbot.*;

import org.jibble.jmegahal.*;



public class JMegaHalBot extends PircBot {

    

    private String name;

    private JMegaHal hal;

    

    public JMegaHalBot(String name) {

        setName(name);

        hal = new JMegaHal( );

        // Add at least one sentence so the bot can always form a reply.

        hal.add("What is the weather like today?");

    }

    

    public void onMessage(String channel, String sender,

            String login, String hostname, String message) {

        

        if (message.toLowerCase( ).indexOf(getNick( ).toLowerCase( )) >= 0) {

            // If the bot's nickname was mentioned, generate a random reply.

            String sentence = hal.getSentence( );

            sendMessage(channel, sentence);

        }

        else {

            // Otherwise, make the bot learn the message.

            hal.add(message);

        }

    }

    

}

Now you just need to create a main method to construct the bot and tell it what nickname to use. The main method will also tell the bot which server to use and which channel to join.

This bot can run in multiple channels, but bear in mind that sentences learned in one channel could end up appearing in other channels.

Create the file JMegaHalBotMain.java:

public class JMegaHalBotMain {

    

    public static void main(String[] args) throws Exception {

        JMegaHalBot bot = new JMegaHalBot("Chatty");

        bot.setVerbose(true);

        bot.connect("irc.freenode.net");

        bot.joinChannel("#irchacks");

    }

    

}

9.6.4 Running the Hack

To compile and run the hack, you will need both the JMegaHal.jar and pircbot.jar files. Both of these must be in the classpath when compiling and running. To compile the bot, type the following:

C:\java\JMegaHalBot> javac -classpath .;pircbot.jar;JMegaHal.jar *.java

To run the bot:

C:\java\JMegaHalBot> java -classpath .;pircbot.jar;JMegaHal.jar JmegaHalBotMain

The bot will echo everything it's doing to the standard output, and you can start chatting with it as soon as it's joined the channel.

9.6.5 The Results

Figure 9-6 shows the JMegaHalBot in action. The bot will obviously learn more if it is placed in a busy channel. Don't expect it to come out with anything too profound or unique until it has learned more than a hundred sentences.

Figure 9-6. The JMegaHalBot trained with the contents of this hack
figs/irch_0906.gif


Although you probably want your bot to learn as fast as it can, it's not always a good idea to place it in an enormously busy channel, as it may not get noticed. Be patient and wait for the best results.

    Previous Section  < Day Day Up >  Next Section