NAME
Chatbot::RiveScript - Rendering Intelligence Very Easily
SYNOPSIS
use Chatbot::RiveScript;
# Create a new RiveScript interpreter.
my $rs = new Chatbot::RiveScript;
# Define a macro.
$rs->setSubroutine (weather => \&weather);
# Load in some RiveScript documents.
$rs->loadDirectory ("./replies");
# Load in another file.
$rs->loadFile ("./more_replies.rs");
# Stream in yet more replies.
$rs->stream ('! global split_sentences = 1');
# Sort them.
$rs->sortReplies;
# Grab a response.
my @reply = $rs->reply ('localhost','Hello RiveScript!');
# print $reply[0] . "\n";
DESCRIPTION
RiveScript was formerly known as Chatbot::Alpha. However, Chatbot::Alpha's syntax is not compatible with RiveScript.
RiveScript is a simple input/response language. It is simple, easy to learn, and mimics and perhaps even surpasses the power of AIML (Artificial Intelligence Markup Language).
PUBLIC METHODS
new
Creates a new Chatbot::RiveScript instance. Pass in any defaults here.
setSubroutine (OBJECT_NAME => CODEREF)
Define a macro (see Object Macros)
loadDirectory (DIRECTORY)
Load a directory of RiveScript (.rs) files.
loadFile (FILEPATH[, STREAM])
Load a single file. Don't worry about the STREAM argument, it is handled in the stream() method.
stream (CODE)
Stream RiveScript code directly into the module.
sortReplies
Sorts the replies. This is ideal for matching purposes. If you fail to do so and just go ahead and call reply(), you'll get a nasty Perl warning. It will sort them for you anyway, but it's always recommended to sort them yourself. For example, if you sort them and then load new replies, the new replies will not be matchable because the sort cache hasn't updated.
reply (USER_ID, MESSAGE)
Get a reply from the bot. This will return an array. The values of this array would be all the replies (i.e. if you use {nextreply} in a response to return multiple).
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 the reference to its file and line number.
setGlobal (VARIABLE => VALUE, ...)
Set a global 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>)
getUservars (USER_ID)
Get all variables for a user, returns a hash reference. (alias for <get var> for every variable). If you don't provide a USER_ID, or provide '__rivescript__' (see Reserved Variables), it will return an array reference of hash references, to get variables of all users.
PRIVATE METHODS
These methods are called on internally and should not be called by you.
debug (MESSAGE)
# print a debug message.
intReply (USER_ID, MESSAGE)
This should not be called. Call reply instead. This method assumes that the variables are neatly formatted and may cause serious consequences for passing in badly formatted data.
splitSentences (STRING)
Splits string at the sentence-splitters and returns an array.
formatMessage (STRING)
Formats the message (runs substitutions, removes punctuation, etc)
mergeWildcards (STRING, HASH)
Merges the hash from HASH into STRING, where the keys in HASH should be from 1 to 100, for the wildcard captor.
stringUtil (TYPE, STRING)
Called on for string format tags (uppercase, lowercase, formal, sentence).
FORMAT
RiveScript documents have a simple format: they're a line-by-line language. The first symbol(s) are the commands, and the following text is typically the command's data.
In its most simple form, a valid RiveScript entry looks like this:
+ hello bot
- Hello human.
RIVESCRIPT COMMANDS
The following are the commands that RiveScript supports.
- ! (Definition)
-
The ! command is for definitions. These are one of the few stand-alone commands (ones that needn't be part of a bigger reply group). They are to define variables and arrays. Their format is as follows:
! type variable = value type = the variable type variable = the name of the variable value = the variable's value
The supported types are as follows:
global - Global settings (top-level things) var - BotVariables (i.e. the bot's name, age, etc) array - An array sub - A substitution pattern
- (LT) and (GT) (Label)
-
The < and > commands are for defining labels. A label is used to treat a part of code differently. Currently there are two uses for labels: begin and topic. Example usage:
// Define a topic > topic some_topic_name // there'd be some triggers here < topic // close the topic
- + (Trigger)
-
The + command is the basis for all triggers. 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" only to get a "Hello human." back.
- % (Previous)
-
The % command is for drawing a user back to complete a thought. You might say it's sort of like <that> in AIML. Example:
+ ask me a question - Do you have any pets? + yes % do you have any pets - What kind of pet? // and so-on...
- - (Response)
-
The - command is the response. The - command has several uses, depending on its context. For example, in the "hello bot/hello human" example, one + with one - gets a one-way question/answer scenario. If more than one - is used, a random one is chosen (and some may be weighted). There are many other uses that we'll get into later.
- ^ (Continue)
-
Sometimes your -REPLY is too long to fit on one line, and you don't like the idea of having a horizontal scrollbar. The ^ command will continue on from the last -REPLY. For example:
+ tell me a poem - Little Miss Muffit sat on her tuffet ^ in a nonchalant sort of way. ^ With her forcefield around her, ^ the Spider, the bounder, ^ is not in the picture today.
- @ (Redirect)
-
The @ command is for directing one trigger to another. For example, there may be complicated ways people have of asking the same thing, and you don't feel like making your main trigger handle all of them.
+ my name is * - Nice to meet you, {formal}<star1>{/formal}. + people around here call me * @ my name is <star1>
Redirections can also be used inline. See the "TAGS" section for more details.
- * (Conditions)
-
The * command is used for checking conditionals. The format is:
* variable=value => say this
For example, you might want to make a condition to differentiate male from female users.
+ am i a guy or a girl * gender=male => You're a guy. * gender=female => You're a girl. - I don't think you ever told me what you are.
- & (Perl)
-
Sometimes RiveScript isn't powerful enough to do what you want. The & command will execute Perl codes to handle these cases. Be sure to read through this whole manpage before resorting to Perl, though. RiveScript has come a long way since it was known as Chatbot::Alpha.
+ what is 2 plus 2 - 500 Internal Error. # $reply = '2 + 2 = 4';
- // (Comments)
-
The comment syntax is //, as it is in other programming languages. Also, /* */ comments may be used to span over multiple lines.
// A one-line comment /* this comment spans across multiple lines */
RIVESCRIPT HOLDS THE KEYS
The RiveScript engine was designed for your RiveScript brain to hold most of the control. As little programming 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 + command can be used for more complex things as a simple, 100% dead-on trigger. This part is passed through a regexp. Therefore, any regexp things can be used in the trigger.
Note: an asterisk * is always converted into (.*?) regardless of its context. Keep this in mind.
Alternations: You can use alternations in the triggers like so:
+ what (s|is) your (home|office|cell) phone number
Anything inside of parenthesis, or anything matched by asterisks, can be obtained through the tags <star1> to <star100>. For example (keeping in mind that * equals (.*?):
+ my name is *
- Nice to meet you, <star1>.
Arrays: This is why it's good to define arrays using the !define tag. The best way to explain how this works is by example.
// Make an array of color names
! array colors = red blue green yellow white black orange
// Now the user can tell us their favorite color from the array
+ my favorite color is (@colors)
- Really! Mine is <star1> too!
It turns your array into regexp form, (red|blue|green|yellow|...) before matching so it saves you a lot of work there. Not to mention arrays can be used in any number of triggers! Just imagine how many triggers you can come up with where a color name would be needed...
COMPLEXITIES OF THE RESPONSE
As mentioned above, the - command has many many uses.
One-way question/answer: A single + and a single - will lead to a dead-on question and answer reply.
Random Replies: A single + with multiple -'s will yield random results from among the responses. For example:
+ hello
- Hey.
- Hi.
- Hello.
Would randomly return any of those three responses.
Conditional Fallback: When using conditionals, you should always provide at least one response to fall back on, in case every conditional returns false.
Perl Code Fallback: When executing Perl code, you should always have a response to fall back on [even if the Perl is going to redefine $reply for itself]. This is in case of an eval error and the Perl couldn't do its thing.
Weighted Responses: Yes, with random responses you can weight them! Responses with higher weight will have a better chance of being chosen over ones with a low weight. For example:
+ hello
- Hello, how are you?{weight=49}
- Yo, wazzup dawg?{weight=1}
In this case, "Hello, how are you?" will almost always be sent back. A 1 in 50 chance would return "Yo, wazzup dawg?" instead.
(as a side note: you don't need to set a weight to 1; 1 is implied for any response without weight. Weights of less than 1 aren't acceptable)
BEGIN STATEMENT
Note: BEGIN statements are not required. That being said, begin statements are executed before any request.
How to define a BEGIN statement
> begin
+ request
- {ok}
< begin
Begin statements are sort of like topics. They are called first. If the response given contains {ok} in it, then the module knows it's allowed to get a reply. Also note that {ok} is replaced with the response. In this way, begin might be useful to format all responses in one way. For a good example:
> begin
// Don't give a reply if the bot is down for maintenance.
+ request
* down=yes => The bot is currently deactivated for maintenance.
- <font color="red"><b>{ok}</b></font>
< begin
That would give the reply about the bot being under maintenance if the variable "down" equals "yes." Else, it would give a response in red bold font.
Note: At the time being, the only trigger that BEGIN ever receives is "request"
TOPICS
Topics are declared in a way similar to the BEGIN statement. The way to declare and close a topic is generally as follows:
> topic TOPICNAME
...
< 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). Example:
+ i hate you
- You're not very nice. I'm going to make you apologize.{topic=apology}
> topic apology
+ *
- Not until you admit that you're sorry.
+ sorry
- Okay, 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.
Define a Macro: This must be done from the Perl side (oh, darn, RiveScript doesn't have full control). This is done like so:
# Define a weather lookup macro.
$rs->setSubroutine (weather => \&weather_lookup);
Use a Macro: You can use a macro within a reply such as this example:
+ give me the local weather for *
- Weather for &weather.cityname(<star1>):\n\n
^ Temperature: &weather.temp(<star1>)\n
^ Feels Like: &weather.feelslike(<star1>)
The subroutine "weather_lookup" will receive two variables: the method and the arguments. The method would be the bit following the dot (i.e. "cityname", "temp", or "feelslike" in this example). The arguments would be the value of <star1>.
Whatever weather_lookup would return is inserted into the reply in place of the macro call.
TAGS
Special tags can be inserted into replies and redirections. They are as follows:
<star>, <star1> - <star100>
These tags will insert the values of $1 to $100, as matched in the regexp, into the reply. They go in order from left to right. <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 said, respectively. Good for things like "You said hello and then I said hi and then you said what's up and then I said not much"
<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 companyname>.
This variable can also 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 each user.
+ my name is *
- <set name={formal}<star1>{/formal}>Nice to meet you, <get name>!
+ who am i
- You are <get name> aren't you?
{topic=...}
The topic tag. This will set the user's topic to something else (see TOPICS). Only one of these should be in a response, and in the case of duplicates only the first one is evaluated.
{nextreply}
Breaks the reply into two (or more) parts there. Will cause the reply method to return multiple responses.
{@...}
An inline redirection. These work like normal redirections, except are inserted inline into a reply.
+ * or something
- Or something. {@<star1>}
{!...}
An inline definition. These can be used to (re)set variables. This tag is invisible in the final response of the bot; the changes are made silently.
{random}...{/random}
Will insert a bit of random text. This has two syntaxes:
Insert a random word (separate by spaces)
{random}red blue green yellow{/random}
Insert a random phrase (separate by pipes)
{random}Yes sir.|No sir.{/random}
{formal}...{/formal}
Will Make Your Text Formal
{sentence}...{/sentence}
Will make your text sentence-cased.
{uppercase}...{/uppercase}
WILL MAKE THE TEXT UPPERCASE.
{lowercase}...{/lowercase}
will make the text lowercase.
RESERVED VARIABLES
The following are all the reserved variables and values within RiveScript's processor.
Reserved Global Variables
These variables cannot 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 reserved and should never be (re)created in your RiveScript files:
__begin__ (used for the BEGIN method)
__that__* (used for the %PREVIOUS command)
Reserved User_ID's
These are the reserved User ID's that you should not pass in to the reply method when getting a reply.
__rivescript__ (to query the BEGIN method)
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: ! . ? ;
debug - Debug mode (1 or 0, default 0)
Make a begin file. This file would handle your BEGIN code. Again, this isn't required but has its benefits. This file might be called "begin.rs" (or you could include it in config.rs if you're a micromanager).
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
You might want to take a look at Chatbot::Alpha, this module's predecessor.
KNOWN BUGS
I'm sure there are some, as this is a beta release, but none have come to show themselves yet.
CHANGES
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
AUTHOR
Cerone Kirsle, kirsle --at-- rainbowboi.com
COPYRIGHT AND LICENSE
Chatbot::RiveScript - Rendering Intelligence Very Easily
Copyright (C) 2005 Cerone J. 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