{"id":17134340,"url":"https://github.com/brianium/vocloj","last_synced_at":"2025-03-24T06:16:30.598Z","repository":{"id":146515425,"uuid":"445969411","full_name":"brianium/vocloj","owner":"brianium","description":"Clojure(Script) voice recognition and synthesis","archived":false,"fork":false,"pushed_at":"2022-02-01T13:39:42.000Z","size":2809,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-03-18T05:56:28.064Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://brianium.github.io/vocloj/","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/brianium.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-01-09T01:44:31.000Z","updated_at":"2022-01-22T00:20:33.000Z","dependencies_parsed_at":"2023-04-28T22:01:56.876Z","dependency_job_id":null,"html_url":"https://github.com/brianium/vocloj","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brianium%2Fvocloj","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brianium%2Fvocloj/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brianium%2Fvocloj/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/brianium%2Fvocloj/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/brianium","download_url":"https://codeload.github.com/brianium/vocloj/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245217945,"owners_count":20579300,"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","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":[],"created_at":"2024-10-14T19:44:39.721Z","updated_at":"2025-03-24T06:16:30.565Z","avatar_url":"https://github.com/brianium.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# vocloj\n\nYou talk to the computer. The computer talks to you. Brought to you by\nsweet sweet parens.\n\n[![cljdoc badge](https://cljdoc.org/badge/com.github.brianium/vocloj)](https://cljdoc.org/d/com.github.brianium/vocloj/CURRENT) [![Clojars Project](https://img.shields.io/clojars/v/com.github.brianium/vocloj.svg)](https://clojars.org/com.github.brianium/vocloj)\n\n## Table of contents\n\n- [Using vocloj](#using-vocloj)\n    - [Web](#voclojweb)\n- [Demo](https://brianium.github.io/vocloj/)\n  - [src](https://github.com/brianium/vocloj/blob/main/dev/cljs/vocloj/dev.cljs)\n- [API Docs](https://cljdoc.org/d/com.github.brianium/vocloj/CURRENT)\n- [State machines](#state-machines)\n    - [add-effect](#add-effect)\n    - [current-state](#current-state)\n- [Recognition](#recognition)\n- [Synthesis](#synthesis)\n- [Microphone Streams](#microphone-streams)\n\n## Using vocloj\n\nClojure(Script) is great. Speech synthesis and recognition are fun and probably useful. The aim of vocloj is to make working with speech synthesis and recognition across different platforms simple. For now only native browser APIs are supported.\n\n```clojure\n(require '[vocloj.core :as vocloj.core]\n         '[vocloj.web :as vocloj.web])\n\n;;; Recognition\n\n(def recognizer (vocloj.web/create-recognizer {:continuous? true}))\n\n(vocloj.core/listen recognizer #(println %))\n\n;; Omitting a handler will return a core.async channel\n\n(let [ch (vocloj.core/listen recognizer)]\n  (go-loop []\n    (println (\u003c! ch))))\n\n;;; Synthesis\n\n(def synthesizer (vocloj.web/create-synthesizer))\n\n(def voice-id \"Alex\")\n\n(vocloj.core/speak synthesizer voice-id {:text \"Hello World!\"})\n```\n\n### vocloj.web\n\nCurrently the only supported implementation. Synthesis is backed by the [SpeechSynthesis](https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis) API, and recognition is backed by the [SpeechRecognition](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition) API.\n\nThe caveat to using vocloj's web interface is that most browsers require user interaction to initialize synthesis and recognition.\n\nSee the demo app for an example.\n\n#### Browser support\n\nAt the time of this writing, Chrome has the best support for speech recognition by far.\n\nIt does work in Safari, but it has gotten so bad as to be nearly unusable (though technically supported).\n\nSee [browser compatability table](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition#browser_compatibility)\n\n## State machines\n\nSpeech synthesizers and speech recognizers implement a simple state machine protocol. It is useful\nto track state in order to know when speech is occurring or when a recognizer is listening. It is also\nuseful for updating and tracking voices that are available for utterances. The `vocloj.core` interface\nsupports several methods for accessing and manipulating that internal state. These are largely used\nfor implementation, but may be useful for adding effects for things such as logging.\n\n### add-effect\n\n`add-effect` is used internally to affect change in response to state transitions. It can be useful\nto monitor internal changes or log transitions.\n\n```clojure\n(require '[vocloj.web :as web]\n         '[vocloj.core :as core])\n\n(def synthesizer (-\u003e (web/create-synthesizer)\n                     (core/add-effect ::logger (fn [synth old-state new-state]\n                                                 (println new-state)))\n                     (core/add-effect ::resumed :paused :speaking #(println \"speaking again\"))))\n```\n\n### current-state\n\nReturns the current state of a state machine as a hash map. For instance, the web based implementation of speech synthesis stores available voices in state:\n\n```clojure\n(require '[vocloj.web :as web]\n         '[vocloj.core :as core])\n\n(def synthesizer (web/create-synthesizer))\n\n;; Get available voices \n(def voices (-\u003e synthesizer core/current-state :voices))\n```\n\n## Recognition\n\nRecognizers are started and stopped. The easiest way to leverage a recognizer is to create one and use\n`vocloj.core/listen` to obtain a channel or use a callback.\n\n```clojure\n(require '[vocloj.core :as vocloj.core]\n         '[vocloj.web :as vocloj.web])\n\n(def recognizer (vocloj.web/create-recognizer {:continuous? true}))\n\n(vocloj.core/listen recognizer #(println %))\n\n;; Omitting a handler will return a core.async channel\n\n(let [ch (vocloj.core/listen recognizer)]\n  (go-loop []\n    (println (\u003c! ch))))\n\n(vocloj.core/stop recognizer) ;; stop listening\n```\n\nSee API docs for all functions and options.\n\n## Synthesis\n\n```clojure\n(require '[vocloj.core :as vocloj.core]\n         '[vocloj.web :as vocloj.web])\n\n(def synthesizer (vocloj.web/create-synthesizer))\n\n(def voice-id \"Alex\")\n\n(vocloj.core/speak synthesizer voice-id {:text \"Hello World!\"})\n```\n\nSee API docs for all functions and options.\n\n## Microphone Streams\n\nMicrophone streams are started and stopped. The easiest way to leverage a stream is to create one and use\n`vocloj.core/listen` to obtain a channel or use a callback.\n\n```clojure\n(require '[vocloj.core :as vocloj.core]\n         '[vocloj.web :as vocloj.web])\n\n(def stream (vocloj.web/create-microphone-stream))\n\n(vocloj.core/listen stream #(println %))\n\n;; Omitting a handler will return a core.async channel\n\n(let [ch (vocloj.core/listen stream)]\n  (go-loop []\n    (println (\u003c! ch))))\n\n(vocloj.core/stop stream) ;; stop listening\n```\n\nThe microphone stream is named for the [MediaStream](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream) API. However, the current implementation provides chunks of js Blobs on channel via the [MediaRecorder](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder) API. \n\nFuture iterations will be targeting true streaming via [AudioWorklets](https://developer.mozilla.org/en-US/docs/Web/API/AudioWorklet).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrianium%2Fvocloj","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbrianium%2Fvocloj","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbrianium%2Fvocloj/lists"}