|
@@ -0,0 +1,376 @@
|
|
|
|
|
+# 批量生成分集功能说明
|
|
|
|
|
+
|
|
|
|
|
+## 功能概述
|
|
|
|
|
+
|
|
|
|
|
+该功能允许用户批量生成多个剧集,支持从当前集数自动往后生成指定数量的剧集。使用队列机制实现异步处理,提升用户体验。
|
|
|
|
|
+
|
|
|
|
|
+## 核心特性
|
|
|
|
|
+
|
|
|
|
|
+1. **队列异步处理**: 任务放入队列异步执行,前端无需长时间等待
|
|
|
|
|
+2. **进度跟踪**: 提供实时任务状态查询接口
|
|
|
|
|
+3. **完全复用逻辑**: 批量生成完全使用 `chatForAce` 方法的逻辑,包括资产库应用、提示词等
|
|
|
|
|
+4. **错误容错**: 单集失败不影响其他集的生成
|
|
|
|
|
+5. **防重复执行**: 同一剧集同时只能有一个批量任务执行
|
|
|
|
|
+
|
|
|
|
|
+## 技术架构
|
|
|
|
|
+
|
|
|
|
|
+### 1. 数据库表结构
|
|
|
|
|
+
|
|
|
|
|
+#### mp_batch_episode_generation_tasks (批量生成任务主表)
|
|
|
|
|
+- `id`: 主键
|
|
|
|
|
+- `anime_id`: 动漫ID
|
|
|
|
|
+- `uid`: 用户ID
|
|
|
|
|
+- `cpid`: 公司ID
|
|
|
|
|
+- `start_episode`: 起始集数
|
|
|
|
|
+- `end_episode`: 结束集数
|
|
|
|
|
+- `total_episodes`: 总集数
|
|
|
|
|
+- `current_episode`: 当前处理的集数
|
|
|
|
|
+- `completed_episodes`: 已完成集数
|
|
|
|
|
+- `status`: 任务状态 (pending/processing/completed/failed)
|
|
|
|
|
+- `request_data`: 请求数据JSON
|
|
|
|
|
+- `error_message`: 错误信息
|
|
|
|
|
+- `completed_at`: 完成时间
|
|
|
|
|
+- `created_at`: 创建时间
|
|
|
|
|
+- `updated_at`: 更新时间
|
|
|
|
|
+
|
|
|
|
|
+#### mp_batch_episode_generation_details (批量生成详情表)
|
|
|
|
|
+- `id`: 主键
|
|
|
|
|
+- `task_id`: 任务ID
|
|
|
|
|
+- `episode_number`: 集数
|
|
|
|
|
+- `status`: 状态 (processing/completed/failed)
|
|
|
|
|
+- `result_data`: 结果数据JSON
|
|
|
|
|
+- `error_message`: 错误信息
|
|
|
|
|
+- `created_at`: 创建时间
|
|
|
|
|
+- `updated_at`: 更新时间
|
|
|
|
|
+
|
|
|
|
|
+### 2. 核心类文件
|
|
|
|
|
+
|
|
|
|
|
+#### ProcessBatchEpisodeGenerationJob (队列任务类)
|
|
|
|
|
+**位置**: `app/Jobs/ProcessBatchEpisodeGenerationJob.php`
|
|
|
|
|
+
|
|
|
|
|
+**职责**:
|
|
|
|
|
+- 处理批量生成任务
|
|
|
|
|
+- 逐集调用 `chatForAceNonStream` 方法
|
|
|
|
|
+- 更新任务进度
|
|
|
|
|
+- 记录每集的生成结果
|
|
|
|
|
+
|
|
|
|
|
+**关键参数**:
|
|
|
|
|
+- `$taskId`: 批量任务ID
|
|
|
|
|
+- `$animeId`: 动漫ID
|
|
|
|
|
+- `$startEpisodeNumber`: 起始集数
|
|
|
|
|
+- `$totalEpisodes`: 总共生成集数
|
|
|
|
|
+- `$requestData`: 请求数据
|
|
|
|
|
+- `$uid`: 用户ID
|
|
|
|
|
+- `$cpid`: 公司ID
|
|
|
|
|
+
|
|
|
|
|
+#### DeepSeekService 新增方法
|
|
|
|
|
+
|
|
|
|
|
+##### chatForAceNonStream
|
|
|
|
|
+**功能**: `chatForAce` 的非流式版本,用于队列任务调用
|
|
|
|
|
+
|
|
|
|
|
+**实现方式**:
|
|
|
|
|
+- 调用 `chatForAce` 流式方法
|
|
|
|
|
+- 收集所有数据块
|
|
|
|
|
+- 返回最终结果
|
|
|
|
|
+
|
|
|
|
|
+**返回值**: 与 `chatForAce` 的 `done` 类型数据一致
|
|
|
|
|
+
|
|
|
|
|
+##### batchGenerateEpisodes
|
|
|
|
|
+**功能**: 创建批量生成任务
|
|
|
|
|
+
|
|
|
|
|
+**参数**:
|
|
|
|
|
+- `anime_id`: 动漫ID (必填)
|
|
|
|
|
+- `generate_episode_number`: 要生成的集数 (必填)
|
|
|
|
|
+- `episode_number`: 起始集数 (可选,默认从当前最大集数+1开始)
|
|
|
|
|
+- 其他与 `chatForAce` 相同的参数
|
|
|
|
|
+
|
|
|
|
|
+**流程**:
|
|
|
|
|
+1. 验证参数
|
|
|
|
|
+2. 检查是否为多剧集模式
|
|
|
|
|
+3. 计算起始和结束集数
|
|
|
|
|
+4. 检查是否超过总集数限制
|
|
|
|
|
+5. 检查是否已有进行中的任务
|
|
|
|
|
+6. 创建任务记录
|
|
|
|
|
+7. 分发到队列
|
|
|
|
|
+
|
|
|
|
|
+**返回值**:
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "task_id": 1,
|
|
|
|
|
+ "anime_id": 123,
|
|
|
|
|
+ "start_episode": 2,
|
|
|
|
|
+ "end_episode": 6,
|
|
|
|
|
+ "total_episodes": 5,
|
|
|
|
|
+ "status": "processing",
|
|
|
|
|
+ "message": "已创建批量生成任务,将生成第2集到第6集,共5集"
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+##### getBatchGenerationTaskStatus
|
|
|
|
|
+**功能**: 查询批量生成任务状态
|
|
|
|
|
+
|
|
|
|
|
+**参数**:
|
|
|
|
|
+- `task_id`: 任务ID (与 `anime_id` 二选一)
|
|
|
|
|
+- `anime_id`: 动漫ID (与 `task_id` 二选一,返回最新任务)
|
|
|
|
|
+
|
|
|
|
|
+**返回值**:
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "task_id": 1,
|
|
|
|
|
+ "anime_id": 123,
|
|
|
|
|
+ "start_episode": 2,
|
|
|
|
|
+ "end_episode": 6,
|
|
|
|
|
+ "total_episodes": 5,
|
|
|
|
|
+ "current_episode": 3,
|
|
|
|
|
+ "completed_episodes": 2,
|
|
|
|
|
+ "progress": 40.00,
|
|
|
|
|
+ "status": "processing",
|
|
|
|
|
+ "error_message": null,
|
|
|
|
|
+ "details": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "episode_number": 2,
|
|
|
|
|
+ "status": "completed",
|
|
|
|
|
+ "error_message": null,
|
|
|
|
|
+ "created_at": "2026-01-29 10:00:00",
|
|
|
|
|
+ "updated_at": "2026-01-29 10:05:00"
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ "episode_number": 3,
|
|
|
|
|
+ "status": "processing",
|
|
|
|
|
+ "error_message": null,
|
|
|
|
|
+ "created_at": "2026-01-29 10:05:00",
|
|
|
|
|
+ "updated_at": "2026-01-29 10:05:00"
|
|
|
|
|
+ }
|
|
|
|
|
+ ],
|
|
|
|
|
+ "created_at": "2026-01-29 10:00:00",
|
|
|
|
|
+ "updated_at": "2026-01-29 10:05:00",
|
|
|
|
|
+ "completed_at": null
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 3. API 接口
|
|
|
|
|
+
|
|
|
|
|
+#### 创建批量生成任务
|
|
|
|
|
+**接口**: `POST /api/anime/batchGenerateEpisodes`
|
|
|
|
|
+
|
|
|
|
|
+**请求参数**:
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "anime_id": 123,
|
|
|
|
|
+ "generate_episode_number": 5,
|
|
|
|
|
+ "episode_number": 2, // 可选,指定起始集数
|
|
|
|
|
+ "file": null,
|
|
|
|
|
+ "content": "",
|
|
|
|
|
+ "bid": 0,
|
|
|
|
|
+ "script_id": 0,
|
|
|
|
|
+ "prompt": "确认分镜大纲",
|
|
|
|
|
+ "products": [],
|
|
|
|
|
+ "art_style": "",
|
|
|
|
|
+ "model": ""
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应示例**:
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "code": 0,
|
|
|
|
|
+ "msg": "success",
|
|
|
|
|
+ "data": {
|
|
|
|
|
+ "task_id": 1,
|
|
|
|
|
+ "anime_id": 123,
|
|
|
|
|
+ "start_episode": 2,
|
|
|
|
|
+ "end_episode": 6,
|
|
|
|
|
+ "total_episodes": 5,
|
|
|
|
|
+ "status": "processing",
|
|
|
|
|
+ "message": "已创建批量生成任务,将生成第2集到第6集,共5集"
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+#### 查询任务状态
|
|
|
|
|
+**接口**: `GET /api/anime/getBatchGenerationTaskStatus`
|
|
|
|
|
+
|
|
|
|
|
+**请求参数**:
|
|
|
|
|
+```
|
|
|
|
|
+task_id=1
|
|
|
|
|
+或
|
|
|
|
|
+anime_id=123
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+**响应示例**: (见上方 getBatchGenerationTaskStatus 返回值)
|
|
|
|
|
+
|
|
|
|
|
+## 使用流程
|
|
|
|
|
+
|
|
|
|
|
+### 前端调用流程
|
|
|
|
|
+
|
|
|
|
|
+1. **发起批量生成请求**
|
|
|
|
|
+```javascript
|
|
|
|
|
+// 用户输入要生成5集,当前是第2集
|
|
|
|
|
+const response = await fetch('/api/anime/batchGenerateEpisodes', {
|
|
|
|
|
+ method: 'POST',
|
|
|
|
|
+ headers: {
|
|
|
|
|
+ 'Content-Type': 'application/json',
|
|
|
|
|
+ 'Authorization': 'Bearer <token>'
|
|
|
|
|
+ },
|
|
|
|
|
+ body: JSON.stringify({
|
|
|
|
|
+ anime_id: 123,
|
|
|
|
|
+ generate_episode_number: 5,
|
|
|
|
|
+ // 其他参数与 chatForAce 一致
|
|
|
|
|
+ })
|
|
|
|
|
+});
|
|
|
|
|
+
|
|
|
|
|
+const result = await response.json();
|
|
|
|
|
+const taskId = result.data.task_id;
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+2. **轮询查询任务状态**
|
|
|
|
|
+```javascript
|
|
|
|
|
+const checkStatus = async () => {
|
|
|
|
|
+ const response = await fetch(`/api/anime/getBatchGenerationTaskStatus?task_id=${taskId}`);
|
|
|
|
|
+ const result = await response.json();
|
|
|
|
|
+
|
|
|
|
|
+ // 更新UI显示进度
|
|
|
|
|
+ updateProgressBar(result.data.progress);
|
|
|
|
|
+ updateEpisodeList(result.data.details);
|
|
|
|
|
+
|
|
|
|
|
+ // 如果任务未完成,继续轮询
|
|
|
|
|
+ if (result.data.status === 'processing') {
|
|
|
|
|
+ setTimeout(checkStatus, 3000); // 每3秒查询一次
|
|
|
|
|
+ } else if (result.data.status === 'completed') {
|
|
|
|
|
+ showSuccessMessage('批量生成完成!');
|
|
|
|
|
+ } else if (result.data.status === 'failed') {
|
|
|
|
|
+ showErrorMessage(result.data.error_message);
|
|
|
|
|
+ }
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 开始轮询
|
|
|
|
|
+checkStatus();
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+3. **防止重复操作**
|
|
|
|
|
+```javascript
|
|
|
|
|
+// 在发起新任务前,先检查是否有进行中的任务
|
|
|
|
|
+const checkExistingTask = async () => {
|
|
|
|
|
+ const response = await fetch(`/api/anime/getBatchGenerationTaskStatus?anime_id=${animeId}`);
|
|
|
|
|
+ const result = await response.json();
|
|
|
|
|
+
|
|
|
|
|
+ if (result.data && ['pending', 'processing'].includes(result.data.status)) {
|
|
|
|
|
+ alert('已有批量生成任务正在进行中,请等待完成后再试');
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+ return true;
|
|
|
|
|
+};
|
|
|
|
|
+
|
|
|
|
|
+// 创建任务前先检查
|
|
|
|
|
+if (await checkExistingTask()) {
|
|
|
|
|
+ // 创建新任务
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+### 前端 UI 建议
|
|
|
|
|
+
|
|
|
|
|
+1. **任务状态显示**
|
|
|
|
|
+ - 显示整体进度条
|
|
|
|
|
+ - 显示当前正在生成的集数
|
|
|
|
|
+ - 显示已完成集数/总集数
|
|
|
|
|
+
|
|
|
|
|
+2. **详细列表**
|
|
|
|
|
+ - 显示每集的状态(等待中/处理中/已完成/失败)
|
|
|
|
|
+ - 失败的集显示错误原因
|
|
|
|
|
+ - 已完成的集提供预览入口
|
|
|
|
|
+
|
|
|
|
|
+3. **操作按钮**
|
|
|
|
|
+ - 禁用"开始生成"按钮当有任务进行中
|
|
|
|
|
+ - 提供"查看任务详情"按钮
|
|
|
|
|
+ - 提供"取消任务"按钮(未来扩展)
|
|
|
|
|
+
|
|
|
|
|
+## 迁移数据库
|
|
|
|
|
+
|
|
|
|
|
+运行以下命令创建所需数据表:
|
|
|
|
|
+
|
|
|
|
|
+```bash
|
|
|
|
|
+php artisan migrate
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+如果需要手动创建,执行:
|
|
|
|
|
+
|
|
|
|
|
+```sql
|
|
|
|
|
+-- 见 database/migrations/2026_01_29_000001_create_batch_episode_generation_tables.php
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+## 队列配置
|
|
|
|
|
+
|
|
|
|
|
+确保 Laravel 队列已正确配置并运行:
|
|
|
|
|
+
|
|
|
|
|
+1. 配置队列驱动 (`.env`):
|
|
|
|
|
+```
|
|
|
|
|
+QUEUE_CONNECTION=database
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+2. 运行队列监听:
|
|
|
|
|
+```bash
|
|
|
|
|
+php artisan queue:work
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+或使用 Supervisor 进行持久化监听。
|
|
|
|
|
+
|
|
|
|
|
+## 注意事项
|
|
|
|
|
+
|
|
|
|
|
+1. **性能考虑**
|
|
|
|
|
+ - 批量生成会占用较多AI接口资源
|
|
|
|
|
+ - 建议限制单次生成的集数上限(如最多10集)
|
|
|
|
|
+ - 合理设置队列worker数量
|
|
|
|
|
+
|
|
|
|
|
+2. **错误处理**
|
|
|
|
|
+ - 单集失败不会中断整个任务
|
|
|
|
|
+ - 所有错误信息都会记录到详情表
|
|
|
|
|
+ - 建议提供"重试失败集数"功能(未来扩展)
|
|
|
|
|
+
|
|
|
|
|
+3. **用户体验**
|
|
|
|
|
+ - 前端应该定期轮询任务状态(建议3-5秒)
|
|
|
|
|
+ - 任务完成后应通知用户(可使用浏览器通知API)
|
|
|
|
|
+ - 提供任务历史记录查询
|
|
|
|
|
+
|
|
|
|
|
+4. **资源管理**
|
|
|
|
|
+ - 定期清理已完成的旧任务记录
|
|
|
|
|
+ - 监控队列任务堆积情况
|
|
|
|
|
+ - 合理设置任务超时时间
|
|
|
|
|
+
|
|
|
|
|
+## 未来扩展
|
|
|
|
|
+
|
|
|
|
|
+1. **取消任务**: 允许用户取消正在进行的批量生成
|
|
|
|
|
+2. **重试机制**: 自动或手动重试失败的集数
|
|
|
|
|
+3. **优先级队列**: 支持任务优先级设置
|
|
|
|
|
+4. **通知系统**: 任务完成后发送邮件或站内通知
|
|
|
|
|
+5. **并行生成**: 支持多集并行生成(需注意资源占用)
|
|
|
|
|
+
|
|
|
|
|
+## 测试建议
|
|
|
|
|
+
|
|
|
|
|
+1. **单元测试**
|
|
|
|
|
+ - 测试 `chatForAceNonStream` 方法
|
|
|
|
|
+ - 测试 `batchGenerateEpisodes` 参数验证
|
|
|
|
|
+ - 测试任务状态查询
|
|
|
|
|
+
|
|
|
|
|
+2. **集成测试**
|
|
|
|
|
+ - 测试完整的批量生成流程
|
|
|
|
|
+ - 测试错误处理机制
|
|
|
|
|
+ - 测试并发任务冲突
|
|
|
|
|
+
|
|
|
|
|
+3. **性能测试**
|
|
|
|
|
+ - 测试大批量生成(如20集)
|
|
|
|
|
+ - 测试多用户同时批量生成
|
|
|
|
|
+ - 监控内存和CPU使用
|
|
|
|
|
+
|
|
|
|
|
+## 常见问题
|
|
|
|
|
+
|
|
|
|
|
+### Q: 如何取消正在进行的批量任务?
|
|
|
|
|
+A: 当前版本不支持取消任务,可以通过停止队列worker来中断,但已提交的任务会在重启后继续执行。
|
|
|
|
|
+
|
|
|
|
|
+### Q: 任务失败后如何重试?
|
|
|
|
|
+A: 可以使用相同的参数重新创建批量任务,系统会自动从已完成的集数继续生成。
|
|
|
|
|
+
|
|
|
|
|
+### Q: 批量生成会影响手动生成吗?
|
|
|
|
|
+A: 不会。批量生成使用独立的队列任务,不影响用户手动操作。
|
|
|
|
|
+
|
|
|
|
|
+### Q: 如何查看队列任务执行日志?
|
|
|
|
|
+A: 查看 `storage/logs/laravel.log` 文件,搜索 `batch_episode_generation` 关键字。
|