RiveScript - Rendering Intelligence Very Easily
use RiveScript;
# Create a new RiveScript interpreter. my $rs = new RiveScript;
# Load some replies. $rs->loadDirectory ("./replies");
# Load in another file. $rs->loadFile ("./more_replies.rs");
# Stream in even more RiveScript code. $rs->stream (q~! global split_sentences = 1~);
# Sort all the loaded replies. $rs->sortReplies;
# Grab a response. my @reply = $rs->reply ('localscript', 'Hello RiveScript!'); print join ("\n", @reply), "\n";
RiveScript is a simple input/response language. It has a simple, easy-to-learn syntax, yet it is more powerful even than Dr. Wallace's AIML (Artificial Intelligence Markup Language). RiveScript was created as a reply language for chatterbots, but it has been used for more complex things above and beyond that.
This part of the manpage documents the methods of the Perl RiveScript library. The RiveScript language specifications are below: see RIVESCRIPT.
Creates a new RiveScript instance.
Define an object macro (see Object Macros)
Load a directory of RiveScript files. @EXTS
is optionally an array of file extensions
to load, in the format (.rs .txt .etc)
. Default is just ".rs"
Load a single RiveScript file. Don't worry about the $STREAM
argument, it is handled
in the stream()
method.
Stream RiveScript codes directly into the module.
Sorts all the loaded replies. This is necessary for reply matching purposes. If you fail
to call this method yourself, it will be called automatically with reply()
, but not without
a nasty Perl warning. It's better to always sort them yourself, for example if you load in
new replies later, they won't be matchible unless a new sortReplies
is called.
Get a reply from the bot. This will (normally) return an array. The values of the array
would be all the replies to that message (i.e. if you use the {nextreply}
tag in a
response, or if you pass in multiple sentences).
%TAGS
is optionally a hash of special reply tags. Each value is boolean.
scalar = Forces the return value into a scalar instead of an array no_split = Don't run sentence-splitters on the message. retry = INTERNAL. Tells the module that it's on a retry run, for special cases such as ;) - winking emoticon - since ; is a default sentence-splitter.
Search all loaded replies for every trigger that $STRING
matches. Returns an array
of results, containing the trigger, what topic it was under, and its file and line number
where applicable.
Writes all the currently loaded replies into a single file. This is useful for if your application dynamically learns replies by editing the loaded hashrefs. It will write all replies to the file under their own topics. Comments and other unnessecary information is ignored.
The default path is to "written.rs" in the working directory.
Note: This method doesn't honor the %PREVIOUS
command in RiveScript.
See Dynamic Replies.
Set a global RiveScript variable directly from Perl (alias for ! global
)
Set a botvariable (alias for ! var
)
Set a substitution setting (alias for ! sub
)
Set a user variable (alias for <set var=value>
for $USER_ID
)
Get all uservars for a user. Returns a hashref of the variables. If you don't pass in a
$USER_ID
, it will return a hashref of hashrefs for each user by their ID.
The RiveScript interpreter can specify some security settings as far as what a RiveScript file is allowed to contain.
Note: These settings only apply to commands found in a RiveScript document
while it's being loaded. It does not apply to tags within RiveScript responses
(for example {! global ...}
could be used in a reply to reset a global variable.
This can't be helped with these commands. For ultimate security, you should have
your program manually check these things).
Valid modes are deny_some
, allow_some
, and allow_all
. allow_all is the default.
Use the deny()
and allow()
methods complementary to the denyMode specified.
Add @COMMANDS
to the denied commands list. These can be single commands or beginnings
of command texts. Example:
$rivescript->deny ( '&', '! global', '! var copyright', '> begin', '< begin', '> __begin__', '< __begin__', );
In that example, &PERL
, !GLOBAL
, the botvariable copyright
, and the BEGIN
statements (and its internal names) are all blocked from being accepted in any loaded
RiveScript file.
Add @COMMANDS
to the allowed commands list. For the highest security, it would be better
to allow_some
commands rather than deny_some
.
$rivescript->allow ( '+', '-', '! var', '@', );
That example would deny every command except for triggers, responses, botvariable setters, and redirections.
These methods are called on internally and should not be called by you.
Print a debug message (when debug mode is active).
Creates a RiveScript::Parser instance, passing in the current data
held by RiveScript
. This call is made before using the parser (to read or write replies)
and destroyed when no longer needed.
This is the internal reply-getting routine. Call reply()
instead. This assumes that the
data is all correctly formatted before being processed.
Splits $STRING
at the sentence-splitters and returns an array.
Formats $STRING
by running substitutions and removing punctuation and symbols.
Merges the values from @STARS
into $STRING
, where the items in @STARS
correspond
to a captured value from $1
to $100+
. The first item in the array should be blank as
there is no <star0>
.
Formats $STRING
by $TYPE
(uppercase, lowercase, formal, sentence).
Run tag filters on $REPLY
. Returns the new $REPLY
.
Runs shortcut tags on $REPLY
. Returns the new $REPLY
.
The following is the RiveScript 1.00 specification.
RiveScript is a line-by-line command-driven language. The first symbol(s)
of each line is
a command, and the following text is its data.
In its most simple form, a valid RiveScript reply looks like this:
+ hello bot - Hello human.
The !
command is for definitions. These are used to define variables and arrays at load
time. Their format is as follows:
! $type $variable = $value
The supported types are as follows:
global - Global settings (eg. debug and sentence_splitters) var - BotVariables (eg. the bot's name, age, etc) array - An array sub - A substitution pattern person - A "person" substitution pattern addpath - Add an include path for RiveScript includibles include - Include a separate RiveScript library or package syslib - Include a Perl module into the RiveScript:: namespace.
Some examples:
// Set global variables (defaults) ! global debug = 0 ! global split_sentences = 1 ! global sentence_splitters = . ! ; ?
// Setup a handler string for object failures. ! global macro_failure = <b>ERROR: Macro Failure</b>
// Set bot vars ! var name = Casey Rive ! var age = 14 ! var gender = male ! var color = blue
// Delete botvar "color" ! var color = undef
// An array of color names ! array colors = red blue green yellow cyan fuchsia
// An array of "can not" variations ! array not = can not|would not|should not|could not
// A few substitutions ! sub can't = can not ! sub i'm = i am
// Person substitutions (swaps 1st- and 2nd-person pronouns) ! person i = you ! person you = me ! person am = are ! person are = am
// Add a path to find libraries. ! addpath C:/MyRsLibraries
// Include some English verb arrays ! include English/EngVerbs.rsl
// Include a package of objects. ! include DateTime.rsp
Note: For arrays with single-word items, separate entries with white spaces. For multi-word items, use pipe symbols.
Note: To delete a variable, set its value to "undef"
See also: Environment Variables and Person Substitution.
The <
and >
commands are for defining labels. A label is used to treat
a part of code differently. Currently there are three uses for labels: begin
, topic
,
and object
. Example:
+ you are stupid - You're mean. Apologize or I'm not talking to you again.{topic=apology}
> topic apology
+ * - No, apologize for being so mean to me.
+ sorry - See, that wasn't too hard. I'll forgive you.{topic=random}
< topic
The +
command is the basis for all reply sets. The +
command is what the user has
to say to activate the reply set. In the example,
+ hello bot - Hello human.
The user would say "hello bot" and get a "Hello human." reply.
Triggers are passed through the regexp engine. They should be completely lowercase and not contain too many foreign characters (use substitutions to format the message any way you want so you don't need to use foreign characters!)
The %
command is for drawing a user back to complete a thought. It's similar to the
<that>
functionality in AIML.
+ ask me a question - Do you have any pets?
+ yes % do you have any pets - What kind of pet?
The %
command is like the +Trigger
, but for the bot's last reply. The same
substitutions are run on the bot's last reply as are run on the user's messages.
! sub who's = who is
+ knock knock - Who's there?
+ * % who is * - <formal> who?
+ * % * who - Haha! <sentence>! That's hilarious!
(see Tags for details on what <formal>
and <sentence>
are)
The -
command is the response to a trigger. The -
command has several different
uses, depending on its context. One +Trigger
with one -Response
makes a one-way
question-and-answer scenario. When multiple -Response
s are used, they become random
replies. For more information, see Complexities of the Response.
The ^
command is to extend the data of the previous command. This is for editor-side
use only and has no effect on the brain when replies have all been loaded.
The following commands can be used with the ^Continue
command:
! global ! var ! array + trigger % previous - response @ redirection
Here's an example of extending a very long -Response
over multiple lines. When the
brain is tested, the reply will come out as one long string. The ^Continue
is only
for you, the reply writer, to make it easier to read the code.
+ tell me a poem - Little Miss Muffit sat on her tuffet\s ^ in a nonchalant sort of way.\s ^ With her forcefield around her,\s ^ the Spider, the bounder,\s ^ is not in the picture today.
Note that spaces are NOT assumed between
breaks. You'll need the \s
tag (see Tags).
The @
command is for directing one trigger to another. For example:
+ my name is * - Nice to meet you, <formal>.
+ people call me * @ my name is <star>
+ i am named * @ my name is <star>
The *
command is for checking conditions. The format is:
* variable = value => say this
For an example, you can differentiate between male and female users:
+ am i a boy or a girl * gender = male => You're a boy. * gender = female => You're a girl. - You've never told me what you are.
You can perform the following operations on variable checks:
= equal to != not equal to < less than <= less than or equal to > greater than >= greater than or equal to ? returns true if the variable is defined
If you want to check the condition of a bot variable, prepend a #
sign to the variable
name. This isn't necessary, but if the user has a variable by the same name, the user's
variable overrides the bot's.
+ is your name still soandso * #name = Soandso => That's still my name. - No, I changed it.
Here's an example of the "defined" condition:
// Only use the user's name if they've defined it to us + hello bot * name ? => Hello there, <get name>, nice to see you again! - Hello there!
The &
command is for executing Perl codes directly from a RiveScript reply set. Use this
only as a last resort, though. RiveScript is powerful enough to handle almost anything you could
want it to, and it can handle these things more securely than this command would, as this command
simply eval
s the expression.
+ what is 2 plus 2 - 500 Internal Error (the eval failed for some reason!) & $reply = '2 + 2 = 4';
The comment syntax is //
, as it is in other scripting languages. Also, /* */
comments
can be used to span across multiple lines:
// A one-line comment
/* this comment spans across multiple lines */
Commands can be used in-line next to RiveScript commands. They need to have at least one white space before and after the comment symbols.
+ what color is my (@colors) * // "What color is my green shoe?" - Your <star2> is <star1>! // "Your shoe is green!"
The Perl comment symbol, #
, can be used in RiveScript as well. It follows the same
principals as the //
commands, but it can not span across multiple lines.
The RiveScript engine was designed for the RiveScript brain to hold most of the control. As little programming as possible on the Perl side as possible has made it so that your RiveScript can define its own variables and handle what it wants to. See A Good Brain for tips on how to approach this.
The +Trigger
can be used for more complex things than just simple, 100% dead-on triggers.
This part is passed through a regexp, hence any regexp commands can be used in the trigger...
however, don't think too much into it, you can get impressive results with simple-looking
patterns.
Note: An asterisk *
is always converted into (.*?)
regardless of its context. Keep
this in mind.
You can write open-ended triggers (called "wildcard triggers"). You can
capture the output of them, in order, by using the tags <star1>
to
<star100>
+. Example:
+ my name is * - Nice to meet you, <star1>.
You can use alternations in the triggers like so:
+ what (s|is) your (home|office|cell) phone number
The values the user chose for each set of alternations are also put into the
<star>
tags like the wildcards are.
You can use optional words in a trigger. These words don't have to exist in the user's message in order to match it, but they can be. Example:
+ what is your [home] phone number - You can call me at 555-5555.
Alternations can be used inside of optionals as well:
+ what (s|is) your [home|office|cell] phone number
This is why it's good to define arrays. Arrays can be used in any number of triggers. Here's an example of how it works:
// Make an array of color names ! array colors = red blue green yellow cyan fuchsia
// Now they can tell us their favorite color! + my favorite color is (@colors) - Really?! Mine is <star> too!
If you want the array choice to be put into a <star>
tag, enclose it in parenthesis.
Without the parenthesis, it will be skipped over and not matchible. Example:
// If the input is "sometimes I am a tool"...
! array be = am are is was were
+ * i @be * // <star1> = 'sometimes' // <star2> = 'tool'
+ * i (@be) * // <star1> = 'sometimes' // <star2> = 'am' // <star3> = 'a tool'
The -Response
command has many uses depending on its context:
A single +
and a single -
will lead to a one-way question/answer scenario.
A single +
with multiple -
's will yield random results from the responses.
+ hello - Hey. - Hi. - Hello.
When using conditionals and Perl codes, you should have at least one -Response
to fall back on in case everything returns false.
With random replies, you can apply weight to them to improve their probability of being chosen. All replies have a default weight of 1, and anything lower than 1 can not be used. Example:
+ hello - Hello, how are you?{weight=49} - Yo, wazzup dawg?{weight=1}
See Tags.
The BEGIN file is the first reply file loaded in a loadDirectory call. If a "begin.rs" file exists in the directory being loaded, it is included first. This is the best place to put your definitions and include statements.
Note: BEGIN statements are not required.
How to define a BEGIN statement
> begin + request - {ok} < begin
BEGIN statements are like topics, but are always called first on every reply. If the
response contains {ok}
in it, then the module gets an actual reply to your message
and substitutes it for {ok}
. In this way, the BEGIN statement could format all the
replies in the same way. For an example:
> begin
// Don't give a reply if the bot is down for maintenance. Else, sentence-case // every reply the bot gives. + request * #maintenance = yes => Sorry, the bot is currently deactivated! - {sentence}{ok}{/sentence}
< begin
Here is a more complex example using a botvariable "mood"
> begin + request * mood = happy => {ok} * mood = sad => {lowercase}{ok}{/lowercase} * mood = angry => {uppercase}{ok}{/uppercase} * mood = pissed => {@not talking} - {ok}
+ not talking - I'm not in a talkative mood. - I don't want to talk right now. < begin
Note: The only trigger that BEGIN receives automatically is request
.
Topics are declared in a similar way to the BEGIN statement. To declare and close a topic, the syntax is as follows:
> topic NAME ... < topic
The topic name should be unique and only one word.
The Default Topic: The default topic name is "random
"
Setting a Topic: To set a topic, use the {topic}
tag (see Tags below).
+ you are stupid - You're mean. Apologize or I'm not talking to you again.{topic=apology}
> topic apology
+ * - No, apologize for being so mean to me.
+ sorry - See, that wasn't too hard. I'll forgive you.{topic=random}
< topic
Always set topic back to "random" to break out of a topic.
Special macros (Perl routines) can be defined and then utilized in your RiveScript code.
You can define objects within your RiveScript code. When doing this, keep in mind that the
object is included as part of the RiveScript::
namespace. That being said, here are some
basic tips to follow:
1) If it uses any modules, they need to be explicitely declared with a 'use' statement. 2) If it refers to any variables global to your main script, 'main::' must be prepended. Example: '$main::hashref->{key}' 3) If it refers to any subroutine of your main program, 'main::' must be prepended. Example: '&main::reload()'
Here's a full example of an object:
+ give me a fortune cookie - Your random fortune cookie: &fortune.get()
> object fortune my ($method,$msg) = @_;
my @cookies = ( 'You will be rich and famous', 'You will meet a celebrity', 'You will go to the moon', );
return $cookies [ int(rand(scalar(@cookies))) ]; < object
This is done like so:
# Define a weather lookup macro. $rivescript->setSubroutine (weather => \&weather_lookup);
To call on an object inside of a reply, the format is:
&object_name.method_name(argument)
All objects receive $method
(the data after the dot) and $argument
(the data inside
the parenthesis). Here's another example:
+ encode * in base64 - &encode.base64(<star>)
+ encode * in md5 - &encode.md5(<star>)
> object encode my ($method,$data) = @_;
use MIME::Base64 qw(encode_base64); use Digest::MD5 qw(md5_hex);
if ($method eq 'base64') { return encode_base64 ($data); } else { return md5_hex ($data); } < object
Note: If an object does not exist, has faulty code, or does not return a reply, the contents
of global macro_failure
will be inserted instead. The module cannot tell you which of the
three errors is the cause, though.
Special tags can be inserted into RiveScript replies. The tags are as follows:
These tags will insert the values of $1
to $100
+, as matched in the trigger regexp.
<star>
is an alias for <star1>
.
Inserts the last 1 to 9 things the user said, and the last 1 to 9 things the bot replied with, respectively.
Inserts the user's ID.
Insert a bot variable (defined with ! var
).
+ what is your name - I am <bot name>, created by <bot author>.
This is also the only tag that can be used in triggers.
+ my name is <bot name> - <set name=<bot name>>What a coincidence, that's my name too!
Get and set a user variable. These are local variables for the current user.
+ my name is * - <set name=<formal>>Nice to meet you, <get name>!
+ who am i - You are <get name> aren't you?
Add, subtract, multiple and divide numeric variables, respectively.
+ give me 5 points - <add points=5>You have receive 5 points and now have <get points> total.
If the variable is undefined, it is set to 0 before the math is done on it. If you try to modify a defined, but not numeric, variable (such as "name") then (Var=NaN) is inserted in place of this tag.
Likewise, if you modify a variable with a non-numeric value, then (Value=NaN) is inserted.
This will change the user's topic. See Topics.
Breaks the reply into two parts here. This will cause reply()
to return multiple
responses for each side of the {nextreply}
tag.
Add some weight to a -Response
. See Complexities of the Response.
An inline redirection. These work like normal redirections but can be inserted into another reply.
+ * or something - Or something. {@<star>}
<@>
is an alias for {@<star>}
An inline definition.
Inserts a random bit of text. Separate single-word items with spaces or multi-word items with pipes.
+ test random - This {random}reply response{/random} has random {random}bits of text|pieces of data{/random}.
Will take the enclosed text and run person substitutions on them. See Person Substitution.
<person>
is an alias for {person}<star>{/person}
Will Make Your Text Formal.
<formal>
is an alias for {formal}<star>{/formal}
Will make your text sentence-cased.
<sentence>
is an alias for {sentence}<star>{/sentence}
WILL MAKE THE TEXT UPPERCASE.
<uppercase>
is an alias for {uppercase}<star>{/uppercase}
will make the text lowercase.
<lowercase>
is an alias for {lowercase}<star>{/lowercase}
This is used only with the Begin Statement. It tells the interpreter that it's okay to get a reply.
Inserts a white space.
Inserts a newline.
Insert a forward slash. This is to include forward slashes without them being interpreted as comments.
Inserts a pound symbol. This is to include pound symbols without them being interpreted as comments.
Environment variables are kept as "botvariables" and can be retrieved with the
<bot>
tags. The variable names are all uppercase and begin with "ENV_"
ENV_OS = The operating system RiveScript is running on. ENV_APPVERSION = The version of RiveScript being used. ENV_APPNAME = A user-agent style string ("RiveScript/1.00") ENV_REPLY_COUNT = The number of loaded triggers.
All Perl variables are prepended with "ENV_SYS_", so that "ENV_SYS_REMOTE_ADDR" would contain the user's IP address if RiveScript was used via HTTP CGI.
RiveScript's syntax prohibits the modification of environment variables through any
loaded RiveScript document. However, you can call the method setVariable()
to
change environment variables from the Perl side if need-be.
The {person}
tag can be used to perform substitutions between 1st- and 2nd-person
pronouns.
You can define these with the !define
tag:
! person i = you ! person my = your ! person mine = yours ! person me = you ! person am = are ! person you = I ! person your = my ! person yours = mine ! person are = am
Then use the {person}
tag in a response. The enclosed text will swap these pronouns.
+ do you think * - What if I do think {person}<star>{/person}?
"Do you think I am a bad person?" "What if I do think you are a bad person?"
Without the person tags, it would say "What if I do think I am a bad person?" and not make very much sense.
Note: RiveScript does not assume any pre-set substitutions. You must define them in your own brains.
Here is an overview of the internal hashref structure of the RiveScript object, for modifying replies directly.
This hashref contains all of the replies. The first keys are the topic name, then the trigger texts under that topic.
So, $rs->{replies}->{random} contains all triggers for the default topic.
$rs-{replies}->{random}->{'my favorite color is (@colors) *'}> would be the location of a specific trigger.
The following keys are underneath a trigger key ($rs-{replies}->{$topic}->{$trigger}>)
1..n - The -Responses
under the trigger, in order.
redirect - The contents of the @Redirect
if applicable.
conditions-{1..n}> - The data from the *Condition
commands, in order.
system-{codes}> - The contents of any &Perl
codes if applicable.
// RiveScript Code + my name is * - <star>, nice to meet you! - Nice to meet you, <star>.
# Perl code. Get the value of the second reply. $rs->{replies}->{random}->{'my name is *'}->{2}
// RiveScript Code > topic favorites + *(@colors)* - I like <star2> too. :-) & &main::log('<id> likes <star2>') < topic
# Perl code. Get the perl data from that trigger. $rs->{replies}->{favorites}->{'*(@colors)*'}->{system}->{codes}
// RiveScript Code + * % whos there - <star> who?
# Perl code. Access this one's reply. $rs->{replies}->{'__that__whos there'}->{1}
Recommended practice is to place all your !include
statements inside your begin.rs file,
as this file is always loaded in first.
RiveScript Libraries (.rsl extension) are special RiveScript documents that are generally full of arrays and substitutions. For instance, the RiveScript distribution comes with English.rsl which is full of English nouns, verbs, and adjectives.
RiveScript Packages (.rsp extension) are special RiveScript documents that are generally full of objects. The RiveScript distribution comes with DateTime.rsp, which has an object for returning time stamps.
The default RiveScript Includes search path is the array of Perl's @INC
, with "/RiveScript"
tacked on to the end of it. Also, the working directory of your script is included in this.
You can use the !addpath
directive to add new search paths.
The following are all the reserved variables within RiveScript which cannot be (re)set by your reply files.
These variables can't be overwritten with the !global
command:
reserved replies array syntax streamcache botvars uservars botarrays sort users substitutions
The following topic names are special and should never be (re)created in your RiveScript files.
__begin__ (used for the BEGIN statement) __that__* (used for the %Previous command)
Since RiveScript leaves a lot of control up to the brain and not the Perl code, here are some general tips to follow when writing your own brain:
This would probably be named "config.rs" and it would handle all your definitions. For example it might look like this:
// Set up globals ! global debug = 0 ! global split_sentences = 1 ! global sentence_splitters = . ! ; ?
// Set a variable to say that we're active. ! var active = yes
// Set up botvariables ! var botname = Rive ! var botage = 5 ! var company = AiChaos Inc. // note that "bot" isn't required in these variables, // it's only there for readibility
// Set up substitutions ! sub won't = will not ! sub i'm = i am // etc
// Set up arrays ! array colors = red green blue yellow cyan fuchsia ...
Here are a list of all the globals you might want to configure.
split_sentences - Whether to do sentence-splitting (1 or 0, default 1) sentence_splitters - Where to split sentences at. Separate items with a single space. The defaults are: ! . ? ; macro_failure - Text to be inserted into a bot's reply when a macro fails to run (or return a reply). debug - Debug mode (1 or 0, default 0)
Create a file called "begin.rs" -- there are several reasons for doing so.
For one, you should use this file for !include
statements if you want your brain
to use some common libraries or packages. Secondly, you can use the <BEGIN statement
to setup a handler for incoming messages.
Your begin file could check the "active" variable we set in the config file to decide if it should give a reply.
> begin + request * active=no => Sorry but I'm deactivated right now! - {ok} < begin
These are the basic tips, just for organizational purposes.
the RiveScript::Parser manpage - Reading and Writing of RiveScript Documents.
the RiveScript::Brain manpage - The reply and search methods of RiveScript.
the RiveScript::Util manpage - String utilities for RiveScript.
Version 1.03 - Fixed a few bugs: - Fixed a bug in which, if you sent in two sentences at once, the module would return only the answer to the first sentence--twice. - Removed attribute "scalar" to reply(). It now uses wantarray to figure out whether it should return an array or a scalar. - The "Defined" condition ? can now check bot variables too.
Version 1.02 - Fixed several bugs: - Makefile.PL was unnecessarily requiring a high version of Perl; not it doesn't. - A typo fixed in Tutorial.pod causing compile errors - MANIFEST file fixed to reflect the new demo brain - Some warnings in Parser.pm were attempted to be fixed
Version 1.00 - Public stable beta release.
Version 0.21 - Added \u tag for inserting an "undefined" character (i.e. set global macro_failure to \u to remove macro failure notifications altogether from the responses) - The code to run objects is now run last in RiveScript::Util::tagFilter, so that other tags such as {random}, <get>, etc. are all run before the object is executed. - Two new standard libraries have been added: - Colors.rsl - Arrays for color names - Numbers.rsl - Arrays for number names
Version 0.20 - Added shortcut tags: <person>, <@>, <formal>, <sentence>, <uppercase>, <lowercase>, for running the respective tags on <star> (i.e. <person> ==> {person}<star>{/person}) - Added environment variable ENV_REPLY_COUNT which holds the number of loaded triggers. - Bugfix: sending scalar=>0 to reply() was returning the scalar of the array of replies, not the array itself. This has been fixed.
Version 0.19 - Added methods for allowing or denying certain commands to be used when RiveScript documents are loaded in. - Bugfix: the sortThats() method of RiveScript::Parser was blanking out the current value of $self->{thatarray} -- meaning, the last file to have %Previous commands used would be kept in memory, previous ones would be lost. This has been fixed now.
Version 0.18 - Minor bugfix with the "%PREVIOUS" internal array.
Version 0.17 - All the "%PREVIOUS" commands found at loading time are now sorted in an internal arrayref, in the same manner that "+TRIGGERS" are. This solves the bug with matchability when using several %PREVIOUS commands in your replies. - Added the # command as a "Perly" alternative to // comments. - Comments can be used in-line next to normal RiveScript code, requiring that at least one space exist before and after the comment symbols. You can escape the symbols too if you need them in the reply. - Created a new package DateTime.rsp for your timestamp-formatting needs.
Version 0.16 - Added "! syslib" directive for including Perl modules at the RiveScript:: level, to save on memory usage when more than one object might want the same module. - The "%PREVIOUS" directive now takes a regexp. The bot's last reply is saved as-is, not formatted to lowercase. The % command now works like a +Trigger for the bot's last reply. - The "%PREVIOUS" directive check has been moved to another subroutine. In this way, its priority is much higher. A trigger of * (catch-all) with a %PREVIOUS will always match, for example. - Fixed a bug with the BEGIN method. The bot's reply is no longer saved while the topic is __begin__ - this messed up the %THAT directive.
Version 0.15 - Broke RiveScript into multiple sub-modules.
Version 0.14 - {formal} and {sentence} tags fixed. They both use regexp's now. {sentence} can take multiple sentences with no problem. - In a BEGIN statement, {topic} tags are handled first. In this way, the BEGIN statement can force a topic before getting a reply under the user's current topic. - Fixed a bug with "blank" commands while reading in a file. - Fixed a bug with the RiveScriptLib Search Paths.
Version 0.13 - The BEGIN/request statement has been changed. The user that makes the "request" is the actual user--no longer "__rivescript__", so user-based conditionals can work too. Also, request tags are not processed until the reply-getting process is completed. So tags like {uppercase} can modify the final returned reply.
Version 0.12 - Migrated to RiveScript:: namespace.
Version 0.11 - When calling loadDirectory, a "begin.rs" file is always loaded first (provided the file exists, of course!) - Added support for "include"ing libraries and packages (see "INCLUDED FILES")
Version 0.10 - The getUservars() method now returns a hashref of hashrefs if you want the vars of all users. Makes it a little easier to label each set of variables with the particular user involved. ;) - Cleaned up some leftover print statements from my debugging in version 0.09 (sorry about that--again!) - Made some revisions to the POD, fixed some typo's, added {weight} and {ok} to the TAGS section.
Version 0.09 - $1 to $100+ are now done using an array rather than a hash. Theoretically this allows any number of stars, even greater than 100. - Arrays in triggers have been modified. An array in parenthesis (the former requirement) will make the array matchable in <star#> tags. An array outside of parenthesis makes it NOT matchable. - Minor code improvements for readibility purposes.
Version 0.08 - Added <add>, <sub>, <mult>, and <div> tags. - Added environmental variable support. - Extended *CONDITION to support inequalities - Botvars in conditions must be explicitely specified with # before the varname. - Added "! person" substitutions - Added {person} tag
Version 0.07 - Added write() method - reply() method now can take tags to force scalar return or to ignore sentence-splitting. - loadDirectory() method can now take a list of specific file extensions to look for. - Cleaned up some leftover debug prints from last release (sorry about that!)
Version 0.06 - Extended ^CONTINUE to cover more commands - Added \s and \n tags - Revised POD
Version 0.05 - Fixed a bug with optionals. If they were used at the start or end of a trigger, the trigger became unmatchable. This has been fixed by changing ' ' into '\s*'
Version 0.04 - Added support for optional parts of the trigger. - Begun support for inline objects to be created.
Version 0.03 - Added search() method. - <bot> variables can be inserted into triggers now (for example having the bot reply to its name no matter what its name is)
Version 0.02 - Fixed a regexp bug; now it stops searching when it finds a match (it would cause errors with $1 to $100) - Fixed an inconsistency that didn't allow uservars to work in conditionals. - Added <id> tag, useful for objects that need a unique user to work with. - Fixed bug that lets comments begin with more than one set of //
Version 0.01 - Initial Release
Special thanks goes out to jeffohrt and harleypig of the AiChaos Forum for helping so much with RiveScript's development.
bot, chatbot, chatterbot, chatter bot, reply, replies, script, aiml, alpha
Casey Kirsle, casey at cuvou.net
RiveScript - Rendering Intelligence Very Easily Copyright (C) 2007 Casey Kirsle
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA