Naia
Tabla de contenidos
  1. 1Manual en vídeo
  2. 2Naia OS Live USB
  3. 3Instalación e implementación
  4. 3.1Instalación de Naia OS (ISO)
  5. 3.2Instalación de la app
  6. 4Empezando
  7. 4.1Naia Model Pricing
  8. 4.2naia-omni-cascade
  9. 4.3demo
  10. 4.4naia-offline
  11. 4.5naia-model-dev
  12. 4.6naia-online
  13. 5Pantalla principal
  14. 6Charla
  15. 6.1DJ de radio personal y guía de exposición
  16. 7Historial de conversaciones
  17. 8Progreso del trabajo
  18. 9Habilidades
  19. 10Canales
  20. 11Agentes
  21. 12Diagnóstico
  22. 13Espacio de trabajo
  23. 14Navegador
  24. 15Gestión de paneles
  25. 16Conversación por voz
  26. 17Configuración
  27. 18Detalles de la herramienta
  28. 19Cuenta Naia
  29. 20Solución de problemas
  30. 21Uso y contribución de código abierto

4.5. naia-model-dev

Guía para desarrolladores sobre el uso del modelo Naia desde código. Después de ejecutar el modelo mediante 4.4 Descarga del modelo Naia, usa la API compatible con OpenAI servida localmente (sin pasarela, sin cola) tal cual. Con cualquier SDK o herramienta de OpenAI, solo tienes que apuntar la baseURL a este modelo.

No es exclusivo de naia-os/la interfaz — cualquier código que hable OpenAI Realtime/Chat/Audio/Embeddings se conecta tal cual, y puedes crear y ejecutar nuevas aplicaciones sobre este modelo.

1. Conexión · autenticación

  • Base REST: http://<host>:8892/v1 (127.0.0.1 en el mismo PC)
  • Realtime (WS): ws://<host>:8892/v1/realtime (un ws://<host>:8892 desnudo también funciona — la ruta /v1/realtime + el modelo predeterminado se aplican automáticamente)
  • Conexión: en local (127.0.0.1) / Tailscale, no se requiere autenticación — el contenedor verifica su propia licencia. Los clientes que necesitan un campo de clave (SDK de OpenAI, etc.) pueden pasar cualquier valor (naia). Cuando lo expongas de forma remota, coloca §4.4 Tailscale/VPN por delante.

🔑 Una sola clave — la clave de suscripción

  • Clave de suscripción — la clave de suscripción que obtienes del portal. Se usa solo en el momento de la ejecución del contenedor (activación) (-e NAIA_ACCOUNT_TOKEN=<subscription-key>). Comprueba la suscripción y obtiene una licencia de tiempo limitado (certificado).
  • No hay una clave de conexión separada. Una vez activado, el contenedor se verifica a sí mismo localmente con el certificado, así que los clientes (naia-os, SDK de OpenAI) solo necesitan conectarse por URL127.0.0.1 en el mismo PC, o Tailscale/VPN (§4.4) desde otro dispositivo. No llama a la pasarela por cada conexión.
  • El api_key de los ejemplos siguientes es un marcador de posición (el SDK de OpenAI requiere el campo) — el contenedor sin conexión no lo comprueba, así que cualquier valor como "naia" funciona.

2. Puntos de conexión (compatibles con OpenAI)

Punto de conexiónUso
GET /healthDisponibilidad {"ready":true,"services":{tts,stt,llm},"vad":true} (sin autenticación)
GET /v1/modelsLista de modelos
WS /v1/realtimeSesión de voz en tiempo real (VAD, barge-in, emoción)
POST /v1/chat/completionsChat (streaming)
POST /v1/audio/speechTexto a voz (TTS)
POST /v1/audio/transcriptionsVoz a texto (STT)
POST /v1/embeddingsEmbeddings

Chat (curl):

curl -s http://127.0.0.1:8892/v1/chat/completions \
  -H "Authorization: Bearer naia" -H "Content-Type: application/json" \
  -d '{"model":"naia-0.9-omni-24g","messages":[{"role":"user","content":"hi"}],"stream":false}'

