Jump to content

help with script containing http request


Erin Grayman
 Share

You are about to reply to a thread that has been inactive for 3454 days.

Please take a moment to consider if this thread is worth bumping.

Recommended Posts

My script is not behaving the way I expected. I would appreciate if an advanced scripter could take a look at this script:

 

key request_id;
integer listen_handle;
integer indexOfFirstIsLetterBefore;
integer indexofFirstLetterAfter;
string beforeIs;
string afterIs;

default
{
    state_entry()
    {
        llSay(0, "Hello everyone. My name is AI Doll Demo Version 1. I was created by Erin Grayman. Please tell me a simple sentence containing the word 'is' in channel 77.");
        listen_handle = llListen(77, "", llDetectedKey(0), " is ");
    }
    listen(integer channel, string name, key id, string msg)
    {
        //Get the index of the character before the space in " is ".
        indexofFirstLetterAfter = (llSubStringIndex(msg, " is "))+4;
        indexOfFirstIsLetterBefore = (llSubStringIndex(msg, " is "))-1;
        beforeIs = llGetSubString(msg, 0, indexOfFirstIsLetterBefore);
        afterIs = llGetSubString(msg, indexofFirstLetterAfter, llStringLength(msg)-1);
        if (llSubStringIndex(beforeIs, " is ") == -1 && llSubStringIndex(beforeIs, " is ") == -1)
        {
            if (llSubStringIndex(beforeIs, ".") != -1 || llSubStringIndex(beforeIs, ",") != -1 || llSubStringIndex(beforeIs, "!") != -1 || llSubStringIndex(beforeIs, "?") != -1)
        {
           llSay(0, "Please state a very simple sentence.");
        }
        else
        {
            list my_list = llParseString2List(beforeIs,[" "],["."]);
            integer myListIndexThe = llListFindList(my_list, ["The"]);
                my_list = llDeleteSubList(my_list, myListIndexThe, myListIndexThe);
            integer myListIndexA1 = llListFindList(my_list, ["A "]);
                my_list = llDeleteSubList(my_list, myListIndexA1, myListIndexA1);
            integer myListIndexA2 = llListFindList(my_list, ["a "]);
                my_list = llDeleteSubList(my_list, myListIndexA2, myListIndexA2);
            integer myListIndexLThe = llListFindList(my_list, ["the "]);
                my_list = llDeleteSubList(my_list, myListIndexLThe, myListIndexLThe);
            integer myListIndexMy = llListFindList(my_list, ["My "]);
                my_list = llDeleteSubList(my_list, myListIndexMy, myListIndexMy);
            integer myListIndexLMy = llListFindList(my_list, ["my "]);
                my_list = llDeleteSubList(my_list, myListIndexLMy, myListIndexLMy);
            integer myListIndexHis = llListFindList(my_list, ["His "]);
                my_list = llDeleteSubList(my_list, myListIndexHis, myListIndexHis);
            integer myListIndexLHis = llListFindList(my_list, ["his "]);
                my_list = llDeleteSubList(my_list, myListIndexLHis, myListIndexLHis);
            integer myListIndexHer = llListFindList(my_list, ["Her "]);
                my_list = llDeleteSubList(my_list, myListIndexHer, myListIndexHer);
            integer myListIndexLHer = llListFindList(my_list, ["her "]);
                my_list = llDeleteSubList(my_list, myListIndexLHer, myListIndexLHer);
            integer myListIndexThat = llListFindList(my_list, ["That "]);
                my_list = llDeleteSubList(my_list, myListIndexThat, myListIndexThat);
            integer myListIndexLThat = llListFindList(my_list, ["that "]);
                my_list = llDeleteSubList(my_list, myListIndexLThat, myListIndexLThat);
            integer myListIndexLAny = llListFindList(my_list, ["any "]);
                my_list = llDeleteSubList(my_list, myListIndexLAny, myListIndexLAny);
            integer myListIndexAny = llListFindList(my_list, ["Any "]);
                list my_final_list = llDeleteSubList(my_list, myListIndexAny, myListIndexAny);
            
                string final_Before_Is = llDumpList2String(my_final_list, " ");

            if (llSubStringIndex(final_Before_Is, "sl") != -1)
                {
                    llInstantMessage(id, "I love sl as much as you do, but I cannot process that abbreviation. ^^");
                }

            //Done parsing text before "is."

             list my_list_after = llParseString2List(afterIs,[" "],["."]);         
            integer myListAfterIndexA = llListFindList(my_list_after, ["a"]);
                my_list_after = llDeleteSubList(my_list_after, myListAfterIndexA, myListAfterIndexA);
            integer myListAfterIndexThe = llListFindList(my_list_after, ["the"]);
                my_list_after = llDeleteSubList(my_list_after, myListAfterIndexThe, myListAfterIndexThe);
            integer myListAfterIndexPeriods = llListFindList(my_list_after, ["..."]);
                my_list_after = llDeleteSubList(my_list_after, myListAfterIndexPeriods, myListAfterIndexPeriods);
            integer myListAfterIndexPeriod = llListFindList(my_list_after, ["."]);
                list my_final_list_after = llDeleteSubList(my_list_after, myListAfterIndexPeriod, myListAfterIndexPeriod);
            string final_After_Is = llDumpList2String(my_final_list_after, " ");

                //Make the request.
                request_id = llHTTPRequest("http://www.thesaurus.com/browse/" + final_Before_Is, [HTTP_METHOD,"POST",HTTP_MIMETYPE,"application/x-www-form-urlencoded"], final_After_Is);
        }
        }
        else 
        {
           llInstantMessage(id, "Please input a sentence with one 'is'."); 
        }
        //Count backwards from that space using
        //uSubStringLastIndex(string source, string patternToLookFor);
        //llSubStringIndex returns index
        //of first pattern instance in source.
        //
    }
    http_response(key requestid, integer status, list metadata, string body)
    {
        if(request_id == requestid)
            {
                llSay(0, "I think the sentence last inputted to me was a definition or equivalence, and not an analogy or description.");
            }
            else
            {
                llSay(0, "I think the sentence last inputted to me was an analogy or descripting, and not a definition or equivalence.");
            }
            llSleep(5.0);
            llSay(0, "Thank you for chatting with me! I hope to talk again soon. Please tell my creator Erin Grayman if I am working correctly ;)");
    }
}

 

