Chatto is a minimal chatbot framework in Go.

Documentation codecov Go Report Card GoDoc Docker Image Version (latest by date)


chatto

botto

Simple chatbot framework written in Go, with configurations in YAML. The aim of this project is to create very simple text-based chatbots using a few configuration files.

The inspiration for this project originally came from Flottbot and my experience using Rasa.

demo

Contents

Installation

go get -u github.com/jaimeteb/chatto

Via Docker:

docker pull jaimeteb/chatto:latest

Documentation

See the Documentation for examples, configuration guides and reference.

docs

Your first bot

Chatto combines the consistency of a finite-state-machine with the flexibility of machine learning. It has three main components: the classifier, the finite-state-machine and the extensions.

A very basic directory structure for Chatto would be the following:

.
└──data
   ├── clf.yml
   └── fsm.yml

Start by creating the data directory as well as the YAML files.

mkdir data
touch data/clf.yml data/fsm.yml

The clf.yml file

The clf.yml file defines how the user messages will be classified into commands (intents). Start with this very simple configuration:

classification:
  - command: "turn_on"
    texts:
      - "turn on"
      - "on"

  - command: "turn_off"
    texts:
      - "turn off"
      - "off"

The fsm.yml file

The fsm.yml file defines the transitions between states, the commands that make these transitions, and the answers to be sent in them. Start with this file contents:

transitions:
  - from:
      - "initial"
    into: "on"
    command: "turn_on"
    answers:
      - text: "Turning on."

  - from:
      - "on"
    into: "initial"
    command: "turn_off"
    answers:
      - text: "Turning off."
      - text: ""

defaults:
  unknown: "Can't do that."

Run your first bot

To start your bot, run:

chatto --path data/

If you're using Docker, run:

docker run \
    -it \
    -e CHATTO_DATA=./data \
    -v $PWD/data:/data \
    jaimeteb/chatto:latest \
    chatto --path data

Interact with your first bot

To interact with your bot, run:

chatto cli

That's it! Now you can say turn on or on to go into the on state, and turn off or off to go back into initial. However, you cannot go from on into on, or from initial into initial either.

Here is a diagram for this simple Finite State Machine:

ON/OFF Finite State Machine

Usage

You can integrate your bot with Telegram, Twilio, Slack and anything you like

Run chatto in the directory where your YAML files are located, or specify a path to them with the --path flag:

chatto --path ./your/data

To run on Docker, use:

docker run \
  -p 4770:4770 \
  -e CHATTO_DATA=./your/data \
  -v $PWD/your/data:/data \
  jaimeteb/chatto

CLI

You can use the Chatto CLI tool by downloading the chatto cli tool. The CLI makes it easy to test your bot interactions.

chatto cli --url 'http://mybot.com' -port 4770

Docker Compose

You can use Chatto on Docker Compose as well. A docker-compose.yml would look like this:

version: "3"

services:
  chatto:
    image: jaimeteb/chatto:${CHATTO_VERSION}
    env_file: .env
    ports:
      - "4770:4770"
    volumes:
      - ${CHATTO_DATA}:/data
    depends_on:
      - ext
      - redis

  ext:
    image: odise/busybox-curl # Busy box with certificates
    command: ext/ext
    expose:
      - 8770
    volumes:
      - ${CHATTO_DATA}/ext:/ext

  redis:
    image: bitnami/redis:6.0
    environment:
      - REDIS_PASSWORD=${STORE_PASSWORD}
    expose:
      - 6379

This requires a .env file to contain the necessary environment variables:

# Chatto configuration
CHATTO_VERSION=latest
CHATTO_DATA=./your/data

# Extension configuration
CHATTO_BOT_EXTENSIONS_EXTENSION_NAME_URL=http://ext:8770

# Redis
CHATTO_BOT_STORE_HOST=redis
CHATTO_BOT_STORE_PASSWORD=pass

# Logs
CHATTO_BOT_DEBUG=true

The directory structure with all the files would look like this:

.
├── data
│   ├── ext
│   │   ├── ext
│   │   └── ext.go
│   ├── bot.yml
│   ├── chn.yml
│   ├── clf.yml
|   └── fsm.yml
├── docker-compose.yml
└── .env

Finally, run:

docker-compose up -d redis ext
docker-compose up -d chatto

The extensions server has to be executed according to its language.

For this docker-compose.yml file, you'd have to build the Go extension first:

go build -o data/ext/ext data/ext/ext.go

The extensions server has to be running before Chatto initializes.

Kubernetes

Under the deploy/kubernetes directory you can find an example deployment:

