{"id":13601665,"url":"https://github.com/asticode/go-astibob","last_synced_at":"2025-10-23T07:59:16.412Z","repository":{"id":57500423,"uuid":"115250368","full_name":"asticode/go-astibob","owner":"asticode","description":"Golang framework to build an AI that can understand and speak back to you, and everything else you want","archived":false,"fork":false,"pushed_at":"2020-01-08T16:26:14.000Z","size":1612,"stargazers_count":244,"open_issues_count":0,"forks_count":20,"subscribers_count":20,"default_branch":"master","last_synced_at":"2025-10-12T07:16:57.624Z","etag":null,"topics":["audio","go","golang","speech-to-text","text-to-speech"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/asticode.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-12-24T08:38:16.000Z","updated_at":"2025-09-10T13:17:04.000Z","dependencies_parsed_at":"2022-08-30T20:51:32.244Z","dependency_job_id":null,"html_url":"https://github.com/asticode/go-astibob","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/asticode/go-astibob","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asticode%2Fgo-astibob","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asticode%2Fgo-astibob/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asticode%2Fgo-astibob/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asticode%2Fgo-astibob/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/asticode","download_url":"https://codeload.github.com/asticode/go-astibob/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/asticode%2Fgo-astibob/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":280583894,"owners_count":26355258,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-23T02:00:06.710Z","response_time":142,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["audio","go","golang","speech-to-text","text-to-speech"],"created_at":"2024-08-01T18:01:05.950Z","updated_at":"2025-10-23T07:59:16.392Z","avatar_url":"https://github.com/asticode.png","language":"Go","readme":"[![GoReportCard](http://goreportcard.com/badge/github.com/asticode/go-astibob)](http://goreportcard.com/report/github.com/asticode/go-astibob)\n[![GoDoc](https://godoc.org/github.com/asticode/go-astibob?status.svg)](https://godoc.org/github.com/asticode/go-astibob)\n\nGolang framework to build an AI that can understand and speak back to you, and everything else you want.\n\nWARNING: the code below doesn't handle errors for readability purposes, however you SHOULD!\n\n# Demos\n\nHere's a list of AIs built with `astibob` (if you're using `astibob` and want your project to be listed here, please submit a PR):\n\n- [Official demos](https://github.com/asticode/go-astibob-demos)\n\n# How it works\n\n## Overview\n\n![Overview](imgs/overview.png)\n\n- humans operate the AI through the **Web UI**\n- the **Web UI** interacts with the AI through the **Index**\n- the **Index** keeps an updated list of all **Workers** and forwards **Web UI** messages to **Workers** and vice versa\n- **Workers** have one or more **Abilities** and are usually located on different machines\n- **Abilities** run simple tasks such as reading an audio input (e.g. a microphone), executing speech-to-text analyses or doing speech-synthesis\n- **Abilities** can communicate directly between each other even if on different **Workers**\n- all communication is done via JSON messages exchanged through HTTP or Websocket\n\n## FAQ\n\n- Why split abilities between several workers?\n\n    Because abilities may need to run on different machines located in different part of the world. The simplest example is wanting to read microphones inputs located in several rooms of your house. Each microphone is an ability whereas each room of your house is a worker.\n\n# Install the project\n\nRun the following command:\n\n```\n$ go get -u github.com/asticode/go-astibob/...\n```\n\n# I want to see some code\n\n## Index\n\n```go\n// Create index\ni, _ := index.New(index.Options{\n    Server: astibob.ServerOptions{\n        Addr:     \"127.0.0.1:4000\",\n        Password: \"admin\",\n        Username: \"admin\",\n    },\n})\n\n// Make sure to properly close the index\ndefer i.Close()\n\n// Handle signals\ni.HandleSignals()\n\n// Serve\ni.Serve()\n\n// Blocking pattern\ni.Wait()\n```\n\n## Worker\n\n```go\n// Create worker\nw := worker.New(\"Worker #1\", worker.Options{\n    Index: astibob.ServerOptions{\n        Addr:     \"127.0.0.1:4000\",\n        Password: \"admin\",\n        Username: \"admin\",\n    },\n    Server: astibob.ServerOptions{Addr: \"127.0.0.1:4001\"},\n})\n\n// Make sure to properly close the worker\ndefer w.Close()\n\n// Create runnables\nr1 := pkg1.NewRunnable(\"Runnable #1\")\nr2 := pkg2.NewRunnable(\"Runnable #2\")\n\n// Register runnables\nw.RegisterRunnables(\n\tworker.Runnable{\n        AutoStart: true,\n        Runnable:  r1,\n    },\n\tworker.Runnable{\n        Runnable:  r2,\n    },\n)\n\n// Create listenables\nl1 := pkg3.NewListenable(pkg3.ListenableOptions{\n\tOnEvent1: func(arg1 string) { log.Println(arg1) },\n})\nl2 := pkg4.NewListenable(pkg4.ListenableOptions{\n\tOnEvent2: func(arg2 string) { log.Println(arg2) },\n})\n\n// Register listenables\nw.RegisterListenables(\n\tworker.Listenable{\n        Listenable: l1,\n        Runnable:   \"Runnable #1\",\n        Worker:     \"Worker #1\",\n    },\n\tworker.Listenable{\n        Listenable: l2,\n        Runnable:   \"Runnable #3\",\n        Worker:     \"Worker #2\",\n    },\n)\n\n// Handle an event and send a message to one of the runnables\nw.On(astibob.DispatchConditions{\n    From: astibob.NewRunnableIdentifier(\"Runnable #1\", \"Worker #1\"),\n    Name: astikit.StrPtr(\"Event #1\"),\n}, func(m *astibob.Message) (err error) {\n    // Send message\n    if err = w.SendMessages(\"Worker #1\", \"Runnable #1\", pkg2.NewMessage1(\"Hello world\")); err != nil {\n        err = errors.Wrap(err, \"main: sending message failed\")\n        return\n    }\n    return\n})\n\n// Handle signals\nw.HandleSignals()\n\n// Serve\nw.Serve()\n\n// Register to index\nw.RegisterToIndex()\n\n// Blocking pattern\nw.Wait()\n```\n\n# Abilities\n\nThe framework comes with a few abilities located in the `abilities` folder:\n\n- [Audio input](#audio-input)\n- [Speech to Text](#speech-to-text)\n- [Text to Speech](#text-to-speech)\n\n## Audio input\n\nThis ability allows you reading from an audio stream e.g. a microphone.\n\n### Dependencies\u003ca name='audio-input-dependencies'\u003e\u003c/a\u003e\n\nIt's strongly recommended to use [PortAudio](http://www.portaudio.com) and its [astibob wrapper](abilities/audio_input/portaudio).\n\nTo know which devices are available on the machine run:\n\n```\n$ go run abilities/audio_input/portaudio/cmd/main.go\n```\n\n### Runnable and operatable\n\n```go\n// Create portaudio\np := portaudio.New()\n\n// Initialize portaudio\np.Initialize()\n\n// Make sure to close portaudio\ndefer p.Close()\n\n// Create default stream\ns, _ := p.NewDefaultStream(portaudio.StreamOptions{\n    BitDepth:             32,\n    BufferLength:         5000,\n    MaxSilenceLevel:      5 * 1e6,\n    NumInputChannels:     2,\n    SampleRate:           44100,\n})\n\n// Create runnable\nr := audio_input.NewRunnable(\"Audio input\", s)\n\n// Register runnables\nw.RegisterRunnables(worker.Runnable{\n    AutoStart: true,\n    Runnable:  r,\n})\n\n// Register listenables\n// This is mandatory for the Web UI to work properly\nw.RegisterListenables(worker.Listenable{\n    Listenable: r,\n    Runnable:   \"Audio input\",\n    Worker:     \"Worker #1\",\n})\n```\n\n### Listenable\n\n```go\n// Register listenables\nw.RegisterListenables(\n    worker.Listenable{\n        Listenable: audio_input.NewListenable(audio_input.ListenableOptions{\n            OnSamples: func(from astibob.Identifier, samples []int, bitDepth, numChannels, sampleRate int, maxSilenceLevel float64) (err error) {\n                // TODO Do something with the samples\n                return\n            },\n        }),\n        Runnable: \"Audio input\",\n        Worker:   \"Worker #1\",\n    },\n)\n```\n\n## Speech to Text\n\nThis ability allows you to execute speech-to-text analyses.\n\n### Dependencies\u003ca name='speech-to-text-dependencies'\u003e\u003c/a\u003e\n\nIt's strongly recommended to install [DeepSpeech](https://github.com/mozilla/DeepSpeech) and its [astibob wrapper](abilities/speech_to_text/deepspeech).\n\n#### I don't want to train a new model\n\n- create a working directory (for simplicity purposes, we'll assume its absolute path is `/path/to/deepspeech`)\n- download a client `native_client.\u003cyour system\u003e.tar.xz\"` matching your system at the bottom of [this page](https://github.com/mozilla/DeepSpeech/releases/tag/v0.5.1)\n- create the `/path/to/deepspeech/lib` directory and extract the `client` content inside it\n- create the `/path/to/deepspeech/include` directory and download [deepspeech.h](https://github.com/mozilla/DeepSpeech/raw/v0.5.1/native_client/deepspeech.h) inside it\n- create the `/path/to/deepspeech/model/en` directory, and download and extract [the english model](https://github.com/mozilla/DeepSpeech/releases/download/v0.5.1/deepspeech-0.5.1-models.tar.gz) inside it\n- whenever you run a worker that needs `deepspeech`, make sure to have the following environment variables:\n\n        CGO_CXXFLAGS=\"-I/path/to/deepspeech/include\"\n        LIBRARY_PATH=/path/to/deepspeech/lib:$LIBRARY_PATH\n        LD_LIBRARY_PATH=/path/to/deepspeech/lib:$LD_LIBRARY_PATH\n    \n#### I want to train a new model\n\nIn addition to the steps above:\n\n- create the `/path/to/deepspeech/model/custom` directory\n- run `git clone https://github.com/mozilla/DeepSpeech` inside `/path/to/deepspeech`\n- [install the dependencies](https://github.com/mozilla/DeepSpeech#training-your-own-model)\n\n### Runnable and Operatable\n\n```go\n// Create deepspeech\nmp := \"/path/to/deepspeech/model/en\"\nd := deepspeech.New(deepspeech.Options{\n    AlphabetPath:   mp + \"/alphabet.txt\",\n    BeamWidth:      1024,\n    ClientPath:     \"/path/to/deepspeech/DeepSpeech/DeepSpeech.py\",\n    LMPath:         mp + \"/lm.binary\",\n    LMWeight:       0.75,\n    ModelPath:      mp + \"/output_graph.pb\",\n    PrepareDirPath: \"/path/to/deepspeech/prepare\",\n    TrainingArgs: map[string]string{\n        \"checkpoint_dir\":   \"/path/to/deepspeech/model/custom/checkpoints\",\n        \"dev_batch_size\":   \"4\",\n        \"export_dir\":       \"/path/to/deepspeech/model/custom\",\n        \"noearly_stop\":     \"\",\n        \"test_batch_size\":  \"4\",\n        \"train_batch_size\": \"20\",\n\n        // Mozilla values\n        \"learning_rate\": \"0.0001\",\n        \"dropout_rate\":  \"0.15\",\n        \"lm_alpha\":      \"0.75\",\n        \"lm_beta\":       \"1.85\",\n    },\n    TriePath:             mp + \"/trie\",\n    ValidWordCountWeight: 1.85,\n})\n\n// Make sure to close deepspeech\ndefer d.Close()\n\n// Initialize deepspeech\nd.Init()\n\n// Create runnable\nr := speech_to_text.NewRunnable(\"Speech to Text\", d, speech_to_text.RunnableOptions{\n    SpeechesDirPath: \"/path/to/speech_to_text/speeches\",\n})\n\n// Initialize runnable\nr.Init()\n\n// Make sure to close the runnable\ndefer r.Close()\n\n// Register runnables\nw.RegisterRunnables(worker.Runnable{\n    AutoStart: true,\n    Runnable:  r,\n})\n\n// Send samples\nw.SendMessage(worker.MessageOptions{\n    Message:  speech_to_text.NewSamplesMessage(\n        from,\n        samples,\n        bitDepth,\n        numChannels,\n        sampleRate,\n        maxSilenceLevel,\n    ),\n    Runnable: \"Speech to Text\",\n    Worker:   \"Worker #3\",\n})\n```\n\n### Listenable\n\n```go\n// Register listenables\nw.RegisterListenables(\n    worker.Listenable{\n        Listenable: speech_to_text.NewListenable(speech_to_text.ListenableOptions{\n            OnText: func(from astibob.Identifier, text string) (err error) {\n                // TODO Do something with the text\n                return\n            },\n        }),\n        Runnable: \"Speech to Text\",\n        Worker:   \"Worker #3\",\n    },\n)\n```\n\n## Text to Speech\n\nThis ability allows you to run speech synthesis.\n\n### Dependencies\u003ca name='text-to-speech-dependencies'\u003e\u003c/a\u003e\n\nIt's strongly recommended to use [astibob wrapper](abilities/text_to_speech/speak).\n\nIf you're using Linux it's strongly recommended to use [ESpeak](http://espeak.sourceforge.net/).\n\n### Runnable\n\n```go\n// Create speaker\ns := speak.New(speak.Options{})\n\n// Initialize speaker\ns.Initialize()\n\n// Make sure to close speaker\ndefer s.Close()\n\n// Register runnables\nw.RegisterRunnables(worker.Runnable{\n    AutoStart: true,\n    Runnable:  text_to_speech.NewRunnable(\"Text to Speech\", s),\n})\n\n// Say something\nw.SendMessage(worker.MessageOptions{\n    Message:  text_to_speech.NewSayMessage(\"Hello world\"),\n    Runnable: \"Text to Speech\",\n    Worker:   \"Worker #1\",\n})\n```\n\n# Create your own ability\n\nCreating your own ability is pretty straight-forward: you need to create an object that implements the **astibob.Runnable** interface. Optionally it can implement the **astibob.Operatable** interface as well.\n\nIf you want other abilities to be able to interact with it you'll need to create another object that implements the **astibob.Listenable** interface.\n\nI strongly recommend checking out how provided abilities are built and trying to copy them first.\n\n## Runnable\n\nThe quickest way to implement the **astibob.Runnable** interface is to add an embedded **astibob.BaseRunnable** attribute to your object. \n\nYou can then use **astibob.NewBaseRunnable** to initialize it which allows you providing the proper options.\n\n## Operatable\n\nThe quickest way to implement the **astibob.Operatable** interface is to add an embedded **astibob.BaseOperatable** attribute to your object.\n\nYou can then use the `cmd/operatable` command to generate an `operatable.go` file binding your `resources` folder containing your `static` and `template` files. You can finally add custom routes manually to the **astibob.BaseOperatable** using the **AddRoute** method.\n\n## Listenable\n\nNo shortcut here, you need to create an object that implements the **astibob.Listenable** interface yourself.\n\n# Contribute\n\nIf you've created an awesome **Ability** and you feel it could be of interest to the community, create a PR [here](https://github.com/asticode/go-astibob/compare).","funding_links":[],"categories":["Go"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasticode%2Fgo-astibob","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fasticode%2Fgo-astibob","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fasticode%2Fgo-astibob/lists"}