Giter VIP home page Giter VIP logo

botml's Introduction

Botml

An open source and production-ready markup language
for designing modern chatbots.


npm npm downloads David travis JavaScript Style Guide test License


Botml is a declarative and powerful markup language for designing modern chatbots (a.k.a. conversational bots).

Anyone (developers and non-developers) can use it to create and teach bots how to behave. Define the behavior of your chatbot using the right tiny bit of formatting and engage the conversation in no time. See for yourself: a calculator bot written in only two lines.

Table of Contents

Install

This project uses node and npm. Go check them out if you don't have them locally installed.

$ npm i -g botml

This will install both the botml node package and the bot client.

Optionally, if you use Atom as an editor, you may want to install syntax highlighting with the language-botml package.

Usage

Either run the cli:

$ bot

or use it in your code:

const Botml = require('botml/lib/botml')
const bot = new Botml('alice.bot')
bot.start()

or even load it statically in your browser:

<script src='https://unpkg.com/botml'></script>
<script>
const bot = new Botml()
// either load an URI:
// bot.load('https://raw.githubusercontent.com/codename-co/botml/master/examples/hello.bot')
// or load the script directly:
bot.parse('> *\n< yes?\n')
bot.start()
bot.send('hey')
</script>

Features

Existing features are of two sorts: basic features that cover a basic bot needs, and advanced features that enable richer conversational capabilities.

Basic features:

Advanced features:

Format

The format aims to achieve the most by using the least. With the right and minimal set of conventions, it can be very powerful.

The general syntax follows 3 important conventions:

  1. The text must be written into blocks of lines separated by at least two line breaks ;
  2. Each line must start with a one-character symbol that defines its type ;
  3. A block type is inferred by the symbol of its heading line.

The most basic .bot file would be:

! BOTML 1

> Hello
< Hello human!

▶️ Try this script on bubl.es

Blocks

Specification

The specification line is needed to tell Botml that it can load the file.

This must be the first line of any .bot file.

! BOTML 1

The 1 stands for the current version of the format.

Comment

Comments can help make your .bot file clearer.

They can be used as standalone blocks or can be inserted within actionable blocks.

They cannot be used inline.

# COMMENT

Dialogue

Dialogues are the core concept of any bot. It defines how the human and the bot can interact.

A dialogue must start with a > line, that defines what sentence(s) can activate the bot to respond.

There must be one or multiple < lines after that define the bot response(s).

There can be multiple back and forth by repeating this sequence within the same block.

> MESSAGE
< MESSAGE

Example:

> Hi
< Hello there. Who are you?
> *
< Nice to meet you.

▶️ Try this script on bubl.es

Random replies

Random replies in dialogues make a bot feel less rigid. When answering to a human, the bot chooses randomly in the reply candidates. Only one of the multiple reply candidates can be chosen by the bot.

> MESSAGE
< REPLY CANDIDATE #1
< REPLY CANDIDATE #2

Example:

> Hello
< Hi there
< Howdy?

▶️ Try this script on bubl.es

List

Lists are helpful to assemble similar notions, or alternatives.

A list must start with a = line, that defines the list name.

It must have at least one list item but can have more. Each list item starts with the - symbol.

= LIST_NAME
- LIST_ITEM
- LIST_ITEM

A list item can reference yet another list.

= LIST_NAME
- LIST_ITEM
- [ANOTHER_LIST]

It can be referenced in a > line for referencing multiple variants of an input pattern.

It can be referenced in a < line for referencing randomly one of the list items as a response.

It can be referenced in a ? line (prompt) for referencing multiple predefined choices.

Referencing a list is done by wrapping the list name with brackets: [LIST_NAME].

Example:

= citrus
- oranges
- lemons
- grapefruits

= random_fruit
- apples
- apricots
- bananas
- [citrus]

> I like [random_fruit]
< Oh. I prefer [random_fruit].

# which is the equivalent to:
#  > I like apples
#  > I like apricots
#  > I like bananas
#  > I like oranges
#  > I like lemons
#  > I like grapefruits
#  < Oh. I prefer apples
#  < Oh. I prefer apricots
#  < Oh. I prefer bananas
#  < Oh. I prefer oranges
#  < Oh. I prefer lemons
#  < Oh. I prefer grapefruits
#
#  > I like [random_fruit]
#  < Oh. I prefer [random_fruit].

