# 迁移方案:废弃云端 `mjk_avatars` 表,数字人元数据全量迁移到本地存储
> **状态:方案已调整(2026-04-17)** — 原方案中提到的 Celery 架构已完全移除,形象克隆现由 `app/scheduler/handlers/avatar_handler.py`(Async Engine Scheduler)统一调度。云端仍保留 `avatars` 表作为形象克隆的持久化记录。
## 方案目标
| 目标 | 说明 |
|------|------|
| ✅ 贯彻设计理念 | 真正做到**轻量云 + 全本地业务数据**,云端只记日志不存业务数据 |
| ✅ 统一接口日志 | 所有接口请求统一记录到 `mjk_interface_request_logs`,按接口统计积分消耗 |
| ✅ 简化后端代码 | 删除大量 CRUD、状态管理、定时任务代码,后端更干净 |
| ✅ 用户掌控数据 | 所有数字人元数据存在用户本地,云端只记克隆请求的消耗积分 |
---
## 存储结构变化
### 变化前(现状)
```
云端 PostgreSQL: mjk_avatars
└─ 存储所有数字人元数据 (name/voice_id/element_id/status 等)
前端本地:
└─ 只做缓存,从云端同步
```
### 变化后(目标)
```
云端 PostgreSQL:
├─ mjk_interface_request_logs ← 只记:avatar_clone 请求 + 消耗积分 + 状态
└─ mjk_avatars ← 废弃,不再写入新数据(存量可保留可删除)
用户本地磁盘:
└─ ~/Documents/Meijiaka/avatars/{avatar_id}/
├─ meta.json ← 完整数字人元数据(JSON)
└─ source.mp4 ← 原始上传视频
```
---
## 本地存储结构定义
### 目录结构
```
~/Documents/Meijiaka/
└── avatars/
└── {avatar_id}/ # avatar_id = avt_{16位随机hex}
├── meta.json # 元数据(JSON 格式)
└── source.mp4 # 原始上传视频
```
### `meta.json` 结构
```json
{
"id": "avt_xxxxxxxxxxxxxxxx",
"name": "我的数字人",
"voiceId": "klingai-voice-id-string",
"elementId": 12345678,
"voiceTaskId": "kling-task-id-string",
"elementTaskId": "kling-task-id-string",
"videoUrl": "https://domain.com/path/to/source.mp4",
"trialUrl": "https://domain.com/path/to/trial.wav",
"status": "succeed",
"failReason": null,
"createdAt": "2026-04-16T10:00:00.000Z",
"updatedAt": "2026-04-16T10:05:00.000Z"
}
```
---
## 代码改动清单
### 后端 Python
| 操作 | 文件 | 改动说明 |
|------|------|----------|
| 🆕 新增 | `app/models/interface_request_logs.py` | SQLAlchemy 模型 `InterfaceRequestLogs` |
| 🆕 新增 | `app/crud/interface_request_logs.py` | CRUD:create / update |
| ✏️ 修改 | `app/models/__init__.py` | 删除 `Avatar` 导入,新增 `InterfaceRequestLogs` |
| ✏️ 修改 | `app/api/v1/avatar.py` | 完全重写
• 保留:`POST /clone` / `GET /tasks/{id}` / `GET /clone/stream` / `POST /tasks/{id}/retry` / `DELETE /{id}`
• 删除:`GET /library` / `PATCH /{id}` / `/health` |
| ✏️ 修改 | `app/scheduler/handlers/avatar_handler.py` | 精简:删除所有对 `mjk_avatars` 读写,只记接口日志,进度放 Redis Registry |
| ❌ 删除 | `app/models/avatar.py` | 模型废弃,删除 |
| ❌ 删除 | `app/crud/avatar.py` | CRUD 废弃,删除 |
| ❌ 删除 | `app/tasks/avatar_clone.py` | 逻辑已合并到 avatar_handler,删除 |
### Rust Tauri(`tauri-app/src-tauri/src/persistence.rs`)
新增以下 IPC 命令:
```rust
/// 列出所有本地数字人(按创建时间倒序)
#[tauri::command]
pub fn list_avatars(app: AppHandle) -> Result, String>;
/// 保存数字人元数据
#[tauri::command]
pub fn save_avatar(app: AppHandle, avatar_id: String, meta: AvatarMeta) -> Result<(), String>;
/// 获取单个数字人元数据
#[tauri::command]
pub fn get_avatar(app: AppHandle, avatar_id: String) -> Result