Kind Name Description
Secret chatto-config-secrets Contains the tokens that Chatto will use for authorization
ConfigMap chatto-config-envs Contains the environment variables for the bot.yml file
ConfigMap chatto-config-files Contains the clf.yml and fsm.yml file
Deployment chatto Chatto deployment based on the jaimeteb/chatto Docker image
Service chatto-service Service for the chatto deployment
Ingress chatto-ingress Ingress for the chatto-service service

Run the following command to deploy on Kubernetes:

kubectl apply -f ./deploy/kubernetes/

Import

An importable bot server and client package is provided to allow embedding into your own application.

To embed the server:

package main

import (
	"flag"

	"github.com/jaimeteb/chatto/bot"
)

func main() {
	port := flag.Int("port", 4770, "Specify port to use.")
	path := flag.String("path", ".", "Path to YAML files.")
	flag.Parse()

	server := bot.NewServer(*path, *port)

	server.Run()
}

To embed the client:

package myservice

import (
	"log"

	"github.com/jaimeteb/chatto/bot"
)

type MyService struct {
	chatto bot.Client
}

func NewMyService(url string, port int) *MyService {
	return &MyService{chatto: bot.NewClient(url, port)}
}

func (s *MyService) Submit(question *query.Question) error {
	answers, err := s.chatto.Submit(question)
	if err != nil {
		return err
	}

	// Print answers to stdout
	for _, answer := range answers {
		fmt.Println(answer.Text)
	}

	return nil
}

Examples

I have provided some config files under examples. Clone the repository and run chatto with the -path of your desired example to test them out (for the ones that use extensions, run their respective extensions first).

More about these examples in the Documentation

  1. Mood Bot - A chatto version of Rasa's Mood Bot Greet the bot to start the conversation.
  2. Pokemon Search - Search for Pokémon by name or number.
  3. Miscellaneous Bot - Weather forecast, random jokes and quotes, and more!
  4. Trivia Quiz - Type start to take a quick trivia quiz.
