# AI 英语学习辅助平台 — 线上部署操作流程

## 项目概述

- **项目名称**：AI 英语学习辅助平台
- **技术栈**：
  - 前端：Vue 3 + Vite + Vue Router（History 模式）
  - 后端：Express.js + FFmpeg（视频合成服务）
- **项目结构**：
  - 前端：纯静态文件（HTML / CSS / JS），可部署到任意静态托管服务
  - 后端：Node.js 服务，需要 FFmpeg 环境，提供视频合成 API

---

## 一、部署前准备

### 1.1 环境要求

| 工具 | 版本要求 | 用途 |
|------|----------|------|
| Node.js | >= 18.x（推荐 20.x LTS） | 前端构建 & 后端服务运行 |
| npm | >= 9.x | 包管理器 |
| FFmpeg | 最新稳定版 | 后端视频合成（仅后端服务需要） |

```bash
# 检查 Node.js 和 npm 版本
node -v
npm -v

# 检查 FFmpeg 是否已安装（后端服务需要）
ffmpeg -version
```

### 1.2 安装 FFmpeg（后端服务必需）

#### Windows

1. 下载 FFmpeg: https://www.gyan.dev/ffmpeg/builds/
2. 解压到 `C:\ffmpeg`
3. 添加 `C:\ffmpeg\bin` 到系统环境变量 PATH
4. 验证安装：
   ```bash
   ffmpeg -version
   ```

#### macOS

```bash
# 使用 Homebrew 安装
brew install ffmpeg

# 验证安装
ffmpeg -version
```

#### Linux (Ubuntu/Debian)

```bash
# 安装 FFmpeg
sudo apt update && sudo apt install ffmpeg

# 验证安装
ffmpeg -version
```

### 1.3 安装依赖

```bash
# 安装前端依赖
cd AI_Demo
npm install

# 安装后端依赖
cd server
npm install
```

---

## 二、关键配置说明

### 2.1 API 配置（必须在部署前确认）

项目所有 API 密钥集中在 `src/config/index.js`，部署前请确认以下配置项均已填写正确：

| 配置项 | 说明 |
|--------|------|
| `GRS_API_KEY` | GRS AI 接口密钥（作文批改） |
| `DOUBAO_KEY` | 豆包 API 密钥 |
| `DOUBAO_APP_ID` | 豆包语音 App ID |
| `DOUBAO_ACCESS_TOKEN` | 豆包语音访问令牌 |
| `DOUBAO_RESOURCE_ID` | 豆包 TTS 资源 ID |
| `DOUBAO_ASR_RESOURCE_ID` | 豆包 ASR 资源 ID |
| `ARK_API_KEY` | 火山引擎 Ark 大模型密钥（口语对话） |
| `ARK_MODEL` | Ark 模型名称（如 doubao-pro-4k） |

### 2.2 跨域响应头要求（重要）

项目使用了 `@ffmpeg/ffmpeg`（WebAssembly），需要服务器返回以下响应头，否则视频讲解功能将无法运行：

```
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corp
```

> 各部署平台的配置方式见下方对应章节。

### 2.3 API 代理配置（重要）

项目在开发环境通过 Vite 代理转发以下 API 请求，**生产环境必须在服务器/网关层配置对应的反向代理**：

| 前端请求路径前缀 | 代理目标 | 用途 | 备注 |
|-----------------|----------|------|------|
| `/api/video` | 后端服务（默认 http://localhost:3001） | 视频合成 | **无需跨域代理**，直接访问后端服务 |
| `/tts-api` | `https://openspeech.bytedance.com` | 豆包 TTS 语音合成 | 需要反向代理 |
| `/ark-api` | `https://ark.cn-beijing.volces.com` | 火山引擎 Ark 大模型 | 需要反向代理 |
| `/dashscope-api` | `https://dashscope.aliyuncs.com` | 阿里云百炼 | 需要反向代理 |
| `/asr-ws` | `wss://openspeech.bytedance.com` | 豆包 ASR WebSocket | 需要反向代理+注入鉴权 Header |

> **后端服务说明**：`/api/video` 接口由本项目的后端服务（`server/`）提供，不需要跨域代理，但需要确保后端服务正常运行。

> **ASR WebSocket 特殊说明**：`/asr-ws` 代理需要在代理层注入以下鉴权 Header（浏览器原生 WebSocket 不支持自定义 Header）：
> - `X-Api-App-Key`
> - `X-Api-Access-Key`
> - `X-Api-Resource-Id`
> - `X-Api-Connect-Id`（每次连接随机 UUID）

