Airi v0.1.0 版本编年史:从 VRM 角色渲染到实时语音交互的基座构建
2026/9/10 15:40:28 网站建设 项目流程

Airi v0.1.0 版本编年史:从 VRM 角色渲染到实时语音交互的基座构建

【免费下载链接】airi💖🧸 Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-sama's altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi

导读:Airi 是一个自托管、数据归你所有的 AI 数字生命体(Grok Companion 同类项目),目标是让"电子灵魂"走进现实世界。本文基于仓库 docs/content/en/docs/chronicles/version-v0.1.0/index.md 中记录的 v0.1.0 版本编年史,梳理该版本为整个项目奠定的六大能力基座——VRM 3D 角色前端集成、嘴部(TTS 口型)、听觉(实时语音转写)、面部表情、多语言与 UI 优化,并结合当前仓库源码逐项验证其底层实现。读完本文,你将理解一个"能看见、会说话、听得懂、有表情"的数字生命体在渲染层与音频链路上是如何一步步搭起来的。


一、版本概览:v0.1.0 在构建什么

从编年史的勾选清单可以清楚看到,v0.1.0 的目标不是某个单一功能,而是为数字生命体补齐感知与表达的最小闭环

功能域关键里程碑完成状态
VRM 前端集成模型接入(12/5)、待机动画(12/6)、眨眼(12/7)✅ 完成
嘴部(Mouth)unspeech 项目、TTS 集成(6/8)、11Labs 封装(12/3)✅ 完成
听觉(Hearing)说话按钮(6/9)、socket.io 双向通信(6/10)、浏览器端 Whisper 转写✅ 完成(WebRTC 方案暂缓)
面部表情前端 VRM 表情控制(12/7)✅ 完成
多语言UI 基础 i18n(12/13)部分完成(UI 层已落地)
UI 优化安全区域(12/4)、移动端适配(12/5)、设置菜单(12/7)✅ 完成

有意思的是,编年史中很多"聆听"相关条目经历了反复的"评估 → 推翻 → 再评估"过程(如 WebRTC 被搁置、Whisper 从whisper.cpp转向浏览器内 WebGPU 推理),这些技术选型决策本身就是一份难得的工程笔记,下文会结合仓库现状逐一还原其最终走向。


二、VRM 前端集成:让角色"活"在浏览器里

编年史第一条主线是前端 VRM 集成。得益于@pixiv/three-vrm生态,Airi 选择了标准的 VRM(3D 虚拟角色模型)格式作为角色载体,并依次完成了模型加载、待机动画(.vrma)与眨眼三件套。

2.1 加载管线:GLTFLoader + VRM 插件链

当前仓库的加载器实现在 packages/stage-ui-three/src/composables/vrm/loader.ts,它基于GLTFLoader注册了三条插件链:

  • VRMLoaderPlugin:解析 VRM 扩展(含自定义的AiriMToonMaterialLoaderPlugin,用于 MToon 材质的描边兜底策略);
  • VRMAnimationLoaderPlugin:解析.vrma动画文件,这正是编年史中"待机动画"的落地依赖;
  • 单例化的GLTFLoader被全局复用,避免重复构建。

2.2 模型加载与场景自举

packages/stage-ui-three/src/composables/vrm/core.ts 的loadVrm()完整展现了加载后的"整形"流程:

  1. 性能优化VRMUtils.removeUnnecessaryVertices()移除不可见顶点、VRMUtils.combineSkeletons()合并骨骼,并遍历关闭frustumCulled
  2. 视线代理:为_vrm.lookAt挂载VRMLookAtQuaternionProxy,让模型能播放"视线跟随"动画;
  3. 朝向矫正:将模型正面朝向预置到 Z 轴负方向;
  4. 包围盒计算:遍历网格(过滤VRMC_springBone_collider前缀的弹簧骨碰撞体)计算模型尺寸与中心,并把枢轴点上移至胸口高度(modelCenter.y += modelSize.y / 5);
  5. 相机自举:以默认 fov=40 计算初始相机偏移(size.x/16, size.y/8, -(size.y/3)/tan(fov/2)),保证画面中呈现模型上 2/3 区域。

