diff --git a/demo/STORYBOARD_VIDEO_CODE_REVIEW.md b/demo/STORYBOARD_VIDEO_CODE_REVIEW.md new file mode 100644 index 0000000..cccbdf0 --- /dev/null +++ b/demo/STORYBOARD_VIDEO_CODE_REVIEW.md @@ -0,0 +1,231 @@ +# 分镜视频功能代码逻辑检查报告 + +## 检查日期 +2025-10-29 + +## 总体评估 +✅ **代码逻辑基本正确**,已修复多个潜在问题。 + +--- + +## 已修复的问题 + +### 1. 前端轮询逻辑优化 ✅ +**问题**: +- 轮询可能在组件卸载后继续运行,造成内存泄漏 +- 错误处理可能导致轮询未正确清理 + +**修复**: +- 添加 `pollIntervalId` 保存轮询ID +- 在组件卸载时使用 `onBeforeUnmount` 清理轮询 +- 优化轮询逻辑:先检查最大次数,再处理任务状态 +- 所有退出路径(成功、失败、超时)都正确清理轮询 + +**代码位置**: +- `demo/frontend/src/views/StoryboardVideoCreate.vue:287-346` + +### 2. 图片URL转换错误处理增强 ✅ +**问题**: +- 外部URL可能因CORS问题无法加载 +- 错误信息不够明确 + +**修复**: +- 添加HTTP状态码检查 +- 区分base64和普通URL的错误处理 +- 提供更清晰的错误提示 + +**代码位置**: +- `demo/frontend/src/views/StoryboardVideoCreate.vue:348-380` + +### 3. 后端权限验证补充 ✅ +**问题**: +- 获取任务详情接口缺少用户权限验证 + +**修复**: +- 添加用户身份验证 +- 检查任务所有者是否匹配当前用户 +- 添加安全日志记录 + +**代码位置**: +- `demo/src/main/java/com/example/demo/controller/StoryboardVideoApiController.java:85-124` + +--- + +## 代码逻辑流程分析 + +### 前端流程 + +1. **生成分镜图步骤** (`startGenerate`) + ``` + 用户输入提示词 + → 验证输入 + → 调用 createStoryboardTask API + → 创建任务成功 + → 开始轮询任务状态 + → 分镜图生成完成 + → 自动切换到视频步骤 + ``` + +2. **生成视频步骤** (`startVideoGenerate`) + ``` + 验证分镜图已生成 + → 将图片URL转换为File对象 + → 调用图生视频API + → 跳转到视频详情页 + ``` + +3. **轮询逻辑** (`pollTaskStatus`) + ``` + 每2秒查询一次任务状态 + → 检查任务状态(COMPLETED/FAILED) + → 达到最大尝试次数(30次=60秒)自动停止 + → 所有退出路径都清理定时器 + ``` + +### 后端流程 + +1. **创建任务** (`StoryboardVideoService.createTask`) + ``` + 验证参数 + → 创建数据库记录(PENDING状态) + → 异步调用 processTaskAsync + → 返回任务ID + ``` + +2. **异步处理任务** (`StoryboardVideoService.processTaskAsync`) + ``` + 重新加载任务实体 + → 更新状态为PROCESSING + → 调用文生图API (RealAIService.submitTextToImageTask) + → 解析API响应获取图片URL + → 更新任务为COMPLETED并保存图片URL + ``` + +3. **文生图API调用** (`RealAIService.submitTextToImageTask`) + ``` + 转换宽高比为图片尺寸 + → 构建请求体(使用ObjectMapper) + → 调用Comfly API + → 返回图片数据(支持url或b64_json) + ``` + +--- + +## 潜在风险和注意事项 + +### 1. 图片URL跨域问题 ⚠️ +**风险**:如果文生图API返回的图片URL是外部域名,前端`fetch`可能因CORS策略失败。 + +**建议**: +- 如果API返回的是外部URL,可能需要后端代理下载后返回base64 +- 或者使用``标签先验证可访问性 + +**当前处理**:已在`urlToFile`中添加错误处理,会提示用户图片无法加载。 + +### 2. 并发创建任务 ⚠️ +**风险**:用户快速点击"开始生成"按钮可能创建多个任务。 + +**当前处理**:使用`inProgress`标志禁用按钮,但组件卸载后重新进入页面时不会检查是否有进行中的任务。 + +**建议**:页面加载时检查是否有未完成的任务,如果有则自动恢复轮询。 + +### 3. 事务管理 ✅ +**状态**:已正确实现 +- 使用`@Async`注解实现异步执行 +- 使用`@Transactional`确保数据一致性 +- 在异步方法中重新加载实体,避免`StaleObjectStateException` + +### 4. 错误处理完整性 ✅ +**状态**:已完善 +- 前端:所有API调用都有try-catch和用户提示 +- 后端:所有异常都有日志记录和错误响应 +- 轮询失败不会导致无限重试(最多30次) + +--- + +## 代码质量评估 + +### ✅ 优点 + +1. **清晰的步骤分离**:两步流程(生成分镜图 → 生成视频)逻辑清晰 +2. **完整的错误处理**:所有关键路径都有错误处理 +3. **良好的用户体验**:自动切换步骤、加载状态提示 +4. **安全性**:用户权限验证、JWT认证 +5. **代码可维护性**:模块化设计、清晰的注释 + +### ⚠️ 可改进点 + +1. **用户体验优化**: + - 可以在页面加载时检查是否有未完成的任务 + - 可以添加任务历史记录展示 + +2. **性能优化**: + - 图片URL转换可能较慢,可以添加进度提示 + - 可以考虑使用Web Worker处理图片转换 + +3. **日志优化**: + - 前端日志较多,生产环境可以移除或使用环境变量控制 + +--- + +## 测试建议 + +### 功能测试 + +1. ✅ 正常流程测试: + - 输入提示词 → 生成分镜图 → 自动切换 → 生成视频 + +2. ✅ 异常流程测试: + - 网络错误时的处理 + - API返回错误时的处理 + - 图片URL无效时的处理 + +3. ✅ 边界测试: + - 超长提示词 + - 空提示词 + - 快速连续点击按钮 + - 组件卸载时轮询清理 + +### 安全性测试 + +1. ✅ 权限验证测试: + - 用户A无法访问用户B的任务 + +2. ✅ JWT认证测试: + - Token过期时的处理 + - 无效Token时的处理 + +--- + +## 总结 + +**代码质量**:✅ 良好 + +**主要改进**: +- ✅ 修复了轮询内存泄漏问题 +- ✅ 增强了图片URL转换的错误处理 +- ✅ 补充了后端权限验证 + +**建议后续优化**: +- 添加任务历史记录功能 +- 优化图片加载性能 +- 添加任务恢复机制 + +--- + +## 相关文件清单 + +### 前端 +- `demo/frontend/src/views/StoryboardVideoCreate.vue` - 主页面组件 +- `demo/frontend/src/api/storyboardVideo.js` - API客户端 +- `demo/frontend/src/api/imageToVideo.js` - 图生视频API +- `demo/frontend/src/api/request.js` - Axios实例配置 + +### 后端 +- `demo/src/main/java/com/example/demo/controller/StoryboardVideoApiController.java` - REST控制器 +- `demo/src/main/java/com/example/demo/service/StoryboardVideoService.java` - 业务逻辑服务 +- `demo/src/main/java/com/example/demo/service/RealAIService.java` - AI API调用服务 +- `demo/src/main/java/com/example/demo/model/StoryboardVideoTask.java` - 数据模型 +- `demo/src/main/java/com/example/demo/repository/StoryboardVideoTaskRepository.java` - 数据访问层 +- `demo/src/main/resources/db/migration/V8__Create_Storyboard_Video_Tasks_Table.sql` - 数据库迁移脚本 + diff --git a/demo/frontend/src/api/promptOptimizer.js b/demo/frontend/src/api/promptOptimizer.js new file mode 100644 index 0000000..c6a0071 --- /dev/null +++ b/demo/frontend/src/api/promptOptimizer.js @@ -0,0 +1,31 @@ +import api from './request' + +/** + * 优化提示词 + * @param {string} prompt - 原始提示词 + * @param {string} type - 优化类型: 'text-to-video' | 'image-to-video' | 'storyboard' + * @returns {Promise} API响应 + */ +export const optimizePrompt = async (prompt, type = 'text-to-video') => { + // 参数验证 + if (!prompt || !prompt.trim()) { + throw new Error('提示词不能为空') + } + + if (prompt.length > 2000) { + throw new Error('提示词过长,请控制在2000字符以内') + } + + // 设置较长的超时时间(30秒),因为AI优化可能需要较长时间 + return api.post('/prompt/optimize', { + prompt: prompt.trim(), + type + }, { + timeout: 30000 + }) +} + +export default { + optimizePrompt +} + diff --git a/demo/frontend/src/api/storyboardVideo.js b/demo/frontend/src/api/storyboardVideo.js new file mode 100644 index 0000000..ee08708 --- /dev/null +++ b/demo/frontend/src/api/storyboardVideo.js @@ -0,0 +1,22 @@ +import api from './request' + +/** + * 创建分镜视频任务 + */ +export const createStoryboardTask = async (data) => { + return api.post('/storyboard-video/create', data) +} + +/** + * 获取任务详情 + */ +export const getStoryboardTask = async (taskId) => { + return api.get(`/storyboard-video/task/${taskId}`) +} + +/** + * 获取用户任务列表 + */ +export const getUserStoryboardTasks = async (page = 0, size = 10) => { + return api.get('/storyboard-video/tasks', { params: { page, size } }) +} diff --git a/demo/frontend/src/views/CleanupTest.vue b/demo/frontend/src/views/CleanupTest.vue index a9e39aa..37f059c 100644 --- a/demo/frontend/src/views/CleanupTest.vue +++ b/demo/frontend/src/views/CleanupTest.vue @@ -127,6 +127,8 @@