▶️ Try this script on bubl.es

Lists can also be used in prompts.

Prompt

Prompts are predefined quick replies in reaction to a specific situation.

They must be placed after a < line, at the end of a dialogue.

They must reference a list to access all the quick replies.

The number of quick replies should be kept minimal.

= LIST_NAME
- LIST_ITEM
- LIST_ITEM

? [LIST_NAME]

Example:

= pizza_types
- Peperroni
- Margherita
- Hawaiian

> I need a pizza
< What kind of pizza?
? [pizza_types]

▶️ Try this script on bubl.es

Service

Services can leverage external APIs endpoints.

A service must be declared in its own block starting with the @ sign. It consists of a name and an JSON-formatted API endpoint (over http or https).

It can (and most of the time should) accept a parameter by using the $ sign within its endpoint.

@ SERVICE_NAME ENDPOINT

It can be consumed within a dialogue.

When the ENDPOINT has a $ sign, it must accept a parameter whose value will replace the $ sign.

The result of the service call can be filtered using an optional OUTPUT. It's a selector whose format is /(\.\w)+/.

@ SERVICE_NAME( PARAMETER )[ OUTPUT ]

Example:

@ geo_domain http://freegeoip.net/json/$

> Where is *{domain}
@ geo_domain($domain).city
< It is running from $.

Script

Scripts can be used to evaluate code.

The language of the code is dependent of the language used of the parser used. The botml parser is in Javascript, thus Javascript code can be used.

It must be inline within dialogues wrapped in ```.

It can access named variables:

  • either from context: context.variables.get('price')
  • or with its named variable shorter form: $price

Example:

> It will cost you #{price} USD
< `$price / 1000`k USD is a lot!

▶️ Try this script on bubl.es

Variable

Variables are the way to detect, format, store and reuse meaningful information.

A variable can be captured within a > line (dialogue).

It must be either textual ($), numeric (#) or alphanumeric (*).

It can be used in < lines.

> My name is *{name}
< Nice to meet you, $name

> I am #{age} years old
< Seems that you are $age

▶️ Try this script on bubl.es

The variable format is ${VARIABLE_NAME} (with its numeric and alphanumeric equivalents). But for convenient of use, the format $VARIABLE_NAME can be used too for textual and numeric variables.

A special $ variable always refers to the last matching value of a dialogue or the result of the previous line (the result of a service consumption for instance).

Regular Expression

Regular expressions can be used in > lines to have more control on what to detect.

A regular expression must be wrapped in / and cannot be mixed with basic expressions.

> /^I (?:.+\s)?(\w+) (?:.+\s)?(it|this)/
< Cool bro.

▶️ Try this script on bubl.es

In fact, the XRegExp library is used under the hood, giving you access to leading named captures, inline comments and mode modifiers.

Dialogue workflow

Dialogue workflows are a superset of the classical dialogues.

A workflow can be used to determine a precise flow of conversation.

It must start with a ~ line, that defines the list name.

Only one workflow can start with a < dialogue. Such a workflow will be activated and used by default when the user connects to the bot.

# grocery shopping
> I want to buy *{items}
< How many $items?
> #{count} $items
> #{count}
< There you go.

▶️ Try this script on bubl.es

Conditional branches

Conditional branches are instructions that direct the bot to another part of the dialogue based on test conditions.

Conditional branches start with --- and listen for all typed information then test it with all cases. Each case being separated by ---:

---
  > first input case
  < first reply
---
  > second input case
  < second reply
---
> last input case
< last reply

Conditional branches work great with another feature labelled checkpoint.

A checkpoint is a marker ~ CHECKPOINT_NAME in the workflow, that makes returning to it at a later stage of the current dialog a breeze. It can be referred to with ~ [CHECKPOINT_NAME], which redirects the flow to the checkpoint mark:

~ ask_howdy
< Hello stranger.
~ checkpoint_name
< How are you?
> meh
< So you feel bad huh
~ [checkpoint_name]

# Example of workflow working:

# < Hello stranger.
# < How are you?
# > meh
# < So you feel bad huh
# < How are you?
# > ...

▶️ Try this script on bubl.es

Both checkpoints and lists make working with conditional branches something really interesting:

= mood
- good
- meh
- great
- ok

= exceptions
- fantastic
- better than ever

~ ask_howdy
< hello stranger.
~ listen_howdy
< how are you?
? [mood]
---
  > meh
  < So you feel bad huh
  ~ [listen_howdy]
---
  > good
  < Oh, it is not bad ;)
  ~ [rechecker]
---
  > [exceptions]
  < Seems you really cool guy!
---
  > ok
  < Hmm, just ok? Okay then...
---
> great
< Nice! Let's continue then...

~ rechecker
< Maybe it is more than good?
> excellent
< Much better!

▶️ Try this script on bubl.es

It is also possible to use the "not equal" sign ! in conditional branching:

= mood
- [bad_mood]
- [good_mood]

= bad_mood
- meh
- bad

= good_mood
- great
- ok

~ ask_howdy
< hello stranger.
~ listen_howdy
< how are you?
? [mood]
---
  > ![mood]
  < I asked you how you are ; please let's start over with another answer?
  ~ [listen_howdy]
---
  > [good_mood]
  < Oh, it is awesome ;)
---
> [bad_mood]
< Hmm... bye then...

▶️ Try this script on bubl.es

Conditional branching also work well with scripts as long as a value is returned. If a script returns the value true, the corresponding branch will be activated. If all tests are false conditional branching will skip all branches and continue with the current workflow:

~ ask_for_email
> start email workflow
~ listen_email
< Your email please?
> *{email}
---
  ` !/^.+@.+\..+/.test('$email')
  < This email $email seems not legit!
  ~ [listen_email]
