The London Perl and Raku Workshop takes place on 26th Oct 2024. If your company depends on Perl, please consider sponsoring and/or attending.

NAME

RiveScript - Rendering Intelligence Very Easily

SYNOPSIS

  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";

DESCRIPTION

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.

PERL PACKAGE

This part of the manpage documents the methods of the Perl RiveScript library. The RiveScript language specifications are below: see "RIVESCRIPT".

Public Methods

new

Creates a new RiveScript instance.

setSubroutine (OBJECT_NAME => CODEREF)

Define an object macro (see "Object Macros")

loadDirectory ($DIRECTORY[, @EXTS])

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"

loadFile ($FILEPATH[, $STREAM])

Load a single RiveScript file. Don't worry about the $STREAM argument, it is handled in the stream() method.

stream ($CODE)

Stream RiveScript codes directly into the module.

sortReplies

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.

reply ($USER_ID, $MESSAGE[, %TAGS])

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 ($STRING)

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.

write ([$FILEPATH])

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".

setGlobal (VARIABLE => VALUE, ...)

Set a global RiveScript variable directly from Perl (alias for ! global)

setVariable (VARIABLE => VALUE, ...)

Set a botvariable (alias for ! var)

setSubstitution (BEFORE => AFTER, ...)

Set a substitution setting (alias for ! sub)

setUservar ($USER_ID, VARIABLE => VALUE, ...)

Set a user variable (alias for <set var=value> for $USER_ID)

getUservars ([$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.

Security Methods

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).

denyMode ($MODE)

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.

deny (@COMMANDS)

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.

allow (@COMMANDS)

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.

Private Methods

These methods are called on internally and should not be called by you.

debug ($MESSAGE)

Print a debug message (when debug mode is active).

makeParser

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.

intReply ($USER_ID, $MESSAGE)

This is the internal reply-getting routine. Call reply() instead. This assumes that the data is all correctly formatted before being processed.

splitSentences ($STRING)

Splits $STRING at the sentence-splitters and returns an array.

formatMessage ($STRING)

Formats $STRING by running substitutions and removing punctuation and symbols.

mergeWildcards ($STRING, @STARS)

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>.

stringUtil ($TYPE, $STRING)

Formats $STRING by $TYPE (uppercase, lowercase, formal, sentence).

tagFilter ($REPLY, $ID, $MESSAGE)

Run tag filters on $REPLY. Returns the new $REPLY.

tagShortcuts ($REPLY)

Runs shortcut tags on $REPLY. Returns the new $REPLY.

RIVESCRIPT

The following is the RiveScript 1.00 specification.

RiveScript Format

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.

RiveScript Commands

! (Definition)

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".

< and > (Label)

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
+ (Trigger)

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!)

% (Previous)

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)

- (Response)

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 -Responses are used, they become random replies. For more information, see "Complexities of the Response".

^ (Continue)

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").

@ (Redirect)

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>
* (Condition)

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!
& (Perl)

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 evals the expression.

  + what is 2 plus 2
  - 500 Internal Error (the eval failed for some reason!)
  & $reply = '2 + 2 = 4';
// or # (Comments)

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.

RiveScript Holds The Keys

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.

Complexities of the Trigger

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.

Wildcards:

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>.
Alternations:

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.

Optionals:

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
Arrays:

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'

Complexities of the Response

The -Response command has many uses depending on its context:

One-way question/answer:

A single + and a single - will lead to a one-way question/answer scenario.

Random Replies:

A single + with multiple -'s will yield random results from the responses.

  + hello
  - Hey.
  - Hi.
  - Hello.
Fallbacks:

When using conditionals and Perl codes, you should have at least one -Response to fall back on in case everything returns false.

Weighted Responses:

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".

Begin Statement

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

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.

Object Macros

Special macros (Perl routines) can be defined and then utilized in your RiveScript code.

Inline Objects

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
Define an Object from Perl

This is done like so:

  # Define a weather lookup macro.
  $rivescript->setSubroutine (weather => \&weather_lookup);
Call an Object

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.

Tags

Special tags can be inserted into RiveScript replies. The tags are as follows:

<star>, <star1> - <star100>+

These tags will insert the values of $1 to $100+, as matched in the trigger regexp. <star> is an alias for <star1>.

<input1> - <input9>, <reply1> - <reply9>

Inserts the last 1 to 9 things the user said, and the last 1 to 9 things the bot replied with, respectively.

<id>

Inserts the user's ID.

<bot>

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>, <set>

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>, <sub>, <mult>, <div>

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.

{topic=...}

This will change the user's topic. See "Topics".

{nextreply}

Breaks the reply into two parts here. This will cause reply() to return multiple responses for each side of the {nextreply} tag.

{weight=...}

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.

{random}...{/random}

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}.
{person}...{/person}, <person>

Will take the enclosed text and run person substitutions on them. See "Person Substitution".

<person> is an alias for {person}<star>{/person}

{formal}...{/formal}, <formal>

Will Make Your Text Formal.

<formal> is an alias for {formal}<star>{/formal}

{sentence}...{/sentence}, <sentence>

Will make your text sentence-cased.

<sentence> is an alias for {sentence}<star>{/sentence}

{uppercase}...{/uppercase}, <uppercase>

WILL MAKE THE TEXT UPPERCASE.

<uppercase> is an alias for {uppercase}<star>{/uppercase}

{lowercase}...{/lowercase}, <lowercase>

will make the text lowercase.

<lowercase> is an alias for {lowercase}<star>{/lowercase}

{ok}

This is used only with the "Begin Statement". It tells the interpreter that it's okay to get a reply.

\s

Inserts a white space.

\n

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

Environment variables are kept as "botvariables" and can be retrieved with the <bot> tags. The variable names are all uppercase and begin with "ENV_"

RiveScript Environment Variables
  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.
Perl Environment Variables

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.

Setting Environment Variables

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.

Person Substitution

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.

Dynamic Replies

Here is an overview of the internal hashref structure of the RiveScript object, for modifying replies directly.

$rs->{replies}

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.

Trigger Sub-Keys

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.

Examples
  // 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}

Included Files

Recommended practice is to place all your !include statements inside your begin.rs file, as this file is always loaded in first.

RiveScript Libraries

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

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.

RiveScript Include Search Path

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.

Reserved Variables

The following are all the reserved variables within RiveScript which cannot be (re)set by your reply files.

Reserved Global Variables

These variables can't be overwritten with the !global command:

  reserved replies array syntax streamcache botvars uservars
  botarrays sort users substitutions
Reserved Topic Names

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)

A Good Brain

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:

Make a config file.

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)
Make a begin file.

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.

SEE OTHER

RiveScript::Parser - Reading and Writing of RiveScript Documents.

RiveScript::Brain - The reply and search methods of RiveScript.

RiveScript::Util - String utilities for RiveScript.

CHANGES

  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

Special thanks goes out to jeffohrt and harleypig of the AiChaos Forum for helping so much with RiveScript's development.

KEYWORDS

bot, chatbot, chatterbot, chatter bot, reply, replies, script, aiml, alpha

AUTHOR

  Casey Kirsle, casey at cuvou.net

COPYRIGHT AND LICENSE

    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