Files
meijiaka-zy/AGENTS.md
T
小鱼开发 bb08d0f586 refactor: 从智影 Fork 重构为智剪,独立 Docker 基础设施,开发模式认证兜底
主要变更:
- 修复 /tasks/script 路由 404(去掉重复 prefix)
- 开发模式自动认证兜底(无需登录即可测试流程)
- Docker 基础设施独立化(共用 db/redis)
- 前端 API 端口改为 8081
- 新增 TTS/语音克隆、视频粗剪、音频混音等智剪功能
- 删除智影专属模块(avatar、model_usage、qiniu 上传等)
2026-04-21 12:35:50 +08:00

33 KiB
Raw Blame History

美家卡智剪 (Meijiaka Smart Cut) - AI 视频剪辑桌面应用

项目概述

美家卡智剪是一个 AI 驱动的短视频剪辑桌面应用,采用 Tauri + React + FastAPI 混合架构。本项目由「美家卡智影」Fork 而来,从"数字人生成"转向"AI 辅助长视频剪辑"方向:用户导入长视频素材,AI 根据脚本自动分镜切割,配合语音克隆/TTS 生成配音,最终合成带字幕的成品短视频。

核心功能流程(6 步)

  1. 脚本生成 (Step 1) - AI 生成或粘贴口播文案,自动拆分为带预估时长的分镜
  2. 视频粗剪 (Step 2) - 导入长视频素材,按脚本时长自动切割为片段
  3. 语音配音 (Step 3) - AI 声音克隆(KlingAI)+ TTS 合成,为每段生成配音音频
  4. 字幕压制 (Step 4) - 基于音频自动对齐时间轴,ASS 字幕渲染并压制到视频
  5. 封面制作 (Step 5) - 提取视频首帧并叠加标题样式生成封面
  6. 视频合成 (Step 6) - FFmpeg 拼接视频片段,替换原声为 TTS 音频,导出成品

技术架构

  • 前端桌面壳: Tauri 2.x + React 19 + TypeScript 5.8 + Vite 7
  • 后端服务: FastAPI (Python 3.13+) + PostgreSQL 15 + Redis 7
  • 任务调度: 自定义 Async Engine(基于 Redis 槽位管理),非 Celery
  • 本地处理: 嵌入式 FFmpeg,Rust 层封装视频/音频处理命令
  • AI 服务: 火山方舟(LLM/字幕)、可灵 AI(TTS/声音克隆)、OpenAI 兼容接口

项目结构

meijiaka-zj/
├── python-api/           # FastAPI 后端服务(AI 代理 + 认证 + 任务调度)
│   ├── app/
│   │   ├── api/v1/       # API 路由: auth, system, caption, voice
│   │   ├── ai/           # AI 模型路由、Provider、提示词模板
│   │   ├── core/         # 安全、配置加载、Token管理器、Redis客户端、异常处理
│   │   ├── crud/         # 数据访问层(users, avatar
│   │   ├── db/           # 数据库配置(PostgreSQL + asyncpg + SQLAlchemy 2.0
│   │   ├── models/       # SQLAlchemy 模型(当前仅 users
│   │   ├── schemas/      # Pydantic 校验模型
│   │   ├── services/     # AI 服务代理、字幕/视频/TTS/声音克隆服务
│   │   ├── scheduler/    # Async Engine 异步任务调度
│   │   ├── config.py     # Pydantic Settings 配置管理
│   │   └── main.py       # FastAPI 入口(含生命周期管理)
│   ├── config/           # AI 模型配置文件(ai_models.yaml),支持热重载
│   ├── alembic/          # 数据库迁移(当前无迁移文件)
│   ├── tests/            # 测试目录(当前仅 test_kling_tts.py
│   ├── pyproject.toml    # Python 依赖和工具配置
│   ├── requirements.lock # uv 锁定依赖版本(如缺失需执行 make update-lock
│   ├── Makefile          # 常用命令封装
│   ├── docker-compose.yml
│   ├── Dockerfile
│   └── .env.example      # 环境变量模板
│
├── 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/        # 页面组件
│   │   │   ├── VideoCreation/   # 6 步视频创作流程
│   │   │   ├── ContentManagement/
│   │   │   ├── Settings/
│   │   │   ├── Profile/
│   │   │   └── Login/
│   │   ├── 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 命令按领域拆分
│   │   │   ├── api_proxy.rs    # Python API 代理转发
│   │   │   └── utils.rs        # 通用工具函数
│   │   ├── Cargo.toml
│   │   ├── tauri.conf.json
│   │   └── binaries/     # 嵌入式 FFmpeg
│   ├── package.json
│   ├── vite.config.ts
│   ├── tsconfig.json
│   └── eslint.config.js
│
├── docs/                 # 项目文档
├── scripts/              # 数据修复/迁移脚本(非部署脚本)
├── package.json          # 根级 package.jsonmonorepo 占位)
└── AGENTS.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 / 字幕调用
TTS/语音 KlingAI API - 语音合成、声音克隆
认证 python-jose + passlib 3.4+ / 1.7+ JWT 认证
HTTP 客户端 httpx + aiohttp 0.28+ / 3.13+ 异步 HTTP
包管理/构建 uv - 虚拟环境、依赖锁定、Docker 构建

