summaryrefslogtreecommitdiff
path: root/bin
diff options
context:
space:
mode:
authorgregor herrmann <gregoa@debian.org>2011-09-24 21:04:07 +0200
committergregor herrmann <gregoa@debian.org>2011-09-24 21:04:07 +0200
commitdbabd8a373b0e5dbc1977405046288fff6a50dfd (patch)
treefe03d1a79cfb413dc78884ec8d414e07f41ded58 /bin
parent6f4db1999c2225c9067411c262ba29e8a7ce38a5 (diff)
Imported Upstream version 1.22
Diffstat (limited to 'bin')
-rwxr-xr-xbin/rivescript363
-rwxr-xr-xbin/rsdemo161
2 files changed, 363 insertions, 161 deletions
diff --git a/bin/rivescript b/bin/rivescript
new file mode 100755
index 0000000..ab7560e
--- /dev/null
+++ b/bin/rivescript
@@ -0,0 +1,363 @@
+#!/usr/bin/perl
+
+# A front-end to RiveScript.
+# See `rivescript --help` for help.
+
+use strict;
+use warnings;
+use RiveScript;
+use JSON;
+use Getopt::Long;
+use Pod::Text;
+
+#------------------------------------------------------------------------------#
+# Command Line Arguments #
+#------------------------------------------------------------------------------#
+
+my $opt = {
+ debug => 0, # --debug, enables debug mode
+ verbose => 1, # Private, verbose mode for RS
+ log => "", # --log, debug logs to file instead of terminal
+ json => 0, # --json, running in batch mode
+ depth => 50, # depth variable
+ strict => 1, # --strict, strict mode
+ help => 0, # --help
+};
+GetOptions (
+ 'debug|d' => \$opt->{debug},
+ 'log=s' => \$opt->{log},
+ 'help|h|?' => \$opt->{help},
+ 'json|j' => \$opt->{json},
+ 'depth=i' => \$opt->{depth},
+ 'strict!' => \$opt->{strict},
+);
+
+# Asking for help?
+if ($opt->{help}) {
+ # Give them our POD instructions.
+ my $pod = Pod::Text->new (sentence => 0, width => 78);
+ $pod->parse_from_filehandle(*DATA);
+ exit(0);
+}
+
+# Debug mode options.
+if ($opt->{log}) {
+ # Logging automatically enables debugging.
+ $opt->{debug} = 1;
+ $opt->{verbose} = 0;
+}
+
+#------------------------------------------------------------------------------#
+# Main Program Begins Here #
+#------------------------------------------------------------------------------#
+
+# A brain has been specified?
+my $root = scalar(@ARGV) ? $ARGV[0] : $RiveScript::basedir . "/demo";
+
+# Create the RiveScript interpreter.
+my $rs = init();
+my $json; # JSON interpreter if we need it.
+
+# Interactive mode?
+if (!$opt->{json}) {
+ # If called with no arguments, hint about the --help option.
+ unless (scalar(@ARGV)) {
+ print "Hint: use `rivescript --help` for documentation on this command.\n\n";
+ }
+
+ print "RiveScript Interpreter - Interactive Mode\n"
+ . "-----------------------------------------\n"
+ . "RiveScript Version: $RiveScript::VERSION\n"
+ . " Reply Root: $root\n\n"
+ . "You are now chatting with the RiveScript bot. Type a message and press Return to send it.\n"
+ . "When finished, type '/quit' to exit the program. Type '/help' for other options.\n\n";
+
+ while (1) {
+ print "You> ";
+ chomp(my $input = <STDIN>);
+
+ # Commands.
+ if ($input =~ /^\/help/i) {
+ print "> Supported Commands:\n"
+ . "> /help - Displays this message.\n"
+ . "> /reload - Reload the RiveScript brain.\n"
+ . "> /quit - Exit the program.\n";
+ }
+ elsif ($input =~ /^\/reload/i) {
+ # Reload the brain.
+ undef $rs;
+ $rs = init();
+ print "> RiveScript has been reloaded.\n\n";
+ }
+ elsif ($input =~ /^\/(?:quit|exit)/i) {
+ # Quit.
+ exit(0);
+ }
+ else {
+ # Get a response.
+ my $reply = $rs->reply("localuser", $input);
+ print "Bot> $reply\n";
+ }
+ }
+}
+else {
+ # JSON mode.
+ $json = JSON->new->pretty();
+
+ # Read from standard input.
+ my $buffer = "";
+ my $stateful = 0;
+ while (my $line = <STDIN>) {
+ chomp($line);
+ $line =~ s/[\x0D\x0A]+//g;
+
+ # Look for the __END__ line.
+ if ($line =~ /^__END__$/i) {
+ # Process it.
+ $stateful = 1; # This is a stateful session.
+ json_in($buffer, 1);
+ $buffer = "";
+ next;
+ }
+
+ $buffer .= "$line\n";
+ }
+
+ # We got the EOF. If the session was stateful, just exit, otherwise
+ # process what we just read.
+ if ($stateful) {
+ exit(0);
+ }
+
+ json_in($buffer);
+ exit(0);
+}
+
+sub init {
+ my $rs = RiveScript->new (
+ debug => $opt->{debug},
+ verbose => $opt->{verbose},
+ debugfile => $opt->{log},
+ depth => $opt->{depth},
+ strict => $opt->{strict},
+ );
+
+ $rs->loadDirectory($root);
+ $rs->sortReplies();
+ return $rs;
+}
+
+sub json_in {
+ my $buffer = shift;
+ my $end = shift;
+
+ my $data = {};
+ my $reply = {
+ status => "ok",
+ };
+
+ # Try to decode their input.
+ eval {
+ $data = $json->decode($buffer);
+ };
+
+ # Error?
+ if ($@) {
+ $reply->{status} = "error";
+ $reply->{reply} = "Failed to decode your input: $@";
+ }
+ else {
+ # Decode their variables.
+ my $username = exists $data->{username} ? $data->{username} : "localuser";
+ if (ref($data->{vars}) eq "HASH") {
+ foreach my $key (keys %{$data->{vars}}) {
+ next if ref($data->{vars}->{$key});
+ $rs->setUservar($username, $key, $data->{vars}->{$key});
+ }
+ }
+
+ # Get their answer.
+ $reply->{reply} = $rs->reply($username, $data->{message});
+
+ # Retrieve vars.
+ $reply->{vars} = {};
+ my $vars = $rs->getUservars($username);
+ foreach my $key (keys %{$vars}) {
+ next if ref($vars->{$key});
+ $reply->{vars}->{$key} = $vars->{$key};
+ }
+ }
+
+ # Encode and print.
+ print $json->encode($reply);
+ print "__END__\n" if $end;
+}
+
+__DATA__
+
+=head1 NAME
+
+rivescript - A command line frontend to the Perl RiveScript interpreter.
+
+=head1 SYNOPSIS
+
+ $ rivescript [options] [path to RiveScript documents]
+
+=head1 DESCRIPTION
+
+This is a command line front-end to the RiveScript interpreter. This script
+obsoletes the old C<rsdemo>, and can also be used non-interactively by third
+party programs. To that end, it supports a variety of input/output and session
+handling methods.
+
+If no RiveScript document path is given, it will default to the example brain
+that ships with the RiveScript module, which is based on the Eliza bot.
+
+=head1 OPTIONS
+
+=over 4
+
+=item --debug, -d
+
+Enables debug mode. This will print all debug data from RiveScript to your
+terminal. If you'd like it to log to a file instead, use the C<--log> option
+instead of C<--debug>.
+
+=item --log FILE
+
+Enables debug mode and prints the debug output to C<FILE> instead of to your
+terminal.
+
+=item --json, -j
+
+Runs C<rivescript> in JSON mode, for running the script in a non-interactive
+way (for example, to use RiveScript in a programming language that doesn't have
+a native RiveScript library). See L<"JSON Mode"> for details.
+
+=item --strict, --nostrict
+
+Enables strict mode for the RiveScript parser. It's enabled by default, use
+C<--nostrict> to disable it. Strict mode prevents the parser from continuing
+when it finds a syntax error in the RiveScript documents.
+
+=item --depth=50
+
+Override the default recursion depth limit. This controls how many times
+RiveScript will recursively follow redirects to other replies. The default is
+C<50>.
+
+=item --help
+
+Displays this documentation in your terminal.
+
+=back
+
+=head1 USAGE
+
+=head2 Interactive Mode
+
+This is the default mode used when you run C<rivescript> without specifying
+another mode. This mode behaves similarly to the old C<rsdemo> script and lets
+you chat one-on-one with your RiveScript bot.
+
+This mode can be used to test your RiveScript bot. Example:
+
+ $ rivescript /path/to/rs/files
+
+=head2 JSON Mode
+
+This mode should be used when calling from a third party program. In this mode,
+data that enters and leaves the script are encoded in JSON.
+
+Example:
+
+ $ rivescript --json /path/to/rs/files
+
+The format for incoming JSON data is as follows:
+
+ {
+ "username": "localuser",
+ "message": "Hello bot!",
+ "vars": {
+ "name": "Aiden"
+ }
+ }
+
+Here, C<username> is a unique name for the user, C<message> is their message to
+the bot, and C<vars> is a hash of any user variables your program might be
+keeping track of (such as the user's name and age).
+
+The response from C<rivescript> will look like the following:
+
+ {
+ "status": "ok",
+ "reply": "Hello, human!",
+ "vars": {
+ "name": "Aiden"
+ }
+ }
+
+Here, C<status> will be C<"ok"> or C<"error">, C<reply> is the bot's response to
+your message, and C<vars> is a hash of the current variables for the user (so
+that your program can save them somewhere).
+
+=head3 End of Message
+
+There are two ways you can use the JSON mode: "fire and forget," or keep a
+stateful session open.
+
+In "fire and forget," you open the program, print your JSON input and send the
+EOF signal, and then C<rivescript> sends you the JSON response and exits.
+
+In a stateful session mode, you must send the text C<__END__> on a line by
+itself after you finish sending your JSON data. Then C<rivescript> will
+process it, return its JSON response and then also say C<__END__> at the end.
+
+Example:
+
+ {
+ "username": "localuser",
+ "message": "Hello bot!",
+ "vars": {}
+ }
+ __END__
+
+And the response:
+
+ {
+ "status": "ok",
+ "reply": "Hello, human!",
+ "vars": {}
+ }
+ __END__
+
+This way you can reuse the same pipe to send and receive multiple messages.
+
+=head1 SEE ALSO
+
+L<RiveScript>, the Perl RiveScript interpreter.
+
+=head1 AUTHOR
+
+Noah Petherbridge, http://www.kirsle.net
+
+=head1 LICENSE
+
+ RiveScript - Rendering Intelligence Very Easily
+ Copyright (C) 2011 Noah Petherbridge
+
+ 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
+
+=cut
diff --git a/bin/rsdemo b/bin/rsdemo
deleted file mode 100755
index ad4a25e..0000000
--- a/bin/rsdemo
+++ /dev/null
@@ -1,161 +0,0 @@
-#!/usr/bin/perl -w
-
-use strict;
-use warnings;
-use lib "./lib";
-use RiveScript;
-
-print "Welcome to the Perl RiveScript Interpreter. This script is a demonstration\n"
- . "of RiveScript. The bot's replies are taken from the files in the\n"
- . "'RiveScript/demo' directory, which by default are based on some of Eliza's\n"
- . "triggers and responses. To load a different set of replies, provide\n"
- . "a path to a directory on the command line, e.g. rsdemo /opt/rs/brain\n\n";
-
-# Get a directory name from the command line.
-my $brain = undef;
-my @opts = ();
-my $help = 0;
-if (@ARGV) {
- foreach my $v (@ARGV) {
- if ($v =~ /^\-*?debug$/i) {
- push (@opts, 'debug', 1);
- next;
- }
- elsif ($v =~ /^\-*?(?:debug|)(?:f|file)=(.+?)$/i) {
- push (@opts, 'debugfile', $1);
- next;
- }
- elsif ($v =~ /^\-*?(?:v|verbose)=(.+?)$/i) {
- push (@opts, 'verbose', $1);
- next;
- }
- elsif ($v =~ /^\-*?(nostrict)$/i) {
- push (@opts, 'strict', 0);
- next;
- }
- elsif ($v =~ /^\-*?(h|help|\?)$/i) {
- $help = 1;
- next;
- }
- else {
- if (-d $v) {
- $brain = $v;
- }
- else {
- warn "Can't load brain from $v: not a directory\n";
- }
- }
- }
-}
-
-if ($help) {
- print "Usage: rsdemo [--debug] [directory]\n";
- exit(0);
-}
-
-my $rs = new RiveScript(@opts);
-
-# Read the test directory.
-my $replies = (defined $brain ? $brain : ($RiveScript::basedir . "/demo"));
-print "Loading RiveScript brain from directory:\n$replies\n\n";
-$rs->loadDirectory ($replies);
-$rs->sortReplies();
-
-print "You\'re now chatting with the RiveScript bot. Why not say hello? When\n"
- . "you get tired of this, type \"quit\" to exit this demonstration.\n\n";
-
-while (1) {
- print "You> ";
- chomp (my $msg = <STDIN>);
-
- if ($msg =~ /^quit/i) {
- exit(0);
- }
-
- my $reply = $rs->reply ('localuser',$msg);
-
- print "Bot> $reply\n";
-}
-
-=head1 NAME
-
-rsdemo - Command-line demonstration and development tool for RiveScript.
-
-=head1 SYNOPSIS
-
- Usage: rsdemo
- rsdemo --debug
- rsdemo /path/to/replies
- rsdemo --debug /path/to/replies
-
-=head1 DESCRIPTION
-
-B<rsdemo> is a program for testing and developing RiveScript code via the
-command line. Run with no arguments, rsdemo loads the default set of RiveScript
-replies that are installed in your Perl lib. The default set is based on the
-classic Eliza bot's personality, with additional triggers for learning and
-repeating user information.
-
-If you have a different directory containing RiveScript documents, pass the
-path to that directory on the command line, and C<rsdemo> will load replies
-from there instead.
-
-=head1 OPTIONS
-
-=over 4
-
-=item --debug
-
-This will enable RiveScript debug mode. A B<lot> of information is printed to
-the terminal when debug mode is active.
-
-=item --debugfile=?, --file=?, -f=?
-
-Specify an external file for debug lines to be printed to. Since a lot of debug
-information gets printed, you might want to use this in conjunction with
-C<--verbose=0>.
-
-=item --verbose=?, -v=?
-
-Enable or disable verbose (debug) mode. This option only has an effect if debug
-mode is on. If verbose is C<1> (the default), all debug information is printed
-to the terminal. Set verbose to C<0> and this information will NOT go to the
-terminal.
-
-If C<debugfile> is provided, all debug information will (also) be printed to the
-debug file.
-
-=item --nostrict
-
-Turn off strict mode when parsing the RiveScript documents. When strict mode
-is enabled (default), a syntax error in the RiveScript code is a fatal error.
-When turned off, it results in a warning, and the rest of the file that caused
-the error is skipped.
-
-=item --help
-
-Prints the usage of the command.
-
-=back
-
-=head1 DEBUGGING
-
-The C<rsdemo> tool can be used for debugging a custom set of RiveScript replies.
-If you pass the C<--debug> option, debug mode is activated. By default, all
-debug information will be printed to the terminal, which is likely going to be
-more lines than your scrollback buffer can display. Unless you have a very small
-amount of replies you're debugging, it'll be more practical to pipe the debug
-information into a file and not display it on the terminal.
-
-Here's an example:
-
- rsdemo --debug --verbose=0 --file=debug.txt /path/to/replies
-
-Or a shortened example:
-
- rsdemo --debug -v=0 -f=debug.txt /path/to/replies
-
-In this case, the terminal would act as normal and allow you to chat with the
-bot, and all debug information would be written to debug.txt.
-
-=cut