Руководство разработчика по использованию модели Naia из кода. После запуска модели через 4.4 Скачивание модели Naia используйте API, совместимый с OpenAI и обслуживаемый локально (без шлюза, без очереди) как есть. С любым OpenAI SDK или инструментом вам нужно лишь указать baseURL на эту модель.
Не только naia-os/оболочка — любой код, говорящий на OpenAI Realtime/Chat/Audio/Embeddings, подключается как есть, и поверх этой модели вы можете создавать и запускать новые приложения.
1. Подключение · аутентификация
- REST-база:
http://<host>:8892/v1(127.0.0.1на том же ПК) - Realtime (WS):
ws://<host>:8892/v1/realtime(голыйws://<host>:8892тоже работает — путь/v1/realtime+ модель по умолчанию применяются автоматически) - Подключение: локально (
127.0.0.1) / через Tailscale аутентификация не требуется — контейнер сам проверяет свою лицензию. Клиенты, которым нужно поле ключа (OpenAI SDK и т. п.), могут передать любое значение (naia). При удалённом доступе поставьте перед ним Tailscale/VPN из §4.4.
🔑 Один ключ — ключ подписки
- Ключ подписки — ключ подписки, который вы получаете в портале. Используется только при запуске контейнера (активации) (
-e NAIA_ACCOUNT_TOKEN=<subscription-key>). Он проверяет подписку и получает лицензию с ограниченным сроком действия (сертификат). - Отдельного ключа подключения нет. После активации контейнер проверяет лицензию локально сам с помощью сертификата, поэтому клиентам (naia-os, OpenAI SDK) достаточно подключиться по URL —
127.0.0.1на том же ПК или Tailscale/VPN (§4.4) с другого устройства. Он не обращается к шлюзу при каждом подключении. api_keyв примерах ниже — это заполнитель (OpenAI SDK требует это поле) — офлайн-контейнер его не проверяет, поэтому подходит любое значение вроде"naia".
2. Эндпоинты (совместимые с OpenAI)
| Эндпоинт | Назначение |
|---|---|
GET /health | Готовность {"ready":true,"services":{tts,stt,llm},"vad":true} (без аутентификации) |
GET /v1/models | Список моделей |
WS /v1/realtime | Голосовая сессия в реальном времени (VAD, перебивание, эмоции) |
POST /v1/chat/completions | Чат (потоковый) |
POST /v1/audio/speech | Текст в речь (TTS) |
POST /v1/audio/transcriptions | Речь в текст (STT) |
POST /v1/embeddings | Эмбеддинги |
Чат (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}'
OpenAI SDK (Python) — просто замените 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)
Транскрипция (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. Голос в реальном времени — поток подключения (WS)
Тот же поток, что использует 4.3 живое демо. (Офлайн запускается сразу, без очереди/назначения шлюза.)
-
Подключение — откройте
ws://<host>:8892. -
Первый кадр (аутентификация · язык) — браузерные WebSocket не могут отправлять заголовки, поэтому отправьте первым сообщением:
{ "setup": { "apiKey": "naia", "locale": "en" } } -
Когда сервер пришлёт
session.created, настройте сессию с помощью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)>" } } -
Обмен
Клиент → Сервер Голосовой ввод {"type":"input_audio_buffer.append","audio":"<base64 PCM16 24kHz>"}(server VAD определяет конец речи)Текстовый ввод conversation.item.create, затемresponse.createПеребивание response.cancelСервер → Клиент response.audio.deltaфрагмент аудио base64 PCM16 24kHz response.audio_transcript.delta/response.text.deltaтекст ответа (потоковый) conversation.item.input_audio_transcription.completedтранскрипция вашей речи emotion.updatedтег эмоции / просодии (§5) response.doneконец одного хода
4. Языки — 30 языков (по умолчанию = авто/глобально)
Модель поддерживает 30 языков (арабский, бирманский, китайский, датский, нидерландский, английский, финский, французский, немецкий, греческий, иврит, хинди, индонезийский, итальянский, японский, кхмерский, корейский, лаосский, малайский, норвежский, польский, португальский, русский, испанский, суахили, шведский, тагальский, тайский, турецкий, вьетнамский).
- По умолчанию (не задано) = глобально/авто — модель определяет язык, на котором вы говорили, и отвечает на этом языке (для каждого хода).
- Чтобы закрепить конкретный язык, укажите код ISO-639-1 (например
ko/en/ja) вsetup.localeили вinput_audio_transcription.languageвнутриsession.update.
5. Формат вывода (эмоции · теги просодии)
Формат вывода настроен для голосового разговора — если клиент знает его, он может выразить ответ богаче.
- Теги просодии: текст ответа содержит строчные английские теги в квадратных скобках вроде
[laughing],[sigh],[breath],[pause],[hesitation], вставленные там, где меняется эмоция (для просодии речи). Модели предписано не использовать корейские теги вроде[웃음], ремарки в скобках вроде(smiling)или звёздочки вроде*smiles*. Известный словарь:laughing/laugh/laughter/chuckle/giggle · sigh/exhale · breath/inhale · pause · hesitation · gasp/cough/sneeze/yawn/sniff/hum · cry/sob/moan/whisper/shout/cheer(прочие теги передаются как есть). - Для каждого тега сервер отправляет одно соответствующее событие
emotion.updated(state== имя тега, строчными буквами):{ "type": "emotion.updated", "state": "laughing", "tag": "[laughing]", "known": true } - Путь TTS сохраняет теги и передаёт их в синтез для просодии речи, тогда как chat
text.deltaотправляет чистый текст с удалёнными тегами. (Никаких эмодзи, markdown или закадровых ремарок в скобках в выводе.) - Сопоставление на клиенте (референс naia-os): сопоставьте
emotion.updated.state(тег просодии) с выражениями аватара —laughing/chuckle/giggle/cheer → happy,sigh/exhale/cry/sob → sad,gasp → surprised,shout → angry,hesitation → think. Неэмоциональная просодия вродеbreath·pauseне меняет выражение (сохраняйте предыдущее — чтобы аватар не моргал в нейтраль при каждом вдохе). - Рекомендуется устойчивая обработка: вывод LLM не всегда точен. Предпочитайте
emotion.updated, но если его нет, автоматически определяйте теги в самой транскрипции (заглавные[HAPPY]/ строчные теги просодии) или просочившиеся ремарки ((smiles)·*sigh*) и отражайте их в выражении; если подсказки нет, сохраняйте текущее выражение (см. naia-osshell/src/lib/vrm/expression.tsextractExpression).
6. Смена модели диалога · загрузка новой версии (эксплуатация)
Это подробное руководство по смене из командной строки. Индивидуальные подписчики могут пользоваться им как есть (ключ не нужен), а также включены опции блокировки для совместной и киоск-эксплуатации. Простую сводку см. в 4.4 Офлайн.
6.1 Смена модели диалога (начиная с 0.91)
Не трогая контейнер, вы меняете только модель, отвечающую за диалог, прямо во время работы. Голос (речь и слух), водяной знак и проверка подписки сохраняются.
Сначала три вещи, которые нужно знать:
- Модель по умолчанию — встроенная открытая LLM. Сменив её, вы в любой момент можете вернуться к модели по умолчанию.
- Загружаемая новая модель должна быть в формате GGUF. И поскольку голосовые функции занимают около 10 ГБ памяти, модель диалога может занимать примерно до 14 ГБ. Более крупные модели будут отклонены, а если при загрузке что-то пойдёт не так, система автоматически вернётся к прежней модели (диалог не прервётся).
- Индивидуальным подписчикам отдельный ключ не нужен. Проверка подписки (лицензия) на вашей собственной машине и есть ваше разрешение, поэтому достаточно сменить модель командой ниже — так же, как голосу не нужен ключ. (Только на совместных и киоск-боксах, которыми пользуется несколько человек, оператор при запуске может поставить блокировку через
-e NAIA_ADMIN_KEY=заданный_пароль, и тогда к запросу нужно добавлять-H "Authorization: Bearer заданный_пароль".)
Практика — сначала зададим адрес:
BASE=http://127.0.0.1:8892 # с другого устройства используйте https-адрес из §4.4 (например, ...:8443)
① Смотрим, какая сейчас модель и сколько осталось памяти:
curl -s $BASE/admin/llm/status
② Меняем модель — замените только место модели внутри кавычек и вставьте.
Можно как есть вставить адрес карточки модели HuggingFace (https://huggingface.co/Qwen/Qwen2.5-7B-Instruct-GGUF) или её 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}'
Префикс hf.co/ и квантизация (quant) добавляются автоматически (по умолчанию Q4_K_M). Если нужна конкретная квантизация, укажите её в конце, например Qwen/Qwen2.5-7B-Instruct-GGUF:Q5_K_M. При первой загрузке модели это займёт от нескольких десятков секунд до нескольких минут.
②-офлайн — смена на ваш собственный GGUF-файл без интернета.
Когда интернета нет, как на выставке или консультации, не скачивайте с HuggingFace, а зарегистрируйте и смените на уже имеющийся у вас GGUF-файл. (Правило различения: если в имени есть слеш, как организация/репозиторий, это онлайн-режим HuggingFace, а простое имя без слеша — это локальная модель.)
Копируйте и вставляйте по одной строке. На место моя_модель впишите желаемое имя, а на место моя_модель.gguf — реальное имя файла:
podman cp ./моя_модель.gguf naia-omni:/app/models/моя_модель.gguf
podman exec naia-omni sh -lc 'printf "FROM /app/models/моя_модель.gguf\n" > /tmp/Modelfile && ollama create моя_модель -f /tmp/Modelfile'
curl -s -X POST $BASE/admin/llm/swap -H "Content-Type: application/json" -d '{"model":"моя_модель:latest","pull":false}'
⚠️ В самостоятельно сконвертированных или слитых GGUF может отсутствовать шаблон чата, из-за чего ответы будут бессвязными или обрезанными. В этом случае на шаге 2 добавьте в Modelfile шаблон чата для семейства модели (
TEMPLATE) и стоп-токены (PARAMETER stop) и зарегистрируйте — подробности для разработчиков в [референсной реализации §7]. (Официальные Instruct GGUF с HuggingFace обычно содержат их встроенно, и их можно использовать как есть.)
③ Возвращаемся к модели по умолчанию:
curl -s -X POST $BASE/admin/llm/restore
Если это совместный или киоск-бокс (оператор установил
NAIA_ADMIN_KEY), добавьте к каждой из команд выше-H "Authorization: Bearer заданный_пароль". Индивидуальным подписчикам это не нужно.
После смены приложения вроде naia-os подключаются по тому же адресу как есть (переподключаться не нужно). Если вы хотите, чтобы после перезапуска или обновления система продолжала запускаться с этой моделью, при запуске контейнера задайте модель по умолчанию через -e NAIA_LLM_MODEL=Qwen/Qwen2.5-7B-Instruct-GGUF.
6.2 Обновление до новой версии
Когда выходит новая версия, вы меняете только образ (версию), а подписку и настройки оставляете как есть. При первом запуске новой версии контейнер автоматически повторно проходит аутентификацию через интернет (с той же подпиской и устройством — вводить ключ заново вручную не нужно). Поэтому при обновлении нужно быть подключённым к интернету.
podman pull ghcr.io/nextain/naia-0.9-omni-24g:latest # получить последнюю версию
podman stop naia-omni && podman rm naia-omni # очистить только контейнер (см. предупреждение ниже)
# Снова выполните ту же команду запуска, что вы использовали при первой установке — достаточно подключить тот же лицензионный том как есть.
⚠️ При обновлении не нажимайте «освобождение устройства (release)». Освобождение используется только при переносе используемого компьютера на другой компьютер. Если вы освободите устройство при попытке обновления, придётся проходить аутентификацию заново с нуля. При обновлении подписка и регистрация устройства сохраняются, если оставить лицензионный том как есть.
Уже прошедшие аутентификацию пользователи, просто получив последнюю версию и снова запустив её как показано выше, плавно переходят на новую версию, в которой можно менять модель (аутентификация сохраняется). Чтобы получить конкретную версию, вместо :latest укажите номер версии, например :0.91.
7. См. также
- Референсная реализация / пример кода (открытый исходный код): голосовой клиент naia-os
shell/src/lib/voice/(Apache 2.0) — содержит реальный клиент, который общается с этим API (naia-omni.ts), и обработку эмоций/просодии (emotion-tags.ts; сопоставление выражений и устойчивое извлечение вvrm/expression.ts). Используйте его как отправную точку для тестирования новых моделей и создания приложений Tauri. Попробуйте вживую в 4.3 живое демо. - Линейка и цены: 4.1 Цены на модели
- Облако (планируется): 4.6 Онлайн