GUIDE

Ruby text to speech for scripts and Rails apps

Ruby has no speech synthesis of its own. Scripts often shell out to say on a Mac or espeak on Linux, which sound robotic, and Rails apps usually send every text to a cloud API that bills per character.

The free SuperClonica engine runs as an HTTP server next to your app, with natural voices in 31 languages, and Ruby’s standard library is all you need to call it. This guide shows a plain script, a Rails setup with Active Job and Active Storage, and the habits that keep it safe in production.

How Ruby can speak

Generate audio once per version of a text and serve the file; do not synthesize on every request.

  • System voices: say or espeak through system(); no setup, but robotic and different on every machine.
  • Cloud APIs: natural voices, but a key, a bill per character and your text on someone else’s servers.
  • SuperClonica: a local server with natural, character and custom voices; Ruby sends JSON and gets a WAV back.
  • It speaks 31 languages; Chinese is not supported yet.

Hear the voices free online

Before you write code, open the page of any voice, type a line of 30 to 100 characters, choose the language and press Voice it. In a few seconds you hear the voice your app could have, with no account.

Start the speech server

An NVIDIA graphics card makes it faster with the cuda image, but an ordinary processor is enough.

  • Start the server on the same machine or a private one: docker run -d -p 8000:8000 -v superclonica-models:/models superclonica/superclonica:cpu.
  • The first start downloads the Supertonic 3 model, about 385 MB; GET /health tells you when it is ready.
  • POST /synthesize takes JSON with text, voice, lang, seed and normalize, and answers with a 16-bit mono WAV.
  • By default a request takes up to 5,000 characters (SUPERCLONICA_MAX_TEXT); split longer texts by paragraph.

Call it from Ruby

No gem is needed: require "net/http"; require "json"; uri = URI("http://localhost:8000/synthesize"); res = Net::HTTP.post(uri, { text: "Hello from Ruby!", voice: "F1", lang: "en" }.to_json, "Content-Type" => "application/json"); File.binwrite("hello.wav", res.body) if res.is_a?(Net::HTTPSuccess). For a catalog voice, send the decoded file instead of a stock name: voice: JSON.parse(File.read("voice.json")). Faraday or HTTParty work the same way if your app already uses them.

Rails: background jobs and Active Storage

In Rails, voice a text in an Active Job, never inside the web request, and attach the result to the record: post.audio.attach(io: StringIO.new(res.body), filename: "post-#{post.id}.wav", content_type: "audio/wav"). Regenerate only when the text changes. Do not expose port 8000 to the internet: set SUPERCLONICA_API_KEY on the server and send it in an Authorization: Bearer header, or keep the server on a private network. Tell listeners the audio is generated.