Introduction

flowdown is a minimal markup language for writing conversations, specifically for the voiceflow platform. It can be thought of a 'voiceflow programming language' of sorts.

The fundamental guiding principles of flowdown are as follows:

  • writing a conversation should be 'text' first, meaning that any functionality should be built as syntax around the dialogue.
  • a conversation should read as it flows - control flow should be obvious to follow and syntax should not be cryptic
  • conversations should be fun to write and not at all tedious!

Also please note that flowdown is very much still a prototype. It lacks many essential features and also may be buggy. If you run into any issues or have feedback, please leave an issue in the github repo.

Getting Started

Installation

You can get the binary from the github release. Currently M1 macos and linux are supported. Simply unzip the files, make the binary executable and place it somewhere in your path.

Installation example for linux

$ wget https://github.com/MrPicklePinosaur/flowdown/releases/download/v0.1/fdc-linux-v0.1.zip
$ unzip fdc-linux-v0.1.zip
$ chmod +x fdc
$ mv fdc /usr/local/bin

Installation example for macos

$ wget https://github.com/MrPicklePinosaur/flowdown/releases/download/v0.1/fdc-macos-v0.1.zip
$ unzip fdc-linux-v0.1.zip
$ chmod +x fdc
$ mv fdc /usr/local/bin

Packaging for various platforms may or may not be coming in the future.

Hello World Conversation

Let's compile a basic hello world conversation. The most basic flowdown file is just a single utterance.

$ echo 'Hello world' > hello.fd
$ fdc -o hello.vf hello.fd

Import to Voiceflow

To be able to run the compiled voiceflow conversation, you will need an account on the voiceflow platform.

Once you are setup, navigate to your dashboard and locate the import button on the top right corner.

import button

Select and upload the compiled hello.vf file, and you should see the project appear in your dashboard. Running our project, we get our first compiled conversation!

run conversation

Developer Tools

An important aspect of a language is not just the language itself, but also the ecosystem and set of tools around the language to make development fun and productive. Here are some developer tool (prototypes) that are included.

Vim

A vim plugin with syntax highlighting can be installed with the following (for vim-plug users)

Plug 'MrPicklePinosaur/flowdown', { 'rtp': 'tools/vim' }

Vscode

Vscode extension is coming soon...

Syntax

This section will highlight the syntax of flowdown.

Utterances

The most basic 'program' is just text:

hello world!

Curly braces represent special text actions, we will break down a couple. Firstly, variables can be incorporated by prefixing an identifier with a dollar sign

hello {$name}, nice to meet you!

We can introduce variations on the text by using the pipe | character. This will generate all the appropriate utterance variations for you.

{what can I get for|how can i help} you today?

Comments