SDK de OpenAI (Python) — solo cambia baseURL:

from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:8892/v1", api_key="naia")
print(client.chat.completions.create(
    model="naia-0.9-omni-24g",
    messages=[{"role": "user", "content": "hi"}],
).choices[0].message.content)

Transcripción (STT):

curl -s http://127.0.0.1:8892/v1/audio/transcriptions \
  -H "Authorization: Bearer naia" \
  -F file=@sample.wav -F model=naia-0.9-omni-24g

3. Voz en tiempo real — flujo de conexión (WS)

El mismo flujo que usa la demo en vivo 4.3. (Sin conexión, comienza de inmediato, sin cola/asignación de la pasarela.)

  1. Conectar — abre ws://<host>:8892.

  2. Primer fotograma (autenticación · idioma) — los WebSockets del navegador no pueden enviar encabezados, así que envía esto como primer mensaje:

    { "setup": { "apiKey": "naia", "locale": "en" } }
    
  3. Cuando el servidor envía session.created, configura la sesión con session.update:

    {
      "type": "session.update",
      "session": {
        "modalities": ["text", "audio"],
        "input_audio_format": "pcm16",
        "output_audio_format": "pcm16",
        "instructions": "<persona instructions>",
        "turn_detection": { "type": "server_vad" },
        "input_audio_transcription": { "language": "en" },
        "ref_audio_url": "<URL of a voice sample to mimic (optional)>"
      }
    }
    
  4. Intercambio

    Cliente → Servidor
    Entrada de voz{"type":"input_audio_buffer.append","audio":"<base64 PCM16 24kHz>"} (el VAD del servidor detecta el final del habla)
    Entrada de textoconversation.item.create y luego response.create
    Barge-inresponse.cancel
    Servidor → Cliente
    response.audio.deltafragmento de audio base64 PCM16 24kHz
    response.audio_transcript.delta / response.text.deltatexto de respuesta (streaming)
    conversation.item.input_audio_transcription.completedtranscripción de tu habla
    emotion.updatedetiqueta de emoción / prosodia (§5)
    response.donefin de un turno

4. Idiomas — 30 idiomas (predeterminado = auto/global)

El modelo admite 30 idiomas (árabe, birmano, chino, danés, neerlandés, inglés, finés, francés, alemán, griego, hebreo, hindi, indonesio, italiano, japonés, jemer, coreano, lao, malayo, noruego, polaco, portugués, ruso, español, suajili, sueco, tagalo, tailandés, turco, vietnamita).

  • Predeterminado (sin definir) = global/auto — detecta el idioma que hablaste y responde en ese idioma (por turno).
  • Para fijar un idioma específico, indica un código ISO-639-1 (p. ej. ko/en/ja) en setup.locale o en input_audio_transcription.language de session.update.

5. Formato de salida (etiquetas de emoción · prosodia)

El formato de salida está ajustado para la conversación de voz — si el cliente lo conoce, puede expresarse de forma más rica.

  • Etiquetas de prosodia: el texto de respuesta contiene etiquetas entre corchetes en inglés en minúsculas como [laughing], [sigh], [breath], [pause], [hesitation] intercaladas donde cambia la emoción (para la prosodia del habla). El modelo recibe la instrucción de no usar etiquetas en coreano como [웃음], acotaciones entre paréntesis como (smiling), ni asteriscos como *smiles*. Vocabulario conocido: laughing/laugh/laughter/chuckle/giggle · sigh/exhale · breath/inhale · pause · hesitation · gasp/cough/sneeze/yawn/sniff/hum · cry/sob/moan/whisper/shout/cheer (las demás etiquetas se transmiten tal cual).
  • Por cada etiqueta, el servidor envía un evento emotion.updated en correspondencia 1:1 (state == nombre de la etiqueta, en minúsculas):
    { "type": "emotion.updated", "state": "laughing", "tag": "[laughing]", "known": true }
    
  • La ruta TTS conserva las etiquetas y las introduce en la síntesis para la prosodia del habla, mientras que el text.delta del chat envía texto limpio con las etiquetas eliminadas. (Sin emojis, markdown ni autonarración entre paréntesis en la salida.)
  • Mapeo del cliente (referencia naia-os): asigna emotion.updated.state (etiqueta de prosodia) a las expresiones del avatar — laughing/chuckle/giggle/cheer → happy, sigh/exhale/cry/sob → sad, gasp → surprised, shout → angry, hesitation → think. La prosodia no emocional como breath·pause no cambia la expresión (mantén la anterior — para que no parpadee a neutral con cada respiración).
  • Se recomienda un manejo robusto: la salida del LLM no siempre es exacta. Prefiere emotion.updated, pero si falta, detecta automáticamente las etiquetas en la propia transcripción (mayúsculas [HAPPY] / etiquetas de prosodia en minúsculas) o las acotaciones filtradas ((smiles)·*sigh*) y refléjalas en la expresión; si no hay ninguna señal, mantén la expresión actual (cf. naia-os shell/src/lib/vrm/expression.ts extractExpression).

