def interactive_mode(): """The built-in RiveScript Interactive Mode. This feature of RiveScript allows you to test and debug a chatbot in your terminal window. There are two ways to invoke this mode:: # By running the Python RiveScript module directly: python rivescript eg/brain # By running the shell.py in the source distribution: python shell.py eg/brain The only required command line parameter is a filesystem path to a directory containing RiveScript source files (with the ``*.rive`` file extension). Additionally, it accepts command line flags. Parameters: --utf8: Enable UTF-8 mode. --json: Use JSON to communicate with the bot instead of plain text. See the JSON Mode documentation below for advanced details. --debug: Enable verbose debug logging. --log (str): The path to a text file you want the debug logging to be written to. This is to be used in conjunction with ``--debug``, for the case where you don't want your terminal window to be flooded with debug messages. --depth (int): Override the recursion depth limit (default ``50``). --nostrict: Disable strict syntax checking when parsing the RiveScript files. By default a syntax error raises an exception and will terminate the interactive mode. --help: Show the documentation of command line flags. path (str): The path to a directory containing ``.rive`` files. **JSON Mode** By invoking the interactive mode with the ``--json`` (or ``-j``) flag, the interactive mode will communicate with you via JSON messages. This can be used as a "bridge" to enable the use of RiveScript from another programming language that doesn't have its own native RiveScript implementation. For example, a program could open a shell pipe to the RiveScript interactive mode and send/receive JSON payloads to communicate with the bot. In JSON mode, you send a message to the bot in the following format:: { "username": "******", "message": "str message", "vars": { "topic": "random", "name": "Alice" } } The ``username`` and ``message`` keys are required, and ``vars`` is a key/value object of all the variables about the user. After sending the JSON payload over standard input, you can either close the input file handle (send the EOF signal; or Ctrl-D in a terminal), or send the string ``__END__`` on a line of text by itself. This will cause the bot to parse your payload, get a reply for the message, and respond with a similar JSON payload:: { "status": "ok", "reply": "str response", "vars": { "topic": "random", "name": "Alice" } } The ``vars`` structure in the response contains all of the key/value pairs the bot knows about the username you passed in. This will also contain a lot of internal data, such as the user's history and last matched trigger. To keep a stateful session, you should parse the ``vars`` returned by RiveScript and pass them in with your next request so that the bot can remember them for the next reply. If you closed the filehandle (Ctrl-D, EOF) after your input payload, the interactive mode will exit after giving the response. If, on the other hand, you sent the string ``__END__`` on a line by itself after your payload, the RiveScript interactive mode will do the same after its response is returned. This way, you can re-use the shell pipe to send and receive many messages over a single session. """ parser = argparse.ArgumentParser(description="RiveScript interactive mode.") parser.add_argument("--debug", "-d", help="Enable debug logging within RiveScript.", action="store_true", ) parser.add_argument("--json", "-j", help="Enable JSON mode. In this mode, you communicate with the bot by " "sending a JSON-encoded object with keys 'username', 'message' and " "'vars' (an object of user variables) over standard input, and " "then close the input (^D) or send the string '__END__' on a line " "by itself. The bot will respond with a similarly formatted JSON " "response over standard output, and then will either exit or send " "'__END__' depending on how you ended your input.", action="store_true", ) parser.add_argument("--utf8", "-u", help="Enable UTF-8 mode (default is disabled)", action="store_true", ) parser.add_argument("--log", help="The path to a log file to send debugging output to (when debug " "mode is enabled) instead of standard output.", type=text_type, ) parser.add_argument("--nostrict", help="Disable strict mode (where syntax errors are fatal)", action="store_true", ) parser.add_argument("--depth", help="Override the default recursion depth limit when fetching a reply " "(default 50)", type=int, default=50, ) parser.add_argument("path", help="A directory containing RiveScript files (*.rive) to load.", type=text_type, # required=True, ) args = parser.parse_args() # Make the bot. bot = RiveScript( debug=args.debug, strict=not args.nostrict, depth=args.depth, utf8=args.utf8, log=args.log ) bot.load_directory(args.path) bot.sort_replies() # Interactive mode? if args.json: # Read from standard input. buffer = "" stateful = False while True: line = "" try: line = input() except EOFError: break # Look for the __END__ line. end = re.match(r'^__END__$', line) if end: # Process it. stateful = True # This is a stateful session json_in(bot, buffer, stateful) buffer = "" continue else: buffer += line + "\n" # We got the EOF. If the session was stateful, just exit, # otherwise process what we just read. if stateful: quit() json_in(bot, buffer, stateful) quit() print( " . . \n" " .:...:: RiveScript Interpreter (Python)\n" " .:: ::. Library Version: v{version}\n" " ..:;;. ' .;;:.. \n" " . ''' . Type '/quit' to quit.\n" " :;,:,;: Type '/help' for more options.\n" " : : \n" "\n" "Using the RiveScript bot found in: {path}\n" "Type a message to the bot and press Return to send it.\n" .format(version=bot.VERSION(), path=args.path) ) while True: msg = input("You> ") if PY2: # For Python 2 only: cast the message to Unicode. msg = msg.decode("utf-8") # Commands if msg == '/help': print("> Supported Commands:") print("> /help - Displays this message.") print("> /quit - Exit the program.") elif msg == '/quit': exit() else: reply = bot.reply("localuser", msg) print("Bot>", reply)
def interactive_mode(): # Get command line options. options, remainder = [], [] try: options, remainder = getopt.getopt(sys.argv[1:], 'dju', [ 'debug', 'json', 'utf8', 'log=', 'strict', 'nostrict', 'depth=', 'help' ]) except: print("Unrecognized options given, try " + sys.argv[0] + " --help") exit() # Handle the options. debug, depth, strict = False, 50, True with_json, help, log = False, False, None utf8 = False for opt in options: if opt[0] == '--debug' or opt[0] == '-d': debug = True elif opt[0] == '--strict': strict = True elif opt[0] == '--nostrict': strict = False elif opt[0] == '--json': with_json = True elif opt[0] == '--utf8' or opt[0] == '-u': utf8 = True elif opt[0] == '--help' or opt[0] == '-h': help = True elif opt[0] == '--depth': depth = int(opt[1]) elif opt[0] == '--log': log = opt[1] # Help? if help: print("""Usage: rivescript [options] <directory> Options: --debug, -d Enable debug mode. --log FILE Log debug output to a file (instead of the console). Use this instead of --debug. --json, -j Communicate using JSON. Useful for third party programs. --strict, --nostrict Enable or disable strict mode (enabled by default). --depth=50 Set the recursion depth limit (default is 50). --help Display this help. JSON Mode: In JSON mode, input and output is done using JSON data structures. The format for incoming JSON data is as follows: { 'username': '******', 'message': 'Hello bot!', 'vars': { 'name': 'Aiden' } } The format that would be expected from this script is: { 'status': 'ok', 'reply': 'Hello, human!', 'vars': { 'name': 'Aiden' } } If the calling program sends an EOF signal at the end of their JSON data, this script will print its response and exit. To keep a session going, send the string '__END__' on a line by itself at the end of your message. The script will do the same after its response. The pipe can then be used again for further interactions.""") quit() # Given a directory? if len(remainder) == 0: print("Usage: rivescript [options] <directory>") print("Try rivescript --help") quit() root = remainder[0] # Make the bot. bot = RiveScript(debug=debug, strict=strict, depth=depth, utf8=utf8, log=log) bot.load_directory(root) bot.sort_replies() # Interactive mode? if with_json: # Read from standard input. buffer = "" stateful = False while True: line = "" try: line = _input() except EOFError: break # Look for the __END__ line. end = re.match(r'^__END__$', line) if end: # Process it. stateful = True # This is a stateful session json_in(bot, buffer, stateful) buffer = "" continue else: buffer += line + "\n" # We got the EOF. If the session was stateful, just exit, # otherwise process what we just read. if stateful: quit() json_in(bot, buffer, stateful) quit() print("""RiveScript Interpreter (Python) -- Interactive Mode" ---------------------------------------------------" rivescript version: %s Reply Root: %s You are now chatting with the RiveScript bot. Type a message and press Return" to send it. When finished, type '/quit' to exit the program." Type '/help' for other options." """ % (str(bot.VERSION()), root)) while True: msg = _input("You> ") # Commands if msg == '/help': print("> Supported Commands:") print("> /help - Displays this message.") print("> /quit - Exit the program.") elif msg == '/quit': exit() else: reply = bot.reply("localuser", msg) print("Bot>", reply)
def test_improve_code_coverage_rivescript(self): from rivescript import __version__ from rivescript import RiveScript self.assertEqual(RiveScript.VERSION(), __version__) self.rs = RiveScript() self.rs.load_directory(self.testdir) self.rs.sort_replies() self.reply("a", "aa") self.reply("aya", "aa") self.reply("bee", "bb") self.reply("cee", "star") self.rs = RiveScript() self.rs.load_file(os.path.join(self.testdir, "star.rive")) self.rs.load_file(os.path.join(self.testdir, "subdir", "cont.rive")) self.rs.sort_replies() self.reply("a", "aa") self.reply("aya", "star") self.new(""" ! global g = gee ! var v = vee + g - <env g> + v - <bot v> """) self.reply("g", "gee") self.reply("v", "vee") self.rs.set_global("g", None) self.rs.set_variable("v", None) self.reply("g", "undefined") self.reply("v", "undefined") self.new(""" + * - star<set m=me><set u=you> """) self.reply("hi", "star") self.assertContains(self.rs.get_uservars(), {self.username: { 'm': "me", 'u': "you" }}) self.rs.set_uservar("u2", "a", "aye") self.rs.clear_uservars(self.username) uv = self.rs.get_uservars() self.assertNotIn(self.username, uv) self.assertContains(uv, {"u2": {'a': "aye"}}) self.new(""" + u - <call>user</call> > object user python return rs.current_user() < object """) self.reply('u', self.username) self.assertEqual(self.rs.current_user(), None)