奈亚
目录
  1. 1视频手册
  2. 2Naia OS Live USB
  3. 3安装部署
  4. 3.1Naia 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个人电台 DJ 与展览导览
  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. 19Naia 账号
  29. 20故障排除
  30. 21开源使用与贡献

4.5. naia-model-dev

从代码使用 Naia 模型的开发者指南。 在按照 4.4 Naia 模型下载运行模型之后,直接使用本地提供的 OpenAI 兼容 API (无网关、无队列)。在任何 OpenAI SDK 或工具中,你只需将 baseURL 指向这个模型。

不局限于 naia-os / 外壳 — 任何会说 OpenAI Realtime/Chat/Audio/Embeddings 的代码都能直接连接, 你还可以在这个模型之上构建并运行新的应用程序

1. 连接 · 认证

  • REST 基址http://<host>:8892/v1(同一台 PC 用 127.0.0.1
  • Realtime(WS)ws://<host>:8892/v1/realtime(裸的 ws://<host>:8892 也可用——路径 /v1/realtime + 默认模型自动应用)
  • 连接:在本地(127.0.0.1)/ Tailscale 上,无需认证——容器会自我校验其许可证。需要密钥字段的客户端(OpenAI SDK 等)可以传入任意值(naia)。当对外暴露时,请在前面加上 §4.4 的 Tailscale/VPN。

🔑 唯一的密钥 — 订阅密钥

  • 订阅密钥 — 你从门户获取的订阅密钥。仅在容器运行时(激活)使用-e NAIA_ACCOUNT_TOKEN=<subscription-key>)。它会检查订阅并获取一个带时限的许可证(证书)。
  • 没有单独的连接密钥。 一旦激活,容器会用证书在本地自我校验,因此客户端(naia-os、OpenAI SDK)只需通过 URL 连接——同一台 PC 用 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嵌入

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}'

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 无法发送 header,因此作为第一条消息发送:

    { "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>"}(服务器 VAD 检测语音结束)
    文本输入conversation.item.create,再 response.create
    打断response.cancel
    服务器 → 客户端
    response.audio.deltabase64 PCM16 24kHz 音频块
    response.audio_transcript.delta / response.text.delta回答文本(流式)
    conversation.item.input_audio_transcription.completed你语音的转录
    emotion.updated情绪 / 韵律标签(§5)
    response.done一轮结束

4. 语言 — 30 种语言(默认 = 自动 / 全局)

模型支持 30 种语言(阿拉伯语、缅甸语、中文、丹麦语、荷兰语、英语、芬兰语、法语、 德语、希腊语、希伯来语、印地语、印尼语、意大利语、日语、高棉语、韩语、老挝语、马来语、挪威语、 波兰语、葡萄牙语、俄语、西班牙语、斯瓦希里语、瑞典语、他加禄语、泰语、土耳其语、越南语)。

  • 默认(未设置)= 全局 / 自动 — 它会检测你所说的语言,并用该语言回复(每轮)。
  • 固定某种特定语言,在 setup.localesession.updateinput_audio_transcription.language 中给出 ISO-639-1 代码(例如 ko/en/ja)。

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(其他标签会原样传递)。
  • 对于每个标签,服务器会发送一个 1:1 的 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 → happysigh/exhale/cry/sob → sadgasp → surprisedshout → angryhesitation → think。像 breath·pause 这样的非情绪韵律不会改变表情 (保持之前的——这样它不会在每次呼吸时都闪回中性)。
  • 建议进行稳健处理:LLM 输出并不总是精确。优先使用 emotion.updated,但如果它 缺失,则在转录文本本身自动检测标签(大写 [HAPPY] / 小写韵律标签)或 泄漏的舞台提示((smiles)·*sigh*)并反映到表情中;如果没有线索,则保持 当前表情(参见 naia-os shell/src/lib/vrm/expression.tsextractExpression)。

6. 更换对话模型 · 上传新版本(运维)

这是通过命令行直接更换的详细指南。个人订阅者也可以照样使用(无需密钥),同时也包含用于共享 / 自助终端运维的锁定选项。简易摘要4.4 离线

6.1 更换对话模型(从 0.91 起)

保持容器不动,仅在运行时更换负责对话的模型。语音(说与听)、水印和订阅认证都保持不变。

先了解三件事:

  1. 默认模型是内置的开源 LLM。换了之后可以随时恢复为默认。
  2. 要上传的新模型必须是 GGUF 格式。而且语音功能已占用约 10GB 内存,因此对话模型最多大约可达 14GB。更大的模型会被拒绝;即便上传过程中失败,也会自动回退到之前使用的模型(对话不会中断)。
  3. 个人订阅者无需单独的密钥。 你本机的订阅认证(许可证)即为权限,因此直接用下面的命令更换即可——这和语音不需要密钥是一样的。(只有在多人共用的共享 / 自助终端机上,运维者才能在启动时用 -e NAIA_ADMIN_KEY=你设定的密码 加锁,此时请求中要一并发送 -H "Authorization: Bearer 你设定的密码"。)

实操 — 先设定好地址:

BASE=http://127.0.0.1:8892     # 在其他设备上请用 §4.4 的 https 地址(例如 ...: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 在线不带斜杠的简单名称则为本地模型。)

请逐行复制粘贴。把 mymodel 处换成你想要的名称,mymodel.gguf 处换成实际文件名:

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

⚠️ 自行转换 / 合并的 GGUF 可能缺少聊天模板,导致回答语无伦次或被截断。这种情况下,请在第 2 步的 Modelfile 中加入对应模型系列的聊天模板(TEMPLATE)和停止标记(PARAMETER stop)后再注册——开发者详情见 [参考实现 §7]。(HuggingFace 官方 Instruct GGUF 通常已内置,可直接使用。)

③ 恢复为默认模型:

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)”。 解除仅用于把当前电脑迁移到另一台电脑。若在更新时误做解除,就得从头重新认证。更新时只要保留许可证卷,订阅和设备注册就会保持不变。

之前已认证的用户只需照上面拉取最新版本并重新启动,即可平滑过渡到支持更换模型的新版本(认证保持)。若要精确指定某个版本,可用 :0.91 这样的版本号代替 :latest

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 在线