Single line comments supported with (//) and multi line comments with (/* */)

Tones and Voices

You can control how the voice assistant outputs the utterance with tone indicators. For example, the voice that is used to say the utterance can be specified.

hello I am the default voice
hello I am a japanese voice # ja-JP-standard-A 

Commands

Commands are actions that we wish to take that are external to the conversation. These should read similar to stage directions in a script. A good way to think of commands are as 'side effects'. Most (if not all) voiceflow blocks for voice assistants are implemented:

Audio

The audio file is provided as a url.

please wait a moment...
[audio https://audio.com/mysound.wav]

Image

Similar to the audio command, takes in an image url to display.

here's a cool picture
[image https://coolpic.com/image.png]

Code

A javascript file can be passed in. It's path is relative to the flowdown file.

got it! placing an order for you right now!
[code placeOrder.js]

Exit

Immediately terminate the program

goodbye!
[end]

Capture

Prompt user and capture entire result to variable

what's your name?
[capture $firstName]

Set

Update or define variable.

[set $name "daniel"]

Dialog and Bookmarks

A fundamental part of writing readable conversations is the ability to break apart conversations into reusable and contained pieces. In the canvas, this is accomplished by topics and flows.

Topics allow us to move intent triggers into it's own section (no functional difference other than organization), whereas flows resemble function calls, allowing us to package up reusable logic.

In flowdown, we have dialogs and bookmarks.

Dialogs

Dialogs are analogous to function calls, they allow us to define reusable blocks of dialog that we can jump to from anywhere.

this is the main dialog

@ welcome

hello welcome to my store!

@ about

my store sells a lot of things

@ contact

contact me!

The output is as follows

> this is the main dialog

Notice how the other dialogs aren't executed. A flowdown conversation has an implicit main dialog before any dialogs are declared. It's also the entry point into the conversation.

Dialogs can be jumped to by using the -> operator like so:

this is the main dialog
-> @welcome

@ welcome
this is the welcome dialog
-> about

@ about
this is the about dialog

And our output will be:

> this is the main dialog
> this is the welcome dialog
> this is the about dialog

When a dialog ends, we entire terminate (if top level dialog), or we return control to the caller.

enter layer1
-> @layer2
exit layer1

@ layer2

    enter layer2
    -> @layer3
    exit layer2

@ layer 3

    enter layer3
    exit layer3

This will output

> enter layer1
> enter layer2
> enter layer3
> exit layer3
> exit layer2
> exit layer1

Bookmarks

Bookmarks are quite like html header links. They give us an anchor to jump to, but don't offer any containment, when the next bookmark starts, we will start executing it. Bookmarks are specifed by using an equal sign (=) followed by a name for the bookmark. We can jump to bookmarks by using the -> operator again, but this time we do not prefix the identifier with an @ sign.

@ self intro

    my name is pinosaur

    ok we don't actually care about backstory lol
    -> present day

    = backstory
    i have been making stores for over 20 years

    = present day
    i am currently making a store

    = future

    i will continue making stores

output:

> my name is pinosaur
> ok we don't actually care about backstory lol
> i am currently making a store
> i will continue making stores

And of course, bookmarks are scoped, they are local to a dialog.

@ dialog 1

    jump to:
    -> bookmark 3 // this will error

    = bookmark 1

    = bookmark 2

@ dialog 2

    = bookmark 2

    = bookmark 3

Control Flow

Simple control flow can be modified using the choice construct. You can think of each choice line as an if-statement. If the condition before the : is true, the statement will be executed. Note that only one statement is supported after a condition. If you need a more involved branch, use a dialog and jump to it, as shown in the 'red' case.

What's your favorite color?
[capture $color]
* $color == "red": -> @red
* $color == "blue": [audio blue_da_ba_dee.wav]
* $color == "green": i guess green is an ok color...

@ red
yay, my favorite color is red too!

Intents (WIP)

Currently not implemented.

Intents are almost to how topics work, we simply mark the topic with intent: and that block can be jumped to from any [listen] command (they behave like normal topics otherwise).

hello, how can i help you today?
[listen]

@ intent: check balance
...

@ intent: deposit money
...

@ intent: withdraw money
...

Examples

This section will provide a couple of example programs to get you started.

Hello World

The most basic flowdown conversation is just plain text. Each line is one utterance that is spoken by the assistant.

In my younger and more vulnerable years my father gave me some advice that I've been turning over in my mind ever since.

'Whenever you feel like criticizing any one,' he told me,

'just remember that all the people in this world haven't had the advantages that you've had.'

Custom Code

You can provide code snippets for code blocks. Just ensure that the location of the source code is relative to the flowdown file. Note that you need to forward declare any variables if the script introduces them.

// dToF.fd
Input temperature
[capture $temperature]
[set $converted "0"]
[code convert.js]

temperature in fahrenheight is {$converted}
// convert.js

// all variables are strings (for now)
const _temp = parseInt(temperature);
converted = (9/5 * _temp) + 32;

Full Example

This example uses most of the supported features in flowdown. It walks through a simple pizzeria customer service experience.

Hello! Welcome to Flowdown Pizzaria, what can I do for you?
[capture $mode]
* $mode == "order pizza": -> @order
* $mode == "menu": [image https://flowdownpizza/menu.png]

@ order

    What type of pizza would you like?
    [capture $pizzaType]

    What size of pizza?
    [capture $pizzaSize]

    How would you like to recieve your pizza?
    [capture $pizzaMethod]
    * $pizzaMethod == "delivery": -> @delivery
    * $pizzaMethod == "take out": -> @take out

    Thank you for choosing Flowdown Pizzaria!
    -> @survey

@ delivery

    Can I get an address
    [capture $address]

    [set $price "0"]
    [set $deliveryTime "0"]
    [code calculatePrice.js]
    [code computeDeliveryRoute.js]

    Your final price is {$price} and you will get your pizza in about {$deliveryTime}! 

@ take out

    When would you like to pick up your food?
    [capture $pickupTime]

    [set $price "0"]
    [code calculatePrice.js]

    Your final price is {$price}.

@ survey

    Would you like to complete an optional survey?
    [capture $survey]
    * $survey == "yes": -> start survey
    * $survey == "no": -> end survey

    = start survey

        How would you rate today's experience?
        [capture $rating]

        Is there any feedback you would like to give?
        [capture $feedback]

    = end survey

        Thank you!