From d29cdb05ee146181d2f1b4a2cb0dfacb4d5119a2 Mon Sep 17 00:00:00 2001
From: huade <491009149@qq.com>
Date: Tue, 30 Jun 2026 17:15:33 +0800
Subject: [PATCH] Generating commit message...
---
.idea/claudeCodeTabState.xml | 10 +
.idea/workspace.xml | 17 +-
AgnesVideoV2.0.md | 527 +++++++++++++++++++++++
SECURITY.md | 41 --
backend-node/src/services/videoClient.js | 42 +-
backend-node/test/agnesVideoPoll.test.js | 27 +-
frontweb/src/views/FilmCreate.vue | 5 +-
7 files changed, 622 insertions(+), 47 deletions(-)
create mode 100644 AgnesVideoV2.0.md
delete mode 100644 SECURITY.md
diff --git a/.idea/claudeCodeTabState.xml b/.idea/claudeCodeTabState.xml
index 4c4739d..abea921 100644
--- a/.idea/claudeCodeTabState.xml
+++ b/.idea/claudeCodeTabState.xml
@@ -14,7 +14,17 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
index 775e2ca..359ac2e 100644
--- a/.idea/workspace.xml
+++ b/.idea/workspace.xml
@@ -2,7 +2,12 @@
+
+
+
+
+
@@ -49,7 +54,7 @@
1782800317217
-
+
@@ -67,7 +72,15 @@
1782802441985
-
+
+
+ 1782804636587
+
+
+
+ 1782804636588
+
+
diff --git a/AgnesVideoV2.0.md b/AgnesVideoV2.0.md
new file mode 100644
index 0000000..90be27c
--- /dev/null
+++ b/AgnesVideoV2.0.md
@@ -0,0 +1,527 @@
+> ## Documentation Index
+> Fetch the complete documentation index at: https://wiki.agnes-ai.com/llms.txt
+> Use this file to discover all available pages before exploring further.
+
+# Agnes Video V2.0
+
+> Agnes-Video-V2.0 API 接入指南
+
+## 概述
+
+Agnes-Video-V2.0 是一款面向生产场景的视频生成模型,支持**文生视频**、**图生视频**、**多图视频生成**以及**关键帧动画**工作流。
+
+开发者可以使用文本提示词、图片 URL 或多张参考图片生成高质量视频。该模型适用于故事讲述、营销视频、产品演示、社交媒体内容、应用动态素材以及 AI 创意工作流。
+
+
+ Agnes-Video-V2.0 采用基于异步任务的 API。您需要先创建一个视频生成任务,然后使用返回的 `video_id` 或 `task_id` 获取视频结果。
+
+
+## 支持能力
+
+
+
+ 通过文本提示词直接生成视频
+
+
+
+ 将静态图片转化为动态视频
+
+
+
+ 使用多张参考图片引导视频生成
+
+
+
+ 在多个关键帧之间生成流畅过渡
+
+
+
+ 通过提示词控制主体动作、镜头运动和场景动态
+
+
+
+ 在帧间保持一致的主体、风格和场景
+
+
+
+ 生成高质量电影级视频
+
+
+
+ 先提交任务,再获取生成结果
+
+
+
+## 使用场景
+
+
+
+ 短片、角色场景、叙事片段
+
+
+
+ 产品广告、宣传视频、推广内容
+
+
+
+ Reels、Shorts、TikTok 风格视频
+
+
+
+ 为肖像、产品、角色或场景添加动画效果
+
+
+
+ 通过文本或图片生成产品展示视频
+
+
+
+ 在不同视觉状态之间生成流畅过渡
+
+
+
+ 为数字产品生成动态视觉素材
+
+
+
+ 生成电影级 AI 场景和氛围视频
+
+
+
+## 前提条件
+
+
+ 在接入之前,请确保您已满足以下条件:
+
+1. 拥有有效的 Agnes AI API Key。
+2. 具备访问 Agnes AI API 网关的网络条件。
+3. 确认模型名称:agnes-video-v2.0。
+4. 准备好用于视频生成的文本提示词。
+5. 如果使用图生视频、多图视频或关键帧动画功能,需要提供可公开访问的图片 URL。
+
+
+## API 接口
+
+### 创建视频任务
+
+| 项目 | 说明 |
+| ------------ | ------------------------------------------------------------------------------ |
+| 接口地址 | [https://apihub.agnes-ai.com/v1/videos](https://apihub.agnes-ai.com/v1/videos) |
+| 请求方法 | POST |
+| Content-Type | application/json |
+| 认证方式 | Bearer Token |
+| 请求头 | Authorization: Bearer YOUR\_API\_KEY |
+
+### 获取视频结果:推荐方式
+
+视频任务创建成功后,响应中会包含一个 `video_id`。
+
+推荐使用 `video_id` 来获取视频结果。
+
+| 项目 | 说明 |
+| ---- | ---------------------------------------------------------- |
+| 接口地址 | `https://apihub.agnes-ai.com/agnesapi?video_id=` |
+| 请求方法 | GET |
+| 认证方式 | Bearer Token |
+| 请求头 | Authorization: Bearer YOUR\_API\_KEY |
+
+### 获取视频结果:兼容旧版方式
+
+为了兼容现有集成,旧版任务查询接口仍然支持使用。
+
+| 项目 | 说明 |
+| ---- | ----------------------------------------------------------------------------------------------------- |
+| 接口地址 | [https://apihub.agnes-ai.com/v1/videos/\{task\_id}](https://apihub.agnes-ai.com/v1/videos/\{task_id}) |
+| 请求方法 | GET |
+| 认证方式 | Bearer Token |
+| 请求头 | Authorization: Bearer YOUR\_API\_KEY |
+
+## 请求参数
+
+### 创建视频任务参数
+
+| 参数 | 类型 | 必填 | 说明 |
+| --------------------- | -------------- | -- | --------------------------- |
+| model | string | 是 | 模型名称。使用 agnes-video-v2.0 |
+| prompt | string | 是 | 视频内容的文本描述 |
+| image | string / array | 否 | 图片 URL 或图片 URL 数组 |
+| mode | string | 否 | 生成模式,例如 ti2vid 或 keyframes |
+| height | integer | 否 | 视频高度。默认值:768 |
+| width | integer | 否 | 视频宽度。默认值:1152 |
+| num\_frames | integer | 否 | 视频帧数。必须 ≤ 441 且遵循 8n + 1 规则 |
+| frame\_rate | number | 否 | 视频帧率。支持范围:1–60 |
+| num\_inference\_steps | integer | 否 | 推理步数 |
+| seed | integer | 否 | 随机种子,用于生成可复现的结果 |
+| negative\_prompt | string | 否 | 反向提示词,描述需要避免的内容 |
+| extra\_body.image | array | 否 | 多图视频或关键帧模式下的输入图片 URL 数组 |
+| extra\_body.mode | string | 否 | 附加模式设置,例如 keyframes |
+
+### 参数标准化
+
+Agnes-Video-V2.0 会对部分视频生成参数进行标准化处理,以确保生成稳定性和输出质量的一致性。当提交的 `width`、`height` 或宽高比与模型支持的标准规格不完全匹配时,系统会自动识别最接近的分辨率档位和宽高比,并将请求映射到对应的标准输出尺寸。
+
+模型目前支持三个标准分辨率档位:`480p`、`720p` 和 `1080p`。推荐使用以下宽高比:
+
+| 宽高比 | 推荐使用场景 |
+| ---- | ------------------------------------------ |
+| 16:9 | 横版视频、产品演示、网站展示、YouTube 风格内容 |
+| 9:16 | 竖版短视频、移动端优先内容、TikTok / Reels / Shorts 风格内容 |
+| 1:1 | 方形视频、社交媒体信息流、角色或产品展示 |
+| 4:3 | 传统横版格式及通用演示内容 |
+| 3:4 | 竖版演示、以肖像为主的视频、以产品为主的内容 |
+
+不同分辨率与宽高比的组合可能对应不同的实际输出尺寸和最大帧数限制。例如,接近 `720p / 16:9` 的输入尺寸将被标准化为对应的标准输出尺寸。
+
+因此,请求中原始的 `width`、`height`、`num_frames` 等参数可能与生成时使用的标准化参数不完全一致。在展示任务信息、计算视频时长或排查生成结果问题时,开发者应以 API 响应中返回的 `size`、`seconds` 等字段为准。
+
+## 创建视频任务
+
+
+
+ 使用此请求通过文本提示词直接生成视频。
+
+ ```bash theme={null}
+ curl -X POST https://apihub.agnes-ai.com/v1/videos \
+ -H "Authorization: Bearer YOUR_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "model": "agnes-video-v2.0",
+ "prompt": "A cinematic shot of a cat walking on the beach at sunset, soft ocean waves, warm golden lighting, realistic motion",
+ "height": 768,
+ "width": 1152,
+ "num_frames": 121,
+ "frame_rate": 24
+ }'
+ ```
+
+
+
+ 使用此请求为单张图片添加动画效果。
+
+ ```bash theme={null}
+ curl -X POST https://apihub.agnes-ai.com/v1/videos \
+ -H "Authorization: Bearer YOUR_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "model": "agnes-video-v2.0",
+ "prompt": "The woman slowly turns around and looks back at the camera, natural facial expression, cinematic camera movement",
+ "image": "https://example.com/image.png",
+ "num_frames": 121,
+ "frame_rate": 24
+ }'
+ ```
+
+
+
+ 使用此请求通过多张输入图片引导视频生成。
+
+ ```bash theme={null}
+ curl -X POST https://apihub.agnes-ai.com/v1/videos \
+ -H "Authorization: Bearer YOUR_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "model": "agnes-video-v2.0",
+ "prompt": "Create a smooth transformation scene between the two reference images, cinematic lighting, consistent character identity, natural motion",
+ "extra_body": {
+ "image": [
+ "https://example.com/image1.png",
+ "https://example.com/image2.png"
+ ]
+ },
+ "num_frames": 121,
+ "frame_rate": 24
+ }'
+ ```
+
+
+
+ 使用此请求在多个关键帧之间生成流畅动画。
+
+ ```bash theme={null}
+ curl -X POST https://apihub.agnes-ai.com/v1/videos \
+ -H "Authorization: Bearer YOUR_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "model": "agnes-video-v2.0",
+ "prompt": "Generate a smooth cinematic transition between the keyframes, maintaining visual consistency and natural camera movement",
+ "extra_body": {
+ "image": [
+ "https://example.com/keyframe1.png",
+ "https://example.com/keyframe2.png"
+ ],
+ "mode": "keyframes"
+ },
+ "num_frames": 121,
+ "frame_rate": 24
+ }'
+ ```
+
+
+
+## 创建任务响应
+
+视频任务创建成功后,API 会返回任务信息。
+
+响应中同时包含 `task_id` 和 `video_id`。
+
+`video_id` 是获取视频结果的推荐 ID。
+
+```json theme={null}
+{
+ "id": "task_YOUR_TASK_ID",
+ "task_id": "task_YOUR_TASK_ID",
+ "video_id": "video_YOUR_VIDEO_ID",
+ "object": "video",
+ "model": "agnes-video-v2.0",
+ "status": "queued",
+ "progress": 0,
+ "created_at": 1780457477,
+ "seconds": "10.0",
+ "size": "1280x768"
+}
+```
+
+### 响应字段
+
+| 字段 | 类型 | 说明 |
+| ----------- | ------- | ------------------ |
+| id | string | 任务 ID。可与旧版查询接口配合使用 |
+| task\_id | string | 任务 ID。作用与 id 相同 |
+| video\_id | string | 视频 ID。推荐用于获取视频结果 |
+| object | string | 对象类型,通常为 video |
+| model | string | 当前任务使用的模型 |
+| status | string | 当前任务状态 |
+| progress | integer | 当前任务进度百分比 |
+| created\_at | integer | 任务创建时间戳 |
+| seconds | string | 视频时长(秒) |
+| size | string | 视频分辨率 |
+
+## 获取视频结果
+
+### 推荐方式:通过 `video_id` 获取
+
+创建视频任务后,使用返回的 `video_id` 来获取视频结果。
+
+```bash theme={null}
+curl --location --request GET 'https://apihub.agnes-ai.com/agnesapi?video_id=' \
+ --header 'Authorization: Bearer '
+```
+
+示例:
+
+```bash theme={null}
+curl --location --request GET 'https://apihub.agnes-ai.com/agnesapi?video_id=video_xxxxxx' \
+ --header 'Authorization: Bearer '
+```
+
+### 可选参数:`model_name`
+
+获取视频结果时,您还可以传入 `model_name` 来显式指定模型名称。
+
+```bash theme={null}
+curl --location --request GET 'https://apihub.agnes-ai.com/agnesapi?video_id=&model_name=' \
+ --header 'Authorization: Bearer '
+```
+
+示例:
+
+```bash theme={null}
+curl --location --request GET 'https://apihub.agnes-ai.com/agnesapi?video_id=video_xxxxxx&model_name=agnes-video-v2.0' \
+ --header 'Authorization: Bearer '
+```
+
+在以下情况下使用 `model_name`:
+
+1. 您使用的是上游原始视频 ID。
+2. 使用的模型不是默认模型 `agnes-video-v2.0`。
+3. 您希望显式指定获取结果所使用的模型。
+
+当提供 `model_name` 时,该参数将优先生效。
+
+### 兼容旧版方式:通过 `task_id` 获取
+
+为兼容旧版本,您仍然可以使用 `task_id` 获取视频结果。
+
+```bash theme={null}
+curl --location --request GET 'https://apihub.agnes-ai.com/v1/videos/' \
+ --header 'Authorization: Bearer '
+```
+
+示例:
+
+```bash theme={null}
+curl --location --request GET 'https://apihub.agnes-ai.com/v1/videos/task_xxxxxx' \
+ --header 'Authorization: Bearer '
+```
+
+此方式仍然支持,但新接入的集成应使用 `video_id` 获取方式。
+
+## 获取结果响应
+
+任务完成后,API 返回最终视频结果。
+
+```json theme={null}
+{
+ "id": "task_YOUR_TASK_ID",
+ "video_id": "video_YOUR_VIDEO_ID",
+ "model": "agnes-video-v2.0",
+ "object": "video",
+ "status": "completed",
+ "progress": 100,
+ "seconds": "10.0",
+ "size": "1280x768",
+ "remixed_from_video_id": "https://storage.googleapis.com/agnes-aigc/aigc/videos/2026/06/03/video_xxxxxx.mp4",
+ "error": null
+}
+```
+
+### 结果字段
+
+| 字段 | 类型 | 说明 |
+| ------------------------ | ------------- | ------------------------------------- |
+| id | string | 任务 ID |
+| video\_id | string | 视频 ID |
+| model | string | 当前任务使用的模型 |
+| object | string | 对象类型 |
+| status | string | 任务状态 |
+| progress | integer | 任务进度百分比 |
+| seconds | string | 视频时长(秒) |
+| size | string | 视频分辨率 |
+| remixed\_from\_video\_id | string | 最终生成的视频 URL。仅在 status 为 completed 时可用 |
+| error | object / null | 任务失败时返回的错误信息 |
+
+## 任务状态
+
+| 状态 | 说明 |
+| ------------ | --------- |
+| queued | 任务正在队列中等待 |
+| in\_progress | 视频正在生成 |
+| completed | 视频生成成功 |
+| failed | 视频生成失败 |
+
+## 视频时长控制
+
+Agnes-Video-V2.0 支持通过 `num_frames` 和 `frame_rate` 控制视频时长。
+
+计算公式:
+
+```text theme={null}
+seconds = num_frames / frame_rate
+```
+
+其中:
+
+* `num_frames` 是生成视频的总帧数;
+* `frame_rate` 是视频帧率,即每秒播放的帧数;
+* `num_frames` 必须小于或等于 `441`;
+* `num_frames` 必须遵循 `8n + 1` 规则;
+* `frame_rate` 支持 `1` 到 `60` 之间的值。
+
+### 常用时长设置
+
+| 目标时长 | 推荐参数 |
+| ------ | --------------------------------- |
+| 约 3 秒 | num\_frames: 81, frame\_rate: 24 |
+| 约 5 秒 | num\_frames: 121, frame\_rate: 24 |
+| 约 10 秒 | num\_frames: 241, frame\_rate: 24 |
+| 约 18 秒 | num\_frames: 441, frame\_rate: 24 |
+
+要生成更长的视频,可以增大 `num_frames` 或降低 `frame_rate`。
+
+要使运动更加流畅,请使用更高的 `frame_rate`,例如 `24` 或 `30`。但在相同的 `num_frames` 下,更高的 `frame_rate` 会导致视频时长更短。
+
+## 推荐参数
+
+| 场景 | 推荐设置 |
+| -------- | ----------------------------------------------------------- |
+| 标准视频生成 | width: 1152, height: 768, num\_frames: 121, frame\_rate: 24 |
+| 社交短视频 | num\_frames: 81 或 121, frame\_rate: 24 |
+| 较长视频 | 增大 num\_frames 或降低 frame\_rate |
+| 更流畅的运动 | 使用 frame\_rate: 24 或 30 |
+| 可复现结果 | 设置固定的 seed |
+| 关键帧过渡 | 使用 extra\_body.mode: "keyframes" |
+| 避免不需要的内容 | 使用 negative\_prompt |
+
+## 提示词最佳实践
+
+
+
+ 对于文生视频任务,建议描述主体、动作、场景、镜头运动、光线和视觉风格。
+
+ 推荐结构:
+
+ ```text theme={null}
+ [主体] + [动作] + [场景] + [镜头运动] + [光线] + [风格]
+ ```
+
+ 示例:
+
+ ```text theme={null}
+ A young astronaut walking across a red desert planet, dust blowing in the wind, slow cinematic tracking shot, dramatic sunset lighting, realistic sci-fi style
+ ```
+
+
+
+ 对于图生视频任务,描述哪些内容应该运动,以及哪些关键主体元素应该保持稳定。
+
+ 示例:
+
+ ```text theme={null}
+ Animate the character with subtle breathing motion, hair moving gently in the wind, background lights flickering softly, while keeping the face and outfit consistent
+ ```
+
+
+
+ 对于多图视频任务,描述输入图片之间的关系以及场景应该如何过渡。
+
+ 示例:
+
+ ```text theme={null}
+ Use the first image as the starting scene and the second image as the target scene. Create a smooth transformation with consistent lighting, natural motion, and cinematic pacing
+ ```
+
+
+
+ 对于关键帧动画任务,清晰描述关键帧之间的过渡关系。
+
+ 示例:
+
+ ```text theme={null}
+ Create a smooth transition from the first keyframe to the second keyframe, maintaining character identity, consistent camera angle, and natural motion between scenes
+ ```
+
+
+
+## 错误码
+
+| 状态码 | 说明 |
+| --- | ----------------- |
+| 400 | 请求无效。请检查请求参数 |
+| 401 | 未授权。请检查您的 API Key |
+| 404 | 任务或视频未找到 |
+| 500 | 服务器错误 |
+| 503 | 服务繁忙。请稍后重试 |
+
+## 定价
+
+| 类型 | 标准价格 | 当前价格 |
+| ---- | ----------- | ------- |
+| 视频时长 | \$0.005 / 秒 | \$0 / 秒 |
+
+## 注意事项
+
+
+ * 使用 `agnes-video-v2.0` 作为模型名称。
+ * 视频生成是异步的。
+ * 您需要先创建视频任务,然后获取视频结果。
+ * 创建任务响应会同时返回 `task_id` 和 `video_id`。
+ * 新接入的集成应使用 `video_id` 获取视频结果。
+ * 旧版 `task_id` 查询接口仍然支持。
+ * `video_url` 仅在 `status` 为 `completed` 时可用。
+ * `num_frames` 必须小于或等于 `441`。
+ * `num_frames` 必须遵循 `8n + 1` 规则,例如 `81`、`121`、`161`、`241` 或 `441`。
+ * 文生视频任务仅需要 `model` 和 `prompt`。
+ * 图生视频任务需要通过 `image` 传入图片 URL。
+ * 多图视频任务需要在 `extra_body.image` 中传入多个图片 URL。
+ * 关键帧动画需要将 `extra_body.mode` 设置为 `keyframes`。
+
diff --git a/SECURITY.md b/SECURITY.md
deleted file mode 100644
index 529fd1d..0000000
--- a/SECURITY.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# 安全政策 / Security Policy
-
-## 支持的版本 / Supported Versions
-
-我们只对最新发布版本提供安全修复。
-Security fixes are only provided for the latest release.
-
-| 版本 / Version | 支持状态 / Support |
-|---------------|-------------------|
-| 最新版 / Latest | ✅ 支持 / Supported |
-| 旧版本 / Older | ❌ 不支持 / Not supported |
-
-## 报告漏洞 / Reporting a Vulnerability
-
-**请勿通过公开 Issue 报告安全漏洞。**
-**Please do NOT report security vulnerabilities via public Issues.**
-
-### 联系方式 / Contact
-
-如果你发现了安全漏洞,请通过以下方式私下联系我们:
-If you discover a security vulnerability, please contact us privately:
-
-- **GitHub Security Advisory**:点击仓库页面的 [Security](../../security/advisories/new) 标签 → Report a vulnerability
-- **微信 / WeChat**:通过 README 中的二维码添加作者微信私信
-
-### 响应流程 / Response Process
-
-1. 收到报告后我们会在 **3 个工作日**内确认收到
-2. 评估漏洞严重程度,制定修复计划
-3. 修复完成后发布新版本,在 Changelog 中说明(不披露细节)
-4. 感谢报告者(如果你愿意,会在 Changelog 中致谢)
-
-### 注意事项 / Notes
-
-本项目是**本地离线桌面应用**,不涉及服务端数据传输。用户的 AI API Key 和项目数据均存储在本地,不经过任何第三方服务器。主要安全风险集中在:
-
-- 本地文件读写权限
-- 对接第三方 AI API 时的网络请求
-- 依赖包的已知漏洞
-
-This is a **local desktop application**. No user data or API keys are transmitted through any third-party server. Security risks are mainly related to local file access, outbound AI API requests, and known dependency vulnerabilities.
diff --git a/backend-node/src/services/videoClient.js b/backend-node/src/services/videoClient.js
index 84e3b69..12ebc19 100644
--- a/backend-node/src/services/videoClient.js
+++ b/backend-node/src/services/videoClient.js
@@ -952,6 +952,38 @@ function buildQueryUrl(config, taskId) {
return base + ep;
}
+function encodeAgnesPollId(taskId, videoId) {
+ const normalizedVideoId = String(videoId || '').trim();
+ if (normalizedVideoId) return `video:${normalizedVideoId}`;
+ return String(taskId || '').trim();
+}
+
+function buildAgnesPollRequest(config, taskId, modelHint) {
+ const rawId = String(taskId || '').trim();
+ const headers = { Authorization: 'Bearer ' + (config.api_key || '') };
+ const safeModel = encodeURIComponent(String(modelHint || 'agnes-video-v2.0').trim() || 'agnes-video-v2.0');
+
+ if (rawId.startsWith('video:')) {
+ const videoId = rawId.slice('video:'.length);
+ return {
+ url: `https://apihub.agnes-ai.com/agnesapi?video_id=${encodeURIComponent(videoId)}&model_name=${safeModel}`,
+ headers,
+ };
+ }
+
+ if (/^video_/i.test(rawId)) {
+ return {
+ url: `https://apihub.agnes-ai.com/agnesapi?video_id=${encodeURIComponent(rawId)}&model_name=${safeModel}`,
+ headers,
+ };
+ }
+
+ return {
+ url: buildQueryUrl(config, rawId),
+ headers,
+ };
+}
+
// ????????? ? API ?? ID ???API ????+???????
const VOLC_MODEL_ALIASES = {
'doubao-seedance-1.0-pro-fast': 'doubao-seedance-1-0-pro-250528',
@@ -2520,7 +2552,10 @@ async function callAgnesVideoApi(db, config, log, opts) {
return { video_url: directUrl };
}
- const taskId = data.id || data.task_id || data.data?.id || data.data?.task_id;
+ const taskId = encodeAgnesPollId(
+ data.id || data.task_id || data.data?.id || data.data?.task_id,
+ data.video_id || data.data?.video_id
+ );
if (taskId) {
log.info('[Agnes] 返回 task_id', { task_id: taskId, status: data.status, video_gen_id });
return { task_id: String(taskId), status: data.status || 'processing' };
@@ -3809,6 +3844,10 @@ async function pollVideoTask(db, log, videoGenId, taskId, config, maxAttempts =
if (!qep.startsWith('/')) qep = '/' + qep;
url = viduBase + qep;
headers = { Authorization: (isOfficialVidu ? 'Token ' : 'Bearer ') + (config.api_key || '') };
+ } else if (isAgnes) {
+ const agnesReq = buildAgnesPollRequest(config, taskId, config.model);
+ url = agnesReq.url;
+ headers = agnesReq.headers;
} else {
url = queryUrl();
headers = { Authorization: 'Bearer ' + (config.api_key || '') };
@@ -4061,6 +4100,7 @@ module.exports = {
normalizeAspectRatioForApi,
isPlausibleHttpVideoUrl,
pickProxyVideoUrl,
+ buildAgnesPollRequest,
buildAgnesVideoImagePayload,
formatVideoPostBodyForLog,
};
diff --git a/backend-node/test/agnesVideoPoll.test.js b/backend-node/test/agnesVideoPoll.test.js
index c56b8f4..96c9508 100644
--- a/backend-node/test/agnesVideoPoll.test.js
+++ b/backend-node/test/agnesVideoPoll.test.js
@@ -1,6 +1,6 @@
const { describe, it } = require('node:test');
const assert = require('node:assert/strict');
-const { pickProxyVideoUrl } = require('../src/services/videoClient');
+const { pickProxyVideoUrl, buildAgnesPollRequest } = require('../src/services/videoClient');
describe('pickProxyVideoUrl Agnes completed task', () => {
it('reads MP4 from remixed_from_video_id when video_url is absent', () => {
@@ -17,3 +17,28 @@ describe('pickProxyVideoUrl Agnes completed task', () => {
);
});
});
+
+describe('buildAgnesPollRequest', () => {
+ it('uses recommended video_id query API when provider poll id is video-prefixed', () => {
+ const req = buildAgnesPollRequest(
+ { api_key: 'k', base_url: 'https://apihub.agnes-ai.com/v1' },
+ 'video:video_abc123',
+ 'agnes-video-v2.0'
+ );
+ assert.equal(
+ req.url,
+ 'https://apihub.agnes-ai.com/agnesapi?video_id=video_abc123&model_name=agnes-video-v2.0'
+ );
+ assert.deepEqual(req.headers, { Authorization: 'Bearer k' });
+ });
+
+ it('falls back to legacy task query API for task ids', () => {
+ const req = buildAgnesPollRequest(
+ { api_key: 'k', base_url: 'https://apihub.agnes-ai.com/v1', query_endpoint: '/videos/{taskId}' },
+ 'task_abc123',
+ 'agnes-video-v2.0'
+ );
+ assert.equal(req.url, 'https://apihub.agnes-ai.com/v1/videos/task_abc123');
+ assert.deepEqual(req.headers, { Authorization: 'Bearer k' });
+ });
+});
diff --git a/frontweb/src/views/FilmCreate.vue b/frontweb/src/views/FilmCreate.vue
index 0d02c62..67a4b70 100644
--- a/frontweb/src/views/FilmCreate.vue
+++ b/frontweb/src/views/FilmCreate.vue
@@ -4152,8 +4152,9 @@ async function onGenerateSbFrameImage(sb, slot) {
const firstImg = getSbFirstImage(sb.id)
if (firstImg) {
const firstUrl = assetImageUrl(firstImg) || firstImg.image_url || firstImg.local_path
- if (firstUrl) {
- refImagesForCreate = [firstUrl]
+ const firstAbsoluteUrl = toAbsoluteImageUrl(firstUrl)
+ if (firstAbsoluteUrl) {
+ refImagesForCreate = [firstAbsoluteUrl]
}
}
}