后端架构说明

  • 后端为"轻量云账号 + 全本地业务数据"模式
  • 云端仅存储:用户账户信息
  • 业务数据(项目/脚本/媒体/成品)全部本地存储
  • 任务调度使用自定义 Async Engine(基于 Redis 的槽位管理),非 Celery
  • 当前活跃 API 模块仅 4 个:auth, system, caption, voice
  • 调度器已注册 7 个 HandlerVideo, Avatar, Image, Subtitle, Copy, Script, TTS

前端 (tauri-app)

组件 技术 版本 用途
桌面框架 Tauri 2.x 桌面应用壳
UI 框架 React 19.1+ 用户界面
路由 自定义 NavigationContext - 页面切换(react-router-dom 已安装但未用于主流程)
状态管理 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 类型
字幕渲染 assjs 0.1.x ASS 字幕前端渲染

Rust 后端 (src-tauri/src)

模块 用途
lib.rs Tauri 应用入口,命令注册(含 FFmpeg / 音频处理 / 视频合成命令)
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 认证状态文件持久化
commands/voice.rs 音频文件保存/列表/删除 IPC 命令
commands/product.rs 成品视频保存/列表/删除/重命名 IPC 命令
api_proxy.rs Python API 代理转发
avatar_cache.rs 头像视频缓存管理

开发环境搭建

1. 启动 Python 后端

cd python-api

# 方式一:Docker Compose(推荐)
cp .env.example .env
# 编辑 .env 填入实际的 AI API Keys
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 15
  • redis: Redis 7
  • api: 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 format-check  # 检查格式但不修改
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
make clean         # 清理缓存文件

# 手动命令
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 构建
make docker

Tauri 前端

cd tauri-app

# 开发
npm run dev          # 纯 Vite 开发(不启动 Tauri
npm run tauri dev    # 完整 Tauri 开发模式

# 构建
npm run build        # 前端生产构建(tsc + vite 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 调用采用 智能路由 策略:

  1. HTTP 直连 Python: 纯数据 API(脚本生成、模型管理、任务轮询等)
  2. Tauri IPC → Rust: 需要本地能力的 API(FFmpeg、文件系统)

路由决策在 tauri-app/src/api/client.ts 中实现。HTTP 客户端会自动处理 camelCasesnake_case 字段名转换。需要走 Rust IPC 的 API 包括:

  • video_composite_synthesis // FFmpeg 视频合成
  • burn_subtitle // 字幕压制
  • extract_video_first_frame // 首帧提取
  • generate_cover_image // 封面生成
  • replace_audio_track // 音频替换
  • mix_audio_tracks // 音频混音
  • standardize_audio // 音频标准化
  • save_project_meta* / load_project_meta* // 本地文件系统
  • save_project_segments* / load_project_segments*
  • save_project_asset / get_video_save_path / get_image_save_path
  • save_final_product / list_local_products / delete_local_product / rename_local_product
  • save_audio / list_project_audios / delete_audio
  • 头像缓存相关 API

