Code Monkey home page Code Monkey logo

chatto's Introduction

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. Trivia Quiz - Type start to take a quick trivia quiz.

chatto's People

Contributors

camerondavison avatar jaimeteb avatar ryancurrah 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  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

chatto's Issues

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?

use internal directory for private apis

It's not clear which APIs should be public and which are private. We should move private APIs to the internal/ directory.

Internal packages
Go's package system makes it easy to structure programs into components with clean boundaries, but there are only two forms of access: local (unexported) and global (exported). Sometimes one wishes to have components that are not exported, for instance to avoid acquiring clients of interfaces to code that is part of a public repository but not intended for use outside the program to which it belongs.

The Go language does not have the power to enforce this distinction, but as of Go 1.4 the go command introduces a mechanism to define "internal" packages that may not be imported by packages outside the source subtree in which they reside.

To create such a package, place it in a directory named internal or in a subdirectory of a directory named internal. When the go command sees an import of a package with internal in its path, it verifies that the package doing the import is within the tree rooted at the parent of the internal directory. For example, a package .../a/b/c/internal/d/e/f can be imported only by code in the directory tree rooted at .../a/b/c. It cannot be imported by code in .../a/b/g or in any other repository.

rename extension.RegisteredFuncs

I think it would be clearer to rename extension.RegisteredFuncs to extension.RegisteredCommands or extension.RegisteredCommandFuncs.

This would make it more inline with the wording used throughout the bot.

use goreleaser for releases

We should use goreleaser for releases.

The following would probably need to change...

  • Change the Dockerfile to work with goreleaser.
  • Change Github actions to run gorleaser when a semver tag is created.

sender should be unique across channels

We should ensure the sender key we use to store the FSM into is unique across channels.

A very simplified example would be...

// Answer takes a user input and executes a transition on the FSM if possible
func (b *Bot) Answer(question *query.Question) ([]query.Answer, error) {
        sender := fmt.Sprintf("%s/%s", channelType, question.Sender).  # <----- Set a sender name based on channel and name?

	if !b.Store.Exists(sender) {
		b.Store.Set(sender, fsm.NewFSM())
	}

make chatto kubernetes friendly

There are a few nice things that we can add to make the chatto server friendly for Kubernetes usage.

  1. Use a prefix for env variables CHATTO_BOT and CHATTO_CHN. [x]
  2. Hot reload when configuration changes. [x]
  3. Provide an example deployment YAML. [x]
  4. Add a liveness/health check endpoint that does not require auth to the bot. [x]

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"

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

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?

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.

automatically get states and commands from transitions

We could make the fsm.yml configuration easier by determining the states and commands automatically from the transitions. It would be a matter of looping the transitions to enumerate each automatically. Below is an example fsm.yml with the proposed changes from the 01_test example.

initial_state: "off"

transitions:
  - from:
      - "off"
    into: "on"
    command: "turn_on"
    message: 
      - text: "Turning on."

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

  - from:
      - "any"
    into: "off"
    command: "hello_universe"
    extension: "any"

defaults:
  unknown: "Can't do that."
  unsure: "???"
  error: "Error"

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.