---

## 三、构建生产包

### 3.1 前端构建

```bash
npm run build
```

构建完成后，产物位于 `dist/` 目录，包含：

```
dist/
├── index.html
├── favicon.svg
└── assets/
    ├── *.js
    └── *.css
```

可在本地预览构建结果：

```bash
npm run preview
```

### 3.2 后端服务准备

后端服务无需构建，直接使用源码运行即可。确保：

1. 已安装 FFmpeg（见 1.2 节）
2. 已安装依赖：
   ```bash
   cd server
   npm install
   ```
3. 测试服务是否正常：
   ```bash
   npm start
   ```
   访问 http://localhost:3001/health 应返回 `{"status":"ok"}`

---

## 四、部署方案

### 方案 A：Nginx 部署（推荐，自有服务器）

#### 4.A.1 上传文件

将 `dist/` 目录内容上传到服务器，例如 `/var/www/ai-demo/`：

```bash
scp -r dist/* user@your-server:/var/www/ai-demo/
```

#### 4.A.2 Nginx 配置

创建或修改 Nginx 站点配置文件（如 `/etc/nginx/sites-available/ai-demo.conf`）：

```nginx
server {
    listen 80;
    server_name your-domain.com;  # 替换为你的域名或 IP

    root /var/www/ai-demo;
    index index.html;

    # 跨域响应头（FFmpeg WASM 必需）
    add_header Cross-Origin-Opener-Policy "same-origin" always;
    add_header Cross-Origin-Embedder-Policy "require-corp" always;

    # Vue Router History 模式：所有路由回退到 index.html
    location / {
        try_files $uri $uri/ /index.html;
    }

    # 后端视频合成服务代理
    location /api/video/ {
        proxy_pass http://localhost:3001/api/video/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        
        # 增大请求体大小限制（视频合成可能需要）
        client_max_body_size 100m;
        
        # 增加超时时间（视频合成耗时较长）
        proxy_connect_timeout 300;
        proxy_send_timeout 300;
        proxy_read_timeout 300;
    }

    # 代理：豆包 TTS
    location /tts-api/ {
        proxy_pass https://openspeech.bytedance.com/;
        proxy_ssl_server_name on;
        proxy_set_header Host openspeech.bytedance.com;
    }

    # 代理：火山引擎 Ark
    location /ark-api/ {
        proxy_pass https://ark.cn-beijing.volces.com/;
        proxy_ssl_server_name on;
        proxy_set_header Host ark.cn-beijing.volces.com;
    }

    # 代理：阿里云百炼
    location /dashscope-api/ {
        proxy_pass https://dashscope.aliyuncs.com/;
        proxy_ssl_server_name on;
        proxy_set_header Host dashscope.aliyuncs.com;
    }

    # 代理：豆包 ASR WebSocket（需注入鉴权 Header）
    location /asr-ws/ {
        proxy_pass https://openspeech.bytedance.com/;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_set_header Host openspeech.bytedance.com;
        proxy_ssl_server_name on;
        # 注入豆包 ASR 鉴权 Header（替换为实际值）
        proxy_set_header X-Api-App-Key "YOUR_DOUBAO_APP_ID";
        proxy_set_header X-Api-Access-Key "YOUR_DOUBAO_ACCESS_TOKEN";
        proxy_set_header X-Api-Resource-Id "volc.bigasr.sauc.duration";
    }

    # 静态资源缓存
    location /assets/ {
        expires 1y;
        add_header Cache-Control "public, immutable";
        add_header Cross-Origin-Opener-Policy "same-origin" always;
        add_header Cross-Origin-Embedder-Policy "require-corp" always;
    }
}
```
```

#### 4.A.3 启用配置并重启 Nginx

```bash
# 启用站点（Ubuntu/Debian）
ln -s /etc/nginx/sites-available/ai-demo.conf /etc/nginx/sites-enabled/

# 检查配置语法
nginx -t

# 重载 Nginx
systemctl reload nginx
```

#### 4.A.4 启动后端服务

后端服务需要使用进程管理器（如 PM2）保持持续运行：

```bash
# 安装 PM2（如果未安装）
npm install -g pm2

# 进入后端目录
cd /path/to/AI_Demo/server

# 启动后端服务
pm2 start index.js --name ai-demo-server

# 查看服务状态
pm2 status

# 查看日志
pm2 logs ai-demo-server