组件层 packages/stage-ui-three/src/components/Model/VRMModel.vue 则负责把这一切接入渲染循环:它管理loadStart / loadingProgress / loaded / error生命周期事件、模型切换时的资源销毁/暂存(vrm-instance-cache),并在每帧依次驱动AnimationMixer → humanoid → lookAt → blink → emote → lipSync → expressionManager → springBoneManager的更新链。

2.3 待机动画:.vrma的加载与重锚定

编年史提到的 VRM 待机动画,仓库中通过 packages/stage-ui-three/src/composables/vrm/animation.ts 实现:loadVRMAnimation()用插件加载.vrma文件并取出首个VRMAnimationclipFromVRMAnimation()将其转换为 three.jsAnimationClip,而reAnchorRootPositionTrack()则把动画的 Hips 根位置轨道整体平移,使动画原点对齐模型原点——这是不同角色套用同一份动作数据时画面不漂移的关键。

2.4 眨眼与眼动:让角色"看起来活着"

编年史 12/7 的"VRM blinking"在当前源码中对应useBlink()

  • 眨眼间隔在1~6 秒间随机;
  • 单次眨眼持续0.2 秒,用正弦曲线Math.sin(π * progress)生成平滑的blink表情权重;
  • 每次眨眼结束后重新掷骰下一次间隔,模拟真实节奏。

同文件还提供了useIdleEyeSaccades()模拟空闲时的眼跳扫视:在注视目标周围 ±0.25 的随机范围内生成新的注视点(模拟 27 寸显示器 65cm 距离的视线落点),并通过lookAt.target.position.lerp()平滑过渡。


三、嘴部系统:TTS 输出如何驱动 VRM 口型

编年史"嘴部(Mouth)"分支记录了两条支线:一是创建了独立的unspeech项目并在 6/8 集成 TTS;二是 12/3 把11Labs封装为独立 npm 包(f9ddf9af)。这体现了 Airi 将"语音合成"与"语音转写"解耦、各自沉淀为可复用包的设计思路。

3.1 口型同步:从音频波形到 BlendShape

渲染侧的口型驱动实现在 packages/stage-ui-three/src/composables/vrm/lip-sync.ts,链路为:TTS 播放的AudioBufferSourceNode→ wLipSync AudioWorklet 分析 → VRM 表情权重。核心细节:

  • 音素映射:wLipSync 输出 A/E/I/O/U/S 五个原始通道,代码先做重映射(S→I),再映射到 VRM BlendShape(A→aaE→eeI→ihO→ohU→ou);
  • winner + runner 混合策略:源码注释指出,若把所有口型按原始权重一起混合,会因 A 口型形变量最大而整体偏向 A。改进后只混合权重最大的两个口型(winner + runner×0.6),口型更自然;
  • 平滑与静音判定ATTACK=50(起始速度)、RELEASE=30(结束速度)、CAP=0.7(权重上限)、SILENCE_VOL=0.04,并用 160ms 的IDLE_MS判定停顿,避免语音间隙时嘴部僵住。

这也是对编年史"嘴部"最完整的注脚:前端角色说话的表现力,取决于"音频 → 音素权重 → BlendShape"这条链路的每一环调校。


四、听觉系统:从说话按钮到实时语音转写

"Hearing"是编年史中篇幅最长、决策过程最曲折的部分,值得单独拆解。

4.1 第一层:说话按钮与 socket.io 双向通信

