Ная
Оглавление
  1. 1Видео-инструкция
  2. 2Naia OS Live USB
  3. 3Установка и развертывание
  4. 3.1Установка Naia OS (ISO)
  5. 3.2Установка приложения
  6. 4Начало работы
  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. 5Главный экран
  14. 6Чат
  15. 6.1Персональный радио-диджей и гид по выставке
  16. 7История разговора
  17. 8Ход работы
  18. 9Навыки
  19. 10Каналы
  20. 11Агенты
  21. 12Диагностика
  22. 13Рабочее пространство
  23. 14Браузер
  24. 15Управление панелями
  25. 16Голосовой чат
  26. 17Настройки
  27. 18Детали инструмента
  28. 19Аккаунт Naia
  29. 20Устранение неполадок
  30. 21Использование и вклад в открытый код

4.5. naia-model-dev

Руководство разработчика по использованию модели 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) достаточно подключиться по URL127.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 живое демо. (Офлайн запускается сразу, без очереди/назначения шлюза.)

  1. Подключение — откройте ws://<host>:8892.

  2. Первый кадр (аутентификация · язык) — браузерные WebSocket не могут отправлять заголовки, поэтому отправьте первым сообщением:

    { "setup": { "apiKey": "naia", "locale": "en" } }
    
  3. Когда сервер пришлёт 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)>"
      }
    }
    
  4. Обмен

    Клиент → Сервер
    Голосовой ввод{"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-os shell/src/lib/vrm/expression.ts extractExpression).

6. Смена модели диалога · загрузка новой версии (эксплуатация)

Это подробное руководство по смене из командной строки. Индивидуальные подписчики могут пользоваться им как есть (ключ не нужен), а также включены опции блокировки для совместной и киоск-эксплуатации. Простую сводку см. в 4.4 Офлайн.

6.1 Смена модели диалога (начиная с 0.91)

Не трогая контейнер, вы меняете только модель, отвечающую за диалог, прямо во время работы. Голос (речь и слух), водяной знак и проверка подписки сохраняются.

Сначала три вещи, которые нужно знать:

  1. Модель по умолчанию — встроенная открытая LLM. Сменив её, вы в любой момент можете вернуться к модели по умолчанию.
  2. Загружаемая новая модель должна быть в формате GGUF. И поскольку голосовые функции занимают около 10 ГБ памяти, модель диалога может занимать примерно до 14 ГБ. Более крупные модели будут отклонены, а если при загрузке что-то пойдёт не так, система автоматически вернётся к прежней модели (диалог не прервётся).
  3. Индивидуальным подписчикам отдельный ключ не нужен. Проверка подписки (лицензия) на вашей собственной машине и есть ваше разрешение, поэтому достаточно сменить модель командой ниже — так же, как голосу не нужен ключ. (Только на совместных и киоск-боксах, которыми пользуется несколько человек, оператор при запуске может поставить блокировку через -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 Онлайн