# 设置开机自启
pm2 startup
pm2 save
```

后端服务将在 `http://localhost:3001` 启动，Nginx 会将 `/api/video` 请求代理到该端口。

#### 4.A.5 配置 HTTPS（推荐）

```bash
# 使用 Certbot 申请免费 SSL 证书
apt install certbot python3-certbot-nginx
certbot --nginx -d your-domain.com
```

---

### 方案 B：Node.js + Express 部署（前后端分离）

适用于需要在 Node.js 环境中自定义响应头的场景，前后端独立部署。

#### 4.B.1 后端服务部署

后端服务已在 `server/` 目录中，需要独立运行：

```bash
# 进入后端目录
cd server

# 安装依赖
npm install

# 使用 PM2 启动服务
pm2 start index.js --name ai-demo-backend

# 设置开机自启
pm2 startup
pm2 save
```

后端服务将在 `http://localhost:3001` 启动。

#### 4.B.2 前端静态服务器

创建前端静态服务器文件 `frontend-server.js`（项目根目录）：

```js
import express from 'express'
import { createProxyMiddleware } from 'http-proxy-middleware'
import { fileURLToPath } from 'url'
import path from 'path'
import crypto from 'crypto'

const __dirname = path.dirname(fileURLToPath(import.meta.url))
const app = express()
const PORT = process.env.PORT || 3000

// 全局注入 COOP/COEP 响应头（FFmpeg WASM 必需）
app.use((req, res, next) => {
  res.setHeader('Cross-Origin-Opener-Policy', 'same-origin')
  res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp')
  next()
})

// 后端视频合成服务代理
app.use('/api/video', createProxyMiddleware({
  target: 'http://localhost:3001',
  changeOrigin: true,
  timeout: 300000, // 5分钟超时
}))

// 第三方 API 代理
app.use('/tts-api', createProxyMiddleware({
  target: 'https://openspeech.bytedance.com',
  changeOrigin: true,
  pathRewrite: { '^/tts-api': '' }
}))

app.use('/ark-api', createProxyMiddleware({
  target: 'https://ark.cn-beijing.volces.com',
  changeOrigin: true,
  pathRewrite: { '^/ark-api': '' }
}))

app.use('/dashscope-api', createProxyMiddleware({
  target: 'https://dashscope.aliyuncs.com',
  changeOrigin: true,
  pathRewrite: { '^/dashscope-api': '' }
}))

app.use('/asr-ws', createProxyMiddleware({
  target: 'wss://openspeech.bytedance.com',
  changeOrigin: true,
  ws: true,
  pathRewrite: { '^/asr-ws': '' },
  on: {
    proxyReqWs: (proxyReq) => {
      proxyReq.setHeader('X-Api-App-Key', process.env.DOUBAO_APP_ID)
      proxyReq.setHeader('X-Api-Access-Key', process.env.DOUBAO_ACCESS_TOKEN)
      proxyReq.setHeader('X-Api-Resource-Id', 'volc.bigasr.sauc.duration')
      proxyReq.setHeader('X-Api-Connect-Id', crypto.randomUUID())
    }
  }
}))

// 静态文件服务
app.use(express.static(path.join(__dirname, 'dist')))

// Vue Router History 模式回退
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'dist', 'index.html'))
})

app.listen(PORT, () => {
  console.log(`Frontend server running at http://localhost:${PORT}`)
  console.log(`Backend API: http://localhost:3001`)
})
```

#### 4.B.3 安装前端服务器依赖

```bash
# 在项目根目录安装
npm install express http-proxy-middleware
```

#### 4.B.4 启动前端服务器

```bash
# 在项目根目录启动
DOUBAO_APP_ID=xxx DOUBAO_ACCESS_TOKEN=xxx pm2 start frontend-server.js --name ai-demo-frontend

# 查看两个服务的状态
pm2 status

# 设置开机自启
pm2 save
```

现在有两个服务运行：
- **前端服务**：`http://localhost:3000`（提供静态文件和代理）
- **后端服务**：`http://localhost:3001`（视频合成 API）

---

### 方案 C：EdgeOne Pages / Vercel / Netlify（纯静态托管）

> **注意**：此类平台**不支持服务端代理**，`/tts-api`、`/ark-api`、`/dashscope-api`、`/asr-ws` 等接口将因跨域或缺少鉴权 Header 而失败。
> 建议仅用于演示或配合独立后端服务使用。

#### 部署步骤（以 Vercel 为例）