添加新 API 流程

  1. Python 端实现端点
  2. 前端直接调用(默认 HTTP
  3. 仅当需要本地能力时,在 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(可灵 AI
└── prompts/                     # 提示词模板(禁止硬编码)

支持的 AI 平台:

  • 火山方舟 (字节跳动) - LLM、字幕服务
  • OpenAI - GPT 系列(可选)
  • 可灵 AI (快手) - TTS 语音合成、声音克隆
  • 文心一言 (百度) - 可选
  • 通义千问 (阿里云) - 可选

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_tasks SET
  • SlotManager (app/scheduler/slot_manager.py): Redis Lua 原子脚本实现并发槽位抢占/释放
  • JobRecord / StateChange (app/scheduler/models.py): 调度器内部类型

已注册的 Handlerapp/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 视频文案提取
TTSHandler - kling:tts_slots Kling TTS 语音合成
AvatarHandler 2 kling:avatar_slots Kling 形象克隆

TokenManagerAPI 认证 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() — 先写 .tmprename 原子替换
    • with_file_lock() — 通过 fs2 实现独占文件锁
    • read_json<T>() — 安全读取,文件不存在返回 None
  • paths.rs: 集中路径计算
    • ~/Documents/Meijiaka/projects/{id}/ (meta.json, segments.json, assets/)
    • ~/Documents/Meijiaka/products/
    • ~/Documents/Meijiaka/avatars.json
    • {app_config_dir}/auth.json

所有本地 JSON 读写必须经过 StorageEngine,禁止在命令处理器中直接调用 fs::write

数据库模型

后端当前仅保留 1 个活跃模型

users              -- 用户账户信息(mobile, nickname, avatar_url

注:avatarsmodel_usage_logs 相关模型及 CRUD 在最近的重构中已移除或清理。crud/avatar.py 仍存在但可能处于未使用状态。

业务数据本地存储

  • 项目/脚本/分镜 → 前端本地 JSON 文件(~/Documents/Meijiaka/projects/
  • 音频/视频/图片文件 → 本地磁盘
  • 成品视频 → ~/Documents/Meijiaka/products/
  • 用户配置 → localStorage(少量 UI 状态)

数据流规范

用户输入主题 ──→ 后端 AI 生成脚本 ──→ 后端返回分镜列表 ──→ 前端保存到本地
     │                                                            │
     └────────────────── 后端不存储脚本数据 ────────────────────────┘

用户导入长视频 ──→ Rust 本地切割 ──→ 生成分段视频 ──→ 前端保存到本地

本地存储结构

~/Documents/Meijiaka/                    # 用户文档目录
├── config.json                          # 全局配置
├── projects/                            # 项目数据
│   └── {project_id}/
│       ├── meta.json                    # 项目元数据
│       ├── segments.json                # 分镜数据
│       ├── media/                       # 导入的原始素材
│       ├── shots/                       # 自动切割后的片段
│       ├── audio/                       # TTS 生成的音频
│       └── assets/                      # 资源文件(封面、成品等)
├── products/                            # 成品视频目录
├── avatars.json                         # 形象列表(本地)
└── cache/                               # 缓存目录

项目元数据 meta.json 关键字段:

  • id, title, topic, status (draft | published)
  • currentStep: 1=脚本生成, 2=视频粗剪, 3=语音配音, 4=字幕压制, 5=封面制作, 6=视频合成
  • createdAt, updatedAt, exportedAt
  • coverPath, finalVideoPath
  • coverConfig, scriptDuration, scriptType

分镜数据 segments.json 字段:

  • id, type (segment | empty_shot), scene, voiceover, duration
  • videoPath, videoUrl, elementId, voiceId
  • alignmentResult, burnedVideoPath, burnedAt

前端导航

主应用壳使用 自定义 NavigationContextReact Context)实现页面切换,映射 Record<PageType, ComponentType>react-router-dom 已安装但主要用于未来扩展或特定路由场景,当前主流程不使用 BrowserRouter 进行导航。

页面结构:

  • video-creation - 6 步视频创作流程
  • avatar-clone - 形象/声音克隆管理
  • my-works - 我的作品
  • profile - 个人中心
  • settings-* - 设置相关页面

状态管理

七个专门的 Zustand store

Store 职责 持久化
authStore JWT、UserInfo、登录/登出 Tauri auth.json(或 localStorage fallback
projectStore 分镜、currentStep、选题、封面配置 仅 UI 标志通过 persist;业务数据显式写入本地 JSON
taskStore 异步任务状态/进度/消息 (内存 only,真相源在后端 Redis)
uiStore Toast 通知队列
progressStore 全局进度模态框
settingsStore 主题模式、用户偏好 localStorage
voiceStore 语音/形象选择状态

projectStore 不自动保存。数据在显式过渡点持久化到磁盘(如进入 step 2、调用 setFinalVideoPath 时触发 saveMetaToLocalFile)。saveMetaToLocalFile() 通过 Promise 链串行化写入,避免并发覆盖。

开发规范

核心原则

  1. 后端环境优先使用 Docker Compose: 开发时通过 docker-compose up -d 启动后端。前端默认连接 http://127.0.0.1:8080/api/v1
  2. 接口契约优先: 后端承诺无论使用什么 AI 模型,输出永远符合同一个 Schema
  3. 类型单一来源: 后端 Schema 是权威,前端通过 OpenAPI 生成类型
  4. Adapter 层隔离: 前后端字段差异只允许在 Adapter 层处理
  5. 数据库分层: API → Service → CRUD → Model,禁止跨层调用
  6. 提示词文件化: 除前端输入外,后端不允许硬编码任何 Prompt
  7. 配置统一管理: 所有配置通过 get_settings() 读取,禁止直接使用 os.getenv()
  8. 本地存储必须经过 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.pySettings 类中定义
  • 敏感信息API Keys、Secrets)必须通过环境变量注入
  • 业务默认值可以硬编码在 Settings

添加新配置流程:

  1. app/config.pySettings 类中添加字段定义
  2. .env 中添加实际值(敏感信息)或使用默认值
  3. 在服务层通过 get_settings() 读取
  4. 更新 .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_idhuman_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-commitBlack、Ruff、uv lock 同步检查)
  • 忽略规则: Ruff 忽略 E501, E402, N802, N803, N806, N815, B008, B904

TypeScript/React

  • 类型: 严格 TypeScript 模式(strict: true, noUnusedLocals: true, noUnusedParameters: true
  • 组件: 函数组件 + Hooks
  • 状态: Zustand 管理全局状态(配合 Immer 处理不可变更新)
  • 样式: 普通 CSS + CSS 变量(tauri-app/src/styles/variables.css
  • ESLint: 使用 eslint.config.jsFlat Config),含 React Hooks 和 React Refresh 规则
  • Prettier: semi=true, singleQuote=true, tabWidth=2, printWidth=100, trailingComma=es5
  • Stylelint: stylelint-config-standard,禁止 magic px 用于 border-radiusfont-size
  • ESLint 规则: no-console 为 warn(允许 warn/error/info),eqeqeq 为 warnno-var 为 error

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
  • 测试路径: tests/

:当前后端测试覆盖非常有限,仅 tests/test_kling_tts.py 一个测试文件,包含 TTSServiceVoiceCloneService 和状态枚举的单元测试。大量模块暂无测试。

前端测试

cd tauri-app

# 运行 Vitest
npm run test

# UI 模式
npm run test:ui

# 覆盖率报告
npm run test:coverage

测试配置:

  • 测试框架: Vitest 4.x + @testing-library/react 16.3.x + jsdom
  • 测试文件: src/**/*.test.ts(x)
  • Mock 配置: src/__tests__/setup.ts
  • 自动 Mock: localStorage, Tauri API (@tauri-apps/api/core)
  • 现有测试:
    • src/store/__tests__/authStore.test.tsx
    • src/store/__tests__/settingsStore.test.tsx

安全注意事项

  1. SECRET_KEY: 生产环境必须修改为强随机密钥(get_settings() 会在生产环境校验)
  2. CORS: 生产环境限制为实际前端域名,开发环境 DEBUG=true 时允许所有来源
  3. API Keys: 不要提交到 Git,使用 .env 文件注入
  4. FFmpeg: 嵌入的二进制文件需验证来源
  5. 文件上传: 限制文件类型和大小,防止攻击
  6. 路径遍历: Rust StorageEngine 的 sanitize_id()sanitize_filename() 防御路径遍历攻击
  7. 原子写入: 所有本地 JSON 使用 atomic_write_json(先写 .tmprename
  8. 文件锁: 并发 RMW 操作使用 with_file_lock 防止竞态
  9. 日志: 后端日志写入 ~/Documents/Meijiaka-zj/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-jian",
  "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, video_generation, image2video, lip_sync, image_generation]
  • task_defaults: 任务类型到模型的默认映射

视频创作流程

  1. 脚本生成 (Step 1) - AI 生成视频脚本和分镜,或用户直接粘贴文案
  2. 视频粗剪 (Step 2) - 导入长视频,按脚本时长自动切割为片段
  3. 语音配音 (Step 3) - 声音克隆 + TTS 生成每段配音
  4. 字幕压制 (Step 4) - 生成字幕并压制到视频中
  5. 封面制作 (Step 5) - 生成视频封面
  6. 视频合成 (Step 6) - FFmpeg 拼接视频片段,替换原声为 TTS 音频,导出最终视频

常见问题

Q: 火山方舟如何配置?

  1. 注册火山引擎账号并实名认证
  2. 创建 API Key
  3. 开通模型并创建推理接入点
  4. .env 中设置 VOLCENGINE_API_KEY

Q: 可灵 AI 如何配置?

  1. 前往可灵 AI 开发者平台 https://klingai.com/document-api
  2. 获取 Access Key 和 Secret Key
  3. .env 中设置 KLINGAI_ACCESS_KEYKLINGAI_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: 如何新增/修改提示词?

  1. 创建文件: app/ai/prompts/my_prompt.txt
  2. 加载使用: prompt = self._load_prompt("my_prompt")
  3. 禁止: 在 Python 代码中直接写 """你是一位..."""

Q: 项目数据是如何持久化的?

  • 项目元数据(meta.json)和分镜数据(segments.json)保存在 ~/Documents/Meijiaka/projects/{project_id}/
  • 不通过 Zustand persist 保存项目数据,而是通过 localProjectApi 显式调用 Tauri IPC 写入文件
  • projectStorepersist 中间件仅保存少量 UI 状态

Q: Async Engine 和 Celery 有什么区别?

本项目使用自定义 Async Engine 替代 Celery

  • 基于 Redis 的槽位管理(SlotManager),限制各类型任务的并发数
  • 独立的 scheduler 进程(python -m app.scheduler.main
  • 每个 Handler 实现 AsyncHandler 接口,状态机驱动任务生命周期
  • 优势:更细粒度的并发控制、统一状态机、无 Celery 依赖

Q: 为什么后端某些 API 模块不存在?

当前项目处于从「美家卡智影」向「美家卡智剪」的重构过程中。app/api/v1/router.py 当前仅注册了 4 个模块(auth, system, caption, voice),历史上存在的 script, video, klingai, qiniu, ai_models, tasks 等路由当前未激活。如需使用相关功能,需在路由中重新引入。


最后更新: 2026-04-21 架构模式: 单机版(轻量云账号 + 全本地业务数据) 项目状态: 从 ai-meijiaka Fork 后的活跃重构中