self-media-james/scripts/jimeng_video_gen.py
邓文兵 2c96bf7b7f fix(jimeng_video_gen): 解决视频下载失败和状态检查问题
- 添加视频下载重试机制,最多重试3次
- 增加下载超时设置为60秒
- 添加下载失败时的错误提示信息
- 修复任务状态检查逻辑,避免空响应导致的错误
- 改进错误处理流程,提高脚本稳定性
2026-03-14 10:26:34 +08:00

157 lines
5.6 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""即梦 AI 视频生成工具
支持:
- 文生视频 (t2v): jimeng_t2v_v30 (720P) / jimeng_t2v_v30_1080p (1080P)
- 图生视频-首帧 (i2v): jimeng_i2v_first_v30 (720P)
"""
import json
import os
import sys
import time
import base64
import requests
from jimeng_gen import jimeng_request, _ensure_dir
# req_key 映射
REQ_KEYS = {
't2v_720p': 'jimeng_t2v_v30',
't2v_1080p': 'jimeng_t2v_v30_1080p',
'i2v_720p': 'jimeng_i2v_first_v30',
}
def generate_video_t2v(prompt, output_path, resolution='720p', aspect_ratio='16:9', frames=121, seed=-1):
"""文生视频:提交任务并轮询获取结果"""
req_key = REQ_KEYS.get(f't2v_{resolution}', REQ_KEYS['t2v_720p'])
print(f"[即梦视频] 文生视频 ({resolution}): {prompt[:50]}...")
body = {
'req_key': req_key,
'prompt': prompt,
'frames': frames,
'aspect_ratio': aspect_ratio,
'seed': seed,
}
return _submit_and_poll(req_key, body, output_path)
def generate_video_i2v(prompt, image_path_or_url, output_path, aspect_ratio='16:9', frames=121, seed=-1):
"""图生视频-首帧:输入首帧图片和提示词生成视频"""
req_key = REQ_KEYS['i2v_720p']
print(f"[即梦视频] 图生视频-首帧: {prompt[:50]}...")
body = {
'req_key': req_key,
'prompt': prompt,
'frames': frames,
'seed': seed,
}
# 判断是 URL 还是本地文件
if image_path_or_url.startswith('http'):
body['image_urls'] = [image_path_or_url]
else:
with open(image_path_or_url, 'rb') as f:
img_b64 = base64.b64encode(f.read()).decode('utf-8')
body['binary_data_base64'] = [img_b64]
return _submit_and_poll(req_key, body, output_path)
def _submit_and_poll(req_key, body, output_path, max_wait=180, poll_interval=10):
"""提交任务并轮询结果,下载视频到本地"""
# 1. 提交任务
submit_resp = jimeng_request('CVSync2AsyncSubmitTask', body)
if submit_resp.get('code') != 10000:
print(f"[即梦视频] 提交失败: {submit_resp}")
return None
task_id = submit_resp['data']['task_id']
print(f"[即梦视频] 任务已提交, task_id: {task_id}")
# 2. 轮询查询结果
max_polls = max_wait // poll_interval
for i in range(max_polls):
time.sleep(poll_interval)
result = jimeng_request('CVSync2AsyncGetResult', {
'req_key': req_key,
'task_id': task_id,
})
resp_code = result.get('code')
resp_data = result.get('data', {})
if resp_code == 10000 and resp_data.get('status') == 'done':
video_url = resp_data.get('video_url')
if video_url:
# 下载视频(带重试)
print(f"[即梦视频] 生成完成,正在下载...")
video_data = None
for attempt in range(3):
try:
video_data = requests.get(video_url, timeout=60, verify=False).content
break
except Exception as e:
print(f"[即梦视频] 下载重试 ({attempt+1}/3): {e}")
import time as _t; _t.sleep(3)
if video_data is None:
print(f"[即梦视频] 下载失败视频URL: {video_url[:200]}")
return None
_ensure_dir(output_path)
with open(output_path, 'wb') as f:
f.write(video_data)
print(f"[即梦视频] 视频已保存: {output_path}")
return output_path
else:
print(f"[即梦视频] 任务完成但未找到视频URL: {json.dumps(result, ensure_ascii=False)[:300]}")
return None
if resp_code != 10000 and (resp_data is None or resp_data.get('status') not in (None, 'running', 'pending')):
print(f"[即梦视频] 任务失败: {json.dumps(result, ensure_ascii=False)[:300]}")
return None
print(f"[即梦视频] 等待中... ({i+1}/{max_polls})")
print("[即梦视频] 超时")
return None
def main():
import argparse
parser = argparse.ArgumentParser(description='即梦 AI 视频生成')
parser.add_argument('prompt', help='视频描述提示词')
parser.add_argument('output', help='输出视频路径 (.mp4)')
parser.add_argument('--mode', choices=['t2v', 'i2v'], default='t2v', help='生成模式: t2v=文生视频, i2v=图生视频')
parser.add_argument('--resolution', choices=['720p', '1080p'], default='720p', help='分辨率 (仅 t2v)')
parser.add_argument('--aspect-ratio', default='16:9', help='宽高比: 16:9, 4:3, 1:1, 3:4, 9:16, 21:9')
parser.add_argument('--frames', type=int, default=121, help='视频帧数 (默认121)')
parser.add_argument('--image', help='首帧图片路径或URL (仅 i2v 模式)')
parser.add_argument('--seed', type=int, default=-1, help='随机种子 (-1=随机)')
args = parser.parse_args()
if args.mode == 'i2v':
if not args.image:
parser.error('i2v 模式需要 --image 参数')
result = generate_video_i2v(args.prompt, args.image, args.output,
aspect_ratio=args.aspect_ratio, frames=args.frames, seed=args.seed)
else:
result = generate_video_t2v(args.prompt, args.output,
resolution=args.resolution, aspect_ratio=args.aspect_ratio,
frames=args.frames, seed=args.seed)
if result:
print(f"\n视频生成成功: {result}")
else:
print("\n视频生成失败")
sys.exit(1)
if __name__ == '__main__':
main()