30 KiB
美家卡智影 (Meijiaka AI Video) - AI 视频创作平台
项目概述
美家卡智影是一个 AI 驱动的视频创作桌面应用,采用 Tauri + React + FastAPI 混合架构。用户可以通过 AI 生成脚本、创建数字人视频,最终合成完整的营销视频。
核心功能
- AI 脚本生成: 基于 LLM 自动生成视频脚本和分镜
- 数字人视频: 基于 KlingAI 创建数字人视频片段
- 字幕生成: 基于火山引擎豆包语音自动生成字幕并压制到视频
- 封面制作: 提取视频首帧并叠加字幕样式生成封面
- 视频合成: 本地 FFmpeg 处理视频拼接、音频混流、导出成品
- 形象克隆: 基于 KlingAI 的自定义数字人形象管理
- 项目管理: 项目数据本地 JSON 文件存储,认证状态云端同步
项目结构
ai-meijiaka/
├── python-api/ # FastAPI 后端服务(AI 代理 + 认证 + 任务调度)
│ ├── app/
│ │ ├── api/v1/ # API 路由 (REST): auth, script, ai_models, klingai,
│ │ │ # qiniu, video, avatar, system,
│ │ │ # caption, tasks
│ │ ├── ai/ # AI 模型路由、Provider、提示词模板
│ │ ├── core/ # 安全、配置加载、Token管理器、Redis客户端、异常处理
│ │ ├── crud/ # 数据访问层(users, model_usage, avatar)
│ │ ├── db/ # 数据库配置(PostgreSQL + asyncpg + SQLAlchemy 2.0)
│ │ ├── models/ # SQLAlchemy 模型(users, model_usage_logs, avatars)
│ │ ├── schemas/ # Pydantic 校验模型
│ │ ├── services/ # AI 服务代理、DTO标准化、七牛/字幕/视频服务
│ │ ├── scheduler/ # Async Engine 异步任务调度(video, image, script,
│ │ │ # subtitle, copy, avatar_clone)
│ │ ├── config.py # Pydantic Settings 配置管理
│ │ └── main.py # FastAPI 入口(含生命周期管理)
│ ├── config/ # AI 模型配置文件(ai_models.yaml),支持热重载
│ ├── alembic/ # 数据库迁移
│ ├── scripts/ # 初始化/测试脚本
│ ├── pyproject.toml # Python 依赖和工具配置
│ ├── requirements.lock # uv 锁定依赖版本
│ ├── Makefile # 常用命令封装
│ ├── docker-compose.yml
│ └── Dockerfile
│
├── tauri-app/ # Tauri 桌面应用(业务数据本地存储)
│ ├── src/ # React 前端源码
│ │ ├── api/
│ │ │ ├── adapters/ # 数据转换层(前后端字段映射)
│ │ │ ├── generated/ # OpenAPI 自动生成类型(只读)
│ │ │ ├── modules/ # API 模块封装(HTTP + IPC)
│ │ │ ├── client.ts # HTTP 客户端(自动 camelCase↔snake_case)
│ │ │ ├── types.ts # 手写核心类型
│ │ │ └── ipc.ts # Tauri IPC 调用封装
│ │ ├── components/ # 可复用组件
│ │ ├── pages/ # 页面组件
│ │ ├── store/ # Zustand 状态管理(+ Immer + persist)
│ │ ├── hooks/ # 自定义 React Hooks
│ │ ├── styles/ # 全局 CSS 变量、主题
│ │ └── utils/ # 工具函数
│ ├── src-tauri/ # Rust 后端源码
│ │ ├── src/
│ │ │ ├── lib.rs # Tauri 应用入口,命令注册
│ │ │ ├── ffmpeg_cmd.rs # FFmpeg 命令封装
│ │ │ ├── video_processing.rs # 视频合成业务逻辑
│ │ │ ├── storage/ # 本地存储引擎(原子写入、文件锁、路径净化)
│ │ │ ├── commands/ # IPC 命令按领域拆分(project/asset/auth/avatar)
│ │ │ ├── api_proxy.rs # Python API 代理转发
│ │ │ ├── auth.rs # 认证命令(已迁移至 commands/auth_state.rs)
│ │ │ ├── avatar_cache.rs # 头像缓存管理
│ │ │ └── utils.rs # 通用工具函数
│ │ ├── Cargo.toml
│ │ ├── tauri.conf.json
│ │ └── binaries/ # 嵌入式 FFmpeg
│ ├── package.json
│ ├── vite.config.ts
│ ├── tsconfig.json
│ └── eslint.config.js
│
└── docs/ # 项目文档
├── anytocopy-api.md
├── anytocopy-integration.md
├── app-update-system.md
├── database-design.md
├── kling-api-dev.md
├── migrate-avatars-to-local.md
├── qiniu-kodo-python-sdk-guide.md
├── video-generation-flow.md
└── volcengine-video-caption-api.md
技术栈
后端 (python-api)
⚠️ Python 版本要求: 3.13+ (项目使用 | 类型注解语法)
| 组件 | 技术 | 版本 | 用途 |
|---|---|---|---|
| Python | - | 3.13+ | 运行环境 |
| Web 框架 | FastAPI | 0.116+ | REST API |
| 数据库 | PostgreSQL | 15+ | 用户认证 + 成本统计 + 形象管理 |
| ORM | SQLAlchemy | 2.0 (异步) | 数据模型 |
| 缓存/调度 | Redis + Async Engine | 5.2+ / 自定义 | 异步任务槽位调度 |
| AI SDK | OpenAI / volcengine | 1.58+ / 5.0+ | LLM 调用 |
| 认证 | python-jose + passlib | 3.4+ / 1.7+ | JWT 认证 |
| 对象存储 | qiniu | 7.13+ | 七牛云存储 |
| HTTP 客户端 | httpx + aiohttp | 0.28+ / 3.13+ | 异步 HTTP |
| 包管理/构建 | uv | - | 虚拟环境、依赖锁定、Docker 构建 |
后端架构说明:
- 后端为"轻量云账号 + 全本地业务数据"模式
- 云端仅存储:用户账户、形象元数据、成本统计
- 业务数据(项目/脚本/媒体)全部本地存储
- 任务调度使用自定义 Async Engine(基于 Redis 的槽位管理),非 Celery
前端 (tauri-app)
| 组件 | 技术 | 版本 | 用途 |
|---|---|---|---|
| 桌面框架 | Tauri | 2.x | 桌面应用壳 |
| UI 框架 | React | 19.1+ | 用户界面 |
| 路由 | React Router DOM | 7.x | 页面路由(主壳使用 NavigationContext) |
| 状态管理 | Zustand | 5.x | 全局状态 + Immer 中间件 |
| 数据获取 | SWR | 2.x | 请求缓存 |
| 虚拟列表 | @tanstack/react-virtual | 3.x | 大数据列表渲染 |
| 构建工具 | Vite | 7.x | 构建、开发服务器 |
| 测试 | Vitest + @testing-library | 4.x | 单元测试 |
| 类型生成 | openapi-typescript | 7.x | 从 OpenAPI 生成 TS 类型 |
Rust 后端 (src-tauri/src)
| 模块 | 用途 |
|---|---|
| lib.rs | Tauri 应用入口,命令注册 |
| ffmpeg_cmd.rs | FFmpeg 命令封装(首帧提取、字幕压制、封面合成) |
| video_processing.rs | 视频合成业务逻辑 |
| storage/engine.rs | 本地存储引擎(原子写入、文件锁、路径净化) |
| storage/paths.rs | 集中化路径计算 |
| commands/project.rs | 项目本地存储 IPC 命令 |
| commands/asset.rs | 资源文件保存 IPC 命令 |
| commands/auth_state.rs | 认证状态文件持久化 |
| api_proxy.rs | Python API 代理转发 |
| avatar_cache.rs | 头像视频缓存管理 |
开发环境搭建
1. 启动 Python 后端
cd python-api
# 方式一:Docker Compose(推荐)
cp .env.example .env
docker-compose up -d
# 方式二:本地开发(若 Docker 不可用)
# 启动 PostgreSQL 和 Redis
docker-compose up -d db redis
# 安装依赖(使用 uv)
uv pip install -e ".[dev]"
# 启动开发服务器(注意:Docker API 会占用 8080 端口)
uvicorn app.main:app --reload --host 0.0.0.0 --port 8000
# 另开终端启动 Async Engine Scheduler(必须同时启动,否则任务不会执行)
python -m app.scheduler.main
后端服务地址:
Docker Compose 服务组成(4 个服务):
db: PostgreSQL 15redis: Redis 7api: FastAPI 开发服务器(端口 8080→8000)scheduler: Async Engine 统一调度器,处理所有第三方异步任务
2. 启动 Tauri 前端
cd tauri-app
# 安装依赖
npm install
# 开发模式(自动启动 Vite + Tauri)
npm run tauri dev
前端窗口:
- Vite 开发服务器: http://localhost:1420
- 应用窗口: 1440×960(最小 960×640,可调整大小)
构建命令
Python 后端
cd python-api
# 使用 Makefile(推荐)
make dev # 安装开发依赖 + pre-commit 钩子
make lint # ruff + mypy
make format # black + ruff --fix
make test # pytest
make test-cov # 覆盖率报告
make security # bandit + pip-audit
make lint-semantic # 语义层禁词检查
make ci # 运行所有 CI 检查(format-check + lint + lint-semantic + test + security)
make docker-run # Docker Compose 启动全部服务
make scheduler # 启动 Async Engine Scheduler
# 手动命令
black app/
ruff check app/
mypy app/
bandit -c pyproject.toml -r app/
pip-audit
pytest
pytest --cov=app
# 导出 OpenAPI 文档到前端
python3 -c "
import logging
logging.disable(logging.WARNING)
from app.main import app
import json
print(json.dumps(app.openapi(), indent=2, ensure_ascii=False))
" > ../tauri-app/src/api/generated/openapi.json
# Docker 构建
docker build -t meijiaka-api .
Tauri 前端
cd tauri-app
# 开发
npm run dev # 纯 Vite 开发(不启动 Tauri)
npm run tauri dev # 完整 Tauri 开发模式
# 构建
npm run build # 前端生产构建
npm run tauri build # 打包桌面应用
# 测试
npm run test # 运行 Vitest
npm run test:ui # UI 模式
npm run test:coverage # 覆盖率报告
# 代码质量
npm run lint # ESLint 检查
npm run lint:fix # ESLint 自动修复
npm run format # Prettier 格式化
npm run format:check # Prettier 格式检查
npm run stylelint # CSS 检查
npm run stylelint:fix # CSS 自动修复
# 类型生成
npm run gen:api # 从 OpenAPI 生成 TypeScript 类型
架构说明
混合路由架构
前端 API 调用采用 智能路由 策略:
- HTTP 直连 Python: 纯数据 API(脚本生成、模型管理、任务轮询等)
- Tauri IPC → Rust: 需要本地能力的 API(FFmpeg、文件系统)
路由决策在 tauri-app/src/api/client.ts 中实现。HTTP 客户端会自动处理 camelCase ↔ snake_case 字段名转换。需要走 Rust IPC 的 API 包括:
video_composite_synthesis// FFmpeg 视频合成burn_subtitle// 字幕压制extract_video_first_frame// 首帧提取generate_cover_image// 封面生成save_project_meta*/load_project_meta*// 本地文件系统save_project_segments*/load_project_segments*save_project_asset/get_video_save_path/get_image_save_pathsave_final_product- 头像缓存相关 API
添加新 API 流程:
- Python 端实现端点
- 前端直接调用(默认 HTTP)
- 仅当需要本地能力时,在 Rust 中添加命令并在
lib.rs注册
AI Provider 架构
后端 AI 模块采用 多 Provider 路由 设计:
app/ai/
├── model_router.py # 模型路由器(自动降级)
├── providers/
│ ├── base.py # Provider 抽象基类
│ ├── generic_llm_provider.py # 通用 OpenAI 兼容 Provider
│ ├── volcengine_provider.py # 火山方舟官方 SDK
│ └── klingai_provider.py # KlingAI 数字人
└── prompts/ # 提示词模板(禁止硬编码)
支持的 AI 平台:
- 火山方舟 (字节跳动) - 推荐,性价比高
- OpenAI - GPT 系列
- 文心一言 (百度)
- 通义千问 (阿里云)
- 可灵 AI (快手) - 视频生成、数字人、形象克隆
AI 模型配置位于 python-api/config/ai_models.yaml,支持热重载,无需重启服务即可更新模型配置。
Async Engine(异步任务调度)
⚠️ 重要:项目不使用 Celery,使用自定义 Async Engine
架构:
API (POST /tasks/{type}) → Redis JobRegistry → AsyncEngine tick loop → Handlers
组件:
AsyncEngine(app/scheduler/engine.py): 每 ~10s 执行tick(),加载运行中任务,按类型分组,并行分发给 Handler,通过 Pipeline 应用StateChange,清理已完成任务JobRegistry(app/scheduler/registry.py): Redis-based 任务 CRUD,使用job:{id}hash +scheduler:running_tasksSETSlotManager(app/scheduler/slot_manager.py): Redis Lua 原子脚本实现并发槽位抢占/释放JobRecord/StateChange(app/scheduler/models.py): 调度器内部类型
已注册的 Handler(app/scheduler/main.py):
| Handler | 槽位数 | Redis Key | 用途 |
|---|---|---|---|
| VideoHandler | 18 | kling:video_slots |
Kling 视频生成(omni + image2video) |
| ImageHandler | 9 | kling:image_slots |
Kling 图片生成 |
| ScriptHandler | 10 | script:slots |
LLM 脚本生成(含 AnyToCopy 视频文案提取) |
| SubtitleHandler | 5 | volc:subtitle_slots |
火山引擎字幕/自动对齐 |
| CopyHandler | 5 | anytocopy:slots |
AnyToCopy 视频文案提取 |
| AvatarHandler | 2 | kling:avatar_slots |
Kling 形象克隆(状态机: pending→voice_processing→element_pending→element_processing→succeed) |
TokenManager(API 认证 Token 管理)
app/core/token_manager.py 提供通用的 API 认证 Token 缓存与自动刷新:
from app.core.token_manager import JWTTokenStrategy, TokenManager
class MyProvider:
def __init__(self, access_key: str, secret_key: str):
self._token_strategy = JWTTokenStrategy(
access_key=access_key,
secret_key=secret_key,
expires_in=1800, # 30分钟
)
async def _get_headers(self) -> dict[str, str]:
token_info = await TokenManager.get_instance().get_token(self._token_strategy)
return {"Authorization": f"Bearer {token_info.token}"}
特性:
- Token 缓存(避免重复生成)
- 自动刷新(Token 即将过期时自动刷新)
- 并发安全(双重检查锁定,确保并发请求只生成一次 Token)
- 后台预热(提前 10 分钟刷新,避免请求时等待)
- 支持 JWT、OAuth2 等多种策略
本地存储引擎(Rust)
Rust 层实现了 defense-in-depth 的本地存储系统:src-tauri/src/storage/
engine.rs: 核心原子操作sanitize_id()— 白名单[a-zA-Z0-9_-]+,防御路径遍历sanitize_filename()— 提取纯文件名,拒绝目录组件atomic_write_json()/atomic_write_bytes()— 先写.tmp再rename原子替换with_file_lock()— 通过fs2实现独占文件锁read_json<T>()— 安全读取,文件不存在返回None
paths.rs: 集中路径计算~/Documents/Meijiaka/projects/{id}/(meta.json, segments.json, assets/)~/Documents/Meijiaka/products/{app_config_dir}/auth.json{app_data_dir}/avatars/
所有本地 JSON 读写必须经过 StorageEngine,禁止在命令处理器中直接调用 fs::write。
数据库模型
后端仅保留 3 个表:
users -- 用户账户信息(mobile, nickname, avatar_url)
model_usage_logs -- 大模型调用记录(token, 成本, 响应时间)
avatars -- 克隆形象元数据(云端备份,前端已迁移至本地 JSON)
业务数据本地存储:
- 项目/脚本/分镜 → 前端本地 JSON 文件(
~/Documents/Meijiaka/projects/) - 音频/视频/图片文件 → 本地磁盘
- 用户配置 → localStorage(少量 UI 状态)
数据流规范
用户输入主题 ──→ 后端 AI 生成脚本 ──→ 后端返回分镜列表 ──→ 前端保存到本地
│ │
└────────────────── 后端不存储脚本数据 ────────────────────────┘
本地存储结构
~/Documents/Meijiaka/ # 用户文档目录
├── config.json # 全局配置
├── projects/ # 项目数据
│ └── {project_id}/
│ ├── meta.json # 项目元数据
│ ├── segments.json # 分镜数据
│ └── assets/ # 资源文件(封面、成品等)
├── products/ # 成品视频目录
├── avatars.json # 形象列表(本地)
└── cache/ # 缓存目录
项目元数据 meta.json 关键字段:
id,title,topic,status(draft | published)currentStep: 1=脚本生成, 2=形象视频, 3=字幕压制, 4=封面制作, 5=视频合成createdAt,updatedAt,exportedAtcoverPath,finalVideoPathselectedElementId,selectedHumanIdcoverConfig,scriptDuration,scriptType
分镜数据 segments.json 字段:
id,type(segment | empty_shot),scene,voiceover,durationvideoPath,videoUrl,elementId,voiceIdalignmentResult,burnedVideoPath,burnedAt
前端导航
主应用壳使用 自定义 NavigationContext(React Context)实现页面切换,映射 Record<PageType, ComponentType>。react-router-dom 已安装但主要用于未来扩展或特定路由场景,当前主流程不使用 BrowserRouter 进行导航。
状态管理
六個專門的 Zustand store:
| Store | 职责 | 持久化 |
|---|---|---|
authStore |
JWT、UserInfo、登录/登出 | Tauri auth.json(或 localStorage fallback) |
projectStore |
分镜、currentStep、选题、封面配置 | 仅 UI 标志通过 persist;业务数据显式写入本地 JSON |
taskStore |
异步任务状态/进度/消息 | 无(内存 only,真相源在后端 Redis) |
uiStore |
Toast 通知队列 | 无 |
progressStore |
全局进度模态框 | 无 |
settingsStore |
主题模式、用户偏好 | localStorage |
projectStore 不自动保存。数据在显式过渡点持久化到磁盘(如进入 step 2、调用 setFinalVideoPath 时触发 saveMetaToLocalFile)。saveMetaToLocalFile() 通过 Promise 链串行化写入,避免并发覆盖。
开发规范
核心原则
- 后端环境优先使用 Docker Compose: 开发时通过
docker-compose up -d启动后端。前端默认连接http://127.0.0.1:8080/api/v1。 - 接口契约优先: 后端承诺无论使用什么 AI 模型,输出永远符合同一个 Schema
- 类型单一来源: 后端 Schema 是权威,前端通过 OpenAPI 生成类型
- Adapter 层隔离: 前后端字段差异只允许在 Adapter 层处理
- 数据库分层: API → Service → CRUD → Model,禁止跨层调用
- 提示词文件化: 除前端输入外,后端不允许硬编码任何 Prompt
- 配置统一管理: 所有配置通过
get_settings()读取,禁止直接使用os.getenv() - 本地存储必须经过 StorageEngine: Rust 层所有文件操作使用
atomic_write_json+with_file_lock
配置管理规范
架构层级:
.env (Layer 1) ──→ Settings (Layer 2) ──→ 服务层 (Layer 3)
↑
唯一配置出口
强制规范:
- 所有服务必须使用
from app.config import get_settings读取配置 - 禁止在服务层使用
os.getenv()或os.environ.get() - 所有配置项必须在
app/config.py的Settings类中定义 - 敏感信息(API Keys、Secrets)必须通过环境变量注入
- 业务默认值可以硬编码在
Settings中
添加新配置流程:
- 在
app/config.py的Settings类中添加字段定义 - 在
.env中添加实际值(敏感信息)或使用默认值 - 在服务层通过
get_settings()读取 - 更新
.env.example文档
语义层防护网
项目强制执行语义分层,禁止供应商术语泄漏到业务层:
| 层级 | 职责 | 禁词示例 |
|---|---|---|
| Layer 6 (Presentation) | API Schema | element_id, kling_task_id |
| Layer 4 (Orchestration) | Scheduler | task_id(应使用 job_id) |
| Layer 3 (Domain) | Service | 供应商特定术语 |
| Layer 2 (Adapter) | Provider | 允许使用供应商原生术语 |
Makefile 提供 make lint-semantic 进行自动化检查:
- API 层(除
klingai.py)禁止使用element_id(应使用provider_element_id或human_id) - Scheduler 层禁止使用
task_id(应使用job_id) - 全局禁止
kling_task_id(应使用provider_task_id) - Scheduler Redis key 必须使用
job:而非task:
快速参考
| 场景 | 正确做法 |
|---|---|
| 后端换 AI 模型 | 修改 services/ai_response_utils.py 标准化层,不修改 Schema |
| 后端新增字段 | Optional[T] = Field(None),向后兼容 |
| 后端修改字段 | 保留旧字段,标记 deprecated,逐步迁移 |
| 前端需要新字段 | Store 中 extends 基础类型 |
| 数据清洗 | 只在 Adapter 层,禁止在组件层 |
| 新增数据库实体 | 创建 Model → CRUD → API(分层开发) |
| 数据库查询 | 在 CRUD 层封装,API 层调用 |
| 事务管理 | API 层控制,通过 get_db 依赖注入 |
| 新增提示词 | 创建 .txt 文件,使用 _load_prompt() 加载 |
| 新增本地文件操作 | 使用 storage::engine 原子写入 + 文件锁 |
后端分层架构
API Layer (api/v1/*.py)
↓ 调用
Service Layer (services/*.py) - 可选,复杂业务
↓ 调用
CRUD Layer (crud/*.py)
↓ 调用
Model Layer (models/*.py)
↓ 调用
Database Layer (db/*.py)
禁止:
- API 层直接操作 Model
- CRUD 层返回 Schema(应返回 Model)
- Service 层直接操作数据库(应通过 CRUD)
- 在业务代码中写 SQL
前端类型规范
| 层级 | 类型来源 | 说明 |
|---|---|---|
| 后端 Schema | python-api/app/schemas/*.py |
Pydantic 模型,OpenAPI 生成源 |
| 前端基础类型 | tauri-app/src/api/types.ts |
手写的核心类型,与后端对齐 |
| 前端完整类型 | tauri-app/src/api/generated/schema.ts |
OpenAPI 自动生成,只读 |
| Store 扩展 | tauri-app/src/store/*.ts |
extends 基础类型添加前端字段 |
间距规范
前端使用基于 4px 的网格系统,定义在 tauri-app/src/styles/variables.css:
| 变量 | 值 | 使用场景 |
|---|---|---|
--spacing-2xs |
2px | 微调控件、边框线 |
--spacing-xs |
4px | 紧凑间隙、图标边距 |
--spacing-sm |
8px | 小间隙、按钮内边距-y |
--spacing-md |
12px | 标准间隙、卡片内边距 |
--spacing-lg |
16px | 大间隙、区块间距 |
--spacing-xl |
24px | 页面区块、内容分隔 |
--spacing-2xl |
32px | 大区块间距、页面边距 |
--spacing-3xl |
48px | 页面级间距、Hero 区域 |
代码风格
Python
- 格式化: Black (line-length: 100, target-version: py313)
- 检查: Ruff (E, F, I, N, W, UP, B, C4, SIM)
- 类型: MyPy(非严格模式全局,但
app.schemas.*、app.crud.*、app.scheduler.handlers.*强制严格模式) - 文档: 中文注释,Google Style Docstrings
- 安全: Bandit + pip-audit
- Git Hooks: pre-commit(Black、Ruff、uv lock 同步检查)
TypeScript/React
- 类型: 严格 TypeScript 模式(
strict: true,noUnusedLocals: true,noUnusedParameters: true) - 组件: 函数组件 + Hooks
- 状态: Zustand 管理全局状态(配合 Immer 处理不可变更新)
- 样式: 普通 CSS + CSS 变量(
tauri-app/src/styles/variables.css) - ESLint: 使用
eslint.config.js(Flat Config),含 React Hooks 和 React Refresh 规则 - Prettier: semi=true, singleQuote=true, tabWidth=2, printWidth=100
- Stylelint:
stylelint-config-standard,禁止 magic px 用于border-radius和font-size
Rust
- 格式化: rustfmt
- 检查: cargo clippy
- 注释: 中文文档注释
提交规范
feat: 新功能
fix: 修复
docs: 文档
refactor: 重构
test: 测试
chore: 构建/工具
测试策略
后端测试
cd python-api
# 运行所有测试
pytest -v
# 覆盖率报告
pytest --cov=app --cov-report=html --cov-report=term
测试配置 (pyproject.toml):
- asyncio_mode = "auto"
- 测试文件命名:
test_*.py
注:当前项目中
python-api/tests/目录尚未创建,后端测试待补充。
前端测试
cd tauri-app
# 运行 Vitest
npm run test
# UI 模式
npm run test:ui
# 覆盖率报告
npm run test:coverage
测试配置:
- 测试框架: Vitest 4.x + @testing-library/react + jsdom
- 测试文件:
src/**/*.test.ts(x) - Mock 配置:
src/__tests__/setup.ts - 自动 Mock: localStorage, Tauri API (
@tauri-apps/api/core) - 示例测试:
src/store/__tests__/authStore.test.tsx
安全注意事项
- SECRET_KEY: 生产环境必须修改为强随机密钥(
get_settings()会在生产环境校验) - CORS: 生产环境限制为实际前端域名,开发环境
DEBUG=true时允许所有来源 - API Keys: 不要提交到 Git,使用
.env文件注入 - FFmpeg: 嵌入的二进制文件需验证来源
- 文件上传: 限制文件类型和大小,防止攻击
- 路径遍历: Rust StorageEngine 的
sanitize_id()和sanitize_filename()防御路径遍历攻击 - 原子写入: 所有本地 JSON 使用
atomic_write_json(先写.tmp再rename) - 文件锁: 并发 RMW 操作使用
with_file_lock防止竞态 - 日志: 后端日志写入
~/Documents/Meijiaka/logs/api_YYYYMMDD.log
配置说明
Python 后端 (.env)
关键环境变量:
# 数据库 (PostgreSQL)
DATABASE_URL=postgresql+asyncpg://postgres:postgres@localhost:5432/meijiaka
# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_DB=0
# JWT 密钥(生产环境必须修改)
SECRET_KEY=your-secret-key-here-change-in-production
ACCESS_TOKEN_EXPIRE_MINUTES=10080
# AI API Keys
VOLCENGINE_API_KEY=your-volcengine-key
VOLCENGINE_CAPTION_APPID=your-caption-appid
VOLCENGINE_CAPTION_TOKEN=your-caption-token
KLINGAI_ACCESS_KEY=your-kling-access-key
KLINGAI_SECRET_KEY=your-kling-secret-key
OPENAI_API_KEY=sk-your-openai-key
# 七牛云存储
QINIU_ACCESS_KEY=your-qiniu-access-key
QINIU_SECRET_KEY=your-qiniu-secret-key
QINIU_VIDEO_BUCKET=media-liche
QINIU_IMAGE_BUCKET=img-liche
# CORS 允许的前端地址
CORS_ORIGINS=http://localhost:1420,http://127.0.0.1:1420,http://localhost:8080
Tauri 配置 (tauri.conf.json)
{
"productName": "美家卡智影",
"identifier": "cn.meijiaka.ai-video",
"build": {
"devUrl": "http://localhost:1420",
"frontendDist": "../dist"
},
"bundle": {
"externalBin": ["binaries/ffmpeg"],
"resources": {
"fonts/*": "fonts/"
}
}
}
AI 模型配置 (config/ai_models.yaml)
模型配置文件支持热重载,无需重启服务即可更新模型配置。主要配置项:
- platforms: AI 平台配置(mock, volcengine, klingai)
- models: 可用模型列表及其能力标签 [script, polish, chat, image, embedding, vision]
- task_defaults: 任务类型到模型的默认映射
视频创作流程
- 脚本生成 (Step 1) - AI 生成视频脚本和分镜
- 形象视频 (Step 2) - 选择数字人形象,生成视频片段
- 字幕压制 (Step 3) - 生成字幕并压制到视频中
- 封面制作 (Step 4) - 生成视频封面
- 视频合成 (Step 5) - FFmpeg 拼接视频片段,导出最终视频
常见问题
Q: 火山方舟如何配置?
- 注册火山引擎账号并实名认证
- 创建 API Key
- 开通模型并创建推理接入点
- 在
.env中设置VOLCENGINE_API_KEY
Q: 可灵 AI 如何配置?
- 前往可灵 AI 开发者平台 https://klingai.com/document-api
- 获取 Access Key 和 Secret Key
- 在
.env中设置KLINGAI_ACCESS_KEY和KLINGAI_SECRET_KEY
Q: FFmpeg 在哪里?
Tauri 应用已嵌入 FFmpeg 二进制文件:
- 位置:
tauri-app/src-tauri/binaries/ffmpeg-* - 使用: Rust 层通过
ffmpeg_cmd模块调用 - 打包时会作为
externalBin资源嵌入
Q: 后端换了 AI 模型,输出格式变了怎么办?
修改 services/ai_response_utils.py 中的标准化函数,增加新的字段映射,不要修改 API Schema。
Q: 如何新增/修改提示词?
- 创建文件:
app/ai/prompts/my_prompt.txt - 加载使用:
prompt = self._load_prompt("my_prompt") - 禁止: 在 Python 代码中直接写
"""你是一位..."""
Q: 项目数据是如何持久化的?
- 项目元数据(
meta.json)和分镜数据(segments.json)保存在~/Documents/Meijiaka/projects/{project_id}/ - 不通过 Zustand
persist保存项目数据,而是通过localProjectApi显式调用 Tauri IPC 写入文件 projectStore的persist中间件仅保存少量 UI 状态
Q: Async Engine 和 Celery 有什么区别?
本项目使用自定义 Async Engine 替代 Celery:
- 基于 Redis 的槽位管理(SlotManager),限制各类型任务的并发数
- 独立的
scheduler进程(python -m app.scheduler.main) - 每个 Handler 实现
AsyncHandler接口,状态机驱动任务生命周期 - 优势:更细粒度的并发控制、统一状态机、无 Celery 依赖
最后更新: 2026-04-17 架构模式: 单机版(轻量云账号 + 全本地业务数据)