RiveScript-Go
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:
$ rivescript eg/brain
> 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() {
bot := rivescript.New(nil)
bot = rivescript.New(rivescript.WithUTF8())
err := bot.LoadDirectory("eg/brain")
if err != nil {
fmt.Printf("Error loading from directory: %s", err)
}
err = bot.LoadFile("./testsuite.rive")
if err != nil {
fmt.Printf("Error loading from file: %s", err)
}
bot.SortReplies()
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,
Strict: false,
UTF8: false,
Depth: 50,
Seed: time.Now().UnixNano(),
SessionManager: memory.New(),
})
For convenience, you can use a shortcut:
bot = rivescript.New(nil)
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 goja library.
Here is how to define a Go object macro:
bot.SetSubroutine(func(rs *rivescript.RiveScript, args []string) string {
return "Hello world!"
})
JavaScript Object Macros
Here is an example how to make JavaScript object macros available via
the goja module:
package main
import (
"fmt"
"github.com/aichaos/rivescript-go"
"github.com/aichaos/rivescript-go/lang/javascript"
)
func main() {
bot := rivescript.New(rivescript.WithUTF8())
js := javascript.New(bot)
bot.SetHandler("javascript", js)
js.VM.Set("helloFunc", func(name string) string {
return fmt.Sprintf("Hello, %s!", name)
})
err := bot.Stream(`
> object add javascript
let a = args[0];
let b = args[1];
return parseInt(a) + parseInt(b);
< object
> object fn javascript
let result = helloFunc(args[0])
return result
< object
+ add # and #
- <star1> + <star2> = <call>add <star1> <star2></call>
+ say hello *
- <call>fn <star></call>
`)
if err != nil {
fmt.Printf("Error loading RiveScript document: %s", err)
}
bot.SortReplies()
inputs := []string{"add 5 and 12", "say hello goja"}
for _, message := range inputs {
fmt.Printf("You said: %s\n", message)
reply, err := bot.Reply("local-user", message)
if err != nil {
fmt.Printf("Error: %s\n", err)
} else {
fmt.Printf("The bot says: %s\n", reply)
}
}
}
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:
bot := rivescript.New(rivescript.WithUTF8())
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.
Testing
The rivescript-go repo submodules the RiveScript Test Suite (rsts) project.
If you didn't do a git clone --recursive
for rivescript-go you can pull the
submodule via the following commands:
git submodule init
git submodule update
Then make test
(or go test
) should show results from the tests run
out of the rsts/ folder.
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/