Owner
Jaime Tenorio
Mechatronics Engineer with a career in Software Development and Machine Learning. Made in Mexico. 🇲🇽
Jaime Tenorio
Comments
  • initial support of slack socket mode - refactor

    initial support of slack socket mode - refactor

    I played around with the Slack integration what I was looking for is to use socket mode so we don't have to expose this chat bot to the internet. Here is my WIP.

  • refactor: use internal directory for private apis

    refactor: use internal directory for private apis

    Use internal dir for private APIs while improving the public APIs for consumption. Also adding more tests. https://github.com/jaimeteb/chatto/issues/8

  • feat: k8s example deployment with some goodies

    feat: k8s example deployment with some goodies

    If the FSM and CLF configs change chatto will auto-reload them. Set consistent env var names. Added an example deployment. Allow setting debug through env var.

    Resolves https://github.com/jaimeteb/chatto/issues/35

  • more complicated example?

    more complicated example?

    A more complicated example, for instance, we want a robot that can solve some basic functions like what's the weather today? Tell me a joke, do u know how is the tallest man in the world, how to combines all these intent into a full example?

  • feat: allow using multiple extension servers

    feat: allow using multiple extension servers

    This feature allows using multiple extension servers. If connecting to an extension fails, an error will be logged instead of killing the Chatto server. That way, if an extension is not running, Chatto can still operate.

    It is key to note that in this solution, we cannot have duplicate extension names. If two extension servers provide the same extension name Chatto will error out on startup. This could cause a denial of service. I am going to think 🤔 this one through, not sure I like it causing Chatto to fatally error out.

    Resolves https://github.com/jaimeteb/chatto/issues/27

    • EDIT (Monday, March, 8th - 9:35AM EST)

    One thought I had was to require extensions to have a namespace associated to them. This would allow duplicate extension commands without naming collisions. As each command would be in it's own extension namespace.

    bot.yml

    extensions:
      pokemon:
        type: RPC
        host: 127.0.0.1
        port: 9001
      weather:
        type: REST
        url: http://127.0.0.1
        port: 8080
    

    fsm.yml config option 1 with a dot notation of <extension_name>.<extension_command>

    transitions:
       - from:
          - search_pokemon
         into: initial
         command: any
         slot:
           name: pokemon
           mode: whole_text
         extension: pokemon.search_pokemon
    

    OR

    fsm.yml config option 2 with a dictionary of name and command

    transitions:
      - from:
          - search_pokemon
        into: initial
        command: any
        slot:
          name: pokemon
          mode: whole_text
        extension:
          name: pokemon
          command: search_pokemon
    

    I kind of prefer the later, option 2. The reason for that is, is if we need to expand the extension options for the fsm later it would not be a breaking change.

  • feat: detect commands and states from transitions

    feat: detect commands and states from transitions

    This feature removes the need to define the commands and states in the FSM config. The FSM will now automatically determine these values from transitions. To further simplify things I the first state is now 'initial' always. This should clarify when writing FSM transitions that everyone knows what the 'initial' state name is. Similar to how nice the 'any' state is.

    Resolves https://github.com/jaimeteb/chatto/issues/36

  • Refactor - Rename and reorganize

    Refactor - Rename and reorganize

    Rename and reorganize fsm.yml to make transitions more intuitive to write. Rename "command functions" to only "extensions" to avoid confusion between Classifier's commands (which are NLU intents) and extensions run in an Extension Server.

  • refactor: add version endpoint to REST and RPC extensions

    refactor: add version endpoint to REST and RPC extensions

    Also match the wording used by fsm for function commands in extensions. Changed endpoint URLs to match wording as well.

    https://github.com/jaimeteb/chatto/issues/22

  • ability to transition from multiple states

    ability to transition from multiple states

    Add ability to transition from multiple states not just any.

    functions:
      - transition:
          from:
            - "gomodules"
            - "goreleaser"
          into: "initial"
        command: "thanks"
        message:
          - text: ":thumbsup: no problem-o"
    
  • feat: use github actions to release on tags

    feat: use github actions to release on tags

    When a tag is created github actions will publish docker images and github releases. Also added golangci-lint and unittest action.

    https://github.com/jaimeteb/chatto/issues/9

  • Read all states / Use `time.Duration` for time configurations

    Read all states / Use `time.Duration` for time configurations

    • Register states from transitions' from and into states, for cases where a state can only be reached via extensions.

    • Use time.Duration for:

      • Store TTL and Purge times.
      • Channel delays.

      Now these times can be specified as:

      # milliseconds
      delay: 300ms
      # seconds
      delay: 5s
      # minutes
      delay: 1m
      # etc...
      
  • configure classifiers and transitions from extensions

    configure classifiers and transitions from extensions

    When connecting to an extension server it would awesome if we could send the bot our own classifiers and transitions. This would allow us to programmatically generate questions and answers.

    An example where this would be used is the company I work at. We have an internal StackOverflow site. We could write an extension that gets all the questions and answers from that site and generate classifiers and transitions and register them with the bot.

    It would be super powerful for automatically training the bot to respond to questions with a set of predefined answers from other tools.

  • feat: initial stab at a swagger spec for extension server

    feat: initial stab at a swagger spec for extension server

    Ok, I have an initial swagger spec that we can use to generate server implementations for multiple languages. https://github.com/jaimeteb/chatto/issues/24

    View the Swagger Doc here: https://app.swaggerhub.com/apis/ryancurrah/chatto-extension/1.0.0

    Generated server stubs:

    1. python-flask-server-generated.zip
    2. nodejs-server-server-generated.zip
  • Porting the extension module to other languages?

    Porting the extension module to other languages?

    Hi there! I have had some success following your docs to stand up a Flask app that roughly supports the restful extension API. Very cool project, thank you.

    I couldn't help but be a bit jealous of the Go examples being able to just import extension and run with it.

    I'd like to help make this more accessible for would-be Python, Ruby, JS, etc. bot authors. @jaimeteb have you or @ryancurrah plotted a way to give the rest server API a quicker onramp?

    I've thought about maybe building a python library to abstract a few of the basic bits of the Flask use case, but maybe a swagger-oriented codegen approach could cover more ground with less work. I haven't yet tried the RPC model so I imagine it's got some implications for potential approaches to bootstrapping new REST integrations..

  • rethink how we expose the fsm to extensions

    rethink how we expose the fsm to extensions

    I’ve been thinking about the FSM.Domain and how we pass it to extensions. When I did the internal refactor I felt like FSM package should be a private API.

    Maybe the bot should have some REST APIs for the extension to work with FSM with some safeguards in place. Instead of directly sending the FSM.Domain to the extension. I do feel like this make it less complex for developing new extensions so the extension author does not need to learn how to work with the FSM directly.

    Thoughts?

FactoriGOChatBot - A Discord chatbot for Factorio written in Golang

FactoriGOChatBot A Discord chatbot for Factorio written in Golang This bot will

Oct 16, 2022
Simple yet customizable bot framework written in Go.
Simple yet customizable bot framework written in Go.

Introduction Sarah is a general-purpose bot framework named after the author's firstborn daughter. This comes with a unique feature called "stateful c

Dec 12, 2022
Golang Framework for writing Slack bots

