- 修复配置窗口'选择本地模型'按钮无响应问题 - 添加 tauri-plugin-dialog 和 tauri-plugin-clipboard-manager 依赖 - 在 main.rs 中注册插件 - 创建 capabilities/default.json 配置权限 - 修复工具栏按钮不显示问题 - 将 .waifu-tool 的 display 从 none 改为 block - 修复模型显示比例问题 - 禁用 reloadPositionScale 避免覆盖尺寸设置 - 移除 onResized 回调中的模型尺寸重置 - 设置模型宽度为窗口的 50% - 修复切换 workspace 后模型尺寸恢复问题 - 添加窗口置顶设置,显示时重新设置 always_on_top - 更新 CLAUDE.md 文档 - 添加 .gitignore - 更新 README.md - 添加 docs/impl/debug-log-20260531.md 记录调试过程 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
489 lines
19 KiB
Markdown
489 lines
19 KiB
Markdown
# EzVibeR+ 实现计划报告
|
||
|
||
## 一、项目定位与融合策略
|
||
|
||
### 1.1 融合方案:Option B
|
||
|
||
- **技术栈基础**:`assets/tauri-live2d`(Vue3 + Tauri 1.x + PIXI.js + pixi-live2d-display)
|
||
- **要移植的逻辑层**:EzVibeR 的 emotion/scheduler/memory/brain 四大模块 + api.rs 的 IPC 命令层
|
||
- **目标**:在 tauri-live2d 的双窗口 + 托盘 + Live2D 渲染架构上,叠加 EzVibeR 的事件驱动情感状态机 + 任务调度 + RAG 记忆 + LLM 分流大脑
|
||
|
||
### 1.2 技术栈版本锁定
|
||
|
||
| 组件 | 版本 | 来源 |
|
||
|------|------|------|
|
||
| Tauri | 1.2.3 | tauri-live2d |
|
||
| Vue | 3.x | tauri-live2d |
|
||
| PIXI.js | 6.5.6 | tauri-live2d |
|
||
| pixi-live2d-display | 0.4.0 | tauri-live2d |
|
||
| Rust | 1.65+ | tauri-live2d |
|
||
| tokio | 1.23 | tauri-live2d |
|
||
| axum | 0.7.5 | tauri-live2d web_server |
|
||
|
||
**新增 Rust 依赖(EzVibeR 逻辑层):**
|
||
|
||
```toml
|
||
rusqlite = "0.29" # Memory SQLite 存储
|
||
ndarray = "0.15" # 向量索引
|
||
rand = "0.8" # Monte Carlo 采样(已有)
|
||
bytemuck = "1.13" # f32↔u8 零拷贝转换
|
||
regex = "1" # Brain action 解析
|
||
tokio = { version = "1.23", features = ["macros", "sync", "time", "rt"] } # 扩展 features
|
||
```
|
||
|
||
---
|
||
|
||
## 二、架构总览
|
||
|
||
```
|
||
┌─────────────────────────────────────────────────────────┐
|
||
│ Frontend (Vue3) │
|
||
│ ┌──────────────┐ ┌──────────────────────────┐ │
|
||
│ │ Config Window │ │ Live2D Window │ │
|
||
│ │ (index.html) │ 事件推送 │ (live2d.html) │ │
|
||
│ │ - 情感状态 │ ───────► │ - PIXI 渲染 Live2D 模型 │ │
|
||
│ │ - 记忆搜索 │ │ - 碰撞检测 / 拖拽区域 │ │
|
||
│ │ - LLM 对话 │ │ - 表情动画驱动 │ │
|
||
│ └──────────────┘ └──────────────────────────┘ │
|
||
└────────────────────────┬────────────────────────────────┘
|
||
│ Tauri invoke / emit
|
||
┌────────────────────────▼────────────────────────────────┐
|
||
│ Backend (Rust) │
|
||
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
|
||
│ │ EmotionEngine │ │ TaskScheduler │ │ AgentBrain │ │
|
||
│ │ (emotion.rs) │ │ (scheduler.rs)│ │ (brain.rs) │ │
|
||
│ │ - 5 状态机 │ │ - 60s tick │ │ - LLM 分流 │ │
|
||
│ │ - MonteCarlo │ │ - 行为触发 │ │ - FallbackCache │ │
|
||
│ │ - 事件驱动 │ │ - 静默小时 │ │ - RAG 注入 │ │
|
||
│ └─────────────┘ └─────────────┘ └─────────────────┘ │
|
||
│ ┌─────────────────────────────────────────────────────┐│
|
||
│ │ MemorySystem (memory.rs) ││
|
||
│ │ SQLite(WAL) + ndarray 向量索引 + 500ms 重建防抖 ││
|
||
│ └─────────────────────────────────────────────────────┘│
|
||
│ ┌──────────────┐ ┌─────────────┐ ┌─────────────────┐ │
|
||
│ │ commands.rs │ │ menu.rs │ │ web_server │ │
|
||
│ │ - IPC 命令 │ │ - 托盘菜单 │ │ - 模型文件服务 │ │
|
||
│ └──────────────┘ └─────────────┘ └─────────────────┘ │
|
||
└─────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 三、Tauri-live2d 既有实现分析
|
||
|
||
### 3.1 双窗口模型
|
||
|
||
- **Live2D 窗口** (`main`): 215×200, transparent, frameless, alwaysOnTop, skipTaskbar
|
||
- **Config 窗口** (`config`): 有标题栏,可调整大小,alwaysOnTop
|
||
- 窗口按需创建/重建:`on_system_tray_event` 中处理 `show` / `config` 点击
|
||
|
||
### 3.2 系统托盘
|
||
|
||
- 托盘图标:`icons/icon.png`
|
||
- 菜单项:显示桌宠 / 隐藏桌宠 / 分隔线 / 配置中心 / 分隔线 / 关闭软件
|
||
- 窗口重建模式:窗口被关闭后,点击托盘菜单会重新 `WindowBuilder::new`
|
||
|
||
### 3.3 插件机制
|
||
|
||
- **autostart** 插件:使用 `auto-launch` crate,支持 macOS LaunchAgent / Windows / Linux
|
||
- **checkupdate** 插件:调用 `app.updater().check()`,弹窗提示下载安装
|
||
|
||
### 3.4 web_server
|
||
|
||
- Axum HTTP 服务器,随机端口(1024-65535)
|
||
- CORS 全开,服务本地模型目录文件
|
||
- WebSocket `/ws` 端点(当前为 echo)
|
||
|
||
---
|
||
|
||
## 四、待移植的 EzVibeR 底层逻辑
|
||
|
||
### 4.1 EmotionEngine(emotion.rs)
|
||
|
||
**核心设计:**
|
||
- 5 状态:`Idle` / `Happy` / `Focused` / `Annoyed` / `Sleepy`
|
||
- 8 事件:`UserInteract` / `UserPraise` / `UserFocused` / `ReminderIgnored` / `SedentaryTooLong` / `LongWorkSession` / `TimePasses` / `UserHealthyAction`
|
||
- 转换逻辑:事件 → boost 增益向量 → 与转移矩阵叠加 → softmax → Monte Carlo 采样
|
||
- 5 秒最低驻留时间防止抖动
|
||
|
||
**关键数据结构:**
|
||
|
||
```rust
|
||
pub enum EmotionState { Idle, Happy, Focused, Annoyed, Sleepy }
|
||
pub enum EventType { ... }
|
||
|
||
// 每个事件返回 3 个 (target, gain) boost
|
||
pub trait Event { fn boosts(&self) -> Vec<(EmotionState, f32)>; }
|
||
|
||
// EmotionEngine 内部状态
|
||
struct EmotionEngine {
|
||
state: EmotionState,
|
||
transition_matrix: [[f32; 5]; 5], // 基础转移概率
|
||
state_since: Instant, // 进入当前状态的时间
|
||
min_residence: Duration, // 最低驻留
|
||
rng: SmallRng, // 随机数
|
||
}
|
||
```
|
||
|
||
### 4.2 TaskScheduler(scheduler.rs)
|
||
|
||
**核心设计:**
|
||
- 行为列表 (`Behavior`): name / action_type / interval_secs / quiet_hours / priority
|
||
- 内置 P0 行为:`remind_water` (45min) / `remind_stretch` (60min)
|
||
- `on_timer_tick()` 由 Rust 后端的 60s 背景循环调用
|
||
- 静默小时:22:00-08:00 自动抑制提醒
|
||
|
||
### 4.3 MemorySystem(memory.rs)
|
||
|
||
**核心设计(三层):**
|
||
|
||
```
|
||
写入路径:
|
||
用户输入 → SQLite(WAL) 立即持久化 → pending_queue → 500ms 防抖 → 合并到 ndarray 向量索引
|
||
|
||
查询路径:
|
||
查询 → embed() → VectorIndex.search(top-K) → SQLite 查完整文本 → 返回 SearchResult
|
||
```
|
||
|
||
**关键数据结构:**
|
||
|
||
```rust
|
||
struct MemoryConfig { db_path, rag_top_k, min_similarity, rebuild_threshold }
|
||
struct MemoryEntry { id, text, embedding: Vec<f32>, tags, metadata, created_at }
|
||
struct SearchResult { id, text, similarity, tags, created_at }
|
||
|
||
trait Embedder { fn embed(&self, text: &str) -> Vec<f32>; fn dimension(&self) -> usize; }
|
||
struct DummyEmbedder { ... } // 基于 hash 的伪嵌入(384维)
|
||
|
||
struct SqliteStore { ... } // WAL + bytemuck::cast_slice 零拷贝 BLOB
|
||
struct VectorIndex { array: Array2<f32>, l2_norm, ids: Vec<i64> }
|
||
struct MemorySystem { store, index, embedder, pending_queue, rebuild_tx }
|
||
```
|
||
|
||
### 4.4 AgentBrain(brain.rs)
|
||
|
||
**核心设计(能量分流):**
|
||
|
||
| InputType | 处理路径 | LLM 调用 |
|
||
|-----------|---------|---------|
|
||
| `UserMessage` | 完整 RAG → LLM → 记忆写入 | **是** |
|
||
| `SystemReminder` | FallbackCache 查表(离线消息) | 否 |
|
||
| `Heartbeat` | 直接返回 `BrainResponse::idle()` | 否 |
|
||
|
||
**FallbackCache 内置消息(EzVibeR 原有):**
|
||
- `remind_water`: 5 条随机消息
|
||
- `remind_stretch`: 5 条随机消息
|
||
- `remind_eyes`: 5 条随机消息
|
||
- `greet_morning/afternoon/evening`: 各 3 条
|
||
|
||
**Action 解析:**
|
||
```rust
|
||
// 来自 LLM 的响应中解析 [ACTION: type: message]
|
||
lazy_regex!(ACTION_RE, r"\[ACTION:\s*(\w+):\s*([^\]]+)\]");
|
||
```
|
||
|
||
---
|
||
|
||
## 五、实施步骤详解
|
||
|
||
### 步骤 1:项目骨架搭建
|
||
|
||
```
|
||
EzVibeR+/
|
||
├── docs/
|
||
│ └── impl/
|
||
│ └── report.md ← 本文档
|
||
├── src/ ← Vue3 前端(来自 tauri-live2d)
|
||
│ ├── main.ts
|
||
│ ├── App.vue
|
||
│ ├── live2d/
|
||
│ │ ├── App.ts
|
||
│ │ └── index.vue
|
||
│ ├── components/
|
||
│ │ ├── Config.vue
|
||
│ │ └── Model.vue
|
||
│ ├── plugins/ ← Tauri plugin JS wrapper
|
||
│ ├── hooks/ ← Vue composition utilities
|
||
│ └── util/
|
||
├── src-tauri/ ← Rust 后端
|
||
│ ├── Cargo.toml ← 新增 rusqlite/ndarray/bytemuck/regex
|
||
│ ├── tauri.conf.json ← 来自 tauri-live2d
|
||
│ ├── src/
|
||
│ │ ├── main.rs ← 来自 tauri-live2d(稍作修改)
|
||
│ │ ├── app/ ← 来自 tauri-live2d
|
||
│ │ ├── modules/ ← 从 EzVibeR 移植
|
||
│ │ │ ├── emotion.rs
|
||
│ │ │ ├── scheduler.rs
|
||
│ │ │ ├── memory.rs
|
||
│ │ │ └── brain.rs
|
||
│ │ └── plugins/ ← 来自 tauri-live2d
|
||
│ └── web_server/ ← 来自 tauri-live2d
|
||
```
|
||
|
||
**操作:**
|
||
1. 复制 `assets/tauri-live2d/` 的前端 `src/`、后端 `src-tauri/` 到 `EzVibeR+/`
|
||
2. 保留 `tauri-live2d` 的 `main.rs`(仅修改以适配新模块)
|
||
3. 保留 `tauri-live2d` 的 `menu.rs` / `commands.rs`(托盘和 IPC 基础)
|
||
|
||
### 步骤 2:前端改造
|
||
|
||
**文件修改清单:**
|
||
|
||
1. **`src/hooks/useBackendEvents.ts`**(新建)
|
||
- 复用 EzVibeR 的事件 hook 模式
|
||
- 监听 `ezvibe:emotion` / `ezvibe:reminder` / `ezvibe:heartbeat` / `ezvibe:action`
|
||
- 返回状态到 Vue 组件
|
||
|
||
2. **`src/hooks/useLookAt.ts`**(新建)
|
||
- 从 EzVibeR 移植(鼠标 EMA 追踪)
|
||
|
||
3. **`src/components/Config.vue`**(改造)
|
||
- 复用 tauri-live2d 的 Config.vue 结构
|
||
- 添加 EzVibeR 状态展示区(当前情绪、记忆条数、调度状态)
|
||
- 添加 LLM 对话 UI(chat 输入框 + 响应展示)
|
||
- 添加记忆搜索 UI
|
||
- 暴露 `invoke("chat")` / `invoke("interact")` / `invoke("search_memories")`
|
||
|
||
4. **`src/live2d/index.vue`**(改造)
|
||
- 复用 tauri-live2d 的 Live2D 渲染
|
||
- 从 `useBackendEvents` 获取情绪状态,驱动 PIXI 动画
|
||
|
||
5. **`src/plugins/index.ts`**(保留 tauri-live2d 原样)
|
||
|
||
### 步骤 3:Rust 模块移植(核心任务)
|
||
|
||
#### 3.1 emotion.rs 移植
|
||
|
||
**从 EzVibeR 复制并做以下适配:**
|
||
|
||
1. 路径调整:从 `crate::modules::emotion` → 保持不变(EzVibeR 路径结构)
|
||
2. 移除 Tauri 绑定:移除 `serde`、`SmallRng`、`Instant` 以外的任何 Tauri 依赖
|
||
3. 事件类型保持不变
|
||
|
||
**新增接口(供 commands.rs 调用):**
|
||
|
||
```rust
|
||
pub fn new_with_config() -> EmotionEngine
|
||
pub fn on_event(&mut self, event: EventType) -> EmotionState
|
||
pub fn get_state(&self) -> EmotionState
|
||
pub fn get_state_since(&self) -> Instant
|
||
```
|
||
|
||
#### 3.2 scheduler.rs 移植
|
||
|
||
**从 EzVibeR 复制并适配:**
|
||
|
||
1. `Behavior` 结构保持不变(name/action_type/interval_secs/quiet_hours 等)
|
||
2. `TaskScheduler::on_timer_tick()` 签名保持:`fn on_timer_tick(&mut self, emotion: &mut EmotionEngine) -> Vec<Behavior>`
|
||
3. 内置行为:`remind_water` / `remind_stretch` 保持不变
|
||
|
||
**新增接口:**
|
||
|
||
```rust
|
||
pub fn new_with_config() -> TaskScheduler
|
||
pub fn on_timer_tick(&mut self, emotion: &mut EmotionEngine) -> Vec<Behavior>
|
||
pub fn get_status(&self) -> Vec<BehaviorStatus>
|
||
```
|
||
|
||
#### 3.3 memory.rs 移植
|
||
|
||
**从 EzVibeR 复制并适配:**
|
||
|
||
1. `Embedder` trait + `DummyEmbedder` 保持不变
|
||
2. `SqliteStore` / `VectorIndex` / `MemorySystem` 保持不变
|
||
3. 配置路径:数据库放在 `app_data_dir()/ezvibe/memory.db`
|
||
4. 重建防抖(500ms tokio timeout)保持不变
|
||
|
||
**新增接口:**
|
||
|
||
```rust
|
||
pub fn new_with_config(app_data_dir: PathBuf) -> MemorySystem
|
||
pub fn add(&mut self, text: &str, tags: Vec<&str>) -> Result<i64>
|
||
pub fn search(&self, query: &str, top_k: usize) -> Result<Vec<SearchResult>>
|
||
pub fn count(&self) -> usize
|
||
```
|
||
|
||
#### 3.4 brain.rs 移植
|
||
|
||
**从 EzVibeR 复制并适配:**
|
||
|
||
1. `InputType` / `LLMProvider` trait / `AgentBrain` 保持不变
|
||
2. `FallbackCache` 内置消息保持不变
|
||
3. `Action` 解析正则保持:`ACTION_RE`
|
||
4. LLM 接口:需要用户配置 API key(存入 AppConf)
|
||
|
||
**新增接口:**
|
||
|
||
```rust
|
||
pub fn new(memory: Arc<MemorySystem>) -> AgentBrain
|
||
pub fn think(&self, input_type: InputType, text: &str) -> BrainResponse
|
||
```
|
||
|
||
### 步骤 4:api.rs 改造(Tauri IPC 命令层)
|
||
|
||
**来自 tauri-live2d 的 commands.rs 基础上,添加 EzVibeR 的命令:**
|
||
|
||
```rust
|
||
// 原有(来自 tauri-live2d)
|
||
read_file / write_file / model_list / read_config / write_config
|
||
|
||
// 新增(来自 EzVibeR api.rs)
|
||
get_emotion() // → EmotionResponse
|
||
get_scheduler_status() // → Vec<BehaviorStatus>
|
||
get_memory_count() // → usize
|
||
search_memories(query: String) // → Vec<SearchResult>
|
||
interact(event: String) // → InteractResponse
|
||
chat(message: String) // → BrainResponse
|
||
trigger_reminder(action_type: String) // → BrainResponse
|
||
```
|
||
|
||
### 步骤 5:lib.rs / main.rs 改造
|
||
|
||
**基于 tauri-live2d 的 main.rs,添加:**
|
||
|
||
1. 引入新模块:`mod modules { emotion, scheduler, memory, brain }`
|
||
2. 创建 `AppState`(类似 EzVibeR 的 `Arc<Mutex<EmotionEngine>>` 等)
|
||
3. 替换 `manage(port)` → `manage(app_state)`
|
||
4. **60s 背景循环**(从 EzVibeR lib.rs 移植):
|
||
```rust
|
||
// Phase 1: scheduler tick → inject TimePasses → check behaviors
|
||
// Phase 2: for each fired behavior → brain.think(SystemReminder) → emit ezvibe:reminder
|
||
// Phase 3: emit ezvibe:heartbeat
|
||
```
|
||
5. 事件推送(emit):使用 tauri-live2d 的 `app.emit()` 方式
|
||
|
||
### 步骤 6:Config 扩展
|
||
|
||
**扩展 tauri-live2d 的 AppConf(config.rs):**
|
||
|
||
```rust
|
||
pub struct AppConf {
|
||
// 来自 tauri-live2d(保留)
|
||
pub port: u16,
|
||
pub model_dir: String,
|
||
pub width: u16, pub height: u16, pub x: u16, pub y: u16,
|
||
pub check_update: bool,
|
||
pub remote_list: Vec<String>,
|
||
pub model_block: bool,
|
||
pub auto_start: bool,
|
||
|
||
// 来自 EzVibeR(新增)
|
||
pub llm_api_key: String, // LLM API 密钥
|
||
pub llm_base_url: String, // LLM API Base URL
|
||
pub memory_enabled: bool, // 记忆系统开关
|
||
}
|
||
```
|
||
|
||
### 步骤 7:前端事件对接
|
||
|
||
**`src/hooks/useBackendEvents.ts` 事件列表:**
|
||
|
||
| 事件名 | payload | 来源 |
|
||
|--------|---------|------|
|
||
| `ezvibe:emotion` | `{state, state_since}` | Rust emit |
|
||
| `ezvibe:reminder` | `{action_type, message, priority}` | Rust emit |
|
||
| `ezvibe:heartbeat` | `{tick, uptime, emotion_state}` | Rust emit |
|
||
| `ezvibe:action` | `{action_type, message, priority}` | Rust emit |
|
||
|
||
**`Config.vue` 组件中消费这些事件:**
|
||
- 情感状态面板实时更新
|
||
- 提醒弹窗(toast)
|
||
- 心跳指示器
|
||
|
||
---
|
||
|
||
## 六、关键实现细节
|
||
|
||
### 6.1 情感状态 ↔ Live2D 动画联动
|
||
|
||
当 `ezvibe:emotion` 事件触发时,`Live2DWindow` 组件根据情绪状态切换 PIXI 动画:
|
||
|
||
```javascript
|
||
// src/live2d/index.vue
|
||
watch(() => emotionState, (state) => {
|
||
if (state === 'Happy') {
|
||
model.motion("happy")
|
||
} else if (state === 'Annoyed') {
|
||
model.motion("annoyed")
|
||
}
|
||
})
|
||
```
|
||
|
||
### 6.2 记忆搜索 RAG 流程
|
||
|
||
```
|
||
User 输入 → Config.vue invoke("chat", {message})
|
||
→ Rust brain.think(UserMessage, text)
|
||
→ memory.search(text, top_k=3)
|
||
→ 构建 context → LLM.chat(context + history)
|
||
→ 返回 BrainResponse
|
||
→ emit("ezvibe:action")
|
||
→ Config.vue 显示 LLM 响应
|
||
```
|
||
|
||
### 6.3 托盘菜单事件 → 情绪触发
|
||
|
||
```
|
||
托盘点击"显示桌宠" → window.show() → 可选:inject UserInteract 事件
|
||
托盘点击"隐藏桌宠" → window.hide()
|
||
```
|
||
|
||
### 6.4 静默小时行为抑制
|
||
|
||
```rust
|
||
// scheduler.rs
|
||
if behavior.quiet_hours_enabled {
|
||
let hour = chrono::Local::now().hour();
|
||
if (hour >= 22) || (hour < 8) { continue; } // 静默时段跳过
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 七、文件操作清单
|
||
|
||
### 前端(Vue3)
|
||
|
||
| 操作 | 文件 |
|
||
|------|------|
|
||
| 复制(来自 tauri-live2d) | `src/main.ts`, `src/App.vue`, `src/style.css` |
|
||
| 复制(来自 tauri-live2d) | `src/live2d/App.ts`, `src/live2d/index.vue` |
|
||
| 复制(来自 tauri-live2d) | `src/components/Config.vue`, `src/components/Model.vue` |
|
||
| 复制(来自 tauri-live2d) | `src/plugins/*.ts`, `src/hooks/*.ts` |
|
||
| 复制(来自 tauri-live2d) | `src/util/*.ts`, `src/types/*.d.ts` |
|
||
| 新建 | `src/hooks/useBackendEvents.ts` |
|
||
| 新建 | `src/hooks/useLookAt.ts` |
|
||
| 改造 | `src/components/Config.vue`(集成 EzVibeR UI) |
|
||
|
||
### Rust(src-tauri)
|
||
|
||
| 操作 | 文件 |
|
||
|------|------|
|
||
| 复制(来自 tauri-live2d) | `src-tauri/Cargo.toml`, `src-tauri/build.rs` |
|
||
| 改造(基于 tauri-live2d main.rs) | `src-tauri/src/main.rs` |
|
||
| 复制(来自 tauri-live2d) | `src-tauri/src/app/config.rs` |
|
||
| 改造(基于 tauri-live2d menu.rs) | `src-tauri/src/app/menu.rs` |
|
||
| 改造(基于 tauri-live2d commands.rs) | `src-tauri/src/app/commands.rs` |
|
||
| 复制(来自 tauri-live2d) | `src-tauri/src/app/mstruct.rs` |
|
||
| 移植(来自 EzVibeR) | `src-tauri/src/modules/emotion.rs` |
|
||
| 移植(来自 EzVibeR) | `src-tauri/src/modules/scheduler.rs` |
|
||
| 移植(来自 EzVibeR) | `src-tauri/src/modules/memory.rs` |
|
||
| 移植(来自 EzVibeR) | `src-tauri/src/modules/brain.rs` |
|
||
| 改造(基于 tauri-live2d plugins) | `src-tauri/src/plugins/autostart.rs` |
|
||
| 改造(基于 tauri-live2d plugins) | `src-tauri/src/plugins/checkupdate.rs` |
|
||
| 复制(来自 tauri-live2d) | `src-tauri/web_server/` |
|
||
|
||
---
|
||
|
||
## 八、审查要点
|
||
|
||
1. **技术栈确认**:是否严格基于 tauri-live2d(Tauri 1.x,Vue3)而非 EzVibeR(Tauri 2.x,React)?
|
||
2. **模块边界**:emotion/scheduler/memory/brain 是否完整从 EzVibeR 移植,无遗漏核心逻辑?
|
||
3. **API 兼容性**:前端 `invoke()` 调用格式是否与后端 `#[tauri::command]` 匹配?
|
||
4. **事件通道**:`emit` 的事件名是否与前端 `listen` 完全一致?
|
||
5. **Config 扩展**:新增字段(llm_api_key 等)是否向后兼容原有字段?
|
||
6. **风险项**:LLM 接口(GPT/MiniMax)的 embed 函数是否需要实现真实调用?
|
||
|
||
---
|
||
|
||
**状态:待审核** |