AIRI 十月 DevLog 技术复盘:Tauri 迁往 Electron、Control Island 与 Eventa 事件驱动架构
2026/9/10 0:13:20 网站建设 项目流程

AIRI 十月 DevLog 技术复盘:Tauri 迁往 Electron、Control Island 与 Eventa 事件驱动架构

【免费下载链接】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 项目的官方开发日志(DevLog @ 2025.10.20)展开,逐一复盘本项目从 Tauri 到 Electron 的完整迁移动因与落地成果(Control Island、字幕浮层、Linux/macOS 适配),并深入解析新 Live2D 模型、Three.js MMD 渲染、Velin 提示词框架、Eventa 事件驱动 IPC/RPC 以及纯 Rust TTS 等前沿探索。读完本文,你将掌握 AIRI 桌面端(apps/stage-tamagotchi)的窗口架构、事件契约设计思路与 3D/2D 模型渲染选型方案,可直接对照源码继续深入。

从 Tauri 到 Electron:一次"知难而退"的技术栈迁移

AIRI 曾是 Tauri 的早期用户。自 2025 年 3 月采用以来,团队一直欣赏 Tauri 的插件设计与 Rust crate 封装生态,并在 6 月发布了 v0.7.2。但为了交付社区呼声最高的实时语音聊天能力,团队在 Tauri 的 WebKit 渲染内核、Web Audio API 与 DevTools 的组合上挣扎了整整 3 个月,直到 9 月,最终在国庆假期期间彻底切换到 Electron。

迁移的决策动因

日志中坦诚地记录了这次迁移的核心矛盾:

  • WebKit 的音频栈难以承载 AIRI 实时语音聊天所需的低延迟、高精度音频处理,Web Audio API 在 Tauri 内核下表现得"别扭";
  • DevTools 调试体验无法满足桌面端复杂窗口与多进程场景的排障需求;
  • 3 个月的反复"修补"最终被证明性价比不足,Electron 成熟的窗口、进程与平台 API 成为更务实的选项。

迁移后的架构落地:仓库现状印证

当前仓库中,AIRI 桌面端位于 apps/stage-tamagotchi,其目录结构完整呈现了迁移后的 Electron 工程形态:

  • src/main:Electron 主进程,负责窗口管理、服务编排(MCP、HTTP server、插件宿主、自动更新等);
  • src/preload:预加载脚本,承载事件桥接;
  • src/renderer:Vue 渲染层,包含舞台、Control Island、字幕浮层等页面;
  • electron.vite.config.ts 与 electron-builder.config.ts:构建与打包配置;
  • ai.moeru.airi.desktop:桌面入口元数据。

迁移并非简单换壳,而是叠加了多项新能力:Linux 支持Control Island(控制岛浮层),以及macOS 全屏模式下依然可以悬浮在界面之上

Linux 适配在源码中有非常具体的证据。在 主进程入口 中可以看到平台相关开关:

if (isLinux) { app.commandLine.appendSwitch('enable-features', 'SharedArrayBuffer') app.commandLine.appendSwitch('enable-unsafe-webgpu') app.commandLine.appendSwitch('enable-features', 'Vulkan') if (env.XDG_SESSION_TYPE === 'wayland') { app.commandLine.appendSwitch('enable-features', 'GlobalShortcutsPortal') app.commandLine.appendSwitch('enable-features', 'UseOzonePlatform') app.commandLine.appendSwitch('enable-features', 'WaylandWindowDecorations') } }

