README

RiveScript-Go

GoDoc Gitter Build Status

Introduction

This is a RiveScript interpreter library written for the Go programming language. RiveScript is a scripting language for chatterbots, making it easy to write trigger/response pairs for building up a bot's intelligence.

This project is currently in Beta status. The API should be mostly stable but things might move around on you.

About RiveScript

RiveScript is a scripting language for authoring chatbots. It has a very simple syntax and is designed to be easy to read and fast to write.

A simple example of what RiveScript looks like:

+ hello bot
- Hello human.

This matches a user's message of "hello bot" and would reply "Hello human." Or for a slightly more complicated example:

+ my name is *
* <formal> == <bot name> => <set name=<formal>>Wow, we have the same name!
* <get name> != undefined => <set name=<formal>>Did you change your name?
- <set name=<formal>>Nice to meet you, <get name>!

The official website for RiveScript is https://www.rivescript.com/

To test drive RiveScript in your web browser, try the RiveScript Playground.

Documentation

Also check out the RiveScript Community Wiki for common design patterns and tips & tricks for RiveScript.

Installation

For the development library:

go get github.com/aichaos/rivescript-go

For the stand-alone rivescript binary for testing a bot:

go get github.com/aichaos/rivescript-go/cmd/rivescript

Usage

The distribution of RiveScript includes an interactive shell for testing your RiveScript bot. Run it with the path to a folder on disk that contains your RiveScript documents. Example:

# (Linux)
$ rivescript eg/brain

# (Windows)
> rivescript.exe eg/brain

See rivescript -help for options it accepts, including debug mode and UTF-8 mode.

When used as a library for writing your own chatbot, the synopsis is as follows:

package main

import (
    "fmt"
    "github.com/aichaos/rivescript-go"
)

func main() {
    // Create a new bot with the default settings.
    bot := rivescript.New(nil)

    // To enable UTF-8 mode, you'd have initialized the bot like:
    bot = rivescript.New(rivescript.WithUTF8())

    // Load a directory full of RiveScript documents (.rive files)
    err := bot.LoadDirectory("eg/brain")
    if err != nil {
      fmt.Printf("Error loading from directory: %s", err)
    }

    // Load an individual file.
    err = bot.LoadFile("./testsuite.rive")
    if err != nil {
      fmt.Printf("Error loading from file: %s", err)
    }

    // Sort the replies after loading them!
    bot.SortReplies()

    // Get a reply.
    reply, err := bot.Reply("local-user", "Hello, bot!")
    if err != nil {
      fmt.Printf("Error: %s\n", err)
    } else {
      fmt.Printf("The bot says: %s", reply)
    }
}

Configuration

The constructor takes an optional Config struct. Here is a full example with all the supported options. You only need to provide keys that are different to the defaults.

bot := rivescript.New(&rivescript.Config{
    Debug: false,                 // Debug mode, off by default
    Strict: false,                // No strict syntax checking
    UTF8: false,                  // No UTF-8 support enabled by default
    Depth: 50,                    // Becomes default 50 if Depth is <= 0
    Seed: time.Now().UnixNano(),  // Random number seed (default is == 0)
    SessionManager: memory.New(), // Default in-memory session manager
})

For convenience, you can use a shortcut:

// A nil config uses all the defaults.
bot = rivescript.New(nil)

// WithUTF8 enables UTF-8 mode (other settings left as default).
bot = rivescript.New(rivescript.WithUTF8())

Object Macros

A common feature in many RiveScript implementations is the object macro, which enables you to write dynamic program code (in your favorite programming language) to add extra capabilities to your bot. For example, your bot could answer a question of "what is the weather like in $location" by running some code to look up their answer via a web API.

The Go version of RiveScript has support for object macros written in Go (at compile time of your application). It also has optional support for JavaScript object macros using the Otto library.

Here is how to define a Go object macro:

bot.SetSubroutine(func(rs *rivescript.RiveScript, args []string) string {
    return "Hello world!"
})

UTF-8 Support

UTF-8 support in RiveScript is considered an experimental feature. It is disabled by default.

