Ir al contenido
Guía

Muestra la mascota de tu agente en Flutter con Wixzel Voice

Al final de esta guía, tu app Flutter muestra la mascota de tu agente, la cara animada que tiene cada agente de Wixzel Voice, y la mascota escucha, piensa y habla al ritmo de una llamada en vivo. El paquete wixzel_voice_flutter la dibuja con AgentMascotView y la mantiene sincronizada con la llamada con MascotRealtimeLink; el SDK de Dart wixzel_voice se encarga de la llamada. Calcula alrededor de una hora, sobre todo para conectar una grabadora y un reproductor. Una sesión se factura como una llamada telefónica con el mismo motor: $0.0491 por minuto conectado con Gemini Live, unos $0.20 por cuatro minutos, sin línea telefónica.

Por · Publicado el · Actualizado el

Duración
Alrededor de una hora
Tiempo de motor
$0.0491 por minuto conectado
La pantalla de una app de teléfono con una mascota verde grande, un saludo en un globo de diálogo encima y un botón Hablar debajo

¿Qué necesitas antes de empezar?

  • Un agente de Wixzel Voice y una clave de API con crédito, guardada en tu servidor. Sirve cualquier agente: todos tienen una mascota, empezando por la verde predeterminada.
  • Flutter 3.27 o posterior.
  • Un servidor que controles y que pueda llamar a la API. El ejemplo usa Node.js y el SDK de TypeScript.
  • Un plugin de grabación que transmita PCM de 16 bits, idealmente a 8 kHz mono con cancelación de eco, y un reproductor que acepte PCM sin procesar, como record y flutter_pcm_sound.