这段代码解决了两个 Linux 专属问题:一是navigator.gpu.requestAdapter()在 Linux 上失败,必须通过命令行开关启用 WebGPU/Vulkan 才能快速处理着色器;二是在 Wayland 会话下需要UseOzonePlatformWaylandWindowDecorationsGlobalShortcutsPortal才能正常显示窗口与注册全局快捷键(对应 issue #757)。这些细节说明迁移后的版本是"为多平台而写",而非简单移植。

字幕浮层:Neuro-sama 式"可见的 AI 输出"

日志提到迁移完成后"终于把字幕浮层跑通了,现在能像 Neuro-sama 一样看到 AI 在输出什么"。这条能力在仓库中有完整的实现:

  • 渲染页面位于 renderer/pages/caption.vue,通过BroadcastChannel(频道名airi-caption-overlay)接收caption-speakercaption-assistant两类字幕事件,字幕项默认 10 秒过期(CAPTION_TEXT_EXPIRY_MS = 10_000);
  • 窗口管理位于 main/windows/caption/index.ts,字幕窗口使用type: 'panel'、透明无边框配置,并执行window.setAlwaysOnTop(true, 'screen-saver', 2)window.setVisibleOnAllWorkspaces(true),macOS 下还调用setWindowButtonVisibility(false)隐藏窗口按钮;
  • 是否"跟随主窗口"由事件契约captionGetIsFollowingWindow(invoke)与captionIsFollowingWindowChanged(event)双向同步,定义在 shared/eventa/index.ts。

Control Island:桌面伴侣的"遥控器"

迁移 Electron 后新增的Control Island是日志中最亮眼的交互创新——它像 iPhone 上的灵动岛一样,悬浮在桌面端窗口边缘,随时可展开为一块完整的控制面板。

从源码看它的功能全貌

控制岛主体实现在 renderer/components/stage-islands/controls-island/index.vue。展开面板(expanded)内包含 8 个动作按钮,全部带埋点(v-track-button):

按钮动作底层事件契约
设置打开设置窗口并跳转路由electronOpenSettings({ route })
切换 Profile弹出角色配置选择器ControlsIslandProfilePicker
刷新窗口重载当前渲染页面window.location.reload()
居中主窗口将主窗口移回屏幕中心electronCenterMainWindow
明暗主题切换 dark/light 模式useTheme().toggleDark()
置顶/取消置顶切换窗口 always-on-topelectronWindowSetAlwaysOnTop
悬停淡出鼠标穿透(点击穿透)模式ControlsIslandFadeOnHover
退出应用请求主进程退出electronAppQuit

常驻主控件区(始终可见)则包括:展开/折叠切换、打开聊天、听力/麦克风控制(ControlsIslandHearingConfigIndicatorMicVolume)、停止说话(controls-island-stop-speaking.vue)以及拖拽窗口按钮。

交互细节:防误触与自动收拢

控制岛在交互上有几个值得借鉴的细节:

  • 鼠标离开自动收拢:通过useElectronMouseInElement(islandElement)检测光标是否移出,再经refDebounced(..., 1500)防抖 1.5 秒后收拢面板;同时用useIntervalFn每 1.5 秒兜底复查;
  • 阻塞覆盖层防误收blockingOverlays集合记录"听力配置""Profile 选择器"等打开中的弹层,只要存在阻塞项,鼠标离开也不会自动收拢;
  • 拖拽的平台差异:源码注释明确指出 Electron 的startDraggingWindow在 Linux 上不可用,因此只有非 Linux 平台才通过defineInvoke注册该事件,Linux 上改用cursor-move+drag-regionclass 方案;
  • 位置与动画:放置逻辑抽离在 use-controls-island-placement.ts,支持四角吸附(top-left/top-right/bottom-left/bottom-right)、进出场动效(entering/leaving/idle相位)与图标尺寸设置(large/small/autoauto目前固定按 large 处理)。

这些交互都有配套测试(如 controls-island-root.test.ts、controls-island-stop-speaking.test.ts、controls-island-auth-button.test.ts),印证了该模块是经过工程化打磨的核心交互组件。

新 Live2D 模型:与官方团队合作的视觉升级

日志中"眼尖的朋友可能已经发现"的彩蛋,是 AIRI 的角色模型完成了更新。这个新模型由两位关键人物参与改进:一位与 Neuro-sama 官方团队合作过的画师,以及一位技术极强的建模专家,新模型的动态表情也丰富了许多。日志调侃式地表示"也许拿到更多赞助就会开源"(原模型尚未直接放入开源仓库),并附上了 演示视频。对于想要自行更换模型的开发者,AIRI 在 packages/stage-ui-live2d 提供了完整的 Live2D 舞台渲染支持,与stage-ui-three(VRM)、stage-ui-mmd(MMD)、stage-ui-spine(Spine)共同构成多模型格式渲染矩阵。

Three.js MMD 支持:让存量 MMD 模型回归舞台

日志指出一个现实问题:手头能找到的模型未必都是 Live2D/VRM,数量最多、质量最好的存量模型其实是 MMD(MikuMikuDance)模型。虽然 AIRI 用 Three.js 做 3D 渲染,但 Three.js 官方生态中"已经没有可用的 MMD 实现"。得益于 kwaa 的工作,Moeru AI 维护了一个专门的 MMD 仓库,AIRI 在此基础上构建了自己的 MMD 渲染包。

stage-ui-mmd 包的能力清单

仓库内的 packages/stage-ui-mmd/README.md 详细说明了该包的定位:在 AIRI 舞台上渲染 PMX/PMD 模型并播放 VMD/VPD 动作,达到与 Live2D、VRM 渲染器对等的功能:

  • 模型加载:支持.pmx/.pmd,可从打包 ZIP(模型 + 贴图)或裸模型 URL 加载;
  • 物理系统:基于 Bullet(Ammo.js)实现头发、裙摆与自定义骨骼的刚体 + 6-DOF 弹簧关节物理,运行时可开关;
  • IK 与继承骨骼:CCD 求解器 IK 与 append-bone(grant)传播,兼容标准与非标骨骼;
  • 动作管理:导入 VMD 动作剪辑(持久化到 IndexedDB 并跨窗口同步)、设为循环待机、一次性预览、删除,以及将 AIRI 情感映射到手势动作;
  • 口型同步:基于共享 wLipSync profile,将音素映射到规范化的"あいうえお"口型 morph,并支持非标模型的逐槽位 morph 重映射;
  • 情感表情:通过 morph 交叉淡入淡出实现;
  • 注视模式:摄像头/光标/关闭三种模式 + 空闲扫视 + 程序化眨眼;
  • 场景设置:模型变换、相机 FOV、环境光 + 方向光、自发光、渲染倍率、物理重力、逐材质透明度——全部实时生效、持久化并跨窗口同步。

物理运行时@moeru/three-mmd-physics-ammo采用懒加载,Ammo WASM 只在真正的 MMD 模型挂载后才初始化,避免舞台启动时的额外开销。

使用方式

stage-ui-mmd暴露与其他渲染器一致的场景契约,由 packages/stage-ui 的Stage.vue在模型解析为mmd渲染器时自动接入:

<MMDScene v-model:state="state" :model-src="modelUrl" :cursor-position="cursorPosition" :current-audio-source="audioSource" :enable-orbit-controls="true" @error="onError" />

组件还暴露canvasElement()captureFrame()setEmotion(name, intensity)listMorphs()listMotions()等方法;运行时配置(物理/IK/grant 开关、注视追踪、缩放、morph 覆盖、情感→动作映射)则存放在useMMDPinia store 中,通过模型设置面板编辑。日志中"如果你也感兴趣,欢迎一起来维护"的号召,对应的是 Moeru AI 旗下该 MMD 相关仓库的开放维护策略。

Velin:用 Vue 写提示词

日志回顾了 5 月分享的提示词库项目:得益于 RainbowBird 的努力与捐赠,Velin 已正式并入 Moeru AI 组织。它的核心理念是一句口号——"You can write prompts with Vue"。AIRI 的提示词几乎全部由 Velin 驱动,并且跨平台能力无需担心:Velin 在 Node.js 环境同样运行良好,这意味着同一套"用 Vue 组件描述提示词"的写法既能服务浏览器场景,也能服务桌面端与后端 Node 进程。这对 AIRI 这类同时拥有 Web / macOS / Windows / Linux 多端形态的项目而言,保证了提示词定义与渲染逻辑的高度复用。

Eventa:事件驱动的 IPC/RPC 框架

日志介绍 Eventa 时引用了一句口号——"Events are all you need"。它源自一个痛点:AIRI 的本地推理只能跑在 Web Workers / worker_threads 中,这些线程之间靠事件通信;Electron 的 IPC 本质也如此,但团队认为"不够优雅"。RainbowBird 将这套思想落地为Eventa——基于事件的 IPC/RPC 实现库,并正式并入 Moeru AI。

仓库中的两级证据

第一级:通用契约包@proj-airi/electron-eventa(packages/electron-eventa)。它是 AIRI 各应用间共享的 Electron IPC 契约定义,分两个入口导出:

  • @proj-airi/electron-eventa:核心契约,按 Electron 模块组织——app(isMacOS/isWindows/isLinux/quit)、window(bounds 变更事件、start-loop-get-bounds、get/setBounds、setIgnoreMouseEvents、setVibrancy、setBackgroundMaterial、resize、close)、screen(光标屏幕坐标事件、getAllDisplays/getPrimaryDisplay、DIP 与物理坐标互转)、powerMonitorsystem-preferences
  • @proj-airi/electron-eventa/electron-updater:自动更新契约与状态类型。

以 window.ts 为例,契约的声明方式非常直观:

export const bounds = defineEventa<Rectangle>('eventa:event:electron:window:bounds') export const startLoopGetBounds = defineInvokeEventa('eventa:event:electron:window:start-loop-get-bounds') const getBounds = defineInvokeEventa<ReturnType<BrowserWindow['getBounds']>>('eventa:invoke:electron:window:get-bounds') const setBounds = defineInvokeEventa<void, Parameters<BrowserWindow['setBounds']>>('eventa:invoke:electron:window:set-bounds') const resize = defineInvokeEventa<void, { deltaX: number, deltaY: number, direction: ResizeDirection }>('eventa:invoke:electron:window:resize')

事件名采用eventa:event:<模块>:<能力>eventa:invoke:<模块>:<能力>的统一命名空间,ResizeDirection支持n/s/e/w/ne/nw/se/sw八个拖拽方向。

第二级:应用级契约src/shared/eventa(apps/stage-tamagotchi/src/shared/eventa/index.ts)。这是整个桌面端进程间通信的"总清单",覆盖:窗口生命周期(electronWindowLifecycleChanged)、全局快捷键(electronShortcutRegister/Unregister/Triggered)、MCP stdio 服务器管理(electronMcpListToolselectronMcpCallToolelectronMcpTestServer等)、插件宿主状态、Godot 舞台旁路进程(electronGodotStageStart/Stop/ApplySceneInput)、小部件窗口(widgetsAdd/Update/Remove)、认证(OIDC PKCE 登录回调)、i18n 与自动更新通道(latest/stable/alpha/beta/nightly/canary)等。主进程侧则通过@moeru/eventa/adapters/electron/maincreateContext统一注册(见 apps/stage-tamagotchi/src/main/index.ts),渲染层再经由@proj-airi/electron-vueuse(packages/electron-vueuse)的useElectronEventaInvoke/useElectronEventaContext消费。这种"声明即契约、跨进程类型安全"的模式,正是 Eventa 相对原生ipcMain.handle更优雅的地方。

一个工程细节值得一提:桌面叠加层(desktop overlay)在加载渲染页面之前必须先注册 eventa RPC,否则onMounted触发的首次轮询 invoke 将永远悬挂,导致后续轮询全部卡死(注释记录在 main/windows/desktop-overlay/index.ts)——这是事件驱动架构下典型的时序陷阱,也印证了"Events are all you need"背后需要严谨的注册顺序管理。

项目状态:50+ 仓库与多语言技术栈

日志披露,Moeru AI 与 Project AIRI 已成长为大型组织:拥有超过 50 个原创仓库,覆盖机器学习、数据处理、前端、后端等方向,技术栈横跨TypeScript / Python / Rust / Go等语言,全部仓库累计关注者超过 800 人。对一年前刚起步的团队而言,这被日志作者称为"当时完全无法想象"的结果。从本仓库的目录结构看,这一描述是可验证的——packages 下数十个独立发布的前端/渲染/服务包、apps 下多端应用、engines 下的 Godot 渲染引擎、integrations 下的 Discord/Telegram/Minecraft 等生态接入,共同构成了一个名副其实的"自托管 AI 伴侣"技术矩阵。

纯 Rust TTS:摆脱 Python 环境的本地推理

日志以"小预告"的形式分享了最新合作:与 kwaa 联手将知名 TTS 模型chatterbox 移植为纯 Rust 实现,目标是"再也不用担心麻烦的 Python 环境配置"。其亮点包括:

  • 推理性能:在 4080S 上单次推理约5 秒
  • 架构保真:基本 1:1 复刻了 Python 版模型架构;
  • 长期目标:将其构建为超级精简的本地 TTS 推理引擎,并叠加其他 SOTA TTS 模型的能力。

对 AIRI 这类"自托管、数据自持"的桌面伴侣而言,纯 Rust 的 TTS 意味着更轻的分发体积、更少的运行时依赖与更可控的延迟——这与项目"self-hosted, you-owned"的核心理念一脉相承。

结语与后续预告

这篇 DevLog 以"one more thing"的方式串起了 AIRI 从渲染内核到模型生态、从进程通信到本地推理的多条技术主线:Electron 迁移换来了稳定而丰富的桌面能力(控制岛、字幕浮层、Linux/全屏适配),MMD 渲染补全了存量模型资产,Eventa 统一了跨进程通信,Rust TTS 则瞄准了极简本地推理。日志最后预告,后续将持续更新,重点介绍团队在VLA(Vision-Language-Action)/VLM(Vision-Language Model)游戏操控方向上的探索思路与阶段性成果——对于想了解"AI 伴侣如何真正看懂并操作游戏"的读者,这是一个值得持续关注的演进方向。

【免费下载链接】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),仅供参考

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

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

立即咨询