Friday, 13 July 2007

A.L.I.C.E. Chatbot Connection in Second Life using Ruby on Rails

Like i told you some month ago, i have quick-hacked a Chatbot for Second Life, which connects to an A.L.I.C.E.-Bot at www.pandorabots.com. In this posting i want to show the LindenScript-Code and the server-side code i've used. On the server-side its Ruby on Rails, as usual. ;)

The Ruby on Rails serverside script:

I have built an "bot_controller.rb" file which looks like this:


require 'net/http'
require 'uri'
require 'cgi'

class BotController < ApplicationController

def ask_question
question = params[:q]
custid = params[:cid]

res = Net::HTTP.post_form(URI.parse('http://www.pandorabots.com/pandora/talk-xml'),
{'botid'=>'###YOUR BOT ID###', 'custid' => custid, 'input'=>question})
case res
when Net::HTTPSuccess, Net::HTTPRedirection

xmlDoc = REXML::Document.new(res.body)

botCustid = xmlDoc.elements["result"].attributes["custid"]
statusCode = xmlDoc.elements["result"].attributes["status"]


case statusCode
when "0"
render :text => xmlDoc.elements["result/that"].get_text.value+"||"+botCustid
else
render :text => 'Help, this error occurred: ' + xmlDoc.elements["result/message"].get_text.value+"||"+botCustid
end

else
render :text => 'error'
end

end

end
The controller just takes a given conversation-id (custId) and the question from the person in 2nd-Life. Like you'll see later, the custId is just for possible future improvements and has now no special use. :)
The other parts in the script are like in the Twitter/Jaiku scripts which i did. They retrieve the XML-document and get the right parts using XPath-expressions. And after that the script builds a nice "||"-separated result-string for the Second Life world.
You also need your own bot-id from the pandorabots-site. Create an account there and you get your own.

The LindenScript:

key requestId;
string custid;

default
{
state_entry()
{
llListen( 0, "", NULL_KEY, "" );
custid = "";
}

touch_start(integer total_number)
{
llWhisper(0, "Talk to me on Chat-Channel 0.");
}

listen(integer channel, string name, key id, string message)
{
requestId = llHTTPRequest("###YOUR URL###/bot/ask_question",[HTTP_METHOD,"POST", HTTP_MIMETYPE, "application/x-www-form-urlencoded"],"q="+message+"&cid="+custid);
}

http_response(key request_id, integer status, list metadata, string body) {

if (request_id == requestId) {

if(body == "erro") {
llWhisper(0, "An error occurred. Please try again later");
} else {

list parts = llParseString2List(body,["||"],[]);

string that = llList2String(parts, 0);
custid = llList2String(parts, 1);
llWhisper(0, that);
}

} else {
llWhisper(0, "An error occurred. Please try again later");
}
}


}

The script is really easy. It just listens on Channel 0, gets the message from the user and calls the Ruby on Rails script. After that it gets the result, splits the string using the "||" separator and then prints the answer for the question.

Possible future extensions:

There are a lot of possible extensions for this script. The most important one i the problem with the conversation-id.
It would be nice, if the Chatbot in Second Life could remember the different users. For example on the server-side we could create a database which manages every person which has talked to the chatbot. We store the SecondLife-username and the appropriate conversation-id in a database-structure. Everytime the user comes back, we get the conversation-id from the database and use this one. So the A.L.I.C.E.-Bot can optimize its questions for every user.

You can also add some error-handling. So that the user gets nice messages if something goes wrong.

So, hope you like it. :)

9 comments:

Anonymous said...

thanks

Anonymous said...

Great posting really got me thinking,


I do some working with SL and mobile.

If you'd like some free space on a private Island for development and social purposes look me up in SL sometime.

Alexander Regent

Anonymous said...

great integration.

Anonymous said...

Awesome publish! Thanks to your example, i have rewritten it to a version that does not require a server in between to query and receive http responses.

Phr0zen Katsu

daniel said...

@Phr0zen Katsu:

thats of course a much smoother integration into SL. cool, that you did it.

mbulu

osgoh said...

Hi Phr0zen Katsu,

Your idea are brilliant, may I know you do it?

osgoh said...

I had developed my own bot using Perl and PHP, can I integrated with SL?

Andrew said...

I have looked at your development and find it amazing. My question is how does the LSL script know to post to my url where the ruby on rails script is?

daniel said...

@ andrew

It knows it, because you start a listen process in your linden script (using llListen and by implementing the listen() function).
So every time a second life avatar stands before your chatbot and talks using the given chat-channel (here: 0), the listen() will be called.

Hope, that helps.