hanu - Go for Slack Bots! The Go framework hanu is your best friend to create Slack bots! hanu uses allot for easy command and request parsing (e.g. w

Oct 24, 2022
Telegram Bot Framework for Go

Margelet Telegram Bot Framework for Go is based on telegram-bot-api It uses Redis to store it's states, configs and so on. Any low-level interactions

Dec 22, 2022
Slack Bot Framework

slacker Built on top of the Slack API github.com/slack-go/slack with the idea to simplify the Real-Time Messaging feature to easily create Slack Bots,

Dec 25, 2022
Slack bot core/framework written in Go with support for reactions to message updates/deletes
Slack bot core/framework written in Go with support for reactions to message updates/deletes

Overview Requirements Features Demo The Name Concepts Create Your Own Slackscot Assembling the Parts and Bringing Your slackscot to Life Configuration

Oct 28, 2022
Telebot is a Telegram bot framework in Go.

Telebot "I never knew creating Telegram bots could be so sexy!" go get -u gopkg.in/tucnak/telebot.v2 Overview Getting Started Poller Commands Files Se

Dec 30, 2022
Parr(B)ot is a Telegram bot framework based on top of Echotron

Parr(B)ot framework A just born Telegram bot framework in Go based on top of the echotron library. You can call it Parrot, Parr-Bot, Parrot Bot, is up

Aug 22, 2022
Automated Trader (at). Framework for building trading bots.
Automated Trader (at). Framework for building trading bots.

Automated Trader (at) Purpose: Framework for building automated trading strategies in three steps: Build your own strategy. Verify it with the backtes

Dec 14, 2022
Gort is a chatbot framework designed from the ground up for chatops.
Gort is a chatbot framework designed from the ground up for chatops.

Gort Gort is considered "minimally viable", but is still a work in progress under active heavy development. Follow for updates! Gort is a chatbot fram

Dec 21, 2022
Go Wechaty is a Conversational SDK for Chatbot Makers Written in Go
Go Wechaty is a Conversational SDK for Chatbot Makers Written in Go

go-wechaty Connecting Chatbots Wechaty is a RPA SDK for Wechat Individual Account that can help you create a chatbot in 6 lines of Go. Voice of the De

Dec 30, 2022
A small chatbot for ssh-chat

ssh-chat-bot A small chatbot for ssh-chat. Installation go get -u github.com/sechanakira/ssh-chat-bot You can also clone the repo and then run make in

Nov 25, 2021
FactoriGOChatBot - A Discord chatbot for Factorio written in Golang

FactoriGOChatBot A Discord chatbot for Factorio written in Golang This bot will

Oct 16, 2022
A minimal framework to build web apps; with handler chaining, middleware support; and most of all standard library compliant HTTP handlers(i.e. http.HandlerFunc).
A minimal framework to build web apps; with handler chaining, middleware support; and most of all standard library compliant HTTP handlers(i.e. http.HandlerFunc).

WebGo v4.1.3 WebGo is a minimalistic framework for Go to build web applications (server side) with zero 3rd party dependencies. Unlike full-fledged fr

Jan 1, 2023
Minimal and Beautiful Go testing framework
Minimal and Beautiful Go testing framework

Goblin A Mocha like BDD testing framework written in Go that requires no additional dependencies. Requires no extensive documentation nor complicated

Dec 25, 2022
7 days golang programs from scratch (web framework Gee, distributed cache GeeCache, object relational mapping ORM framework GeeORM, rpc framework GeeRPC etc) 7天用Go动手写/从零实现系列

7 days golang programs from scratch README 中文版本 7天用Go从零实现系列 7天能写什么呢?类似 gin 的 web 框架?类似 groupcache 的分布式缓存?或者一个简单的 Python 解释器?希望这个仓库能给你答案

Jan 5, 2023
Minimal cgo bindings for libenca

enca This is a minimal cgo bindings for libenca. If you need to detect the language of a string you can use guesslanguage package. Supported Go versio

Nov 6, 2022
Minict is a minimal container runtime written in Go.

Minict Minict is a minimal container runtime written in Go. It was made mainly for learning purposes and is intended to be as simple as possible.

Oct 31, 2022
Minimal UART client in Golang that dumps LPC1343 chips that are locked at CRP1.

Howdy y'all, This is a quick and dirty client for the UART bootloader of the LPC1343, and probably other bootloaders in that chip family. This client

Dec 2, 2022
Minimal and idiomatic WebSocket library for Go

websocket websocket is a minimal and idiomatic WebSocket library for Go. Install go get nhooyr.io/websocket Highlights Minimal and idiomatic API First

Dec 30, 2022