By default (without UTF-8 mode on), triggers may only contain basic ASCII characters (no foreign characters), and the user's message is stripped of all characters except letters, numbers and spaces. This means that, for example, you can't capture a user's e-mail address in a RiveScript reply, because of the @ and . characters.

When UTF-8 mode is enabled, these restrictions are lifted. Triggers are only limited to not contain certain metacharacters like the backslash, and the user's message is only stripped of backslashes and HTML angled brackets (to protect from obvious XSS if you use RiveScript in a web application). Additionally, common punctuation characters are stripped out, with the default set being /[.,!?;:]/g. This can be overridden by providing a new regexp string literal to the RiveScript.SetUnicodePunctuation function. Example:

// Make a new bot with UTF-8 mode enabled.
bot := rivescript.New(rivescript.WithUTF8())

// Override the punctuation characters that get stripped
// from the user's message.
bot.SetUnicodePunctuation(`[.,!?;:]`);

The <star> tags in RiveScript will capture the user's "raw" input, so you can write replies to get the user's e-mail address or store foreign characters in their name.

Building

I use a GNU Makefile to make building and running this module easier. The relevant commands are:

  • make setup - run this after freshly cloning this repo. It runs the git submodule commands to pull down vendored dependencies.
  • make build - this will build the front-end command from cmd/rivescript and place its binary into the bin/ directory. It builds a binary relevant to your current system, so on Linux this will create a Linux binary. It's also recommended to run this one at least once, because it will cache dependency packages and speed up subsequent builds and runs.
  • make run - runs the front-end command and points it to the eg/brain folder as its RiveScript source.
  • make fmt - runs gofmt -w on all the source files.
  • make test - runs the unit tests.
  • make clean - cleans up the .gopath, bin and dist directories.
Releasing

You can build a release for an individual platform by running a command like make linux/amd64. The valid build targets are currently as follows:

  • Linux: linux/386 and linux/amd64
  • Windows: windows/386 and windows/amd64
  • MacOS: darwin/amd64

Run make release to automatically build releases for all supported platforms.

A directory for the release is created in dist/rivescript-$VERSION-$OS-$ARCH/ that contains the built binary, README.md, Changes.md and examples. You can inspect this directory afterwards; its contents are automatically tarred up (zip for Windows) and placed in the root of the git repo.

If you are cross-compiling for a different system, you may need to mess with permissions so that Go can download the standard library for the new target. Example:

% sudo mkdir /usr/lib/golang/pkg/windows_386
% chown your_user:your_user /usr/lib/golang/pkg/windows_386

See Also

  • rivescript-go/parser - A standalone package for parsing RiveScript code and returning an "abstract syntax tree."
  • rivescript-go/macro - Contains an interface for creating your own object macro handlers for foreign programming languages.
  • rivescript-go/sessions - Contains the interface for user variable session managers as well as the default in-memory manager and the NullStore for testing. Other official session managers (e.g. Redis) are in here as well.

License

The MIT License (MIT)

Copyright (c) 2017 Noah Petherbridge

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

See Also

The official RiveScript website, http://www.rivescript.com/

Expand ▾ Collapse ▴

Documentation

Overview

Package rivescript implements the RiveScript chatbot scripting language.

About RiveScript

RiveScript is a scripting language for authoring chatbots. It has a very simple syntax and is designed to be easy to read and fast to write.

A simple example of what RiveScript looks like:

+ hello bot
- Hello human.

This matches a user's message of "hello bot" and would reply "Hello human." Or for a slightly more complicated example:

+ my name is *
* <formal> == <bot name> => <set name=<formal>>Wow, we have the same name!
* <get name> != undefined => <set name=<formal>>Did you change your name?
- <set name=<formal>>Nice to meet you, <get name>!

The official website for RiveScript is https://www.rivescript.com/