1. 将项目推送到 GitHub
2. 在 Vercel 控制台导入仓库
3. 构建命令：`npm run build`，输出目录：`dist`
4. 创建 `vercel.json` 配置 History 模式路由回退和响应头：

```json
{
  "rewrites": [{ "source": "/(.*)", "destination": "/index.html" }],
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        { "key": "Cross-Origin-Opener-Policy", "value": "same-origin" },
        { "key": "Cross-Origin-Embedder-Policy", "value": "require-corp" }
      ]
    }
  ]
}
```

---

## 五、部署后验证清单

### 5.1 后端服务验证

| 验证项 | 检查方法 | 预期结果 |
|--------|----------|----------|
| 后端服务运行 | `pm2 status` 或 `ps aux \| grep node` | 显示 ai-demo-server 进程 |
| 健康检查接口 | `curl http://localhost:3001/health` | 返回 `{"status":"ok"}` |
| FFmpeg 可用 | `curl http://localhost:3001/api/video/health` | 返回 `{"status":"ok","message":"视频合成服务正常运行"}` |
| 后端日志无错误 | `pm2 logs ai-demo-server` | 无报错信息 |

### 5.2 前端服务验证

| 验证项 | 检查方法 |
|--------|----------|
| 页面正常加载 | 访问首页，确认功能卡片显示正常 |
| 路由刷新不 404 | 直接访问 `/pronunciation`、`/speaking` 等子路由 |
| COOP/COEP 响应头 | 浏览器 DevTools → Network → 查看 index.html 响应头 |
| TTS 语音合成 | 进入发音练习页，测试语音播放 |
| ASR 语音识别 | 进入口语对话页，测试麦克风录音识别 |
| 作文批改 | 进入作文批改页，提交一段英文作文 |
| 试题分析 | 进入试题分析页，上传图片或输入题目 |
| 单词拼写练习 | 进入单词拼写页，测试拼写检测功能 |

### 5.3 视频合成功能验证

| 验证项 | 检查方法 |
|--------|----------|
| 前端可访问后端 | 浏览器 Network 标签查看 `/api/video/health` 请求 |
| 视频合成接口 | 在试题分析页生成视频讲解，检查是否能正常下载 |

---

## 六、常见问题排查

### Q1：视频讲解页面报错 `SharedArrayBuffer is not defined`

**原因**：服务器未返回 `Cross-Origin-Opener-Policy: same-origin` 和 `Cross-Origin-Embedder-Policy: require-corp` 响应头。
**解决**：参考第二节 2.2，在 Nginx 或 Node.js 服务器中添加对应响应头。

### Q2：刷新页面出现 404

**原因**：Vue Router 使用 History 模式，服务器未配置路由回退。
**解决**：Nginx 添加 `try_files $uri $uri/ /index.html;`，Node.js 添加通配路由返回 `index.html`。

### Q3：API 请求跨域报错（CORS）

**原因**：生产环境未配置反向代理，浏览器直接请求第三方 API 被跨域拦截。
**解决**：参考第二节 2.3，在 Nginx 或 Node.js 中配置对应代理规则。

### Q4：ASR 语音识别 WebSocket 连接失败

**原因**：代理未注入豆包 ASR 鉴权 Header，或 WebSocket 升级配置缺失。
**解决**：确认 Nginx 配置中包含 `proxy_set_header Upgrade $http_upgrade;` 及三个 `X-Api-*` Header。

### Q5：视频合成失败或接口 504 超时

**原因**：视频合成耗时较长，默认代理超时时间不足，或后端服务未启动。
**解决**：
1. 检查后端服务是否运行：`pm2 status` 或 `curl http://localhost:3001/health`
2. 检查 FFmpeg 是否安装：`ffmpeg -version`
3. 增加 Nginx 超时时间（已在配置中设置为 300 秒）
4. 查看后端日志：`pm2 logs ai-demo-server`

### Q6：后端服务启动失败：`FFmpeg not found`

**原因**：系统未安装 FFmpeg 或未添加到环境变量。
**解决**：参考第一节 1.2，安装 FFmpeg 并配置环境变量。

### Q7：视频合成返回 `Internal server error`

**原因**：可能是 FFmpeg 处理错误、临时目录权限问题或资源下载失败。
**解决**：
1. 查看后端详细日志：`pm2 logs ai-demo-server`
2. 检查 `server/temp/` 目录权限：`ls -la server/temp`
3. 测试后端健康检查：`curl http://localhost:3001/api/video/health`

### Q8：构建时内存不足