6/9 先实现了"talk button";6/10 采用socket.io做前端到后端音频流的双向通道。编年史里留下了非常诚实的技术笔记:

  • Socket.IO 并非基于原生 WebSocket(它在此基础上增加了重连、心跳、二进制分包等语义),这一认知直接决定了后续的架构判断;
  • 前端使用socket.io-client、后端使用socket.io,并调研了 Nuxt 3 + socket.io 在生产环境 WebSocket 失效的坑(Nuxt/Nitro 对 WebSocket 的支持仍在演进);
  • 曾评估用WebRTC传输音频(VueUse 也支持),但结论是"Nuxt 和 Nitro 尚不支持,暂缓,可留待群聊或 Discord 场景"——这正是当前仓库中 packages/better-ws 等 WebSocket 基础设施出现的背景。

4.2 第二层:浏览器内 Whisper 转写的技术选型

编年史记录了转写引擎的探索轨迹:最初考虑whisper.cpp以 Node.js C++ Addon 嵌入,随后发现 Chrome/Edge 已支持WebGPUTransformers.js + ONNX Runtime WebGPU可以让 Whisper 直接跑在浏览器里(当时已有 Xenova 的 Realtime Whisper WebGPU 实时演示)。这一"模型下放到端侧"的方向,与 Airi 强调的"自托管、数据归你"理念一脉相承。

4.3 今日实现:Silero VAD + 分段录音 + 音量兜底

编年史最后还残留两个未勾选项(Whisper WebGPU Demo 12/10、MicVAD Demo 12/11、MicVAD + ONNX Whisper 实时转写 12/12),它们在当前仓库中已被完整落地,核心实现位于:

  • packages/stage-ui/src/workers/vad/vad.ts:基于onnx-community/silero-vad(fp32)的 VAD 处理器,默认配置如下:
参数默认值含义
sampleRate16000送入模型的采样率
speechThreshold0.3语音判定概率阈值
exitThreshold0.1已处于录音态时的退出阈值(迟滞)
minSilenceDurationMs400判定语音结束所需的最短静音
speechPadMs80语音前后保留的静音填充
minSpeechDurationMs250最短有效语音,过短则取消
maxBufferDuration30单段缓冲最大秒数

其内部用"前一缓冲区队列"实现语音前导填充(createLeadingSpeechAudio),用processingChain串行化 AudioWorklet 的消息处理,避免并发乱序——这正是编年史 12/12"MicVAD + 实时转写"的最终形态。

  • packages/stage-ui/src/composables/audio/voice-input-session.ts:把 VAD 事件(speech-start/end/cancel/ready)编排成完整的"录音段"生命周期,并内置音量兜底方案:用AnalyserNode的时域电平(默认起始阈值 10、停止阈值 6、连续 4 帧触发)在 VAD 初始化失败或流式模式外继续保障分段可用。

  • packages/stage-ui/src/composables/audio/voice-input-vad-startup.ts:startVoiceInputVadDetectionSafely()对 VAD 初始化做容错启动,初始化失败会记录vad-init-failed日志并优雅降级,不影响整体会话。


五、面部表情:7 种情绪状态的权重编排

编年史 12/7 的"Frontend VRM facial expression control"对应 packages/stage-ui-three/src/composables/vrm/expression.ts 的useVRMEmote(),它定义了一张情绪状态表:

情绪BlendShape 组合(权重)混合时长
happyhappy 0.7 + aa 0.20.4s
sadsad 0.7 + oh 0.150.4s
angryangry 0.7 + ee 0.30.3s
surprisedsurprised 0.8 + oh 0.40.15s
neutralneutral 1.00.6s
thinkthink 0.70.5s
relaxedrelaxed 0.70.4s

实现要点:

  • 主表情权重刻意压到0.7~0.8,源码注释明确指出这是为了避免 issue #590 中"表情过猛/笑过头"的问题;
  • 过渡用lerp+easeInOutCubic缓动,且从当前显示值而非 0 开始过渡,避免表情跳变;
  • setEmotionWithResetAfter(name, ms)支持"播放 N 毫秒后自动回到 neutral",适合对话中一句一表情的驱动节奏;
  • 所有表达式在vrm.expressionManager.expressionMap中做大小写不敏感的模型适配,兼容不同作者命名习惯的 VRM。