Link to comment
Share on other sites

I don't really understand what's happening in the script, but there's one obvious problem.

  listen_handle = llListen(77, "", llDetectedKey(0), " is ");

 doesn't really make sense.   It can't detect anyone in state_entry (so I think, in effect, you're listening to NULL_KEY, which means anyone, and is probably what you want).   But  You're listening for the literal string " is ", and nothing else (so if you say, "Today is my birthday" it will ignore you, which probably isn't what you want).

Try

listen_handle = llListen(77,"","","");//listen for anything on chan 77

 and check for the the string " is " in the sentence by putting in something like this right at the start of the listen event

		if (!~llSubStringIndex(llToLower(msg)," is ")){//if it's not there			llRegionSayTo(id,0,"Please say something with /" is /" in it");			return;		}

 And for parsing the text, rather than doing it the way you have (which I think, if myListIndexWhatever is -1, because "whatever" isn't there, will remove the last item on the list, no matter what it is), I would take the simpler course of looping through it, something like this

 

list temp = llParseString2List(msg,[" "],[""]);		integer max = llGetListLength(temp);		while(max--){//count backwards, since we're deleting stuff			string s = llToLower(llList2String(temp,max));			if(~llListFindList(["the","a","my","his","her","that","any"],[s])){				temp = llDeleteSubList(temp,max,max);			}		}		string result = llDumpList2String(temp," ");		llOwnerSay(result);

 which should remove all instances of "the", "a" and so on, no matter what case they are.

I just can't understand the http_response.   If it gets any sort of response all, even an errror message, it's going to say, 

"I think the sentence last inputted to me was a definition or equivalence, and not an analogy or description."

because if (request_id == requestid) is always going to be true, I would think, unless something very odd has happened.

I'd strongly advise doing some error handling if (status != 200) and also, while I don't know what the request is likely to return, I think it's string body that's going to be of interest.

 

Link to comment
Share on other sites

Lotsa artificial, very little intelligence :)

Innula covered most of it. As far as I'm concerned the worst thing here is HTTP part, the rest is somewhat salvagable... with Innula's help. SL HTTP communications come in pairs. You are not going to get a response unless you send a request, so the request is the cause and a response is the effect. llHTTPRequest() returns an identifier key. The same key is received back in http_response event. So in this code

if(request_id == requestid)
{
llSay(0, "I think the sentence last inputted to me was a definition or equivalence, and not an analogy or description.");
}
else
{
llSay(0, "I think the sentence last inputted to me was an analogy or descripting, and not a definition or equivalence.");
}

you will always have request_id equal to  requestid. Well almost always there might be a 0.0001% probability of a difference but I wouldn't count on it :)

The reason llHTTPRequest() returns this identifier is that there may be several scripts in the linkset sending HTTP requests. The response is propagated to all of them (provided a script has the http_response event. So the request returns the identifier to enable to sort to which request the reply came. Another situation is that the same script might be sending a very rapid series of HTTP requests perhaps to different sources so the replies come asynchronously. None of it applies to your design.

Perhaps for your purpose you might consider HTTP server described in here: http://wiki.secondlife.com/wiki/LSL_HTTP_server

 

 

Link to comment
Share on other sites


Erin Grayman wrote:

Ok I'm pretty new to this. How do I make up the request? Thanks.

That rather depends, doesn't it ... what do you need to pass out to the thesaurus and what sort of response [are you expecting]?

You have to tell us what it's meant to do before we can suggest how to do it!  Most importantly for that particular event-handler we have no idea what the thesaurus will return in different circumstances.  If you explain it we can probably help.

Link to comment
Share on other sites

Like Peter, I'd find some more details helpful.

Forget about the script mechanics for the time being.  Could you give us a couple of examples of what someone might say to the device, what the device is supposed to extract from that to send to the website, and what you expect the website to send back as a result?

Link to comment
Share on other sites

I wanted the script to listen for a sentence with " is " contained in it on channel 77, then parse it until probably what is left would be the noun or noun phrase in the sentence (by removing articles and such from the string), next looking up a url ("http://www.thesaurus.com/" + resultant word from parse, once on the page look for some words after the " is " in the sentence it listened for, and finally, if the string from after " is " exists in the thesaurus page, script says that the sentence is a definition (since the words after " is "are actually mentioned on the thesaurus page) or otherwise if it can't find that string, return a message saying that the sentence was an analogy or comparison. Thanks!

Link to comment
Share on other sites

Innula made some helpful remarks about the parsing of the input string - you should look at them and consider them.

Also, there are some things to say about the http request. If I get you right, the input "The house is green" should result in requests that look up "house" and "green". For getting the response, you use:

request_id = llHTTPRequest("http://www.thesaurus.com/browse/" + final_Before_Is, [HTTP_METHOD,"POST",HTTP_MIMETYPE,"application/x-www-form-urlencoded"], final_After_Is);

 This request means that "house" would go in the URL (for a GET request) and "green" goes into the body of the request (for a POST request. I doubt that the script at www.thesaurus.com looks at the body at all. You would have to make 2 requests - one for each word - the word you are looking for schould go in the URL. And you should make it a GET request - just replace the POST in the parameter list. That should get you a response - the may however be some other things you have to change.

The next problem is what yu do in the http_response.

What you do there is you test if the request id equals the request id that of the response id of the response just received. That#s good - but it will only tell you if the response received is the response to the request you have sent. It doesn't tell you anything of the contents of the response. In order to find out if the response yielded a successful look up in the thesaurus, you would have to parse the body of the response:

http_response(key request_id, integer status, list metadata, string body) {	if (request_id == requestid) {		//look at the body for certain key words that will tell you if there's a meaningful response	}}

 Here is the next problem: LSL will only return a certain number of characters (I can't remember how many) - but it's very likely that with all the information on the html page before you get to the actual search result, this result may get cut off. That again means, you would have to do the analysis of the result outside LSL - e.g. in a php script on a webserver.

Link to comment
Share on other sites

You're going to have to find someone who knows more about web pages and php than me -- which won't take you long -- to explain how do it (if it's possible)  but I don't think this webpage behaves quite the way you think it does.

I simplified things, and used this test script, which I think is the bare bones of yours, to see what would happen if I said "water is wet" to your object and it was working.

 

key request_id;default{    state_entry()    {       string final_Before_Is ="water";       string final_After_Is ="wet";        request_id = llHTTPRequest("http://thesaurus.com/browse/"+ final_Before_Is, [HTTP_METHOD,"POST",HTTP_MIMETYPE,"application/x-www-form-urlencoded"], final_After_Is);            }    http_response(key id,integer status,list metadata,string body){        if(request_id==id){            llOwnerSay((string)status);            llOwnerSay(body);        }     }}

 What seems to happen, no matter what I put in for final_Before_is (whether it's English or gibberish) is I get start of the html for the web page and it ignores  final_After_Is altogether.  

So, unless someone who understands web forms can help us out, I'm stuck.

Link to comment
Share on other sites

Well to make the story short, if you enter the same url in your browser you'll get back a web page, so lotsa of formatting via HTML code. The sending server has no idea that a request came from a dumb SL object, so it sends the same page. And as was pointed out by Dark, the SL http response cuts out after either 2400 chars or 3600 or something in between, don't remember from the top of my head. In any case it cuts out long before the relevant part. Have to go thru your own web server with some PHP to talk to the SL object, that's why I mentioned SL HTTP server before in this thread.

Link to comment
Share on other sites

I've fiddling around with this - it was fun. 

Anyhow, you could use a thesaurus with an API that returns data without any mark up. Big Huge Thesaurus does that (it's free for up to 10,000 requests a day - you have to sign up to get an API key) - so I'm using that in the example (with the API key taken out, of course. The example which contains most of whart other people have proposed here should do about what you want

key request_id;integer listen_handle;list requests;list req_ids;default {		state_entry() {		listen_handle = llListen(77,"","","");//listen for anything on chan 77	}		listen(integer channel, string name, key id, string msg) {		msg = llToLower(msg);		integer pos;		requests = [];		req_ids = [];		if (!~llSubStringIndex(msg," is ")){//if it's not there			llRegionSayTo(id,0,"Please say something with ' is ' in it");			return;		} else {			list temp = llParseString2List(msg,[" "],[""]);			integer max = llGetListLength(temp);			while(max--){//count backwards, since we're deleting stuff				string s = llList2String(temp,max);				if(~llListFindList(["the","a","my","his","her","that","any", ",", "."],[s])){					temp = llDeleteSubList(temp,max,max);				}			}			llSay(0, llDumpList2String(temp, " ,"));			if(pos = llListFindList(temp, ["is"])) {				req_ids += llHTTPRequest("http://words.bighugelabs.com/api/2/fc42d736f4db4a5f4a44529b76bbc307/" + llList2String(temp, pos - 1) + "/", [], "");				requests += llList2String(temp, pos - 1);				} else {				req_ids += "";				requests += "";			}						if (pos < llGetListLength(temp) - 1) {				req_ids += llHTTPRequest("http://words.bighugelabs.com/api/2/fc42d736f4db4a5f4a44529b76bbc307/" + llList2String(temp, pos + 1) + "/", [], "");				requests += llList2String(temp, pos + 1);			}  else {				req_ids += "";				requests += "";			}		}	}		http_response(key request_id, integer status, list metadata, string body) {		integer pos;		if((pos = llListFindList(req_ids, [request_id])) != -1) {			if (status == 200) {				list temp = llParseString2List(body, ["|", "\n"], []);				llSay(0, "The first synonyme for " + llList2String(requests, pos) + " is " + llList2String(temp, 2));			} else {				llSay(0, llList2String(requests, pos) + " hasn't been found in the thesaurus.");			}		}	}}

 

Link to comment
Share on other sites

  • 1 year later...

Hello everybody, I also have a problem with a script containing llhttprequest.

I want the script to send requests to a web server and ask for the contents of a table. The table contains 3 columns: Question, Answer, Tip. I want to send the requests 30 times and take as a return 3 lists, each one containing the questions, the answers and the help. My lsl script is the following:

key param1; // just to check if we're getting the result we've asked for; all scripts in the same object get the same replieskey param2;key param3;list question;list answer;list tip;default{    state_entry()    {        llSetText("Retrieve questions", <0.9, 0.4, 0.1>, 1.0);    }        touch_start(integer num)        {        integer i;        for ( i = 1; i <= 30; i++ )            {            param1 = llHTTPRequest("http://papavasa.webpages.auth.gr/opensim/send_data.php",                  [HTTP_METHOD, "POST", HTTP_MIMETYPE, "application/x-www-form-urlencoded"],                 "paramQ=" + i);            param2 = llHTTPRequest("http://papavasa.webpages.auth.gr/opensim/send_data.php",                  [HTTP_METHOD, "POST", HTTP_MIMETYPE, "application/x-www-form-urlencoded"],                 "paramA=" + i);            param3 = llHTTPRequest("http://papavasa.webpages.auth.gr/opensim/send_data.php",                  [HTTP_METHOD, "POST", HTTP_MIMETYPE, "application/x-www-form-urlencoded"],                 "paramT=" + i);            }        }        http_response(key request_id, integer status, list metadata, string body)    {        if (request_id == param1)            question += llParseString2List(body,["\n"],[" "]);            llOwnerSay( (string)question );        if (request_id == param2)            answer += llParseString2List(body,["\n"],[" "]);            llOwnerSay( (string)answer );        if (request_id == param3)            tip += llParseString2List(body,["\n"],[" "]);            llOwnerSay( (string)tip );       //llOwnerSay(body);    }        }

 And my php code is this:

<?// Only works with PHP compiled as an Apache module$headers = apache_request_headers();$objectName = $headers["X-SecondLife-Object-Name"];$objectKey     = $headers["X-SecondLife-Object-Key"];$ownerKey     = $headers["X-SecondLife-Owner-Key"];$ownerName = $headers["X-SecondLife-Owner-Name"];$region        = $headers["X-SecondLife-Region"];// and so on for getting all the other variables ...// get things from $_POST[]// Naturally enough, if this is empty, you won't get anything$parameter1 = $_POST["paramQ"];$parameter2 = $_POST["paramA"];$parameter3 = $_POST["paramT"];// Connect to MySQL$con = mysql_connect("localhost","stesia","stesia");if (!$con)  {  die('Could not connect: ' . mysql_error());  }// Select the databasemysql_select_db("stesia")   or die("Unable to select database: " . mysql_error());// Select only the row of the sent parametersif ( $parameter1 ){$result = mysql_query(" SELECT * FROM questions					   WHERE ID='" .$parameter1. "' ");$r = mysql_fetch_array($result);echo $r['Question'] . "\n";}else if ( $parameter2 ){$result = mysql_query(" SELECT * FROM questions					   WHERE ID='" .$parameter2. "' ");$r = mysql_fetch_array($result);echo $r['Answer'] . "\n";}else if ( $parameter3 ){$result = mysql_query(" SELECT * FROM questions					   WHERE ID='" .$parameter3. "' ");$r = mysql_fetch_array($result);echo $r['Help'] . "\n";}// close the connectionmysql_close($con);?>

 My problem is that the data returned is not in order (as in the table). I want to save the data in 3 different lists, one for questions, one for answers and one for tips. I don't know if i use correctly the http_request and response and the lists part..

I would very much appreciate it if anyone could help me out. Thank you in advance! :matte-motes-bashful-cute:

Link to comment
Share on other sites

The problem is that on touch you instantly fire-off 90 (30 x 3) requests to the web host, only ever remembering the most recent param1/2/3.  The responses will be added to the event queue but it's a queue, not an interrupt, so the first response can't be processed until touch_start() has finished sending all 90 requests.

I would send one at a time using the same index number, sending the next in the response handlee:

touch_start(...){   Index = 1;   Type = "Q";   Request = llHTTPRequest(..., "paramQ=1");}http_response(...){   if(request_id = Request){      if("Q" == Type){         ... add to questions list ..         Type = "A";         Request = llHTTPRequest(..., "paramA=" + (string) Index);      }else if("A" == Type){         ... add to answers list ..         Type = "T";         Request = llHTTPRequest(..., "paramT=" + (string) Index);      }else{         ... add to tips list ..         Type = "Q"; // <== Next question         Request = llHTTPRequest(..., "paramA=" + (string) ++Index);      }   }}

 

PS: Yours is a considerably different question to the OP's.  It would have been better to start a new thread than to resurrect this 18-month old one.

Link to comment
Share on other sites

Thank you very much for the reply! I tried this one and I think it will work now. But this creates an infinite loop... when the script runs, it returns to me all the Questions, Answers, Tips of the table, but then it returns empty records and never stops. Do you think I could make it stop when it finds empty record in the table? Or this should happen inside the php code?

 

I'm sorry to post in this old thread, but I'm new to this forum and couldn't find where I could create new thread :P

Link to comment
Share on other sites

Er, yes, it's an infinite loop in that pseudo-code.  Sorry if I wasn't clear.

IF you know you'll always want the first 30 the stick an 'if(30 > Index){ ... }' around the lines that set and send a new 'Q' request from the response handler.  That'll stop it incrementing the count and, since it won't send the request either, the job is complete.

Not hard-coding that limit will give you more flexibility.  In that case you'll presumably want to check for an empty-string (or just '\n') in the response you get to a 'Q' request - this being the first one to use a particular index.  Then you need only process the response at all if you've got a valid (non-empty) response.

 

Link to comment
Share on other sites


stecia1 wrote:

Thank you very much, I managed to stop the infinite loop!

 

Sorry, but this button doesn't show up on me.. the only thing I find is Topic Options->Start an article

but access is denied...
:(

That's because you are trying to start a new thread from within an existing one.  Back out of this thread and start a new one.  The button is right at the top.

Link to comment
Share on other sites

You are about to reply to a thread that has been inactive for 3454 days.

Please take a moment to consider if this thread is worth bumping.

Please sign in to comment

You will be able to leave a comment after signing in



Sign In Now
 Share

×
×
  • Create New...