¿Cómo construyes esto en Wixzel Voice, paso a paso?

  1. 01Añade los paquetes

    wixzel_voice_flutter dibuja la mascota; wixzel_voice es el SDK de Dart sobre el que se construye:

    pubspec.yaml
    dependencies:
      wixzel_voice: ^0.8.0
      wixzel_voice_flutter: ^0.1.0
      http: ^1.2.0

    El paquete depende de sensors_plus, para que los ojos de la mascota sigan la inclinación del teléfono, y de visibility_detector, para que solo se anime mientras está en pantalla. No graba ni reproduce audio.

  2. 02Dale a la app el agente y una sesión, desde tu servidor

    Tu clave de API nunca va en la app. Tu servidor obtiene el agente y crea una sesión de un solo uso válida durante un minuto, y la app le pide ambas cosas a tu servidor:

    server.mjs
    import express from 'express';
    import { WixzelVoice } from 'wixzel-voice';
    
    const wixzel = new WixzelVoice({ apiKey: process.env.WIXZEL_API_KEY });
    const app = express();
    const AGENT_ID = process.env.AGENT_ID;
    
    // Put your own sign-in check in front of both routes.
    app.get('/agent', async (req, res) => {
      res.json(await wixzel.agents.retrieve(AGENT_ID));
    });
    
    app.post('/session', async (req, res) => {
      res.json(await wixzel.realtime.createSession({ agent_id: AGENT_ID, max_duration_seconds: 300 }));
    });
    
    app.listen(3000);

    El JSON del agente incluye mascot.spec, la pequeña especificación a partir de la cual se dibuja la mascota. Crear una sesión no cuesta nada; la facturación empieza cuando la app se conecta.

  3. 03Dibuja la mascota

    Agent.fromJson lee lo que envió tu servidor, y AgentMascotView lo dibuja:

    agent_face.dart
    import 'dart:convert';
    
    import 'package:flutter/widgets.dart';
    import 'package:http/http.dart' as http;
    import 'package:wixzel_voice/wixzel_voice.dart';
    import 'package:wixzel_voice_flutter/wixzel_voice_flutter.dart';
    
    const backendUrl = 'https://api.example.com';
    
    Future<Agent> loadAgent() async {
      final res = await http.get(Uri.parse('$backendUrl/agent'));
      return Agent.fromJson(jsonDecode(res.body) as Map<String, dynamic>);
    }
    
    Widget agentFace(Agent agent, MascotController controller) =>
        AgentMascotView(agent: agent, controller: controller, size: 220);
    
    // In a list, draw one frame and run no animation:
    Widget agentRow(Agent agent) => AgentMascotView(agent: agent, size: 40, still: true);

    Un agente sin spec recibe el aspecto predeterminado. Una mascota casi negra o casi blanca se coloca sobre un fondo de su propio color, para que no desaparezca en una pantalla oscura o clara; desactívalo con stage: false. Un toque reproduce una expresión, y MascotController reproduce movimientos por nombre, como mascot.play('hello').

  4. 04Vincula la mascota a una llamada

    Conéctate con RealtimeConnection del SDK de Dart y pásaselo a MascotRealtimeLink. El vínculo hace que la mascota piense mientras la llamada se conecta, salude, escuche mientras el usuario habla y mueva la boca con el audio del agente:

    talk.dart
    import 'dart:async';
    import 'dart:convert';
    import 'dart:typed_data';
    
    import 'package:http/http.dart' as http;
    import 'package:wixzel_voice/wixzel_voice.dart';
    import 'package:wixzel_voice_flutter/wixzel_voice_flutter.dart';
    
    /// Your audio plugins, behind a small interface.
    abstract class PcmPlayer {
      void add(Int16List samples); // 16-bit PCM, 8 kHz mono
      void clear();
    }
    
    class MascotCall {
      MascotCall(this.mascot, this.player);
    
      final MascotController mascot;
      final PcmPlayer player;
      RealtimeConnection? _conn;
      MascotRealtimeLink? _link;
      StreamSubscription<Int16List>? _mic;
    
      /// [micFrames] is 16-bit PCM at 8 kHz in 160-sample (20 ms) frames.
      Future<void> start(Stream<Int16List> micFrames) async {
        final res = await http.post(Uri.parse('https://api.example.com/session'));
        final session = RealtimeSession.fromJson(jsonDecode(res.body) as Map<String, dynamic>);
    
        final conn = RealtimeConnection.forSession(session);
        _conn = conn;
        _link = MascotRealtimeLink(mascot, conn);
        conn.events.listen((event) {
          switch (event) {
            case RealtimeAudio(:final mulaw):
              player.add(mulawToPcm16(mulaw)); // the mouth follows this audio through the link
            case RealtimeAudioClear():
              player.clear(); // the user spoke over the agent
            case RealtimeEnded():
              unawaited(end());
            default:
          }
        });
        await conn.ready;
        _mic = micFrames.listen((frame) {
          conn.sendAudio(pcm16ToMulaw(frame));
          _link?.micAudio(frame); // it leans in while the user talks
        });
      }
    
      Future<void> end() async {
        await _mic?.cancel();
        await _link?.dispose(); // leaves the mascot idle; does not end the call
        await _conn?.end();
        _mic = null;
        _link = null;
        _conn = null;
      }
    }

    Muéstrala con AgentMascotView(agent: agent, controller: mascot), el mismo controlador que maneja la llamada. Libera el controlador cuando la pantalla desaparezca.

    Activa la cancelación de eco de la plataforma en tu grabadora, o el agente se oirá a sí mismo por el altavoz y se interrumpirá.

  5. 05Haz exacta la sincronización labial, si tu reproductor programa el audio

    Por defecto, el vínculo supone que tu reproductor empieza cada fragmento unos 120 ms después de recibirlo. Si tu reproductor sabe exactamente cuándo suena un fragmento, díselo al vínculo:

    exact_timing.dart
    import 'dart:typed_data';
    
    import 'package:wixzel_voice/wixzel_voice.dart';
    import 'package:wixzel_voice_flutter/wixzel_voice_flutter.dart';
    
    MascotRealtimeLink exactLink(MascotController mascot, RealtimeConnection conn) =>
        MascotRealtimeLink(mascot, conn, estimatePlayback: false);
    
    // In your player, each time it schedules a chunk, on the player's own clock:
    void scheduled(MascotRealtimeLink link, Int16List pcm, double playAt, double now) {
      link.agentAudio(pcm, playAt: playAt, currentTime: now, sampleRate: 8000);
    }

¿Cuánto cuesta esto en Wixzel Voice?

Tiempo de motor para sesiones de 4 minutos con el motor gemini-live a $0.0491 por minuto conectado: unos $0.20 por sesión. No hay costo de telefonía, porque no hay línea telefónica.

Costo mensual de motor de lo que construye esta guía
Sesiones al mesMinutos conectadosCosto de motor al mes
5002000$98.20
250010.000$491
10.00040.000$1,964

Los paquetes son gratuitos y tienen licencia MIT. Dibujar una mascota no cuesta nada; solo una sesión en vivo gasta crédito, al precio por minuto del motor, por segundo, desde tu saldo prepago.