To test drive RiveScript in your web browser, try the [RiveScript Playground](https://play.rivescript.com/).

Object Macros

A common feature in many RiveScript implementations is the object macro, which enables you to write dynamic program code (in your favorite programming language) to add extra capabilities to your bot. For example, your bot could answer a question of `what is the weather like in _____` by running some code to look up their answer via a web API.

The Go version of RiveScript has support for object macros written in Go (at compile time of your application). It also has optional support for JavaScript object macros using the Otto library.

UTF-8 Support

UTF-8 support in RiveScript is considered an experimental feature. It is disabled by default. Enable it by setting `RiveScript.SetUTF8(true)`.

By default (without UTF-8 mode on), triggers may only contain basic ASCII characters (no foreign characters), and the user's message is stripped of all characters except letters, numbers and spaces. This means that, for example, you can't capture a user's e-mail address in a RiveScript reply, because of the @ and . characters.

When UTF-8 mode is enabled, these restrictions are lifted. Triggers are only limited to not contain certain metacharacters like the backslash, and the user's message is only stripped of backslashes and HTML angled brackets (to protect from obvious XSS if you use RiveScript in a web application). Additionally, common punctuation characters are stripped out, with the default set being `/[.,!?;:]/g`. This can be overridden by providing a new regexp string literal to the `RiveScript.SetUnicodePunctuation` function. Example:

// Make a new bot with UTF-8 mode enabled.
bot := rivescript.New(config.UTF8())

// Override the punctuation characters that get stripped from the
// user's message.
bot.SetUnicodePunctuation(`[.,!?;:]`);

The `<star>` tags in RiveScript will capture the user's "raw" input, so you can write replies to get the user's e-mail address or store foreign characters in their name.

See Also

The official homepage of RiveScript, http://www.rivescript.com/

Example
Output:

Index

Examples

Constants

View Source
const (
	// UNDEFINED is the text "undefined", the default text for variable getters.
	UNDEFINED = "undefined"

	// UNDEFTAG is the "<undef>" tag for unsetting variables in !Definitions.
	UNDEFTAG = "<undef>"
)

    Forms of undefined.

    View Source
    const Version = "0.3.0"

      Version number for the RiveScript library.

      Variables

      View Source
      var (
      	ErrDeepRecursion    = errors.New("Deep Recursion Detected")
      	ErrRepliesNotSorted = errors.New("Replies Not Sorted")
      	ErrNoDefaultTopic   = errors.New("No default topic 'random' was found")
      	ErrNoTriggerMatched = errors.New("No Trigger Matched")
      	ErrNoReplyFound     = errors.New("The trigger matched but yielded no reply")
      )

        The types of errors returned by RiveScript.

        Functions

        This section is empty.

        Types

        type Config

        type Config struct {
        	// Debug enables verbose logging to standard output. Default false.
        	Debug bool
        
        	// Strict enables strict syntax checking, where a syntax error in RiveScript
        	// code is considered fatal at parse time. Default true.
        	Strict bool
        
        	// UTF8 enables UTF-8 mode within the bot. Default false.
        	//
        	// When UTF-8 mode is enabled, triggers in the RiveScript source files are
        	// allowed to contain foreign characters. Additionally, the user's incoming
        	// messages are left *mostly* intact, so that they send messages with
        	// foreign characters to the bot.
        	UTF8 bool
        
        	// Depth controls the global limit for recursive functions within
        	// RiveScript. Default 50.
        	Depth uint
        
        	// Random number seed, if you'd like to customize it. The default is for
        	// RiveScript to choose its own seed, `time.Now().UnixNano()`
        	Seed int64
        
        	// SessionManager is an implementation of the same name for managing user
        	// variables for the bot. The default is the in-memory session handler.
        	SessionManager sessions.SessionManager
        }

          Config provides options to configure the RiveScript bot.

          Create a pointer to this type and send it to the New() constructor to change the default settings. You only need to provide settings you want to override; the zero-values of all the options are handled appropriately by the RiveScript library.

          The default values are documented below.

          func WithUTF8

          func WithUTF8() *Config

            WithUTF8 provides a Config object that enables UTF-8 mode.

            type RiveScript

            type RiveScript struct {
            	// Parameters
            	Debug              bool // Debug mode
            	Strict             bool // Strictly enforce RiveScript syntax
            	Depth              uint // Max depth for recursion
            	UTF8               bool // Support UTF-8 RiveScript code
            	Quiet              bool // Suppress all warnings from being emitted
            	UnicodePunctuation *regexp.Regexp
            	// contains filtered or unexported fields
            }

              RiveScript is the bot instance.

              Example (Javascript)
              Output:
              
              
              Example (Subroutine)
              Output:
              
              
              Example (Utf8)
              Output:
              
              

              func New

              func New(cfg *Config) *RiveScript

                New creates a new RiveScript instance.

                A RiveScript instance represents one chat bot personality; it has its own replies and its own memory of user data. You could make multiple bots in the same program, each with its own replies loaded from different sources.

                func (*RiveScript) ClearAllUservars

                func (rs *RiveScript) ClearAllUservars()

                  ClearAllUservars deletes all variables for all users.

                  func (*RiveScript) ClearUservars

                  func (rs *RiveScript) ClearUservars(username string)

                    ClearUservars deletes all the variables that belong to a user.

                    func (*RiveScript) CurrentUser

                    func (rs *RiveScript) CurrentUser() (string, error)

                      CurrentUser returns the current user's ID.

                      This is only useful from within an object macro, to get the ID of the user who invoked the macro. This value is set at the beginning of `Reply()` and unset at the end, so this function will return empty outside of a reply context.

                      func (*RiveScript) DeleteSubroutine

                      func (rs *RiveScript) DeleteSubroutine(name string)

                        DeleteSubroutine removes a Go object macro.

                        Parameters

                        name: The name of the object macro to be deleted.
                        

                        func (*RiveScript) DumpSorted

                        func (rs *RiveScript) DumpSorted()

                          DumpSorted is a debug method which pretty-prints the sort tree of topics from the bot's memory.

                          func (*RiveScript) DumpTopics

                          func (rs *RiveScript) DumpTopics()

                            DumpTopics is a debug method which pretty-prints the topic tree structure from the bot's memory.

                            func (*RiveScript) FreezeUservars

                            func (rs *RiveScript) FreezeUservars(username string) error

                              FreezeUservars freezes the variable state of a user.

                              This will clone and preserve the user's entire variable state, so that it can be restored later with `ThawUservars()`.

                              func (*RiveScript) GetAllUservars

                              func (rs *RiveScript) GetAllUservars() map[string]*sessions.UserData

                                GetAllUservars gets all the variables for all the users.

                                This returns a map of username (strings) to `map[string]string` of their variables.

                                func (*RiveScript) GetDebug

                                func (rs *RiveScript) GetDebug() bool

                                  GetDebug tells you the current status of the debug mode.

                                  func (*RiveScript) GetDepth

                                  func (rs *RiveScript) GetDepth() uint

                                    GetDepth returns the current recursion depth limit.

                                    func (*RiveScript) GetGlobal

                                    func (rs *RiveScript) GetGlobal(name string) (string, error)

                                      GetGlobal gets a global variable.

                                      This is equivalent to `<env name>` in RiveScript. Returns `undefined` if the variable isn't defined.

                                      func (*RiveScript) GetStrict

                                      func (rs *RiveScript) GetStrict() bool

                                        GetStrict returns the strict syntax check setting.

                                        func (*RiveScript) GetUTF8

                                        func (rs *RiveScript) GetUTF8() bool

                                          GetUTF8 returns the current status of UTF-8 mode.

                                          func (*RiveScript) GetUservar

                                          func (rs *RiveScript) GetUservar(username, name string) (string, error)

                                            GetUservar gets a user variable.

                                            This is equivalent to `<get name>` in RiveScript. Returns `undefined` if the variable isn't defined.

                                            func (*RiveScript) GetUservars

                                            func (rs *RiveScript) GetUservars(username string) (*sessions.UserData, error)

                                              GetUservars gets all the variables for a user.

                                              This returns a `map[string]string` containing all the user's variables.

                                              func (*RiveScript) GetVariable

                                              func (rs *RiveScript) GetVariable(name string) (string, error)

                                                GetVariable gets a bot variable.

                                                This is equivalent to `<bot name>` in RiveScript. Returns `undefined` if the variable isn't defined.

                                                func (*RiveScript) LastMatch

                                                func (rs *RiveScript) LastMatch(username string) (string, error)

                                                  LastMatch returns the user's last matched trigger.

                                                  func (*RiveScript) LoadDirectory

                                                  func (rs *RiveScript) LoadDirectory(path string, extensions ...string) error

                                                    LoadDirectory loads multiple RiveScript documents from a folder on disk.

                                                    Parameters

                                                    path: Path to the directory on disk
                                                    extensions...: List of file extensions to filter on, default is
                                                                   '.rive' and '.rs'
                                                    

                                                    func (*RiveScript) LoadFile

                                                    func (rs *RiveScript) LoadFile(path string) error

                                                      LoadFile loads a single RiveScript source file from disk.

                                                      Parameters

                                                      path: Path to a RiveScript source file.
                                                      

                                                      func (*RiveScript) RemoveHandler

                                                      func (rs *RiveScript) RemoveHandler(lang string)

                                                        RemoveHandler removes an object macro language handler.

                                                        If the handler has already loaded object macros, they will be deleted from the bot along with the handler.

                                                        Parameters

                                                        lang: The programming language for the handler to remove.
                                                        

                                                        func (*RiveScript) Reply

                                                        func (rs *RiveScript) Reply(username, message string) (string, error)

                                                          Reply fetches a reply from the bot for a user's message.

                                                          Parameters

                                                          username: The name of the user requesting a reply.
                                                          message: The user's message.
                                                          

                                                          func (*RiveScript) SetDebug

                                                          func (rs *RiveScript) SetDebug(value bool)

                                                            SetDebug enables or disable debug mode.

                                                            func (*RiveScript) SetDepth

                                                            func (rs *RiveScript) SetDepth(value uint)

                                                              SetDepth lets you override the recursion depth limit (default 50).

                                                              func (*RiveScript) SetGlobal

                                                              func (rs *RiveScript) SetGlobal(name, value string)

                                                                SetGlobal sets a global variable.

                                                                This is equivalent to `! global` in RiveScript. Set the value to `undefined` to delete a global.

                                                                func (*RiveScript) SetHandler

                                                                func (rs *RiveScript) SetHandler(lang string, handler macro.MacroInterface)

                                                                  SetHandler sets a custom language handler for RiveScript object macros.

                                                                  Parameters

                                                                  lang: What your programming language is called, e.g. "javascript"
                                                                  handler: An implementation of macro.MacroInterface.
                                                                  

                                                                  func (*RiveScript) SetPerson

                                                                  func (rs *RiveScript) SetPerson(name, value string)

                                                                    SetPerson sets a person substitution pattern.

                                                                    This is equivalent to `! person` in RiveScript. Set the value to `undefined` to delete a person substitution.

                                                                    func (*RiveScript) SetStrict

                                                                    func (rs *RiveScript) SetStrict(value bool)

                                                                      SetStrict enables strict syntax checking when parsing RiveScript code.

                                                                      func (*RiveScript) SetSubroutine

                                                                      func (rs *RiveScript) SetSubroutine(name string, fn Subroutine)

                                                                        SetSubroutine defines a Go object macro from your program.

                                                                        Parameters

                                                                        name: The name of your subroutine for the `<call>` tag in RiveScript.
                                                                        fn: A function with a prototype `func(*RiveScript, []string) string`
                                                                        

                                                                        func (*RiveScript) SetSubstitution

                                                                        func (rs *RiveScript) SetSubstitution(name, value string)

                                                                          SetSubstitution sets a substitution pattern.

                                                                          This is equivalent to `! sub` in RiveScript. Set the value to `undefined` to delete a substitution.

                                                                          func (*RiveScript) SetUTF8

                                                                          func (rs *RiveScript) SetUTF8(value bool)

                                                                            SetUTF8 enables or disabled UTF-8 mode.

                                                                            func (*RiveScript) SetUnicodePunctuation

                                                                            func (rs *RiveScript) SetUnicodePunctuation(value string)

                                                                              SetUnicodePunctuation allows you to override the text of the unicode punctuation regexp. Provide a string literal that will validate in `regexp.MustCompile()`

                                                                              func (*RiveScript) SetUservar

                                                                              func (rs *RiveScript) SetUservar(username, name, value string)

                                                                                SetUservar sets a variable for a user.

                                                                                This is equivalent to `<set>` in RiveScript. Set the value to `undefined` to delete a substitution.

                                                                                func (*RiveScript) SetUservars

                                                                                func (rs *RiveScript) SetUservars(username string, data map[string]string)

                                                                                  SetUservars sets a map of variables for a user.

                                                                                  Set multiple user variables by providing a map[string]string of key/value pairs. Equivalent to calling `SetUservar()` for each pair in the map.

                                                                                  func (*RiveScript) SetVariable

                                                                                  func (rs *RiveScript) SetVariable(name, value string)

                                                                                    SetVariable sets a bot variable.

                                                                                    This is equivalent to `! var` in RiveScript. Set the value to `undefined` to delete a bot variable.

                                                                                    func (*RiveScript) SortReplies

                                                                                    func (rs *RiveScript) SortReplies() error

                                                                                      SortReplies sorts the reply structures in memory for optimal matching.

                                                                                      After you have finished loading your RiveScript code, call this method to populate the various sort buffers. This is absolutely necessary for reply matching to work efficiently!

                                                                                      If the bot has loaded no topics, or if it ends up with no sorted triggers at the end, it will return an error saying such. This usually means the bot didn't load any RiveScript code, for example because it looked in the wrong directory.

                                                                                      func (*RiveScript) Stream

                                                                                      func (rs *RiveScript) Stream(code string) error

                                                                                        Stream loads RiveScript code from a text buffer.

                                                                                        Parameters

                                                                                        code: Raw source code of a RiveScript document, with line breaks after
                                                                                              each line.
                                                                                        

                                                                                        func (*RiveScript) ThawUservars

                                                                                        func (rs *RiveScript) ThawUservars(username string, action sessions.ThawAction) error

                                                                                          ThawUservars unfreezes a user's variables.

                                                                                          The `action` can be one of the following: * thaw: Restore the variables and delete the frozen copy. * discard: Don't restore the variables, just delete the frozen copy. * keep: Keep the frozen copy after restoring.

                                                                                          type Subroutine

                                                                                          type Subroutine func(*RiveScript, []string) string

                                                                                            Subroutine is a function prototype for defining custom object macros in Go.

                                                                                            Directories

                                                                                            Path Synopsis
                                                                                            Package ast defines the Abstract Syntax Tree for RiveScript.
                                                                                            Package ast defines the Abstract Syntax Tree for RiveScript.
                                                                                            cmd
                                                                                            rivescript
                                                                                            Stand-alone RiveScript Interpreter.
                                                                                            Stand-alone RiveScript Interpreter.
                                                                                            eg
                                                                                            lang
                                                                                            javascript
                                                                                            Package javascript implements JavaScript object macros for RiveScript.
                                                                                            Package javascript implements JavaScript object macros for RiveScript.
                                                                                            Package macros exports types relevant to object macros.
                                                                                            Package macros exports types relevant to object macros.
                                                                                            Package parser is a RiveScript language parser.
                                                                                            Package parser is a RiveScript language parser.
                                                                                            Package sessions provides the interface and default session store for RiveScript.
                                                                                            Package sessions provides the interface and default session store for RiveScript.
                                                                                            memory
                                                                                            Package memory provides the default in-memory session store.
                                                                                            Package memory provides the default in-memory session store.
                                                                                            null
                                                                                            Package null provides a session manager that has no memory.
                                                                                            Package null provides a session manager that has no memory.
                                                                                            redis
                                                                                            Package redis implements a Redis backed session manager for RiveScript.
                                                                                            Package redis implements a Redis backed session manager for RiveScript.