
Dale Voz a tu Agente
Quick Start — React SDK
useFormmyVoice — API
| Propiedad | Tipo | Descripción |
|---|---|---|
| start(opts?) | (opts?: { systemPrompt?: string }) => Promise<void> | Inicia la sesión de voz. Opcional: { systemPrompt: '...' } para override per-session |
| stop() | () => void | Cierra sesión y libera recursos |
| toggleMute() | () => void | Alterna silencio del micrófono |
| setMuted(muted) | (boolean) => void | Control explícito de mute (complementa toggleMute) |
| clearTranscripts() | () => void | Limpia el array de transcripciones |
| status | VoiceStatus | "idle" | "connecting" | "ready" | "speaking" | "error" |
| isMuted | boolean | Si el mic está silenciado |
| isSpeaking | boolean | Shortcut: status === 'speaking' |
| isListening | boolean | Shortcut: status === 'ready' |
| error | Error | null | Último error (conexión, mic, etc.) |
| transcripts | VoiceTranscript[] | Transcripciones en tiempo real |
Options
| Opción | Tipo | Descripción |
|---|---|---|
| agentId | string | ID del agente (requerido) |
| voiceId | string | Voz a usar (default: "carlos") |
| sensitivity | "HIGH" | "MEDIUM" | "LOW" | Turn-taking: HIGH (~1.5s), MEDIUM (~1.75s, default), LOW (~2.0s) |
| onStatusChange | (status: VoiceStatus) => void | Callback en cada cambio de status — evita useEffect |
| onError | (error: Error) => void | Callback en errores — evita useEffect |
| onTranscript | (transcript: VoiceTranscript) => void | Callback por cada transcript — para logging, analytics, o sync externo |
| onMicAudio | (float32: Float32Array) => void | Raw mic audio por frame — para visualizaciones de intensidad o waveforms |
| onServerEvent | (type: string, payload: unknown) => void | Catch-all para eventos del servidor (artifacts, toolUse, custom) |
| audioDestination | AudioNode | Nodo intermedio para playback (ej. GainNode para volumen, AnalyserNode para visualizar) |
| wsUrl | string | Override de la URL WebSocket — para conexiones self-hosted o first-party |
systemPrompt per-session: Pasa un system prompt custom al llamar start({ systemPrompt: '...' }). Esto override las instrucciones del agente solo para esa sesión — útil para cambiar tono, idioma o comportamiento sin tocar el dashboard.
FormmyVoiceClient — Vanilla JS
Config
| Propiedad | Tipo | Descripción |
|---|---|---|
| baseUrl | string | URL base del servidor (requerido) |
| publishableKey | string | Tu pk_live key |
| agentId | string | ID del agente (requerido) |
| voiceId | string | Voz (default: "carlos") |
| sensitivity | "HIGH" | "MEDIUM" | "LOW" | Turn-taking sensitivity |
| wsUrl | string | Override de URL WebSocket (ignora baseUrl + pk) |
| audioDestination | AudioNode | Nodo destino para playback (GainNode, AnalyserNode, etc.) |
| tools | Array | Client-side tools (name, description, inputSchema) |
| onToolUse | Function | Handler para tool calls del agente |
Event Handlers
| Handler | Tipo | Descripción |
|---|---|---|
| onStatusChange | (status: VoiceStatus) => void | "idle" | "connecting" | "ready" | "speaking" | "error" |
| onTranscript | (t: VoiceTranscript) => void | Streaming + final transcripts (role, text, isFinal) |
| onMicAudio | (float32: Float32Array) => void | Raw mic frame por cada chunk — para waveforms o intensidad |
| onServerEvent | (type: string, payload: unknown) => void | Artifacts, toolUse, y eventos custom del servidor |
| onError | (error: Error) => void | Errores de conexión, mic, etc. |
Métodos
| Método | Descripción |
|---|---|
| connect(opts?) | Conecta WebSocket, pide mic, inicia handshake. Opcional: { systemPrompt: '...' } para override per-session |
| disconnect() | Cierra sesión y libera todos los recursos |
| sendText(text) | Envía texto durante la llamada (cross-modal) |
| setMuted(bool) | Silencia/activa el micrófono |
| getStatus() | VoiceStatus actual |
| getIsPlaying() | true si el agente está reproduciendo audio |
| getPlaybackContext() | AudioContext de playback (24kHz) — para análisis externo |
WebSocket Nativo — Quick Start
Qué Necesitas
Publishable Key
Agent ID
Plan Pro
Parámetros de conexión
| Param | Requerido | Descripción |
|---|---|---|
| chatbotId | Sí | El ID de tu agente |
| pk | Sí | Publishable key (formmy_pk_live_) |
| voiceId | No | Voz a usar (default: carlos) |
| sensitivity | No | Turn-taking: HIGH (~1.5s), MEDIUM (~1.75s, default), LOW (~2.0s) |
Voces Disponibles
carlos
lupe
tiffany
matthew
amy
ambre
florian
beatrice
lorenzo
greta
lennart
Esto no es Text-to-Speech
La mayoría de las soluciones de "voz con IA" usan un pipeline de 3 pasos: STT → LLM → TTS. Transcriben tu voz a texto, procesan el texto con un modelo de lenguaje, y luego sintetizan la respuesta a audio. Tres modelos. Tres puntos de latencia. Tres puntos de falla donde se pierde tono, emoción e intención.
Pipeline tradicional (STT + LLM + TTS)
Audio → Whisper → Texto → GPT → Texto → ElevenLabs → Audio
~2-4s de latencia. 3 modelos. 3 facturas.
Formmy Voice (Speech-to-Speech nativo)
Audio → Un solo modelo → Audio
<1s de latencia. 1 modelo. Sin intermediarios.
Formmy Voice usa un modelo speech-to-speech nativo. El audio entra y el audio sale — directamente. No hay transcripción intermedia, no hay síntesis artificial. El modelo entiende tu voz y genera su respuesta como voz, en un solo paso. Resultado: conversaciones que se sienten naturales, con latencia menor a un segundo y a una fracción del costo.
Full-duplex real — sin mute, sin turnos
No es un walkie-talkie. El audio fluye en ambas direcciones al mismo tiempo. Puedes hablar mientras la IA habla — sin bloqueos, sin mute automático, sin esperar turno. La IA te escucha incluso mientras responde, y si la interrumpes, se adapta al instante. Exactamente como una conversación real.
Barge-in y Echo Cancellation
Barge-in — la IA lo maneja
Tu único trabajo:
NO hagas:
Echo Cancellation — el browser lo maneja
Android — Activa AEC del hardware
Transcripciones en Tiempo Real
Si usas WebSocket directo:
Cómo Funciona
Tú hablas → Formmy → Agente IA → Formmy → Tú escuchas
1. Conexión
2. Handshake automático
3. Audio continuo
4. La IA responde
5. Cierre
Reglas Críticas
Envía audio siempre. audioStart una vez, luego audioInput sin parar. Nunca pauses el mic.
Reproduce inmediato. No bufferees todo el audio. Queue + play cada chunk que llegue.
Barge-in = solo limpiar queue. Cuando recibas contentEnd(INTERRUPTED), limpia tu cola de audio. Nada más.
NO implementes VAD. No detectes silencio, no detectes voz. El servidor lo maneja todo.
NO pauses el mic. Ni por agentSpeaking, ni por nada. Full-duplex = siempre abierto.
Ojo con Esto — Errores Comunes
Audio duplicado (SPECULATIVE vs FINAL)
Solución:
El saludo no se reproduce (patrón speaks-first)
Secuencia correcta:
No mezcles textInput con audioStart
sendText() — Texto durante una llamada de voz
const { start, stop, sendText, status } = useFormmyVoice({
agentId: 'agent_123',
});
// During an active voice session:
sendText("Check my order status");Ejemplos Completos
Web (TypeScript) — WebSocket + AudioWorklet
Android (Kotlin) — OkHttp + Client Tools
Superpoder: Tools del Lado del Cliente
Comportamiento async de los tools
Paso 1: Registra tools antes de sessionStart
Paso 2: El servidor confirma
Paso 3: La IA invoca tu tool a media conversación
Paso 4: Envía el resultado de vuelta
Audio Pipeline
audioDestination factory
getPlaybackContext()
onMicAudio
Referencia
Eventos
| Dirección | Evento | Descripción |
|---|---|---|
| Servidor | initialized | Servidor listo, contiene chatbotId y chatbotName |
| Cliente | registerTools | Registra tools del cliente (antes de sessionStart) |
| Servidor | toolsRegistered | Confirmación de tools registrados |
| Cliente | sessionStart | Inicia la sesión de voz. Opcional: { systemPrompt: '...' } para override per-session |
| Servidor | ready | Sesión lista, contiene sessionId |
| Cliente | audioStart | Abre stream de audio (enviar UNA VEZ) |
| Cliente | audioInput | Chunk de audio (PCM 16kHz mono, base64) — enviar continuamente |
| Servidor | audioOutput | Audio de la IA (PCM 24kHz mono, base64) |
| Servidor | contentStart | Inicio de contenido — contiene role y generationStage |
| Servidor | textOutput | Transcripción parcial (acumular hasta contentEnd) |
| Servidor | contentEnd | Fin de contenido. stopReason: END_TURN o INTERRUPTED |
| Cliente | textInput | Mensaje de texto (alternativa a voz) |
| Servidor | clientToolUse | La IA quiere que el cliente ejecute un tool |
| Cliente | toolResult | Resultado del tool ejecutado por el cliente |
| Servidor | error | Mensaje de error |
| Cliente | close | Cerrar la sesión |
Formato de Audio
| Dirección | Formato | Sample Rate | Canales | Codificación |
|---|---|---|---|---|
| Entrada (mic) | PCM 16-bit | 16,000 Hz | Mono | Base64 |
| Salida (bocina) | PCM 16-bit | 24,000 Hz | Mono | Base64 |