**原因**：项目包含 FFmpeg WASM，构建产物较大。
**解决**：

```bash
# 增大 Node.js 内存限制
NODE_OPTIONS=--max-old-space-size=4096 npm run build
```

---

## 七、页面路由清单

| 路由路径 | 页面名称 | 功能说明 |
|----------|----------|----------|
| `/` | 首页 | 功能导航卡片 |
| `/pronunciation` | 发音练习 | TTS 语音合成，音标学习 |
| `/speaking` | 口语对话 | ASR 语音识别，AI 对话 |
| `/essay-correction` | 作文批改 | 图片/文本作文批改 |
| `/exam-analysis` | 试题分析 | 图片题目分析解答 |
| `/spell-practice` | 单词拼写 | 单词拼写练习检测 |
| `/problem-solving` | 解题指导 | AI 解题步骤指导 |
| `/question-generator` | 题目生成 | 自动生成练习题 |
| `/question-variant` | 题目变体 | 生成相似题目变体 |
| `/audio-to-text` | 语音转文字 | 音频转文本功能 |
| `/question-explanation` | 视频讲解 | 视频合成讲解（使用后端服务）|

---

## 八、依赖版本参考

### 前端依赖（package.json）

| 依赖包 | 版本 |
|--------|------|
| vue | ^3.5.30 |
| vue-router | ^5.0.3 |
| vite | ^8.0.0 |
| @ffmpeg/ffmpeg | ^0.12.15 |
| @ffmpeg/util | ^0.12.2 |
| axios | ^1.13.6 |
| marked | ^17.0.5 |
| pako | ^2.1.0 |

### 后端依赖（server/package.json）

| 依赖包 | 版本 | 用途 |
|--------|------|------|
| express | ^4.21.0 | Web 服务器框架 |
| cors | ^2.8.5 | 跨域中间件 |
| fluent-ffmpeg | ^2.1.3 | FFmpeg Node.js 封装 |
| axios | ^1.7.0 | HTTP 客户端 |
| uuid | ^10.0.0 | UUID 生成 |

---

## 九、目录结构参考

```
AI_Demo/
├── dist/                    # 前端构建产物（部署此目录）
├── server/                  # 后端服务
│   ├── routes/              # 路由模块
│   │   └── video.js         # 视频合成 API
│   ├── temp/                # 临时文件目录（自动创建）
│   ├── index.js             # 后端服务入口
│   ├── package.json         # 后端依赖配置
│   └── README.md            # 后端服务文档
├── src/                     # 前端源码
│   ├── config/index.js      # API 密钥配置（部署前确认）
│   ├── router/index.js      # 路由定义
│   ├── views/               # 页面组件
│   │   ├── HomePage.vue     # 首页
│   │   ├── Pronunciation.vue # 发音练习
│   │   ├── Speaking.vue      # 口语对话
│   │   ├── EssayCorrection.vue # 作文批改
│   │   ├── ExamAnalysis.vue  # 试题分析
│   │   ├── SpellPractice.vue # 单词拼写
│   │   ├── ProblemSolving.vue # 解题指导
│   │   ├── QuestionGenerator.vue # 题目生成
│   │   ├── QuestionVariant.vue # 题目变体
│   │   ├── AudioToText.vue  # 语音转文字
│   │   └── QuestionExplanation.vue # 视频讲解
│   ├── components/          # 公共组件
│   ├── assets/              # 静态资源
│   └── MainLayout.vue       # 布局组件
├── vite.config.js           # 开发代理配置（生产环境需在服务器复现）
├── package.json             # 前端依赖配置
└── DEPLOY.md                # 本文档
```

---

## 十、后端服务详细说明

### 10.1 服务架构

后端服务基于 Express.js 构建，主要提供视频合成功能：

- **技术栈**：Express.js + Fluent-FFmpeg
- **默认端口**：3001
- **主要功能**：接收图片和音频 URL，合成 MP4 视频文件

### 10.2 API 接口

#### POST `/api/video/compose`

合成视频接口，将多组图片和音频合成为视频。

**请求体示例**：
```json
{
  "slides": [
    {
      "imageUrl": "https://example.com/image1.png",
      "audioUrl": "https://example.com/audio1.mp3"
    },
    {
      "imageUrl": "https://example.com/image2.png",
      "audioUrl": "https://example.com/audio2.mp3"
    }
  ],
  "width": 1920,
  "height": 1080
}
```