六、多语言支持:i18n 基础设施

编年史中"Multilingual Support"仅勾选了 UI 层(12/13 的basic i18n提交)。这一决策在仓库中留下了清晰的足迹:packages/i18n维护着覆盖en / ja / ko / zh-Hans / es等多个语言目录的 yaml 词条与类型化导出(packages/i18n/src),并在docs/content下配套了 en、ja、ko、zh-Hans 多语言文档体系。UI 文本、设置项、舞台相关文案均已走统一词条,为后续内容层多语言铺好了路。


七、UI 优化:移动端与桌面端的适配细节

编年史"UI Optimization"记录了四条移动端与交互相关的优化,与仓库stage-ui/stage-ui-three的演进方向吻合:

  • 安全区域(12/4):为刘海屏/异形屏预留安全区,保证控制按钮不被系统手势遮挡;
  • Canvas 场景移动端适配(12/5):配合 Live2D Viewer 改进与"模型缩放 + 自适应比例",让角色在不同屏幕宽高比下保持构图;
  • 设置菜单与溢出优化(12/7):收敛入口、处理窄屏溢出,交互密度向桌面体验看齐。

这些条目看似琐碎,却是"数字生命体走进现实"的必要条件——无论手机还是桌面窗口,角色都必须以正确比例、正确区域呈现在用户面前。


八、模型生态:VRM 工具链与素材来源

编年史末尾专门列出了 Models 章节,记录了@pixiv/three-vrm的引入(感谢 kwaa 的引导)以及完整的配套工具链,这组工具在 v0.1.0 的日常迭代中承担角色制作与动画生产:

  • 模型制作:Blender 的 VRM Add-on(导入/导出 VRM);
  • 摆姿/预览:Steam 上的 VRM Posing Desktop,可用于快速验证模型姿态;
  • 素材市场:Vket Store 的角色商品列表,是现成 VRM 模型的主要来源之一;
  • 动画规范:VRM Animation(.vrma)1.0 规范,以及 Unity 侧把普通 AnimationClip 转换为.vrma的示例工程(AnimationClipToVrmaSample),配合 BOOTH 等平台可购买/下载角色动画。

仓库侧,packages/stage-ui-three已内置 VRM 动画资源目录 packages/stage-ui-three/src/assets/vrm/animations/index.ts,且engines/stage-tamagotchi-godot中还有独立的 VRM 运行时导入文档 docs/vrm-runtime-import.md,说明 VRM 资产链已延伸到多个渲染后端。


九、小结:v0.1.0 的遗产

回看整份编年史,v0.1.0 最大的价值不是某一次提交,而是确立了一条可复用的"数字生命能力链":

  1. 看见:VRM 模型加载、待机动画、眨眼与眼动(animation.ts);
  2. 说话:TTS(unspeech / 11Labs)+ wLipSync 口型驱动(lip-sync.ts);
  3. 听得懂:从 socket.io 音频通道演进到 Silero VAD + 端侧 Whisper 的实时转写(vad.ts、voice-input-session.ts);
  4. 有表情:7 种情绪的权重化混合编排(expression.ts)。

这条链上的每个环节都经历了"选型 → 试错 → 落地"的完整过程,而仓库源码正是这些决策的最终见证。对希望构建同类"AI 角色 + 实时语音 + 3D 渲染"项目的开发者而言,v0.1.0 编年史 + 当前源码的组合,是一份难得的端到端参考:既能看到为什么这么选(编年史的废弃勾选项),也能看到怎么做(源码的每一处调参注释)。

【免费下载链接】airi💖🧸 Self hosted, you-owned Grok Companion, a container of souls of waifu, cyber livings to bring them into our worlds, wishing to achieve Neuro-sama's altitude. Capable of realtime voice chat, Minecraft, Factorio playing. Web / macOS / Windows supported.项目地址: https://gitcode.com/GitHub_Trending/ai/airi

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询