6. Cambiar el modelo de conversación · subir una nueva versión (operación)

Esta es la guía detallada para cambiarlo directamente desde la línea de comandos. Los suscriptores individuales pueden usarla tal cual (sin necesidad de clave), e incluye opciones de bloqueo para la operación compartida o de quiosco. El resumen sencillo está en 4.4 Sin conexión.

6.1 Cambiar el modelo de conversación (desde la 0.91)

Deja el contenedor tal cual y cambia, en tiempo de ejecución, solo el modelo que se encarga de la conversación. La voz (hablar y escuchar), la marca de agua y la verificación de la suscripción se mantienen.

Tres cosas que conviene saber primero:

  1. El modelo predeterminado es un LLM abierto integrado. Puedes volver al predeterminado en cualquier momento después de cambiarlo.
  2. El modelo que subas debe estar en formato GGUF. Además, como las funciones de voz consumen unos 10 GB de memoria, el modelo de conversación puede llegar a unos 14 GB aproximadamente. Los modelos más grandes se rechazan, y si la carga llega a fallar, se vuelve automáticamente al modelo que se estaba usando (la conversación no se interrumpe).
  3. Los suscriptores individuales no necesitan una clave aparte. La verificación de la suscripción (licencia) de tu propia máquina es ya tu autorización, así que basta con cambiarlo con los comandos de abajo — igual que la voz no necesita clave. (Solo en una caja compartida o de quiosco usada por varias personas, el operador puede poner un bloqueo en el arranque con -e NAIA_ADMIN_KEY=contraseña_definida, y en ese caso debes enviar también -H "Authorization: Bearer contraseña_definida" en las solicitudes.)

Práctica — primero fija solo la dirección:

BASE=http://127.0.0.1:8892     # desde otro dispositivo, usa la dirección https de §4.4 (p. ej. ...:8443)

① Mira qué modelo hay ahora y cuánta memoria queda:

curl -s $BASE/admin/llm/status

