PHP RiveScript-clone interpreter|joe|info@kaszazsolt.hu|1261305539|joe|xx|0|89.186.121.188|Hi everyone!<br /><br />A few years ago I made a simple and stupid chatbot. The robot is a macro language to overcomplicated was programmed. I would like to draw up a simplified RiveScript PHP interpreter, and rewrite my chatbot.<br />||||
Re: PHP RiveScript-clone interpreter|joe|info@kaszazsolt.hu|1261652395|joe|xx|0|89.186.125.100|Hi!<br /><br />Which is correct?<br /><br />[code]<br />+ question 1<br />- random answer 1<br />- random answer 2<br />@ other question<br /><br />or:<br /><br />+ question 2<br />@ other question<br />[/code]||||
Re: PHP RiveScript-clone interpreter|Kirsle|casey@cuvou.net|1261673045|Kirsle|xx|0|72.37.252.50|The second one is correct.||||
Re: PHP RiveScript-clone interpreter|joe|info@kaszazsolt.hu|1261731276|joe|xx|0|89.186.125.100|Thanks!<br /><br />And &quot;*&quot; command followed by a number of unconditional answer? Randomly selected them?<br /><br />[code]<br />+ question 1<br />* condition 1<br />* condition 2<br />- unconditional aswer<br /><br />or:<br />+ question 2<br />* condition 1<br />* condition 2<br />- unconditional aswer 1<br />- unconditional answer 2<br /><br />[/code]<br />And the &quot;^&quot; command used only unconditional answer, or all command?<br /><br />[code]<br />- answer<br />^answer second part<br />^answer third part<br /><br />and:<br /><br />* condition<br />^ condition part 2<br />^ condition part 3<br /><br />and: <br />@ redirect<br />^ redirect part 2, etc...<br />[/code]||||
Re: PHP RiveScript-clone interpreter|Kirsle|casey@cuvou.net|1261774275|Kirsle|xx|0|69.232.60.104|When looking for a reply to a matched trigger...<br /><br />1) If any redirection exists (@), it will redirect to that trigger immediately. Also, in case you ask this later, if there is more than one @ for some reason, only the last one is used (the spec only allows for a single @, and I coded the perl rivescript interpreter to only keep room for one, so each @ it finds is copied to the same variable overwriting the previous one).<br /><br />2) If any conditions exist, it will test all the conditions in the order they appeared in the source code.<br /><br />3) If no reply was found yet (no redirection, or all the conditions were false), then it looks at the replies. If there's more than one it picks them randomly.<br /><br />So..<br /><br />[code]+ question 1<br />* condition 1<br />* condition 2<br />- unconditional aswer<br /><br />If you say &quot;question 1&quot;, it will try condiiton 1 first, then condition 2, and if neither one is true then it gives the unconditional answer.<br /><br />+ question 2<br />* condition 1<br />* condition 2<br />- unconditional aswer 1<br />- unconditional answer 2<br /><br />here it'll try condition 1, then condition 2, and if neither is true it will randomly pick between unconditional answer 1 and 2.<br /><br />If you want random redirections, you can use the inline redirection format.<br /><br />+ question<br />- &#123;@answer one&#125;<br />- &#123;@answer two&#125;[/code]<br /><br />As for the extension commands... your questions are uncovering some interesting errors in my perl module. :)<br /><br />[blue]The ^ command is supposed to be able to extend all other commands. When it does so, it should not add any spacing of its own; if the writer intends for there to be a space between the joined parts they should insert the \s tag.[/blue] This is how it *should* behave:<br /><br />[code]- answer<br />^answer second part<br />^answer third part<br /><br />is equivalent to:<br /><br />- answeranswer second partanswer third part<br /><br />and:<br /><br />* condition<br />^ condition part 2<br />^ condition part 3<br /><br />is equivalent to:<br /><br />* conditioncondition part 2condition part 3<br /><br />and:<br />@ redirect<br />^ redirect part 2, etc...<br /><br />is equivalent to:<br /><br />@ redirectredirect part 2, etc...[/code]<br /><br />Although, in testing this with the Perl RiveScript interpreter, I found some bugs that I need to fix. Here's my test code:<br /><br />[code]+ test one<br />- answer<br />^ answer second part<br />^ answer third part<br /><br />/*<br />   + test two<br />   * &lt;id&gt; ==<br />   ^ localuser =&gt;<br />   ^ conditions can span multiple lines too<br />   - normal reply<br />*/<br /><br />+ test three<br />* &lt;id&gt; == localuser =&gt; conditions<br />^ can span multiple lines too<br />- normal reply<br /><br />+ test four<br />@ test<br />^ one<br /><br />+ test five<br />@ test<br />^ \sone[/code]<br /><br />The output:<br /><br />[code]You&gt; test one<br />Bot&gt; answeranswer second partanswer third part<br />You&gt; test two<br />Bot&gt; ERR: No Reply Matched<br />You&gt; test three<br />Bot&gt; conditionscan span multiple lines too<br />You&gt; test four<br />Bot&gt; ERR: No Reply Matched<br />You&gt; test five<br />Bot&gt; answeranswer second partanswer third part<br />You&gt; ^C[/code]<br /><br />So, there's a few bugs here:<br /><br />* Test one behaved the way I expected it to.<br /><br />* Test two gave me syntax errors, so I had to comment it out of the file. It said &quot;Syntax error in ./extend.rs line 6: Invalid format for !Condition: should be like `* value symbol value =&gt; response` (near: * &lt;id&gt; ==)&quot;<br /><br />* Test three worked the way I expected it to. After the syntax error from test two I rewrote it so that the majority of the condition logic is on the same line, and the only part extended is the response part for the condition.<br /><br />* Test four worked the way I expected it to. Since the join caused the line to be effectively &quot;@ testone&quot; with no space, it didn't match any trigger.<br /><br />* Test five also worked the way I expected it to. I put a \s in there so that the redirection became &quot;@ test one&quot; -- however, there was a small bug. If I put the \s on the same line as the @ symbol, it gave me a syntax error, saying that &quot;\s&quot; isn't a legal character for a trigger or redirection.<br /><br />So, generally yes, the ^ command can extend any other command. I just need to fix my Perl module so that it doesn't whine about syntax errors before it actually joins the lines together. My commented-out condition test should've worked just fine, for example.<br /><br />The spec can still be changed though, so certain things could still be added to it, such as allowing multiple @ commands for a single reply and have them be chosen randomly...||1261774660|Kirsle|
Re: PHP RiveScript-clone interpreter|joe|info@kaszazsolt.hu|1261786937|joe|xx|0|79.120.161.205|I did a test page, where you can try it, how to load the script of the interpreter: kaszazsolt.hu/bot/rtest.php <br />( :'( I can't write a link)<br /><br />(Does not do anything, just print the loaded information.)<br /><br />This code works well:<br />[code]<br />+ test one<br />% previous message\s<br />^ with multi<br />^ ple lines<br />- answer<br />^ answer second part<br />^ answer third part<br />- second answer<br /><br />+ test two<br />* &lt;id&gt; ==<br />^ localuser =&gt;<br />^ conditions/*can span*/ multiple /*lines*/ too // many comments<br />- normal reply<br /><br />+ test three<br />* &lt;id&gt; == localuser =&gt; conditions<br />^ can span multiple lines too<br />- normal reply<br /><br />+ test four<br />@ test<br />^ one<br /><br />+ test five<br />@ test<br />^ \sone [/code]||||
Re: PHP RiveScript-clone interpreter|Kirsle|casey@cuvou.net|1261790323|Kirsle|xx|0|69.232.60.104|You need 5 posts before you can start posting links. &nbsp;;)<br /><br />A while back I was working on a rivescript implementation in pure JavaScript (using ajax to load the rs files)... I can't seem to find it though. It supported almost as much as my current Java one does, like it could chat and some tags worked but it didn't support everything. Anyway, your PHP thing that writes out the data structures reminded me of it, cuz mine had a button to dump the data out too.||||
Re: PHP RiveScript-clone interpreter|joe|info@kaszazsolt.hu|1261822930|joe|xx|0|79.120.163.119|The _ and the # wildcard match only one word? And the * wildchard match several words?<br /><br />And Another problem.  ::) The sub variables. <br /><br />[code]<br />! sub l o l = lol<br />[/code]<br /><br />The example code change &quot;this is l o l message&quot; text to &quot;this is lol message&quot;. But! Change &quot;mill o load&quot; to &quot;milloload&quot;?<br />(sorry this stupid text, I hope to understand in some degree.  ;D)||1261832735|joe|
Re: PHP RiveScript-clone interpreter|Kirsle|casey@cuvou.net|1261859595|Kirsle|xx|0|69.232.60.104|All the wildcard symbols should match multiple words (if the perl module doesn't do this, it's another bug and will be fixed :P). _ should match letters and spaces, # should match numbers and spaces, and * matches anything.<br /><br />[code]_ = /[A-Za-z\s]+?/<br /># = /[0-9\s]+?/<br />* = /.+?/[/code]<br /><br />And when &quot;l o l&quot; is substituted, the &quot;l o l&quot; has to be isolated in the message. So &quot;mill o load&quot; is left unmodified. This can be seen in the `rsdemo` app that comes with the perl RiveScript module, if you run it on some code that has a substitution for &quot;l o l&quot; (the default set doesn't include this substitution) using `rsdemo --debug`<br /><br />[quote]You&gt; my name is Kirsle l o l<br />RiveScript: Get reply to [localuser] my name is Kirsle l o l<br />RiveScript: Checking topic __begin__ for any %previous's.<br />RiveScript: Trying to match &quot;request&quot; against request (request)<br />RiveScript: Found a match!<br />RiveScript: Processing responses to this trigger.<br />RiveScript: Reply: &#123;ok&#125;<br />RiveScript: Checking topic random for any %previous's.<br />RiveScript: There's a %previous in this topic<br />RiveScript: lastReply: that is interesting please continue<br />RiveScript: Try to match lastReply (that is interesting please continue) to whats her name<br />RiveScript: Try to match lastReply (that is interesting please continue) to whats his name<br />RiveScript: Trying to match &quot;[blue]my name is kirsle lol[/blue]&quot; against shutdown&#123;weight=10000&#125; (shutdown)<br />[...]<br />Bot&gt; Kirsle Lol, nice to meet you.<br /><br />and<br /><br />You&gt; my name is mill o load<br />[...]<br />RiveScript: Trying to match &quot;[blue]my name is mill o load[/blue]&quot; against my name is * (my name is (.+?))<br />RiveScript: Found a match!<br />RiveScript: Processing responses to this trigger.<br />RiveScript: Reply: &lt;set name=&lt;formal&gt;&gt;Nice to meet you, &lt;get name&gt;.<br />RiveScript: Set uservar name =&gt; Mill O Load<br />Bot&gt; Nice to meet you, Mill O Load.[/quote]<br /><br />PHP is pretty similar to Perl in syntax so you might be able to adapt the substitution code directly over to PHP. Here's the code:<br /><br />[code]sub _formatMessage &#123;<br /> &nbsp; &nbsp; &nbsp;my ($self,$string) = @_;<br /><br /> &nbsp; &nbsp; &nbsp;# Lowercase it.<br /> &nbsp; &nbsp; &nbsp;$string = lc($string);<br /><br /> &nbsp; &nbsp; &nbsp;# Run substitutions on it.<br /> &nbsp; &nbsp; &nbsp;foreach my $pattern (@&#123;$self-&gt;&#123;sortlist&#125;-&gt;&#123;subs&#125;&#125;) &#123;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;my $result = $self-&gt;&#123;subs&#125;-&gt;&#123;$pattern&#125;;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$result =~ tr/A-Za-z/N-ZA-Mn-za-m/;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;my $qm = quotemeta($pattern);<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$string =~ s/^$qm$/&lt;rot13sub&gt;$result&lt;bus31tor&gt;/ig;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$string =~ s/^$qm(\W+)/&lt;rot13sub&gt;$result&lt;bus31tor&gt;$1/ig;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$string =~ s/(\W+)$qm(\W+)/$1&lt;rot13sub&gt;$result&lt;bus31tor&gt;$2/ig;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$string =~ s/(\W+)$qm$/$1&lt;rot13sub&gt;$result&lt;bus31tor&gt;/ig;<br /> &nbsp; &nbsp; &nbsp;&#125;<br /> &nbsp; &nbsp; &nbsp;while ($string =~ /&lt;rot13sub&gt;(.+?)&lt;bus31tor&gt;/i) &#123;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;my $rot13 = $1;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$rot13 =~ tr/A-Za-z/N-ZA-Mn-za-m/;<br /> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$string =~ s/&lt;rot13sub&gt;(.+?)&lt;bus31tor&gt;/$rot13/i;<br /> &nbsp; &nbsp; &nbsp;&#125;<br /><br /> &nbsp; &nbsp; &nbsp;# Format punctuation.<br /> &nbsp; &nbsp; &nbsp;$string =~ s/[^A-Za-z0-9 ]//g;<br /> &nbsp; &nbsp; &nbsp;$string =~ s/^\s+//g;<br /> &nbsp; &nbsp; &nbsp;$string =~ s/\s+$//g;<br /><br /> &nbsp; &nbsp; &nbsp;return $string;<br />&#125;[/code]<br /><br />Basically, it takes the result text for each substitution (e.g. &quot;what is&quot; for &quot;whats&quot;), rot13-encodes it, and then substitutes &quot;whats&quot; for &quot;&lt;rot13sub&gt;jung vf&lt;/bus31tor&gt;&quot; until it's all done running substitutions, and then it goes through and looks for the rot13-encoded text it put in and decodes it and removes the temporary tags it put around it.<br /><br />quotemeta() is a Perl function that automatically escapes regular expression special characters.<br /><br />The regexps themselves:<br /><br />[code]/^$qm$/<br />/^$qm(\W+)/<br />/(\W+)$qm(\W+)/<br />/(\W+)$qm$/[/code]<br /><br />(\W+) matches any character that is not a word character (word characters are numbers and letters, but not spaces). So for &quot;l o l&quot; these regexps match:<br /><br />1. if the message consists *only* of the text &quot;l o l&quot;<br />2. if the message begins with &quot;l o l&quot; &amp; is then followed by a space or other non-word character<br />3. if the message contains &quot;l o l&quot; as one of its words (surrounded by a space or non-word character on either side)<br />4. if the message ends with &quot;l o l&quot; and has a space or non-word char before it.<br /><br />The reason for the rot13 encoding is to stop the substitutions from undoing each other. This is especially important for person substitutions, where you might have:<br /><br />[code]! person you are = I am<br />! person i am = you are[/code]<br /><br />If it replaces &quot;you are&quot; with &quot;I am&quot;, and then replaces &quot;I am&quot; with &quot;you are&quot;, you'd end up with the same text you started with. So, it rot13-encodes it when it puts in the substituted text so that the rest of the substitutions don't interfere with the text that it already replaced. It's a weak approach, I know; perhaps a better one would be to keep an array of all the substitutions it made and just insert small numbered tags, like &lt;0&gt;, &lt;1&gt;, &lt;2&gt;, etc... and then replace those tags with the items from the array.||1261859669|Kirsle|
