add doubao-seedance node
This commit is contained in:
@@ -20,7 +20,7 @@
|
||||
- 视频时长固定5秒
|
||||
- 自动下载和保存视频文件
|
||||
|
||||
### 3. Volcengine Img Edit V3.0 - 图生图指令编辑节点 (新增)
|
||||
### 3. Volcengine Img Edit V3.0 - 图生图指令编辑节点
|
||||
- 火山引擎图生图3.0指令编辑模型
|
||||
- 根据文字指令智能编辑图片内容
|
||||
- 支持精确的编辑强度控制(0.1-1.0)
|
||||
@@ -28,6 +28,16 @@
|
||||
- 保持原图主体结构的同时进行局部编辑
|
||||
- 自动保存编辑后的图片
|
||||
|
||||
### 4. Volcengine Doubao Seedance - 豆包Seedance视频生成节点 (新增)
|
||||
- 火山引擎豆包Seedance视频生成模型
|
||||
- 支持文生视频和图生视频两种模式
|
||||
- 支持所有模型文本命令参数:分辨率、宽高比、时长、帧率等
|
||||
- 支持多种视频分辨率:480p、720p、1080p
|
||||
- 支持9种宽高比和2种特殊比例模式
|
||||
- 支持5秒和10秒视频时长选择
|
||||
- 异步任务处理,自动轮询查询结果
|
||||
- 自动下载和保存视频文件
|
||||
|
||||
## 安装
|
||||
|
||||
1. 克隆此仓库到 ComfyUI 的 custom_nodes 目录:
|
||||
@@ -71,7 +81,7 @@ pip install -r requirements.txt
|
||||
- **seed**: 随机种子 (可选,-1表示随机)
|
||||
- **filename_prefix**: 保存文件名前缀 (可选)
|
||||
|
||||
### Volcengine Img Edit V3.0 使用 (新增功能)
|
||||
### Volcengine Img Edit V3.0 使用
|
||||
1. 在节点列表中找到 `JM-Volcengine-API/ImgEdit` 分类
|
||||
2. 添加 `Volcengine Img Edit V3.0` 节点
|
||||
3. 配置参数:
|
||||
@@ -84,6 +94,24 @@ pip install -r requirements.txt
|
||||
- **filename_prefix**: 保存文件名前缀 (可选)
|
||||
- **return_url**: 是否返回图片URL链接 (可选,默认True,24小时有效)
|
||||
|
||||
### Volcengine Doubao Seedance 使用 (新增功能)
|
||||
1. 在节点列表中找到 `JM-Volcengine-API/Video` 分类
|
||||
2. 添加 `Volcengine Doubao Seedance` 节点
|
||||
3. 配置参数:
|
||||
- **ark_api_key**: 火山方舟API密钥
|
||||
- **model**: 模型ID (默认doubao-seedance-1-0-pro-250528)
|
||||
- **prompt**: 视频生成提示词,支持中英文
|
||||
- **image**: 输入图片 (可选,图生视频模式)
|
||||
- **image_role**: 图片角色 (可选,first_frame或last_frame)
|
||||
- **resolution**: 视频分辨率 (可选,480p/720p/1080p)
|
||||
- **ratio**: 视频宽高比 (可选,9种比例+特殊模式)
|
||||
- **duration**: 视频时长 (可选,5秒或10秒)
|
||||
- **framepersecond**: 帧率 (可选,16或24)
|
||||
- **watermark**: 是否包含水印 (可选)
|
||||
- **seed**: 随机种子 (可选,-1表示随机)
|
||||
- **camerafixed**: 是否固定摄像头 (可选)
|
||||
- **filename_prefix**: 保存文件名前缀 (可选)
|
||||
|
||||
## 参数说明
|
||||
|
||||
### SeeDream V3 参数
|
||||
@@ -114,7 +142,7 @@ pip install -r requirements.txt
|
||||
- 支持中英文,建议使用简洁明确的描述
|
||||
- 可以包含镜头切换、人物动作、情绪演绎等描述
|
||||
|
||||
### Img Edit V3.0 参数 (新增)
|
||||
### Img Edit V3.0 参数
|
||||
- **prompt**: 编辑指令,支持中英文,建议长度<=120字符,描述具体的编辑需求,例如:
|
||||
- "把天空改成夜晚"
|
||||
- "给人物添加墨镜"
|
||||
@@ -136,6 +164,41 @@ pip install -r requirements.txt
|
||||
- 局部编辑时指令描述尽量精准
|
||||
- 发现编辑效果不明显时,可以调整scale数值
|
||||
|
||||
### Doubao Seedance 参数 (新增)
|
||||
- **支持的视频分辨率**:
|
||||
- 480p → 低分辨率
|
||||
- 720p → 标准高清(默认)
|
||||
- 1080p → 全高清
|
||||
|
||||
- **支持的宽高比**:
|
||||
- 21:9 → 超宽屏比例
|
||||
- 16:9 → 标准横屏比例
|
||||
- 4:3 → 传统电视比例
|
||||
- 1:1 → 正方形比例
|
||||
- 3:4 → 竖屏比例
|
||||
- 9:16 → 手机竖屏比例
|
||||
- 9:21 → 超高竖屏比例
|
||||
- keep_ratio → 保持输入图片的宽高比
|
||||
- adaptive → 根据输入图片自动选择最合适的宽高比(默认)
|
||||
|
||||
- **视频时长**:
|
||||
- 5秒(默认)
|
||||
- 10秒
|
||||
|
||||
- **帧率选项**:
|
||||
- 16fps → 较低帧率
|
||||
- 24fps → 标准帧率(默认)
|
||||
|
||||
- **图片角色**(图生视频模式):
|
||||
- first_frame → 首帧图片(默认)
|
||||
- last_frame → 尾帧图片
|
||||
|
||||
- **使用建议**:
|
||||
- 提示词描述要清晰具体,避免过于抽象
|
||||
- 图生视频模式下,输入图片质量会影响生成效果
|
||||
- 建议根据实际需求选择合适的分辨率和时长
|
||||
- 使用keep_ratio或adaptive可以更好地适配输入图片
|
||||
|
||||
## 输出说明
|
||||
|
||||
### SeeDream V3 输出
|
||||
@@ -147,11 +210,14 @@ pip install -r requirements.txt
|
||||
- **video_url**: 生成的视频URL链接 (有效期1小时)
|
||||
- **local_video_path**: 本地保存的视频文件路径
|
||||
|
||||
### Img Edit V3.0 输出 (新增)
|
||||
### Img Edit V3.0 输出
|
||||
- **image**: 编辑后的图片张量,可连接到其他节点
|
||||
- **image_url**: 图片的URL链接(当return_url=True时)或Base64数据信息(当return_url=False时)
|
||||
- **local_image_path**: 本地保存的图片文件路径
|
||||
|
||||
### Doubao Seedance 输出 (新增)
|
||||
- **video_path**: 本地保存的视频文件路径
|
||||
|
||||
## 注意事项
|
||||
|
||||
### 通用注意事项
|
||||
@@ -172,7 +238,7 @@ pip install -r requirements.txt
|
||||
- 输入图片和提示词需要通过内容审核
|
||||
- 建议根据输入图片的实际比例选择合适的aspect_ratio
|
||||
|
||||
### Img Edit V3.0 特定注意事项 (新增)
|
||||
### Img Edit V3.0 特定注意事项
|
||||
- 使用SeedEdit 3.0指令编辑模型,服务标识固定为"seededit_v3.0"
|
||||
- 编辑效果取决于输入图片质量和编辑指令的准确性
|
||||
- 建议使用清晰、具体的编辑指令以获得更好的效果
|
||||
@@ -182,6 +248,17 @@ pip install -r requirements.txt
|
||||
- 编辑后的图片保持原图的基本构图和主体结构
|
||||
- 输入图片格式支持JPEG、PNG,最大5MB,分辨率最大4096×4096
|
||||
|
||||
### Doubao Seedance 特定注意事项 (新增)
|
||||
- 视频生成为异步处理,通常需要几分钟时间
|
||||
- 程序会自动轮询查询结果,请耐心等待
|
||||
- 支持文生视频和图生视频两种模式
|
||||
- 图生视频模式下,输入图片质量会影响生成效果
|
||||
- 生成的视频URL有效期为24小时,请及时下载保存
|
||||
- 输入图片和提示词需要通过内容审核
|
||||
- 建议根据实际用途选择合适的分辨率和时长参数
|
||||
- 所有模型文本命令参数都可以通过UI直接设置
|
||||
- 使用keep_ratio或adaptive可以更好地适配输入图片比例
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 常见错误及解决方案
|
||||
@@ -198,7 +275,7 @@ pip install -r requirements.txt
|
||||
- **任务超时**: 可能服务器繁忙,可稍后重试
|
||||
- **宽高比不匹配**: 建议选择与输入图片比例接近的aspect_ratio
|
||||
|
||||
#### Img Edit V3.0 (新增)
|
||||
#### Img Edit V3.0
|
||||
- **认证失败**: 检查AccessKey和SecretKey是否正确并有相应权限
|
||||
- **编辑指令错误**: 检查编辑指令是否清晰明确,避免过于复杂的描述
|
||||
- **提示词过长**: 确保提示词长度不超过120字符
|
||||
@@ -207,6 +284,16 @@ pip install -r requirements.txt
|
||||
- **任务超时**: 可能服务器繁忙,任务处理时间过长,可稍后重试
|
||||
- **任务未找到或过期**: 任务可能已过期(12小时),请重新提交
|
||||
|
||||
#### Doubao Seedance (新增)
|
||||
- **认证失败**: 检查ARK API密钥是否正确并有相应权限
|
||||
- **模型不可用**: 确认所选模型是否已开通并可正常使用
|
||||
- **提示词审核未通过**: 检查提示词内容是否符合平台规范
|
||||
- **图片审核未通过**: 检查输入图片内容是否符合平台规范
|
||||
- **参数错误**: 确认所有参数值是否在支持范围内
|
||||
- **任务超时**: 可能服务器繁忙,可稍后重试
|
||||
- **视频生成失败**: 检查提示词和参数设置,重新尝试
|
||||
- **下载失败**: 网络连接问题,检查网络状态
|
||||
|
||||
## 技术实现
|
||||
|
||||
### SeeDream V3
|
||||
@@ -221,7 +308,7 @@ pip install -r requirements.txt
|
||||
- 完整的错误处理和重试机制
|
||||
- 视频文件自动下载和命名管理
|
||||
|
||||
### Img Edit V3.0 (新增)
|
||||
### Img Edit V3.0
|
||||
- 实现完整的火山引擎SeedEdit 3.0异步接口调用
|
||||
- 支持任务提交和轮询查询的异步处理机制
|
||||
- 智能图片格式转换和处理
|
||||
@@ -229,6 +316,16 @@ pip install -r requirements.txt
|
||||
- 完善的错误处理和异常捕获
|
||||
- 自动文件命名和保存管理
|
||||
|
||||
### Doubao Seedance (新增)
|
||||
- 实现火山方舟标准API调用流程
|
||||
- 支持异步任务提交和轮询查询机制
|
||||
- 完整的模型文本命令参数支持
|
||||
- 智能图片格式转换和Base64编码
|
||||
- 支持文生视频和图生视频两种模式
|
||||
- 完善的错误处理和重试机制
|
||||
- 视频文件自动下载和命名管理
|
||||
- 支持所有官方模型参数配置
|
||||
|
||||
## 系统要求
|
||||
- ComfyUI 环境
|
||||
- Python 3.8+
|
||||
@@ -237,7 +334,16 @@ pip install -r requirements.txt
|
||||
|
||||
## 更新日志
|
||||
|
||||
### v3.0.0 (最新)
|
||||
### v4.0.0 (最新)
|
||||
- 新增 Volcengine Doubao Seedance 视频生成节点
|
||||
- 支持火山引擎豆包Seedance模型的文生视频和图生视频功能
|
||||
- 完整支持所有模型文本命令参数:分辨率、宽高比、时长、帧率、水印、种子、摄像头固定等
|
||||
- 支持3种分辨率、9种宽高比和2种特殊比例模式
|
||||
- 实现异步任务处理和自动轮询查询
|
||||
- 自动视频下载和文件命名管理
|
||||
- 优化用户界面参数配置
|
||||
|
||||
### v3.0.0
|
||||
- 新增 Volcengine Img Edit V3.0 图生图指令编辑节点(SeedEdit 3.0)
|
||||
- 支持根据文字指令智能编辑图片内容
|
||||
- 实现异步任务处理机制,支持任务提交和轮询查询
|
||||
|
||||
+5
-2
@@ -1,17 +1,20 @@
|
||||
from .nodes.volcengine_seedream_v3 import VolcengineSeeDreamV3Node
|
||||
from .nodes.volcengine_i2v_s2pro import VolcengineI2VS2Pro
|
||||
from .nodes.volcengine_img_edit_v3 import VolcengineImgEditV3
|
||||
from .nodes.volcengine_doubao_seedance import VolcengineDoubaoSeedance
|
||||
|
||||
NODE_CLASS_MAPPINGS = {
|
||||
"volcengine-seedream-v3": VolcengineSeeDreamV3Node,
|
||||
"volcengine-i2v-s2pro": VolcengineI2VS2Pro,
|
||||
"volcengine-img-edit-v3": VolcengineImgEditV3
|
||||
"volcengine-img-edit-v3": VolcengineImgEditV3,
|
||||
"volcengine-doubao-seedance": VolcengineDoubaoSeedance
|
||||
}
|
||||
|
||||
NODE_DISPLAY_NAME_MAPPINGS = {
|
||||
"volcengine-seedream-v3": "Volcengine SeeDream V3",
|
||||
"volcengine-i2v-s2pro": "Volcengine I2V S2.0Pro",
|
||||
"volcengine-img-edit-v3": "Volcengine Img Edit V3.0"
|
||||
"volcengine-img-edit-v3": "Volcengine Img Edit V3.0",
|
||||
"volcengine-doubao-seedance": "Volcengine Doubao Seedance"
|
||||
}
|
||||
|
||||
__all__ = ['NODE_CLASS_MAPPINGS', 'NODE_DISPLAY_NAME_MAPPINGS']
|
||||
@@ -0,0 +1,347 @@
|
||||
import json
|
||||
import time
|
||||
import base64
|
||||
import hashlib
|
||||
import hmac
|
||||
import datetime
|
||||
from urllib.parse import urlencode
|
||||
import requests
|
||||
import torch
|
||||
import numpy as np
|
||||
from PIL import Image
|
||||
import io
|
||||
import os
|
||||
import folder_paths
|
||||
|
||||
class VolcengineDoubaoSeedance:
|
||||
@classmethod
|
||||
def INPUT_TYPES(s):
|
||||
return {
|
||||
"required": {
|
||||
"ark_api_key": ("STRING", {
|
||||
"default": "",
|
||||
"multiline": False,
|
||||
"tooltip": "火山方舟API密钥"
|
||||
}),
|
||||
"model": (["doubao-seedance-1-0-pro-250528"], {
|
||||
"default": "doubao-seedance-1-0-pro-250528",
|
||||
"tooltip": "模型ID"
|
||||
}),
|
||||
"prompt": ("STRING", {
|
||||
"default": "",
|
||||
"multiline": True,
|
||||
"tooltip": "视频生成提示词,支持中英文"
|
||||
}),
|
||||
},
|
||||
"optional": {
|
||||
"image": ("IMAGE", {
|
||||
"tooltip": "输入图片(图生视频模式)"
|
||||
}),
|
||||
"image_role": (["first_frame", "last_frame"], {
|
||||
"default": "first_frame",
|
||||
"tooltip": "图片角色:首帧或尾帧"
|
||||
}),
|
||||
"resolution": (["480p", "720p", "1080p"], {
|
||||
"default": "720p",
|
||||
"tooltip": "视频分辨率"
|
||||
}),
|
||||
"ratio": (["21:9", "16:9", "4:3", "1:1", "3:4", "9:16", "9:21", "keep_ratio", "adaptive"], {
|
||||
"default": "adaptive",
|
||||
"tooltip": "视频宽高比"
|
||||
}),
|
||||
"duration": ([5, 10], {
|
||||
"default": 5,
|
||||
"tooltip": "视频时长(秒)"
|
||||
}),
|
||||
"framepersecond": ([16, 24], {
|
||||
"default": 24,
|
||||
"tooltip": "帧率"
|
||||
}),
|
||||
"watermark": ("BOOLEAN", {
|
||||
"default": False,
|
||||
"tooltip": "是否包含水印"
|
||||
}),
|
||||
"seed": ("INT", {
|
||||
"default": -1,
|
||||
"min": -1,
|
||||
"max": 2**32 - 1,
|
||||
"tooltip": "随机种子,-1表示随机"
|
||||
}),
|
||||
"camerafixed": ("BOOLEAN", {
|
||||
"default": False,
|
||||
"tooltip": "是否固定摄像头"
|
||||
}),
|
||||
"filename_prefix": ("STRING", {
|
||||
"default": "doubao_seedance",
|
||||
"tooltip": "保存文件名前缀"
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
RETURN_TYPES = ("STRING",)
|
||||
RETURN_NAMES = ("video_path",)
|
||||
FUNCTION = "generate_video"
|
||||
CATEGORY = "JM-Volcengine-API/Video"
|
||||
DESCRIPTION = "火山引擎豆包Seedance视频生成模型 - 支持文生视频和图生视频"
|
||||
|
||||
def __init__(self):
|
||||
self.base_url = "https://ark.cn-beijing.volces.com/api/v3/contents/generations/tasks"
|
||||
|
||||
def image_to_base64(self, image_tensor):
|
||||
"""将ComfyUI图片张量转换为Base64"""
|
||||
# image_tensor shape: [1, H, W, 3]
|
||||
if image_tensor.dim() == 4:
|
||||
image_tensor = image_tensor.squeeze(0) # 移除batch维度
|
||||
|
||||
# 转换为numpy数组并确保数据类型正确
|
||||
image_np = image_tensor.cpu().numpy()
|
||||
if image_np.dtype != np.uint8:
|
||||
image_np = (image_np * 255).astype(np.uint8)
|
||||
|
||||
# 转换为PIL图像
|
||||
pil_image = Image.fromarray(image_np)
|
||||
|
||||
# 转换为Base64
|
||||
buffer = io.BytesIO()
|
||||
pil_image.save(buffer, format='PNG')
|
||||
image_base64 = base64.b64encode(buffer.getvalue()).decode('utf-8')
|
||||
|
||||
return f"data:image/png;base64,{image_base64}"
|
||||
|
||||
def build_text_command(self, prompt, resolution="720p", ratio="adaptive", duration=5,
|
||||
framepersecond=24, watermark=False, seed=-1, camerafixed=False):
|
||||
"""构建文本命令字符串"""
|
||||
commands = []
|
||||
|
||||
# 添加基础提示词
|
||||
text_content = prompt.strip()
|
||||
|
||||
# 添加参数命令
|
||||
if resolution != "720p":
|
||||
commands.append(f"--resolution {resolution}")
|
||||
|
||||
if ratio != "adaptive":
|
||||
commands.append(f"--ratio {ratio}")
|
||||
|
||||
if duration != 5:
|
||||
commands.append(f"--duration {duration}")
|
||||
|
||||
if framepersecond != 24:
|
||||
commands.append(f"--framepersecond {framepersecond}")
|
||||
|
||||
if watermark:
|
||||
commands.append("--watermark true")
|
||||
|
||||
if seed != -1:
|
||||
commands.append(f"--seed {seed}")
|
||||
|
||||
if camerafixed:
|
||||
commands.append("--camerafixed true")
|
||||
|
||||
# 组合完整的文本内容
|
||||
if commands:
|
||||
text_content += " " + " ".join(commands)
|
||||
|
||||
return text_content
|
||||
|
||||
def create_task(self, ark_api_key, model, content_list):
|
||||
"""创建视频生成任务"""
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {ark_api_key}"
|
||||
}
|
||||
|
||||
payload = {
|
||||
"model": model,
|
||||
"content": content_list
|
||||
}
|
||||
|
||||
try:
|
||||
response = requests.post(self.base_url, headers=headers, json=payload, timeout=30)
|
||||
response.raise_for_status()
|
||||
|
||||
result = response.json()
|
||||
if "id" in result:
|
||||
return result["id"]
|
||||
else:
|
||||
print(f"创建任务失败: {result}")
|
||||
return None
|
||||
|
||||
except Exception as e:
|
||||
print(f"创建任务时发生错误: {str(e)}")
|
||||
return None
|
||||
|
||||
def query_task(self, ark_api_key, task_id, max_retries=60, retry_interval=10):
|
||||
"""查询任务结果"""
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {ark_api_key}"
|
||||
}
|
||||
|
||||
query_url = f"{self.base_url}/{task_id}"
|
||||
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
response = requests.get(query_url, headers=headers, timeout=30)
|
||||
response.raise_for_status()
|
||||
|
||||
result = response.json()
|
||||
status = result.get("status")
|
||||
|
||||
print(f"查询任务 {task_id} 状态: {status} (尝试 {attempt + 1}/{max_retries})")
|
||||
|
||||
if status == "succeeded":
|
||||
content = result.get("content", {})
|
||||
video_url = content.get("video_url")
|
||||
if video_url:
|
||||
print(f"任务完成,视频URL: {video_url}")
|
||||
return {"status": "success", "video_url": video_url, "result": result}
|
||||
else:
|
||||
print("任务成功但未找到视频URL")
|
||||
return {"status": "error", "message": "未找到视频URL"}
|
||||
|
||||
elif status == "failed":
|
||||
error_info = result.get("error", {})
|
||||
error_message = error_info.get("message", "任务失败")
|
||||
print(f"任务失败: {error_message}")
|
||||
return {"status": "error", "message": error_message}
|
||||
|
||||
elif status == "cancelled":
|
||||
print("任务被取消")
|
||||
return {"status": "error", "message": "任务被取消"}
|
||||
|
||||
elif status in ["queued", "running"]:
|
||||
print(f"任务进行中,状态: {status},等待 {retry_interval} 秒后重试...")
|
||||
time.sleep(retry_interval)
|
||||
continue
|
||||
|
||||
else:
|
||||
print(f"未知状态: {status}")
|
||||
time.sleep(retry_interval)
|
||||
continue
|
||||
|
||||
except Exception as e:
|
||||
print(f"查询任务时发生错误: {str(e)}")
|
||||
if attempt < max_retries - 1:
|
||||
time.sleep(retry_interval)
|
||||
continue
|
||||
else:
|
||||
return {"status": "error", "message": f"查询任务失败: {str(e)}"}
|
||||
|
||||
return {"status": "error", "message": "任务超时"}
|
||||
|
||||
def download_video(self, video_url, filename_prefix):
|
||||
"""下载视频到ComfyUI output目录"""
|
||||
try:
|
||||
# 确保输出目录存在
|
||||
output_dir = folder_paths.get_output_directory()
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
# 生成唯一文件名
|
||||
counter = 1
|
||||
while True:
|
||||
filename = f"{filename_prefix}_{counter:04d}.mp4"
|
||||
file_path = os.path.join(output_dir, filename)
|
||||
if not os.path.exists(file_path):
|
||||
break
|
||||
counter += 1
|
||||
|
||||
print(f"开始下载视频到: {file_path}")
|
||||
|
||||
# 下载视频
|
||||
response = requests.get(video_url, stream=True, timeout=300)
|
||||
response.raise_for_status()
|
||||
|
||||
with open(file_path, 'wb') as f:
|
||||
for chunk in response.iter_content(chunk_size=8192):
|
||||
if chunk:
|
||||
f.write(chunk)
|
||||
|
||||
print(f"视频下载成功: {file_path}")
|
||||
return file_path
|
||||
|
||||
except Exception as e:
|
||||
print(f"下载视频时发生错误: {str(e)}")
|
||||
return None
|
||||
|
||||
def generate_video(self, ark_api_key, model, prompt, image=None, image_role="first_frame",
|
||||
resolution="720p", ratio="adaptive", duration=5, framepersecond=24,
|
||||
watermark=False, seed=-1, camerafixed=False, filename_prefix="doubao_seedance"):
|
||||
"""主要的视频生成函数"""
|
||||
|
||||
# 验证必需参数
|
||||
if not ark_api_key:
|
||||
return ("错误:请提供有效的ARK API密钥",)
|
||||
|
||||
if not prompt.strip():
|
||||
return ("错误:请提供视频生成提示词",)
|
||||
|
||||
try:
|
||||
# 构建内容数组
|
||||
content_list = []
|
||||
|
||||
# 构建文本命令
|
||||
text_with_commands = self.build_text_command(
|
||||
prompt, resolution, ratio, duration, framepersecond,
|
||||
watermark, seed, camerafixed
|
||||
)
|
||||
|
||||
# 添加文本内容
|
||||
content_list.append({
|
||||
"type": "text",
|
||||
"text": text_with_commands
|
||||
})
|
||||
|
||||
# 如果有图片,添加图片内容(图生视频模式)
|
||||
if image is not None:
|
||||
print("检测到输入图片,使用图生视频模式")
|
||||
image_base64 = self.image_to_base64(image)
|
||||
|
||||
image_content = {
|
||||
"type": "image_url",
|
||||
"image_url": {
|
||||
"url": image_base64
|
||||
}
|
||||
}
|
||||
|
||||
# 如果指定了图片角色,添加role字段
|
||||
if image_role in ["first_frame", "last_frame"]:
|
||||
image_content["role"] = image_role
|
||||
|
||||
content_list.append(image_content)
|
||||
else:
|
||||
print("使用文生视频模式")
|
||||
|
||||
print(f"创建视频生成任务...")
|
||||
print(f"模型: {model}")
|
||||
print(f"提示词: {text_with_commands}")
|
||||
|
||||
# 创建任务
|
||||
task_id = self.create_task(ark_api_key, model, content_list)
|
||||
|
||||
if not task_id:
|
||||
return ("错误:任务创建失败",)
|
||||
|
||||
print(f"任务创建成功,task_id: {task_id}")
|
||||
print("开始查询任务状态...")
|
||||
|
||||
# 查询任务结果
|
||||
result = self.query_task(ark_api_key, task_id)
|
||||
|
||||
if result["status"] != "success":
|
||||
return (f"错误:{result['message']}",)
|
||||
|
||||
video_url = result["video_url"]
|
||||
print(f"获取到视频URL: {video_url}")
|
||||
|
||||
# 下载视频
|
||||
video_path = self.download_video(video_url, filename_prefix)
|
||||
|
||||
if not video_path:
|
||||
return ("错误:视频下载失败",)
|
||||
|
||||
return (video_path,)
|
||||
|
||||
except Exception as e:
|
||||
print(f"生成视频时发生错误: {str(e)}")
|
||||
return (f"错误:{str(e)}",)
|
||||
Reference in New Issue
Block a user