GUÍA

Texto a voz en Rust sin conexión

Rust tiene crates que envuelven los motores de voz del sistema operativo, válidos para accesibilidad pero con voces robóticas distintas en cada plataforma, y SDK en la nube que cobran por carácter. Para un juego, un bot o una herramienta de línea de comandos que necesita una voz natural en todas partes, ninguno es ideal.

Esta guía muestra cómo llamar al motor gratuito SuperClonica desde Rust a través de un servidor HTTP local: voces naturales, archivos WAV que conservas y unas pocas líneas con reqwest.

Formas de hablar desde Rust

Para una salida tipo lector de pantalla, las voces del sistema van bien; para la voz de un producto o un juego, usa un motor.

  • Crates que envuelven las voces del sistema: sin conexión y ligeros, pero robóticos y distintos en Windows, macOS y Linux.
  • SDK en la nube: voces naturales, pero cuenta, clave, cobro por carácter y tu texto en sus servidores.
  • SuperClonica: un servidor HTTP local con voces naturales, de personajes y propias, sin conexión, donde funcione Docker.
  • 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.

Arranca el servidor de voz

Una tarjeta gráfica NVIDIA lo acelera con la imagen cuda, pero no es obligatoria.

  • Arranca el servidor en cualquier CPU: docker run -d -p 8000:8000 -v superclonica-models:/models superclonica/superclonica:cpu.
  • El primer arranque descarga el modelo Supertonic 3, unos 385 MB, en el volumen; 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.
  • voice es un nombre de serie de M1 a M5 y de F1 a F5, o el contenido JSON de un archivo de voz.

Llámalo desde Rust

Con el crate reqwest y su feature blocking, dentro de una función que devuelve un Result, una petición ocupa unas líneas: let voice = std::fs::read_to_string("voice.json")?; let body = format!(r#"{{"text": "¡Hola desde Rust!", "lang": "es", "seed": 7, "voice": {voice}}}"#); let wav = reqwest::blocking::Client::new().post("http://localhost:8000/synthesize").header("Content-Type", "application/json").body(body).send()?.bytes()?; std::fs::write("hello.wav", wav)?; En código asíncrono, usa del mismo modo el cliente asíncrono de reqwest. Para una voz de serie, envía "voice": "F1" en lugar del archivo. El mismo texto, voz y seed dan siempre el mismo audio, así que cachea los archivos de frases repetidas; serde_json mantiene ordenadas las peticiones grandes.

Hábitos para producción

Reutiliza un único cliente reqwest y pon un tiempo de espera. No expongas el puerto 8000 a internet tal cual: define SUPERCLONICA_API_KEY y envíala como token Bearer, o mantén el servidor en una red privada. Si llegan muchas peticiones a la vez, ejecuta más copias del modelo con SUPERCLONICA_LANES, y mide en tu hardware: en nuestras pruebas una frase corta tardó 0,12 s en una RTX 5070 Ti y 0,43 s con cuatro hilos de CPU.