② Cambia el modelo — solo sustituye la parte del modelo entre comillas y pégalo. Puedes poner tal cual la dirección de la tarjeta de modelo de HuggingFace (https://huggingface.co/Qwen/Qwen2.5-7B-Instruct-GGUF) o su id (Qwen/Qwen2.5-7B-Instruct-GGUF):

curl -s -X POST $BASE/admin/llm/swap \
  -H "Content-Type: application/json" \
  -d '{"model":"Qwen/Qwen2.5-7B-Instruct-GGUF","pull":true}'

El prefijo hf.co/ y la cuantización (quant) se añaden automáticamente (el predeterminado es Q4_K_M). Si quieres una cuantización concreta, escríbela al final, como Qwen/Qwen2.5-7B-Instruct-GGUF:Q5_K_M. La primera vez que se descarga un modelo puede tardar de unas decenas de segundos a unos minutos.

②-sin conexión — cambiar con un archivo GGUF que tengas, sin internet. Cuando no hay internet, como en exposiciones o atención al cliente, en lugar de descargarlo de HuggingFace registras y usas un archivo GGUF que ya tienes. (Regla de distinción: si el nombre lleva una barra, como organización/repositorio, es HuggingFace en línea; si es un nombre simple sin barra, es un modelo local.)

Copia y pega línea por línea. En el lugar de mimodelo pon el nombre que quieras, y en el de mimodelo.gguf el nombre real del archivo:

podman cp ./mimodelo.gguf naia-omni:/app/models/mimodelo.gguf
podman exec naia-omni sh -lc 'printf "FROM /app/models/mimodelo.gguf\n" > /tmp/Modelfile && ollama create mimodelo -f /tmp/Modelfile'
curl -s -X POST $BASE/admin/llm/swap -H "Content-Type: application/json" -d '{"model":"mimodelo:latest","pull":false}'

⚠️ Un GGUF convertido o fusionado por ti mismo puede no incluir la plantilla de chat, lo que provoca respuestas incoherentes o cortadas. En ese caso, añade al Modelfile del paso 2 la plantilla de chat de esa familia de modelos (TEMPLATE) y los tokens de parada (PARAMETER stop) al registrarlo — los detalles para desarrolladores están en [implementación de referencia §7]. (Los GGUF Instruct oficiales de HuggingFace suelen llevarla integrada y se pueden usar tal cual.)

③ Vuelve al modelo predeterminado:

curl -s -X POST $BASE/admin/llm/restore

En una caja compartida o de quiosco (cuando el operador ha puesto NAIA_ADMIN_KEY), añade -H "Authorization: Bearer contraseña_definida" a cada comando de arriba. Los suscriptores individuales no lo necesitan.

Después de cambiarlo, las aplicaciones como naia-os pueden seguir conectándose a la misma dirección, tal cual (no hace falta reconectar). Si quieres que siga arrancando con ese modelo incluso tras reiniciar o actualizar, indica el modelo predeterminado al levantar el contenedor con -e NAIA_LLM_MODEL=Qwen/Qwen2.5-7B-Instruct-GGUF.

6.2 Actualizar a una nueva versión

Cuando salga una nueva versión, cambia solo la imagen (versión) y deja la suscripción y la configuración tal cual. La primera vez que enciendas la nueva versión, el contenedor se vuelve a autenticar automáticamente por internet (con la misma suscripción y el mismo dispositivo — no hace falta volver a introducir la clave a mano). Por eso, al actualizar debes estar conectado a internet.

podman pull ghcr.io/nextain/naia-0.9-omni-24g:latest      # descargar la última versión
podman stop naia-omni && podman rm naia-omni      # limpiar solo el contenedor (ver aviso abajo)
# Vuelve a ejecutar exactamente el mismo comando de arranque que usaste en la primera instalación — basta con montar el mismo volumen de licencia y listo.

⚠️ Al actualizar, no pulses "liberar dispositivo (release)". La liberación solo se usa cuando trasladas a otro ordenador el que estabas usando. Si liberas al intentar actualizar, tendrás que autenticarte desde cero. Para actualizar, basta con dejar tal cual el volumen de la licencia y se mantienen la suscripción y el registro del dispositivo.

Los usuarios que ya se hayan autenticado, con solo descargar la última versión y volver a encenderla como se ve arriba, pasan tal cual a la nueva versión que permite cambiar de modelo (la autenticación se mantiene). Si quieres descargar una versión concreta, en lugar de :latest usa el número de versión, como :0.91.

7. Véase también

  • Implementación de referencia / código de ejemplo (código abierto): el cliente de voz de naia-os shell/src/lib/voice/ (Apache 2.0) — contiene el cliente real que se comunica con esta API (naia-omni.ts) y el manejo de emoción/prosodia (emotion-tags.ts; mapeo de expresiones y extracción robusta en vrm/expression.ts). Úsalo como punto de partida para probar nuevos modelos y crear aplicaciones Tauri. Pruébalo en vivo en la demo en vivo 4.3.
  • Gama y precios: 4.1 Precios de los modelos
  • Nube (prevista): 4.6 En línea </content>
</invoke>