---
< Cool. We'll reach you over at $email

▶️ Try this script on bubl.es

Trigger

Triggers are a way for the bot to be integrated with an other program.

There are two types of events: standard events and custom events.

Standard events are as follow:

  • 'start'
  • 'patterns:set' with two String parameters: pattern name & value
  • 'match' with two String parameters: label, pattern
  • 'current-dialogue-start' with one String parameter: dialogueLabel
  • 'reply' with one String parameter: message
  • 'smart-replies' with one Array parameter: replies
  • 'current-dialogue-end' with one String parameter: dialogueLabel
  • 'variable:set' with two String parameters: variable name & value
  • 'quit'
  • '*' catches all the standard and custom events

Custom events can be triggered within dialogues.

A custom event must have a name.

It can have parameters. Parameters can rely on named variables.

@ trigger( 'EVENT_NAME' [, PARAMETER] )

Example:

> hello
< hi
@ trigger('said_hi')

Then handle the 'said_hi' event in your code according to your needs:

bot.on('said_hi', () => console.log('The bot said hi'));

Stanford TokensRegex

TokensRegex is a framework for defining advanced patterns based of priori Natural Language Processing such as Named Entities and Parts-of-Speech tagging.

> ([ner: PERSON]+) /was|is/ /an?/ []{0,3} /painter|artist/
< An accomplished artist you say.

This feature is enabled through code integration. See an example.

Natural Language Processing

NLP can be enabled through code integration. See an example.

Examples

See the examples/ directory.

Develop

Start the unit tests with:

npm test
npm run autotest  # this is for continuous testing

Use the CLI for trying botml scripts from the console:

node lib/cli.js
node lib/cli.js examples/echo.bot  # load script from a local file
debug=true node lib/cli.js  # add logging verbosity

In CLI mode, a few special commands can help with debugging too:

  • /stats
  • /inspect
  • /block
  • /activators
  • /current

Contribute

Feel free to dive in! Open an issue or submit PRs.

License

Botml is MIT licensed.

botml's People

Contributors

0xflotus avatar arnaud avatar codenametype avatar dependabot[bot] avatar totomakers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

botml's Issues

how to instance for multiple conversations?

if we have a bot where state is managed internally, eg for variables or current conversation topic, how can we deal with an app that has multiple conversations?
for example passing a userId in when the bot is instantiated?

const bot = new Botml('alice.bot')

or, some way to set the state before the parser is run, which would mean a way to get at the resulting botState after a message parse and then set that state before a new message parse, keeping track of the user:state table ourselves.

conditional logic problems

I made a simple "survey" type bot, but the conditionals logic doesn't seem to work like expected. .bot script is here:
https://github.com/dcsan/botml/blob/master/examples/survey.bot

