Texto a voz en Ruby para scripts y apps de Rails
Ruby no tiene síntesis de voz propia. Los scripts suelen llamar a say en Mac o a espeak en Linux, que suenan robóticos, y las apps de Rails suelen enviar cada texto a una API en la nube que cobra por carácter.
El motor gratuito SuperClonica funciona como un servidor HTTP junto a tu app, con voces naturales en 31 idiomas, y basta la biblioteca estándar de Ruby para llamarlo. Esta guía muestra un script sencillo, una configuración de Rails con Active Job y Active Storage, y los hábitos que lo mantienen seguro en producción.
Cómo puede hablar Ruby
Genera el audio una vez por versión del texto y sirve el archivo; no sintetices en cada petición.
- Voces del sistema: say o espeak con system(); sin configuración, pero robóticas y distintas en cada máquina.
- APIs en la nube: voces naturales, pero una clave, una factura por carácter y tu texto en servidores ajenos.
- SuperClonica: un servidor local con voces naturales, de personajes y propias; Ruby envía JSON y recibe un WAV.
- Habla 31 idiomas; el chino aún no está disponible.
Escucha las voces gratis
Antes de escribir código, abre la página de cualquier voz, escribe una frase de 30 a 100 caracteres, elige el idioma y pulsa el botón para generarla. En unos segundos oyes la voz que podría tener tu app, sin cuenta.
Inicia el servidor de voz
Una tarjeta gráfica NVIDIA con la imagen cuda lo acelera, pero un procesador normal basta.
- Inicia el servidor en la misma máquina o en una privada: docker run -d -p 8000:8000 -v superclonica-models:/models superclonica/superclonica:cpu.
- El primer arranque descarga el modelo Supertonic 3, unos 385 MB; GET /health indica cuándo está listo.
- POST /synthesize recibe JSON con text, voice, lang, seed y normalize, y responde con un WAV mono de 16 bits.
- Por defecto una petición admite hasta 5000 caracteres (SUPERCLONICA_MAX_TEXT); divide los textos largos por párrafos.
Llámalo desde Ruby
No hace falta ninguna gema: require "net/http"; require "json"; uri = URI("http://localhost:8000/synthesize"); res = Net::HTTP.post(uri, { text: "¡Hola desde Ruby!", voice: "F1", lang: "es" }.to_json, "Content-Type" => "application/json"); File.binwrite("hello.wav", res.body) if res.is_a?(Net::HTTPSuccess). Para una voz del catálogo, envía el archivo decodificado en lugar de un nombre de serie: voice: JSON.parse(File.read("voice.json")). Faraday o HTTParty funcionan igual si tu app ya los usa.
Rails: trabajos en segundo plano y Active Storage
En Rails, genera la voz en un Active Job, nunca dentro de la petición web, y adjunta el resultado al registro: post.audio.attach(io: StringIO.new(res.body), filename: "post-#{post.id}.wav", content_type: "audio/wav"). Regenera solo cuando cambie el texto. No expongas el puerto 8000 a internet: define SUPERCLONICA_API_KEY en el servidor y envíala en una cabecera Authorization: Bearer, o mantén el servidor en una red privada. Avisa a los oyentes de que el audio es generado.