예제 #1
0
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)
예제 #2
0
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)
예제 #3
0
    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)