409 lines
18 KiB
Markdown
409 lines
18 KiB
Markdown
# AGENTS.md — 美家卡智影
|
||
|
||
> 本文档面向 AI Coding Agent。项目主要使用中文进行注释和界面文案,文档亦以中文撰写。
|
||
|
||
---
|
||
|
||
## 项目概述
|
||
|
||
**美家卡智影**是一款面向桌面端的 AI 视频创作应用,采用"Python 后端 API + Tauri 桌面前端"的混合架构。
|
||
|
||
- **产品标识**: `cn.meijiaka.ai-video` / `cn.meijiaka.ai-zy`
|
||
- **版本**: `1.9.1`
|
||
- **核心功能**: AI 脚本生成、AI 配音合成(TTS)、声音复刻、视频生成(Vidu)、视频字幕生成、压制成片(FFmpeg)、项目本地持久化
|
||
|
||
### 技术栈总览
|
||
|
||
| 层级 | 技术 |
|
||
|------|------|
|
||
| 后端框架 | FastAPI (Python 3.13, 异步) |
|
||
| 数据库 | PostgreSQL 15+ + SQLAlchemy 2.0 (asyncpg) |
|
||
| 缓存/队列 | Redis 7.x |
|
||
| 异步调度 | 自研 Async Engine(Slot Scheduler) |
|
||
| 桌面壳 | Tauri v2 (Rust) |
|
||
| 前端框架 | React 19 + TypeScript |
|
||
| 前端构建 | Vite 7 |
|
||
| 状态管理 | Zustand 5 + Immer 11 |
|
||
| 路由 | `react-router-dom` |
|
||
| 数据请求 | HTTP 客户端 (`src/api/client.ts`) + SWR |
|
||
| 测试(后端) | pytest + pytest-asyncio |
|
||
| 测试(前端) | Vitest 4 + jsdom + `@testing-library/react` |
|
||
| 部署 | Docker + Docker Compose + Nginx |
|
||
|
||
---
|
||
|
||
## 仓库结构
|
||
|
||
本仓库为 Monorepo,包含两个主要子项目:
|
||
|
||
```
|
||
.
|
||
├── python-api/ # Python 后端 API
|
||
├── tauri-app/ # Tauri 桌面前端
|
||
├── docs/ # 项目文档(架构设计、API 对接指南等)
|
||
├── scripts/ # 辅助脚本
|
||
├── .github/workflows/ # GitHub Actions CI/CD 配置
|
||
└── AGENTS.md # 本文档
|
||
```
|
||
|
||
### python-api/ 目录结构
|
||
|
||
```
|
||
python-api/
|
||
├── app/ # 主应用代码
|
||
│ ├── api/v1/ # API 路由(按领域拆分:auth, script, voice, vidu, caption, tasks, upload, materials, system, bgm_music, cover_background, image, points, update, events)
|
||
│ ├── core/ # 核心工具(配置加载、安全、异常、Redis 客户端、健康检查)
|
||
│ ├── db/ # 数据库配置与会话管理
|
||
│ ├── models/ # SQLAlchemy ORM 模型(BaseModel 提供 UUID 主键 + 时间戳)
|
||
│ ├── schemas/ # Pydantic Schema(请求/响应校验)
|
||
│ ├── services/ # 业务逻辑层
|
||
│ ├── scheduler/ # Async Engine 异步任务调度(Slot Manager + Task Registry + Handlers)
|
||
│ ├── ai/ # AI 模型封装(providers: volcengine, vidu, generic_llm)
|
||
│ ├── crud/ # 数据库 CRUD 封装
|
||
│ ├── config.py # Pydantic Settings 配置管理
|
||
│ └── main.py # FastAPI 应用入口(含 lifespan 管理)
|
||
├── config/ # 运行时配置文件(platform-config.yaml, points-config.yaml)
|
||
├── alembic/ # 数据库迁移脚本
|
||
├── nginx/ # Nginx 反向代理配置(含 acme.sh SSL 证书脚本)
|
||
├── Dockerfile # 多阶段构建镜像(builder + production)
|
||
├── docker-compose.prod.yml # 生产环境编排
|
||
├── docker-compose.test.yml # 测试环境编排
|
||
├── pyproject.toml # Python 依赖与工具配置(black, ruff, mypy, pytest, bandit)
|
||
├── requirements.lock # 锁定依赖(uv pip compile 生成)
|
||
├── uv.lock # uv 锁定文件
|
||
├── Makefile # 常用开发命令
|
||
└── .pre-commit-config.yaml # Git 钩子配置
|
||
```
|
||
|
||
### tauri-app/ 目录结构
|
||
|
||
```
|
||
tauri-app/
|
||
├── src/ # React 前端源码
|
||
│ ├── api/ # API 客户端与模块
|
||
│ │ ├── client.ts # HTTP 客户端(camelCase ↔ snake_case 自动转换)
|
||
│ │ └── modules/ # 按领域拆分的 API 模块
|
||
│ ├── components/ # 可复用组件(PascalCase 文件夹)
|
||
│ ├── pages/ # 页面级组件(PascalCase 文件夹)
|
||
│ ├── store/ # Zustand 状态管理
|
||
│ ├── hooks/ # 自定义 React Hooks
|
||
│ ├── utils/ # 工具函数
|
||
│ ├── styles/ # CSS 变量与全局样式
|
||
│ └── __tests__/setup.ts # Vitest 全局 setup(mock localStorage / Tauri API)
|
||
├── src-tauri/ # Rust 后端源码
|
||
│ ├── src/
|
||
│ │ ├── main.rs # 程序入口
|
||
│ │ ├── lib.rs # Tauri Builder、Command 定义、公共类型
|
||
│ │ ├── ffmpeg_cmd.rs # FFmpeg 命令封装
|
||
│ │ ├── video_processing.rs # 压制成片业务逻辑
|
||
│ │ ├── storage/ # 本地存储引擎(项目、认证、配置、头像等)
|
||
│ │ ├── commands/ # Tauri IPC 命令(按领域拆分:asset, auth_state, cover_avatar, file, product, project, video_compose, voice 等)
|
||
│ │ └── utils.rs # 通用工具
|
||
│ ├── Cargo.toml # Rust 依赖
|
||
│ ├── tauri.conf.json # Tauri 应用配置(窗口、CSP、打包、sidecar)
|
||
│ └── binaries/ # FFmpeg / ffprobe sidecar 二进制
|
||
├── package.json # Node 依赖与脚本
|
||
├── vite.config.ts # Vite 配置(端口 1420)
|
||
├── vitest.config.ts # 测试配置
|
||
├── tsconfig.json # TypeScript 主配置(strict: true)
|
||
├── eslint.config.js # ESLint 配置
|
||
├── .prettierrc # Prettier 配置
|
||
└── .stylelintrc.json # Stylelint 配置
|
||
```
|
||
|
||
---
|
||
|
||
## 运行时架构
|
||
|
||
采用**混合通信架构**:
|
||
|
||
1. **纯数据 API**(脚本、TTS、字幕、视频生成、任务查询等)→ 前端通过 HTTP **直连 Python 后端**。
|
||
- 脚本/TTS/字幕/视频生成统一走异步任务调度(`POST /tasks/{task_type}` + 轮询 `/tasks/{task_id}`),由 Scheduler 独立进程消费。
|
||
2. **需要本地系统能力**(FFmpeg 压制成片、文件系统读写、项目本地持久化、认证状态存储)→ 走 **Tauri IPC → Rust 层** 处理。
|
||
|
||
> 新增纯数据 API 时,**无需修改 Rust 代码**,直接在 `tauri-app/src/api/modules/` 下使用 `client.post/get` 调用即可。只有涉及本地系统能力的 API 才需要在 Rust 层新增 `#[tauri::command]`。
|
||
|
||
### 服务拓扑(生产/测试环境)
|
||
|
||
```
|
||
┌─────────────┐ HTTP ┌─────────────────┐
|
||
│ Tauri │ ────────────▶ │ Nginx (SSL) │
|
||
│ 桌面端 │ │ 反向代理 │
|
||
└─────────────┘ └────────┬────────┘
|
||
│ │
|
||
│ IPC (Rust) │
|
||
▼ ▼
|
||
┌─────────────┐ ┌─────────────────┐
|
||
│ FFmpeg │ │ FastAPI (8000) │
|
||
│ Sidecar │ │ - API 路由 │
|
||
│ 本地文件系统 │ │ - 业务逻辑 │
|
||
└─────────────┘ └────────┬────────┘
|
||
│
|
||
┌─────────────┼─────────────┐
|
||
▼ ▼ ▼
|
||
┌────────┐ ┌─────────┐ ┌──────────┐
|
||
│PostgreSQL│ │ Redis │ │ AI 服务商 │
|
||
└────────┘ └─────────┘ └──────────┘
|
||
│
|
||
▼
|
||
┌───────────────┐
|
||
│ Async Engine │
|
||
│ Scheduler │
|
||
└───────────────┘
|
||
```
|
||
|
||
---
|
||
|
||
## 构建与开发命令
|
||
|
||
### 后端(python-api/)
|
||
|
||
```bash
|
||
cd python-api
|
||
|
||
# 安装开发依赖(使用 uv)
|
||
make dev
|
||
|
||
# 启动开发服务器
|
||
make run # uvicorn --reload --port 8000
|
||
|
||
# 启动异步调度器(另开终端)
|
||
make scheduler # python -m app.scheduler.main
|
||
|
||
# 代码质量
|
||
make lint # ruff check + mypy
|
||
make format # black + ruff --fix
|
||
make format-check # 检查格式(不修改)
|
||
make lint-semantic # 语义层禁词检查(防止供应商术语泄漏)
|
||
|
||
# 测试
|
||
make test # pytest -v
|
||
make test-cov # pytest + 覆盖率报告
|
||
|
||
# 安全扫描
|
||
make security # bandit + pip-audit
|
||
|
||
# CI 全量检查
|
||
make ci # format-check + lint + lint-semantic + test + security
|
||
|
||
# Docker 操作
|
||
make docker-run # 启动 api + scheduler(共享外部 db/redis)
|
||
make docker-rebuild # 强制重建
|
||
make docker-stop # 停止(保留 db/redis)
|
||
make docker-logs # 查看日志
|
||
|
||
# 数据库迁移
|
||
alembic revision --autogenerate -m "描述"
|
||
alembic upgrade head
|
||
```
|
||
|
||
### 前端(tauri-app/)
|
||
|
||
```bash
|
||
cd tauri-app
|
||
|
||
# 前端开发服务器(Vite,端口 1420)
|
||
npm run dev
|
||
|
||
# 生产构建(tsc + vite build)
|
||
npm run build
|
||
|
||
# Tauri 开发(启动 Rust + 前端)
|
||
npm run tauri dev
|
||
|
||
# Tauri 生产打包
|
||
npm run tauri build
|
||
|
||
# 测试
|
||
npm run test # Vitest
|
||
npm run test:ui # Vitest UI 模式
|
||
npm run test:coverage # 覆盖率
|
||
|
||
# 代码质量
|
||
npm run lint # ESLint
|
||
npm run lint:fix # ESLint --fix
|
||
npm run format # Prettier
|
||
npm run format:check # Prettier --check
|
||
npm run stylelint # Stylelint
|
||
npm run stylelint:fix # Stylelint --fix
|
||
|
||
# 注:当前项目未配置 OpenAPI 自动生成 TypeScript 类型的脚本
|
||
```
|
||
|
||
---
|
||
|
||
## 代码风格与约定
|
||
|
||
### 命名规范
|
||
|
||
| 类型 | 规范 | 示例 |
|
||
|------|------|------|
|
||
| 组件/页面文件夹 | PascalCase | `VideoCreation/`, `ErrorBoundary/` |
|
||
| Store/Hooks/API 文件 | camelCase | `authStore.ts`, `useProjectData.ts` |
|
||
| 类型/接口 | PascalCase | `ApiResponse<T>` |
|
||
| Python 模块/函数 | snake_case | `script_handler.py`, `get_settings()` |
|
||
| Python 类 | PascalCase | `AsyncEngine`, `BaseModel` |
|
||
| 常量 | UPPER_SNAKE_CASE | `PYTHON_API_BASE_URL` |
|
||
|
||
### 注释语言
|
||
|
||
- 项目内**统一使用中文注释**。
|
||
- 关键架构决策需在代码中以多行注释说明(参考 `python-api/app/scheduler/engine.py` 和 `tauri-app/src/api/client.ts` 顶部注释)。
|
||
|
||
### Python 代码质量
|
||
|
||
- **格式化**: black (line-length: 100)
|
||
- **检查**: ruff (select: E, F, I, N, W, UP, B, C4, SIM)
|
||
- **类型检查**: mypy(对 `app.schemas.*`, `app.crud.*`, `app.scheduler.handlers.*` 启用严格模式)
|
||
- **安全扫描**: bandit + pip-audit
|
||
- **依赖管理**: uv(`requirements.lock` 必须与实际依赖同步,pre-commit 会检查)
|
||
|
||
### TypeScript 配置
|
||
|
||
- `strict: true` 已开启。
|
||
- `noUnusedLocals: true`、`noUnusedParameters: true` 已开启。
|
||
- `jsx: "react-jsx"`,无需手动引入 `React`。
|
||
- 路径别名 `@/` 映射到 `./src`。
|
||
|
||
### 状态管理约定(前端)
|
||
|
||
- 使用 **Zustand + Immer** 进行不可变更新。
|
||
- `projectStore` 使用自定义 `persist` 存储,将项目数据通过 Tauri IPC 持久化到本地文件系统(`app_config_dir/current_project.json`),而不是 localStorage。
|
||
- 其他 Store(如 `authStore`、`settingsStore`)使用 `localStorage` 做持久化。
|
||
|
||
### API 开发流程
|
||
|
||
1. **判断是否需要本地能力**(FFmpeg、文件系统、系统调用)。
|
||
2. **不需要** → 直接在 `tauri-app/src/api/modules/` 使用 `client.get/post/put/delete` 调用 Python HTTP API。
|
||
3. **需要** → 在 `tauri-app/src/api/modules/` 中通过 `@tauri-apps/api/core` 的 `invoke` 调用 Rust 命令,并在 `tauri-app/src-tauri/src/commands/` 或 `lib.rs` 中实现对应的 `#[tauri::command]` 处理器。
|
||
|
||
### 语义层防护网(后端)
|
||
|
||
Makefile 中 `lint-semantic` 目标会检查以下规则:
|
||
- API 层禁止使用 `element_id` 作为字段/参数名(应使用 `provider_element_id`)。
|
||
- Scheduler 层统一使用 `task` 命名(`TaskRegistry`、`task_id`、`task:` Redis key 前缀),禁止混用 `job`。
|
||
|
||
---
|
||
|
||
## 测试说明
|
||
|
||
### 后端测试
|
||
|
||
- **框架**: pytest + pytest-asyncio(asyncio_mode: auto)
|
||
- **覆盖率**: pytest-cov
|
||
- **当前状态**: 后端尚无正式的 `tests/` 目录,测试用例待补充。
|
||
|
||
### 前端测试
|
||
|
||
- **框架**: Vitest(globals: true,environment: `jsdom`)
|
||
- **组件测试**: `@testing-library/react` + `@testing-library/jest-dom`
|
||
- **文件位置**:
|
||
- 全局 setup: `src/__tests__/setup.ts`
|
||
- 组件/页面测试: 建议放在被测文件同目录或 `__tests__` 子目录中
|
||
- **Mock 策略**: `setup.ts` 中已全局 mock `localStorage`、`@tauri-apps/api/core` 的 `invoke` 方法、`window.__TAURI_INTERNALS__`。每个测试后自动调用 `vi.clearAllMocks()`。
|
||
|
||
---
|
||
|
||
## 安全与部署
|
||
|
||
### 后端安全
|
||
|
||
- **JWT 认证**: `SECRET_KEY` 生产环境必须设置为强随机字符串(至少 32 位),否则应用启动时会抛出 `ValueError`。
|
||
- **CORS**: 生产环境若包含 `localhost` 会触发 `RuntimeWarning`。
|
||
- **依赖安全**: `aiohttp>=3.13.4` 和 `orjson>=3.11.0` 为强制最低版本(修复 CVE)。
|
||
- **输入验证**: 所有 API 入参通过 Pydantic Schema 校验。
|
||
- **数据库**: 使用参数化查询(SQLAlchemy ORM),无直接 SQL 拼接。
|
||
|
||
### 前端安全
|
||
|
||
- **CSP**: `tauri.conf.json` 中已配置 Content Security Policy。
|
||
- **Asset Protocol**: 已启用,范围限定在 `$APPLOCALDATA/**`、`$APPDATA/**`、`$APPCONFIG/**`。
|
||
|
||
### 部署流程
|
||
|
||
#### 测试环境(GitHub Actions)
|
||
|
||
`.github/workflows/` 存放 CI/CD 工作流:
|
||
- `release.yml`:Tauri 桌面端 Release 打包工作流(按 tag 触发,支持 macOS / Windows 平台及 sidecar 二进制下载)。
|
||
- 后端 api + scheduler 的测试/生产部署目前通过手动执行 `docker-compose.test.yml` / `docker-compose.prod.yml` 完成。
|
||
|
||
#### 生产环境
|
||
|
||
1. 从环境变量或密钥管理注入配置。
|
||
2. `docker compose -f docker-compose.prod.yml up -d --build`
|
||
3. 外部提供 PostgreSQL 和 Redis(云数据库或自建集群)。
|
||
4. Nginx 反向代理 + acme.sh SSL 证书。
|
||
|
||
### 外部二进制与 Sidecar
|
||
|
||
- **FFmpeg / ffprobe** 作为 **sidecar** 打包到 Tauri 应用(`bundle.externalBin`)。
|
||
- Rust 层通过 `tauri_plugin_shell` 的 `sidecar("ffmpeg")` 调用。
|
||
- 合成过程中解析 FFmpeg stderr 中的 `time=` 字段,通过 Tauri Event 向前端发送进度。
|
||
|
||
---
|
||
|
||
## 环境变量(后端)
|
||
|
||
关键配置项见 `python-api/.env.example`:
|
||
|
||
| 变量 | 说明 | 默认值 |
|
||
|------|------|--------|
|
||
| `DATABASE_URL` | PostgreSQL 连接字符串 | `postgresql+asyncpg://postgres:postgres@localhost:5432/meijiaka_zy` |
|
||
| `REDIS_HOST` / `REDIS_PORT` / `REDIS_DB` | Redis 连接信息 | `localhost:6379:0` |
|
||
| `SECRET_KEY` | JWT 签名密钥 | 必须修改 |
|
||
| `CORS_ORIGINS` | 允许的跨域来源 | `http://localhost:1420,...` |
|
||
| `VOLCENGINE_API_KEY` | 火山方舟 API Key | - |
|
||
| `VIDU_API_KEY` | Vidu API Key | - |
|
||
| `QINIU_ACCESS_KEY` / `QINIU_SECRET_KEY` | 七牛云存储密钥 | - |
|
||
| `APP_BASE_URL` | 应用公网地址(第三方回调用) | 按 ENV 自动推断 |
|
||
|
||
### 配置变更策略
|
||
|
||
> Python 的模块导入机制决定了**运行时热替换配置是反模式**,FastAPI/Pydantic 官方不推荐。测试与生产环境统一遵循以下策略:
|
||
|
||
| 场景 | 做法 | 说明 |
|
||
|------|------|------|
|
||
| 数值/业务规则配置 | **代码常量** | 如 SMS 验证码位数、过期时间等,不走 `.env`,防止运维随意修改 |
|
||
| 环境配置(密钥、URL 等) | **`.env` 文件** | 变更后统一走 Docker 滚动重启,**所有环境均不支持热重载** |
|
||
| 更新方式 | **`docker compose up -d --build`** | 测试/生产完全一致:`docker-compose.test.yml` 与 `docker-compose.prod.yml` 保持相同的重启策略 |
|
||
|
||
**注意**:`reload_settings()` 仅作为代码级工具保留(内部调试直接 import 调用),HTTP 接口已删除,测试与生产环境统一走 Docker 滚动重启更新配置。
|
||
|
||
---
|
||
|
||
## 数据库与迁移
|
||
|
||
- **ORM**: SQLAlchemy 2.0(异步,asyncpg 驱动)
|
||
- **迁移工具**: Alembic
|
||
- **基础模型**: `app.models.base.BaseModel` 提供 UUID 主键、`created_at`、`updated_at`
|
||
- **当前模型**: 包括 `User`(用户/设备认证)、`UserDevice`、`UserPoint`、`PointRechargeOrder`、`PointTransaction`、`BrollCategory`、`BrollMaterial`、`BrollTag`、`CoverBackground`、`BgmMusic`、`Update` 等
|
||
- **迁移注意**: Alembic 使用同步连接(psycopg2),会自动将 `+asyncpg` 替换掉。
|
||
|
||
---
|
||
|
||
## 异步任务调度(Async Engine)
|
||
|
||
后端采用自研的**统一异步任务调度引擎**,核心概念:
|
||
|
||
- **TaskRegistry**: 基于 Redis 的任务注册表,维护 running / pending / finished 状态。
|
||
- **SlotManager**: 基于 Redis 的并发槽位管理,按 task_type 限制最大并发数,统一使用 `acquire_ctx` 上下文管理器。
|
||
- **AsyncHandler**: 各领域的异步任务处理器(`script`/`tts`/`subtitle`/`video`)。
|
||
- **Engine Tick**: 定时轮询所有 running 任务,批量查询状态、批量更新。
|
||
|
||
调度器需单独启动:`make scheduler` 或 `python -m app.scheduler.main`。
|
||
|
||
---
|
||
|
||
## 给 Agent 的快速检查清单
|
||
|
||
在修改代码前,建议确认以下事项:
|
||
|
||
1. **新增 API 是否需要 Rust 层?** 不需要则只改前端 `src/api/modules/` 和后端 `app/api/v1/`。
|
||
2. **修改 Store 后是否影响持久化?** `projectStore` 的 `partialize` 字段决定哪些状态会被保存到本地文件。
|
||
3. **新增组件是否遵循 PascalCase 文件夹约定?**
|
||
4. **后端代码是否触发语义层禁词?** 运行 `make lint-semantic`。
|
||
5. **依赖变更后是否更新了 lock 文件?** 运行 `uv pip compile pyproject.toml -o requirements.lock`。
|
||
6. **测试是否通过?** 前端运行 `npm run test`,后端运行 `make test`。
|
||
7. **Tauri 配置变更后是否需要重新 `tauri dev`?** 是的,`tauri.conf.json` 或 `Cargo.toml` 变更后需重启 Tauri 进程。
|
||
8. **修改 pyproject.toml 后 pre-commit 是否通过?** `requirements.lock` 必须与 pyproject.toml 同步。
|