**参数说明**：
- `slides`（必需）：幻灯片数组，每个元素包含：
  - `imageUrl`：图片 URL（支持 HTTP/HTTPS URL 或 base64 data URI）
  - `audioUrl`：音频 URL（MP3 格式）
- `width`（可选）：视频宽度，默认 1920
- `height`（可选）：视频高度，默认 1080

**响应**：
- Content-Type: `video/mp4`
- 返回合成后的 MP4 视频文件

#### GET `/api/video/health`

健康检查接口，检查 FFmpeg 服务状态。

**响应示例**：
```json
{
  "status": "ok",
  "message": "视频合成服务正常运行",
  "formats": 300
}
```

#### GET `/health`

服务健康检查接口。

**响应示例**：
```json
{
  "status": "ok",
  "timestamp": "2024-01-01T12:00:00.000Z"
}
```

### 10.3 环境变量配置

后端服务支持以下环境变量：

| 环境变量 | 默认值 | 说明 |
|---------|--------|------|
| `PORT` | 3001 | 服务监听端口 |

使用示例：
```bash
PORT=3002 pm2 start index.js --name ai-demo-server
```

### 10.4 临时文件管理

- 后端服务在 `server/temp/` 目录下存储临时文件
- 每个视频合成任务会创建独立的子目录（使用 UUID 命名）
- 任务完成后，临时文件会自动清理
- 如遇异常中断，可手动清理 `temp/` 目录

### 10.5 性能与资源要求

**建议配置**：
- **CPU**：2 核以上（视频合成需要较多 CPU 资源）
- **内存**：2GB 以上
- **磁盘**：10GB 以上可用空间（临时文件存储）

**并发处理**：
- 单个视频合成任务处理时间：约 10-60 秒（取决于片段数量和时长）
- 建议使用队列机制处理高并发请求（当前版本为同步处理）

### 10.6 日志查看

使用 PM2 查看后端服务日志：
```bash
# 查看实时日志
pm2 logs ai-demo-server

# 查看最近 100 行日志
pm2 logs ai-demo-server --lines 100

# 清空日志
pm2 flush ai-demo-server
```

日志包含：
- 服务启动信息
- FFmpeg 命令执行日志
- 视频合成进度
- 错误信息

### 10.7 监控与告警

建议监控以下指标：
- 服务进程状态（PM2 监控）
- 端口 3001 响应状态（健康检查）
- 磁盘空间（`temp/` 目录）
- CPU 和内存使用率

---

## 十一、Docker 部署（可选）

### 11.1 后端服务 Dockerfile

已提供 Dockerfile 位于 `Dockerfiles/backend.Dockerfile`（如需创建）：

```dockerfile
FROM node:20-alpine

# 安装 FFmpeg
RUN apk add --no-cache ffmpeg

WORKDIR /app

# 复制依赖文件
COPY server/package*.json ./
RUN npm ci --only=production

# 复制源码
COPY server/ ./

# 创建临时目录
RUN mkdir -p temp

EXPOSE 3001

CMD ["node", "index.js"]
```

### 11.2 Docker Compose 部署

创建 `docker-compose.yml`：

```yaml
version: '3.8'

services:
  backend:
    build:
      context: .
      dockerfile: Dockerfiles/backend.Dockerfile
    ports:
      - "3001:3001"
    volumes:
      - ./server/temp:/app/temp
    restart: unless-stopped
    environment:
      - PORT=3001

  frontend:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./dist:/usr/share/nginx/html
      - ./nginx.conf:/etc/nginx/conf.d/default.conf
    depends_on:
      - backend
    restart: unless-stopped
```

启动：
```bash
docker-compose up -d
```

---

## 十二、安全建议

1. **HTTPS 强制**：生产环境务必启用 HTTPS
2. **API 密钥保护**：不要将 API 密钥提交到代码仓库
3. **文件上传限制**：限制视频合成的图片和音频大小
4. **频率限制**：对 `/api/video/compose` 接口添加速率限制
5. **临时文件清理**：定期检查并清理异常终止的临时文件
6. **日志审计**：记录所有视频合成请求的来源和处理结果

---

## 十三、更新与维护

### 更新前端

```bash
git pull
npm install
npm run build
# 重新部署 dist/ 目录
```

### 更新后端

```bash
cd server
git pull
npm install
pm2 restart ai-demo-server
```

### 查看服务状态

```bash
pm2 status
pm2 logs
```

---

**文档版本**：v2.0  
**更新日期**：2024-01-01  
**更新内容**：新增后端视频合成服务部署说明