Prepago, sin suscripción y sin plan gratuito: agrega crédito desde $5 y el uso lo va consumiendo. Calcula tu propia combinación.

¿Qué límites de Wixzel Voice se aplican a esto?

  • El paquete no graba ni reproduce audio. Tu app aporta ambas cosas mediante los plugins que elija.
  • Audio de calidad telefónica: G.711 µ-law a 8 kHz en ambas direcciones.
  • Las sesiones cuentan para el límite de llamadas simultáneas de la cuenta, cinco por defecto.
  • Flutter 3.27 o posterior. La inclinación necesita un acelerómetro; sin él, la mascota mira a su alrededor por sí sola.
  • Cambiar el aspecto de una mascota es una llamada a la API desde tu servidor (agents.updateMascot), no desde la app, porque necesita tu clave de API.

Preguntas frecuentes

¿Cómo muestro la mascota de un agente de Wixzel Voice en Flutter?

Añade wixzel_voice y wixzel_voice_flutter a tu pubspec, lee el agente que obtuvo tu servidor con Agent.fromJson y dibuja su mascota con AgentMascotView(agent: agent). Pasa un MascotController para controlarla desde el código.

¿Cómo sincroniza la mascota los labios con el agente?

MascotRealtimeLink escucha los eventos de RealtimeConnection y mueve la boca con el audio del agente, sincronizada según su propia estimación del retraso de tu reproductor o, con estimatePlayback: false, según los tiempos que tu reproductor informa mediante agentAudio. También fija los estados: pensando mientras se conecta, escuchando mientras el usuario habla y en reposo cuando termina la llamada.

¿La mascota se ve igual que en el sitio web?

Sí. El runtime de Flutter es una adaptación del de la web, y hay pruebas que exigen a ambos los mismos valores, así que un spec se ve y se mueve igual en tu app, en la app de Wixzel Voice, en el enlace para compartir y en el widget web.

¿Existe lo mismo para apps web?

Sí. mountMascot de wixzel-voice/mascot (wixzel-voice 0.10.0 en npm) dibuja la mascota en un canvas, y face.connect(session) inicia la llamada en tiempo real con la mascota ya conectada, incluidos el micrófono y la reproducción.

Dónde leer más

  • SDKdocumentación

    Los SDK de Dart y TypeScript y los widgets de la mascota.

  • Mascotasdocumentación

    El spec, cómo cambiar el aspecto y cómo generar uno a partir de un sitio web.

  • Realtime: web y móvildocumentación

    Crear sesiones, el protocolo y la facturación.

API para telefonía con agentes

Acerca de Wixzel Voice

Wixzel Voice es una API de IA de voz para crear agentes de IA que hacen y contestan llamadas telefónicas reales a través de tu propia troncal SIP, o que hablan con personas en tus apps web y móviles. Una clave de API y un saldo prepagado cubren todos los motores de voz, con cobro por segundo de uso real.

Dale a Claude una línea telefónica con el MCP de Wixzel Voice

Claude, en Claude Code o claude.ai, haciendo una llamada real por tu troncal SIP y leyéndote la transcripción, con una confirmación antes de marcar.

Recepcionista con IA para Twilio en Node.js con Wixzel Voice

Tu número actual de Twilio atendido por un recepcionista de IA que agenda citas en la API, hecho en Node.js.

Agente telefónico en hindi y malayalam con sarvam en Wixzel Voice

Dos agentes telefónicos, uno en hindi y otro en malayalam, con los modelos de Sarvam para idiomas de la India, que atienden o hacen llamadas por tu troncal SIP.

Añade un agente de voz a Flutter por WebSocket con Wixzel Voice

Una app Flutter en la que los usuarios hablan con tu agente de voz por WebSocket, con la clave de API guardada en tu servidor y sin ningún número de teléfono.

Gemini Live en una llamada real con la API de Wixzel Voice

Un agente Gemini Live llamando a un teléfono real por tu troncal SIP a partir de cuatro peticiones cURL, y el registro de la llamada con su transcripción y su costo.

Haz una campaña de calificación de leads con IA con Wixzel Voice

Una lista de leads llamados por tu agente a través de tu troncal SIP, en lotes ajustados a tu límite de llamadas simultáneas, con el estado y la transcripción de cada llamada.

Añade una mascota de IA que habla a tu web con Wixzel Voice

Una mascota que habla en la esquina de tu sitio web, a la que los visitantes llaman desde el navegador, limitada a tus dominios y a tus límites diarios, con cada persona que llama registrada.