A text-based scripting language, dialog system and bot engine for Conversational User Interfaces (CUI)
This is a part of project yeu.ai. An open platform for experiment and training Vietnamese chatbot!
Here is a list of resources to get you started
- 👯 Read the wiki for all the details on how to get started playing with BotScript
- 🤔 Read API References to start coding
- 💬 Playground to say hello?
To get started playing with BotScript, you must follows the following rules:
A definition
is an identifier of an entity, a group, a list or a property.
The syntax start with symbol !
:
! name
- CuteBot
The CuteBot
is value instance of the property name
. Think of bots with many names!
To define a list of items, just enter item in a new line which started with symbol -
:
! colors
- red
- green
- blue
Also, you can define intents by data samples as following:
! intent:goodbye
- bye
- goodbye
- see you around
- see you later
- talk to you later
! intent:ask_identity
- who are you
- what is your name
- how should i address you
- may i know your name
- are you a bot
Comments make your code clearer, you can add a comment in BotScript document by starting the symbol #
at the begining of a line or followed by a space:
# here is a comment
# here is an other
The continuation allows the code to break to span multiple of lines. In the case, you can write a really long reply or prompt.
A continuation must start with symbol ^
at the beginning of the line.
Example:
+ tell me a joke
- As a scarecrow, people say I'm outstanding in my field.
^ But hay - it's in my jeans.
- I told my girlfriend she drew her eyebrows too high.
^ She seemed surprised.
- I have kleptomania.
^ But when it gets bad, I take something for it!
A dialogue is a piece of conversation that human and bot interact with each other.
A dialogue must contains a +
line, that defines a pattern can activate the bot to respond. This line also called with other name trigger.
A dialogue also must contains a -
line, that defines a pattern response which is output to reply to human.
A dialogue must have at least one reply and one trigger.
+ message pattern
- message reply
Example:
+ hello bot
- Hello, human!
A dialogue may contains:
- triggers
- replies
- flows
- conditions
- variables
- commands
- prompts
A trigger is a pattern help bot knows what human is saying.
A trigger begins with symbol +
in the dialogue.
A trigger may contains wildcards, Alternations, or Defintion. With wildcards, you can set a placeholder within trigger that the bot can capture. The values matched by the wildcards can be retrieved in the responses by using the tags $var
or values in order $1
, $2
, $3
.
Example:
## trigger uses asterisk as a wildcard
+ My name is *{name}
- Nice to meet you $name!
## trigger use a parentheses and straight slash as an alternations
+ (hello|hallo|chào)
- Hello $1
## trigger use defintion as alternations array.
+ my favorite color is [colors]
- I like $1 too.
A dialogue may contains more than one trigger. Which helps bot to detect exactly in more case.
+ My name is *{name}
+ *{name} is my name
- Nice to meet you $name!
A trigger may contains:
- definitions
- patterns
- variable
A reply begins with -
symbol in the dialogue and goes with the trigger. If the dialogue has multiple replies then a random reply will be selected.
+ hello
- Hello. What is your name?
- Hi. Could you tell me your name?
- [yes]. What's your name?
A reply may contains:
- definitions
- variables
Flows are tasks which need to be resolved. A flow can used to determine a precise flow of conversation
A flow must start with a ~
line, that defines the the task name.
A flow contains lines started with symbol -
to guide human answers the quiz and may contains lines +
help the bot captures the information. If the flow does not contains +
, after responded the flow will ends.
A flow can referenced by an other.
Flows are activated within a dialogue. The bot will respond if all tasks are resolved!
~ maker
- What cell phone vendor?
- Which brand of smartphone do you want to buy?
+ I want to buy *{maker}
+ *{maker}
The dialogue jumps to the splash flow then back to continue.
~ random
- I am happy to hear you!
- It's fine today.
+ hello *
~ random
- Great!
A flow may contains:
- triggers
- replies
- flows
- conditions
- commands
- variables
- prompts
Prompt is suggested answers which helps human quickly select and reply.
Prompt must be started with symbol ?
.
Prompt declared in a dialogue, flows or defined within a conditional prompt. If the conditional prompt is satisfied, the prompt in the dialogue will be overrided.
If the dialogue has multiple prompts then a random one will be selected.
Example:
! pizza_types
- Pepperoni
- Margherita
- Hawaiian
+ I need a pizza
- What kind of pizza?
? [pizza_types]
A conditions begins with star symbol: *
Syntax: * expression
There are two categories of conditions in the dialogue:
- Conditional activation: monitoring the ability to activate the dialogue in the conversation
- Conditional reply: checking the operation process in the dialogue and ability to respond to human
For example:
+ knock knock
- who is there
+ *
* $previous[0] == 'who is there' # must have happened
* $input == 'its me' -> i know you!
- $1 who?
A conditional reply allows bot test the conditions and do some logics before replies to human.
Syntax: * expression [type] [action]
There are six subcategories of conditional processing:
- Conditional reply
- Conditional flow
- Conditional redirect
- Conditional command
- Conditional prompt
- Conditional event
Example:
* expression => - a reply
* expression => @ a command
* expression => ~ a flow
* expression => + a redirect
* expression => * an event
* expression => ? a prompt
A conditional reply let bot replies smarter base on the condition or pick random replies from a list definition. That means before reply bot will check its memory and create reponse if the bot knows.
* $name == undefined -> You never told me your name
A conditional flow let bot resolves an additional task if the condition is match.
* $topic == buy phone ~> ask phone
A conditional redirect let bot breaks current dialogue and flows to turn to other dialogue. This helps bot cancel current task and do a new one if the condition is met.
* $action == cancel >> task cancel
A conditional prompt allows bot sending to human additional prompt list. This helps human knows how to reply to the bot after that.
* $input == i dont know ?> [show the list]
A conditional command let bot execute an http POST request to an api endpoint with req
data context. Once the endpoint returns json data then it will be populated before generate speech response.
* $input == play music @> play favorite music
* $input == confirm order @> send the order
A conditional event can be integrated with code instead of using conditional command
.
* $var == true +> event name
Example:
# conditional reply
+ what is my name
* $name == undefined -> You never told me your name.
- Your name is $name!
- Aren\'t you $name?
# conditional flow
+ *advise me
* $topic == buy phone ~> ask phone
* $topic == ask warranty ~> warranty guide
~ ask something
- You are done! Do you want ask more?
# conditional redirect
+ i want to say *{action}
* $action == cancel >> task cancel
* $action == something -> [bot say something]
- You said $action
An action command allow you to do more powerful things with bot's responses.
A command must starting with the sign @
. Followed by the command name and its API endpoint.
A command can be consumed within a dialogue conditions that means the command only executes if the condition satisfied.
The command will be sent with req
data context. Once the endpoint returns json data then it will be populated before generate speech response.
Syntax:
@ COMMAND_NAME [POST|GET] API_ENDPOINT
For example, you can allow the user to ask the bot questions about the current weather or about movie ticket prices, and your bot can send an http request that goes out to the internet to fetch that information.
@ geoip https://api.ipify.org/?format=json
# output result: {"ip":"10.10.10.100"}
+ what is my ip
* true @> geoip
- Here is your ip: $ip.
What good is a chatbot if it can't even remember your name? BotScript has the capability to captures the information given by human and automatically store its into the request context.
A variable appears in a dialogue in both triggers and replies.
A variable is declared within parentheses: *{var1}
to capture a string and #{var2}
to captures a number.
A variable is populated in replies by defining after $var1
sign or within form ${var2}
.
Example:
+ My name is *{name}
- Nice to meet you $name!
+ I am #{age} years old
- You are $age
System variables:
$previous
: history of dialogue chat$flows
: available in context of dialogue is flowing$input
: human message input
A pattern within trigger which helps the dialogue human <-> bot
can be activated and bot has a better capability to reply human.
Advanced pattern helps bot exactly knows what human is saying.
There are two ways add pattern capability in BotScript:
- Built-in pattern capability using Regular Expression
- Custom pattern capability by add new handler
Built-in pattern capability already supported in BotScript. Just declare and use basic Regular Expressions within form: /(\w+)\s(\w+)/
and it will capture two words John Smith
, for example.
A pattern must be wrapped in /
to use advanced syntax which XRegExp supports.
A part of a pattern can be enclosed in parentheses (...). This is called a capturing group
Note: Pattern will capture entities in a group then it can be accessed via variables in order $1, $2, ...
Example:
# I like to buy it -> Do you really buy it
# I really need this -> So you need this, right?
+ /^I (?:.+\s)?(\w+) (?:.+\s)?(it|this)/
- Do you really $1 $2?
- So you $1 $2, right?
This way, bot is added a new matching handler and trying to match the input which human say, with highest priority. This feature is enabled through code integration.
NLP can be integrated by this way. See an example.
Example:
+ ([ner: PERSON]+) /was|is/ /an?/ []{0,3} /painter|artist/
- An accomplished artist you say.
- Yeah, i know $1!
By combining NLP
, Command Service
, Events
you can teach the bot to be smarter.
BotScript allows to define plugins which will be activated usage if the one added via code implementation
A plugin started with >
line for pre, post-processing
A plugin runs in pipeline of message request processing
A plugin may contain conditional activation
A plugin may be grouped in a group
Syntax:
> plugin name
* conditional expression
From
v1.6.0
: A plugin can be compiled directly in the botscript document
Example:
/**
> addTimeNow
> noReplyHandle
+ what time is it
- it is $time
*/
function addTimeNow(req: Request, ctx: Context) {
const now = new Date();
req.variables.time = `${now.getHours()} : ${now.getMinutes()}`;
}
/**
* plugin for post-processing
* */
function noReplyHandle() {
const postProcessing = (res: Request) => {
if (res.message === "NO REPLY!") {
res.message = `Sorry! I don't understand!`;
}
};
return postProcessing;
}
Directive is an instruction that helps Engine understand enhanced implementation. Imagine the directive as a switch to direct action.
Syntax:
/directive: name
- option 1
- option 2
Available built-in supported directives:
- include
- nlu
- format
- plugin
Example:
# import botscript document from urls
/include:
- url 1
- url 2
Example:
# use your custom nlu server
/nlu: name of command
Example:
/format: bold
<strong>{{value}}</strong>
+ bold *{me}
- $me :bold
# addvanced example, use handlebars syntax
# format variable in population
/format: list
{{#each people}}
{{name}} / {{age}},
{{/each}}
+ show my list
* true @> cmd_list_patient
- Here is your list: $people :list
A plugin uses available context params: ({ req, ctx, utils, logger })
A plugin is compiled in the script document and one defined in a directive:
Syntax:
/plugin: name
```js
# javascript code here;
# access human request or bot context via name: req, ctx
# normalize message or what you need
console.log('Human say: ', req.message)
return (req, ctx) => {
// do post-processing.
if (req.isNotResponse) {
req.speechResponse = 'I dont know!';
}
}
```
Example:
# add time now to current variable for each request
/plugin: addTimeNow
```js
const now = new Date();
req.variables.time = `${now.getHours()}:${now.getMinutes()}`;
```
See the examples/
directory.
Pull requests and stars are highly welcome.
For bugs and feature requests, please create an issue.
BotScript is licensed under the MIT License - see the LICENSE file for details