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:
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. :)
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 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. :)
16 comments:
thanks
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
great integration.
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
@Phr0zen Katsu:
thats of course a much smoother integration into SL. cool, that you did it.
mbulu
Hi Phr0zen Katsu,
Your idea are brilliant, may I know you do it?
I had developed my own bot using Perl and PHP, can I integrated with SL?
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?
@ 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.
Re Phr0zen Katsu's rewrite with no server: it's nice to share :)
Same thing happens on other forums, someone posts "I fixed it" but doesn't tell how. :(
Example code that doesn't use Ruby (not that it wasn't worthwhile exploring that whole solution!)
key requestId;
string custid;
string botId="***YOUR BOT ID***";
string botURL="http://www.pandorabots.com/pandora/talk-xml";
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(botURL,[HTTP_METHOD,"POST", HTTP_MIMETYPE, "application/x-www-form-urlencoded"],"input="+message+"&botid="+botId);
}
http_response(key request_id, integer status, list metadata, string body) {
if (request_id == requestId) {
if(body == "error") {
llWhisper(0, "An error occurred. Please try again later");
} else {
integer start = llSubStringIndex(body, "<that>");
integer end = llSubStringIndex(body, "</that>");
if (start != -1 && end != -1)
llSay(0, llGetSubString(body, start+6, end-1));
}
} else {
llWhisper(0, "An error occurred. Please try again later");
}
}
}
@Eric: Thanks for your contribution. I like the idea of a none-server approach. But the server also offers nice possibilities like additional processing and you can handle the XML in a nicer way. Or is there a XML API in the meanwhile in Linden Script? That would be awesome.
Daniel
Eric, with that code, is it possible to somehow sent a custid code along with the chatter?
Right now, everyone's called '.'
Hm maybe that's older code... I started making the custid out of the avatar first+last
name to get unique connections to the Chatbot. If there's a local variable 'custid'
that gets set in the listen() method like this:
listen(integer channel, string name, key id, string msg)
{
custid=name;
llListenRemove(listening);
llSetTimerEvent(5.0);
message = msg;
}
Then when sending the request to the chatbot server, it gets baked into the URL at
the end like this:
requestId = llHTTPRequest(botURL,[HTTP_METHOD,"POST", HTTP_MIMETYPE, "application/x-www-form-urlencoded"],"input="+message+"&botid="+botId+"&custid="+custid);
Hey dan i wonder if u could help me m trying to build chat bot and connect it to sl so could tell me the pocedure for doin that
I could not get Eric's script (including is updated code snippet)sample to work. Can someone provide me with the exact code? It is much appreciated!
Post a Comment