I run it with
nodemon --ext js,bot lib/cli.js examples/survey.bot

~ survey
< OK lets go
~ [color]
~ [age]
# ~ [name]
# ~ [birthplace]
< OK thanks!
~ [status]

~ color
< What's your favorite color?
> *{color}
---
  > purple
  < Do you like Prince?
---
  > blue
  < Don't be sad!
---
< OK you like ${color}

but I get a result like this on running it:

< OK lets go
< What's your favorite color?
> red
< Do you like Prince?
>

how does 'return' work from conditionals?

sometimes when a conditional matches a response, the conversation will seem to return and continue.
but other times it does not. I can't quite figure out the logic.

given this example

on bubbles

~ start
< start
  [intro]
~ [colors]
~ [ending]

~ colors
< Whats your favorite color?
---
  > red
  < roses are red
---
  > blue
  < sky is blue
---
> *{color}
< you like $color

= intro
- Let's begin

~ ending
< Thanks and goodnight.

> reset
~ [start]

image

Load other .bot files

Is it possible to load other .bot files containing a workflow for example. I would like to create one mail file for my bot which will use workflows defined across different files which should be loaded at the beginning of the file.

For example :

! BOTML 1
[load file containing main-workflow]

# Bot

> Hi
~ main-workflow

Return bot reply to client side, instead of server side log

Testing hello.bot with a node.js app.

'askBot': function(command) { 
   var reply = bot.send(command); 
   return reply;
}

The app will receive command from client side, for example hi.

However, this server side method can only output the log, i.e.

INFO:  [botml] < Good day. What's your name?

How can I return the reply (Good day. What's your name?) back to client side?

Thanks.

Events get triggered only when the conversation is over

I'm trying to implement BotML in my Discord chat bot, but I ran into a problem with receiving bot responses. The thing is that events only get triggered when the conversation is over.

Using the hello.bot example:
When I send "Hi", I can see the bot responding with "Hi. What's your name?" in the console, but no event is triggered. Only when I respond to that message, the reply event gets triggered. I also tried other events and the same problem occurs.

Additionally, It would be nice if I could disable the CLI functionality in general, because I don't really want my console logs to be filled with bot conversations.

Does this support length wildcard???

Does this support length wildcard like superscript.js???
example:

+ hello *~2
- That is crazy!

● Matches Hello John Doe
● Does not match Hello John

+ hello *(2-4)

● Matches Hello John Doe and Hello John Dorian Doe
● Does not match Hello John

Lack of Documentation

I feel hard to understand the documentation (specially the regular expression). Please make the documentation more clear with live example (playground). And also include a demo bot. Thanks

design questions

this seems to be an interesting project... I've used Rivescript quite a lot and had some questions about your design, hope it's OK to raise as an issue for now.

topics

to get beyond a Q&A bot and have conversations, how does botML handle changing topics? Is that what workflows are for? Basically to group together triggers.

redirecting

Is there a way to "goto" another topic based on an input? ie to set the state of the bot

async replies

I guess this isn't there now, but to make the bot feel more human, how would you add something like a callback after 60 seconds "You still there?"

conditionals

any support for this in the script language? or would you drop down to JS functions?

Start bot from checkpoint or previous point

Is there a way or can there be a way to start a bot from a previous point in a conversation?
for example if I were storing responses and position, I would want to be able to set a bot to that state and continue

~ collect_name
> My name is *{name}
< Nice to meet you, $name

~ collect_email
< What is your email
> ${email}
< Great!
bot.set({name: 'bobby'})
bot.goto('collect_email')
bot.start()

licensing

Also, as per licensing, botml v1 is open source (MIT) so usable as-is in most situations, whereas botml v2 is copyrighted, with the software free to use in non-commercial projets; any commercial use of this version 2 needs a license, as per https://github.com/BotML/botml-js/blob/2.0-dev/LICENSE.txt

can you explain more your thoughts on this?

Ability to load script manually

It looks like it can only load from disk or urls.

Id really like to be able to generate the workflows from an application and load them into a bot directly

const Botml = require('botml')
const bot = new Botml()

bot.load(`
! BOTML 1

> Hello
< Hello human!
`.trim()
)
bot.start()

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.