OpenClaw调用火山引擎即梦API生成视频

火山引擎即梦API图生视频功能信息:

  1. 文生视频 (text-to-video)
  2. 图生视频 (image-to-video)

即梦AI

开通服务(即梦AI-视频生成3.0 1080P)---需提前实名认证

新建密钥

Python环境和requests包安装指令:

1. 检查Python环境

python 复制代码
# 检查Python版本
python --version
# 或
python3 --version

# 检查pip版本
pip --version
# 或
pip3 --version

2. 安装Python环境

更新本地软件包列表

python 复制代码
sudo apt-get update

安装pip

python 复制代码
sudo apt install python3-pip

3. **安装requests包(**使用虚拟环境(virtual environment))

虚拟环境可以隔离项目依赖,不会影响系统 Python。

  1. 安装 venv(如果尚未安装)

    python 复制代码
    sudo apt install python3-venv
  2. 创建虚拟环境

    在项目目录下执行:

    python 复制代码
    python3 -m venv myenv

    这会创建一个名为 myenv 的文件夹。

  3. 激活虚拟环境

    • 对于 bash/zsh:

      python 复制代码
      source myenv/bin/activate
    • 激活后,终端提示符前会显示 (myenv)

  4. 安装 requests

    python 复制代码
    pip install requests
  5. 验证安装

    python 复制代码
    python -c "import requests; print(requests.__version__)"
  6. 退出虚拟环境

    python 复制代码
    deactivate

4. 核心脚本内容:

volcengine_jimeng.py

python 复制代码
#!/usr/bin/env python3
"""
火山引擎即梦API集成脚本
支持文生视频和图生视频
"""

import os
import json
import time
import hashlib
import hmac
import datetime
import requests
from typing import Dict, Any, Optional, Tuple
import base64

# 配置信息
class VolcConfig:
    # 从环境变量或直接配置获取
    ACCESS_KEY = os.environ.get('VOLC_ACCESS_KEY', 'AKLTNjZlZDdiODI5YTk4NGFkYzlmZGY3ZDUwOTczMzEXXXX')
    SECRET_KEY = os.environ.get('VOLC_SECRET_KEY', 'WldSa1pEVmpaVFV6TXpVek5ETTVNR0V6T0dNeU4yTTNORGMzWVRBd0XXXX==')

    # req_key配置
    TEXT2VIDEO_REQ_KEY = os.environ.get('VOLC_TEXT2VIDEO_REQ_KEY', 'jimeng_t2v_v30_1080p')
    IMAGE2VIDEO_REQ_KEY = os.environ.get('VOLC_IMAGE2VIDEO_REQ_KEY', 'jimeng_i2v_first_v30_1080')

    # AIGC元数据
    AIGC_META_JSON = os.environ.get('AIGC_META', '{"content_producer":"葡萄星球","producer_id":"rgzn","content_propagator":"default","propagate_id":"syh"}')

    # API配置
    REGION = 'cn-north-1'
    SERVICE = 'cv'
    HOST = 'visual.volcengineapi.com'
    ENDPOINT = 'https://visual.volcengineapi.com'

    @classmethod
    def get_aigc_meta(cls) -> Dict[str, str]:
        """获取AIGC元数据"""
        try:
            return json.loads(cls.AIGC_META_JSON)
        except json.JSONDecodeError:
            return {
                "content_producer": "葡萄星球",
                "producer_id": "rgzn",
                "content_propagator": "default",
                "propagate_id": "syh"
            }


class VolcSignature:
    """V4签名实现"""

    @staticmethod
    def sign(key: bytes, msg: str) -> bytes:
        """HMAC-SHA256签名"""
        return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()

    @staticmethod
    def get_signature_key(key: str, date_stamp: str, region_name: str, service_name: str) -> bytes:
        """生成签名密钥链"""
        k_date = VolcSignature.sign(key.encode('utf-8'), date_stamp)
        k_region = VolcSignature.sign(k_date, region_name)
        k_service = VolcSignature.sign(k_region, service_name)
        k_signing = VolcSignature.sign(k_service, 'request')
        return k_signing

    @staticmethod
    def sign_v4(
        access_key: str,
        secret_key: str,
        region: str,
        service: str,
        method: str,
        canonical_uri: str,
        canonical_querystring: str,
        headers: Dict[str, str],
        payload: str
    ) -> Tuple[str, str]:
        """V4签名算法"""
        t = datetime.datetime.utcnow()
        amz_date = t.strftime('%Y%m%dT%H%M%SZ')
        date_stamp = t.strftime('%Y%m%d')

        # 规范化请求
        signed_headers = ';'.join([k.lower() for k in sorted(headers.keys())])
        canonical_headers = ''.join([f"{k.lower()}:{headers[k]}\n" for k in sorted(headers.keys())])

        payload_hash = hashlib.sha256(payload.encode('utf-8')).hexdigest()

        canonical_request = f"{method}\n{canonical_uri}\n{canonical_querystring}\n{canonical_headers}\n{signed_headers}\n{payload_hash}"

        # 待签名字符串
        algorithm = 'HMAC-SHA256'
        credential_scope = f"{date_stamp}/{region}/{service}/request"
        string_to_sign = f"{algorithm}\n{amz_date}\n{credential_scope}\n{hashlib.sha256(canonical_request.encode('utf-8')).hexdigest()}"

        # 计算签名
        signing_key = VolcSignature.get_signature_key(secret_key, date_stamp, region, service)
        signature = hmac.new(signing_key, string_to_sign.encode('utf-8'), hashlib.sha256).hexdigest()

        # 构建Authorization头
        authorization_header = f"{algorithm} Credential={access_key}/{credential_scope}, SignedHeaders={signed_headers}, Signature={signature}"

        return authorization_header, amz_date


class VolcJimengAPI:
    """火山引擎即梦API客户端"""

    def __init__(self, config: VolcConfig = None):
        self.config = config or VolcConfig()
        self.session = requests.Session()

    def _make_request(
        self,
        action: str,
        req_key: str,
        payload: Dict[str, Any],
        version: str = '2022-08-31'
    ) -> Dict[str, Any]:
        """发送API请求"""
        # 构建URL参数
        query_params = {
            'Action': action,
            'Version': version
        }
        canonical_querystring = '&'.join([f"{k}={v}" for k, v in sorted(query_params.items())])

        # 请求体
        payload_str = json.dumps(payload, ensure_ascii=False)

        # 初始请求头
        headers = {
            'Content-Type': 'application/json',
            'Host': self.config.HOST
        }

        # 计算签名
        authorization, amz_date = VolcSignature.sign_v4(
            access_key=self.config.ACCESS_KEY,
            secret_key=self.config.SECRET_KEY,
            region=self.config.REGION,
            service=self.config.SERVICE,
            method='POST',
            canonical_uri='/',
            canonical_querystring=canonical_querystring,
            headers=headers,
            payload=payload_str
        )

        # 添加签名头
        headers['X-Date'] = amz_date
        headers['X-Content-Sha256'] = hashlib.sha256(payload_str.encode('utf-8')).hexdigest()
        headers['Authorization'] = authorization

        # 发送请求
        url = f"{self.config.ENDPOINT}?{canonical_querystring}"
        response = self.session.post(url, headers=headers, data=payload_str.encode('utf-8'))

        if response.status_code != 200:
            raise Exception(f"API请求失败: HTTP {response.status_code}")

        result = response.json()
        if result.get('code') != 10000:
            raise Exception(f"API业务错误: {result.get('message', 'Unknown error')}")

        return result

    def submit_text2video_task(
        self,
        prompt: str,
        seed: int = -1,
        frames: int = 121,
        aspect_ratio: str = "16:9"
    ) -> str:
        """提交文生视频任务"""
        payload = {
            "req_key": self.config.TEXT2VIDEO_REQ_KEY,
            "prompt": prompt,
            "seed": seed,
            "frames": frames,
            "aspect_ratio": aspect_ratio
        }

        result = self._make_request(
            action='CVSync2AsyncSubmitTask',
            req_key=self.config.TEXT2VIDEO_REQ_KEY,
            payload=payload
        )

        return result['data']['task_id']

    def submit_image2video_task(
        self,
        image_urls: list,
        prompt: str,
        seed: int = -1,
        frames: int = 121
    ) -> str:
        """提交图生视频任务"""
        payload = {
            "req_key": self.config.IMAGE2VIDEO_REQ_KEY,
            "image_urls": image_urls,
            "prompt": prompt,
            "seed": seed,
            "frames": frames
        }

        result = self._make_request(
            action='CVSync2AsyncSubmitTask',
            req_key=self.config.IMAGE2VIDEO_REQ_KEY,
            payload=payload
        )

        return result['data']['task_id']

    def get_task_result(
        self,
        task_id: str,
        req_key: str,
        max_retries: int = 60,
        interval: int = 5
    ) -> Dict[str, Any]:
        """查询任务结果(带轮询)"""
        aigc_meta = self.config.get_aigc_meta()

        for attempt in range(max_retries):
            try:
                payload = {
                    "req_key": req_key,
                    "task_id": task_id,
                    "req_json": json.dumps({"aigc_meta": aigc_meta})
                }

                result = self._make_request(
                    action='CVSync2AsyncGetResult',
                    req_key=req_key,
                    payload=payload
                )

                data = result['data']
                status = data.get('status', '').lower()

                if status in ['done', 'success']:
                    return {
                        'status': 'success',
                        'video_url': data.get('video_url'),
                        'task_id': task_id,
                        'attempts': attempt + 1
                    }
                elif status == 'failed':
                    return {
                        'status': 'failed',
                        'error': data.get('error_msg', '任务失败'),
                        'task_id': task_id,
                        'attempts': attempt + 1
                    }
                # pending/processing 继续轮询

            except Exception as e:
                print(f"第{attempt + 1}次查询失败: {e}")

            if attempt < max_retries - 1:
                time.sleep(interval)

        return {
            'status': 'timeout',
            'error': f'任务超时({max_retries * interval}秒)',
            'task_id': task_id,
            'attempts': max_retries
        }

    def generate_text_video(
        self,
        prompt: str,
        seed: int = -1,
        frames: int = 121,
        aspect_ratio: str = "16:9"
    ) -> Dict[str, Any]:
        """文生视频完整流程"""
        print(f"提交文生视频任务: {prompt}")

        try:
            task_id = self.submit_text2video_task(
                prompt=prompt,
                seed=seed,
                frames=frames,
                aspect_ratio=aspect_ratio
            )

            print(f"任务提交成功,Task ID: {task_id}")
            print("开始轮询任务状态...")

            result = self.get_task_result(
                task_id=task_id,
                req_key=self.config.TEXT2VIDEO_REQ_KEY
            )

            return result

        except Exception as e:
            return {
                'status': 'error',
                'error': str(e),
                'task_id': None
            }

    def generate_image_video(
        self,
        image_urls: list,
        prompt: str,
        seed: int = -1,
        frames: int = 121
    ) -> Dict[str, Any]:
        """图生视频完整流程"""
        print(f"提交图生视频任务: {prompt}")
        print(f"使用图片: {image_urls}")

        try:
            task_id = self.submit_image2video_task(
                image_urls=image_urls,
                prompt=prompt,
                seed=seed,
                frames=frames
            )

            print(f"任务提交成功,Task ID: {task_id}")
            print("开始轮询任务状态...")

            result = self.get_task_result(
                task_id=task_id,
                req_key=self.config.IMAGE2VIDEO_REQ_KEY
            )

            return result

        except Exception as e:
            return {
                'status': 'error',
                'error': str(e),
                'task_id': None
            }


# 工具函数
def test_text2video():
    """测试文生视频"""
    api = VolcJimengAPI()

    result = api.generate_text_video(
        prompt="千军万马",
        seed=-1,
        frames=121,
        aspect_ratio="16:9"
    )

    print("\n=== 文生视频结果 ===")
    print(json.dumps(result, indent=2, ensure_ascii=False))

    if result['status'] == 'success':
        print(f"\n✅ 视频生成成功!")
        print(f"视频URL: {result['video_url']}")
        print(f"轮询次数: {result['attempts']}")
    else:
        print(f"\n❌ 视频生成失败: {result.get('error', '未知错误')}")


def test_image2video(image_url: str):
    """测试图生视频"""
    api = VolcJimengAPI()

    result = api.generate_image_video(
        image_urls=[image_url],
        prompt="夕阳下的海滩",
        seed=-1,
        frames=121
    )

    print("\n=== 图生视频结果 ===")
    print(json.dumps(result, indent=2, ensure_ascii=False))

    if result['status'] == 'success':
        print(f"\n✅ 视频生成成功!")
        print(f"视频URL: {result['video_url']}")
        print(f"轮询次数: {result['attempts']}")
    else:
        print(f"\n❌ 视频生成失败: {result.get('error', '未知错误')}")


def main():
    """主函数"""
    import argparse

    parser = argparse.ArgumentParser(description='火山引擎即梦API客户端')
    parser.add_argument('--mode', choices=['text', 'image'], required=True, help='生成模式: text=文生视频, image=图生视频')
    parser.add_argument('--prompt', required=True, help='视频提示词')
    parser.add_argument('--image-url', help='图片URL(图生视频模式需要)')
    parser.add_argument('--seed', type=int, default=-1, help='随机种子,-1表示随机')
    parser.add_argument('--frames', type=int, default=121, help='视频帧数')
    parser.add_argument('--aspect-ratio', default='16:9', help='宽高比(仅文生视频)')

    args = parser.parse_args()

    api = VolcJimengAPI()

    if args.mode == 'text':
        result = api.generate_text_video(
            prompt=args.prompt,
            seed=args.seed,
            frames=args.frames,
            aspect_ratio=args.aspect_ratio
        )
    else:
        if not args.image_url:
            print("错误: 图生视频模式需要 --image-url 参数")
            return

        result = api.generate_image_video(
            image_urls=[args.image_url],
            prompt=args.prompt,
            seed=args.seed,
            frames=args.frames
        )

    # 输出结果
    if result['status'] == 'success':
        print(f"\n✅ 视频生成成功!")
        print(f"任务ID: {result['task_id']}")
        print(f"视频URL: {result['video_url']}")
        print(f"轮询次数: {result['attempts']}")
    elif result['status'] == 'timeout':
        print(f"\n⚠️  任务超时")
        print(f"任务ID: {result['task_id']}")
        print(f"错误: {result['error']}")
        print("提示: 可以稍后使用任务ID手动查询")
    else:
        print(f"\n❌ 任务失败")
        print(f"错误: {result.get('error', '未知错误')}")


if __name__ == '__main__':

5. 提交任务脚本

generate_socks_video.py

python 复制代码
#!/usr/bin/env python3
"""
生成袜子多角度展示视频
使用火山引擎即梦API
"""

import os
import sys
import json
import time
import base64
import requests
from volcengine_jimeng_fixed import VolcJimengAPIFixed, VolcConfig

def generate_socks_video():
    """生成袜子展示视频"""
    print("=== 开始生成袜子多角度展示视频 ===")

    # 1. 读取袜子图片
    image_path = "/home/rgzn/.openclaw/media/inbound/4e39c2dc-0cde-416f-bff1-55b20f0a570d.jpg"
    print(f"读取图片: {image_path}")

    with open(image_path, 'rb') as f:
        image_data = f.read()
        image_base64 = base64.b64encode(image_data).decode('utf-8')

    print(f"图片大小: {len(image_data)} bytes")
    print(f"Base64长度: {len(image_base64)} chars")

    # 2. 优化后的提示词
    prompt = """A professional product showcase video of a pair of high-quality socks.
The video features smooth 360-degree rotation of the socks on a clean white background,
with close-up shots showing fabric texture and details.
Dynamic camera movements include slow zoom-ins on key features, panning shots, and multi-angle presentations.
On-screen text appears with the words "Anti-odor, Antibacterial, Fashionable" in elegant typography.
The style is modern e-commerce product presentation with soft lighting, crisp visuals, and professional composition.
The video should be 5 seconds long with seamless transitions between shots."""

    print(f"\n提示词: {prompt[:100]}...")

    # 3. 创建API客户端
    print("\n初始化API客户端...")
    api = VolcJimengAPIFixed()

    # 4. 提交图生视频任务
    print("提交图生视频任务...")
    try:
        task_id = api.submit_image2video_task(
            image_base64=image_base64,
            prompt=prompt,
            seed=-1,
            frames=121,  # 5秒视频大约需要121帧(24fps)
            aspect_ratio="16:9"
        )

        print(f"✅ 任务提交成功!")
        print(f"任务ID: {task_id}")

        # 5. 轮询查询结果
        print("\n开始轮询任务状态...")
        max_attempts = 60  # 最多尝试60次
        interval = 5  # 每次间隔5秒

        for attempt in range(max_attempts):
            print(f"第{attempt + 1}次查询...")

            try:
                result = api.get_task_result(task_id, 'image2video')
                data = result.get('data', {})
                status = data.get('status', '').lower()

                if status in ['done', 'success']:
                    video_url = data.get('video_url')
                    print(f"\n🎉 视频生成成功!")
                    print(f"视频URL: {video_url}")
                    print(f"轮询次数: {attempt + 1}")

                    # 尝试下载视频
                    if video_url:
                        try:
                            print("尝试下载视频...")
                            response = requests.get(video_url, timeout=30)
                            if response.status_code == 200:
                                video_path = "/home/rgzn/.openclaw/workspace/socks_showcase_video.mp4"
                                with open(video_path, 'wb') as f:
                                    f.write(response.content)
                                print(f"✅ 视频已保存到: {video_path}")
                                return {
                                    'status': 'success',
                                    'video_url': video_url,
                                    'local_path': video_path,
                                    'task_id': task_id,
                                    'attempts': attempt + 1
                                }
                            else:
                                print(f"⚠️  视频下载失败: HTTP {response.status_code}")
                        except Exception as e:
                            print(f"⚠️  视频下载失败: {e}")

                    return {
                        'status': 'success',
                        'video_url': video_url,
                        'task_id': task_id,
                        'attempts': attempt + 1
                    }

                elif status == 'failed':
                    error_msg = data.get('error_msg', '未知错误')
                    print(f"❌ 任务失败: {error_msg}")
                    return {
                        'status': 'failed',
                        'error': error_msg,
                        'task_id': task_id,
                        'attempts': attempt + 1
                    }

                elif status in ['pending', 'processing', '']:
                    print(f"⏳ 任务状态: {status}")
                    # 继续等待

                else:
                    print(f"⚠️  未知状态: {status}")

            except Exception as e:
                print(f"⚠️  查询失败: {e}")

            # 等待下一次查询
            if attempt < max_attempts - 1:
                time.sleep(interval)

        # 超时
        print(f"\n⚠️  任务超时({max_attempts * interval}秒)")
        return {
            'status': 'timeout',
            'error': f'任务超时({max_attempts * interval}秒)',
            'task_id': task_id,
            'attempts': max_attempts
        }

    except Exception as e:
        print(f"❌ 任务提交失败: {e}")
        import traceback
        traceback.print_exc()
        return {
            'status': 'error',
            'error': str(e),
            'task_id': None
        }

def main():
    """主函数"""
    print("袜子多角度展示视频生成器")
    print("=" * 50)

    result = generate_socks_video()

    print("\n" + "=" * 50)
    print("最终结果:")
    print("=" * 50)

    if result['status'] == 'success':
        print("✅ 视频生成成功!")
        print(f"任务ID: {result['task_id']}")
        print(f"视频URL: {result.get('video_url', 'N/A')}")
        if 'local_path' in result:
            print(f"本地文件: {result['local_path']}")
        print(f"轮询次数: {result['attempts']}")
    elif result['status'] == 'failed':
        print("❌ 视频生成失败!")
        print(f"任务ID: {result['task_id']}")
        print(f"错误: {result['error']}")
    elif result['status'] == 'timeout':
        print("⚠️  任务超时!")
        print(f"任务ID: {result['task_id']}")
        print(f"错误: {result['error']}")
    else:
        print("❌ 任务错误!")
        print(f"错误: {result.get('error', '未知错误')}")

    print("=" * 50)

if __name__ == '__main__':

6. 查询生成任务脚本

query_video_task.py

python 复制代码
#!/usr/bin/env python3
"""
查询视频生成任务状态
"""

import os
import json
import time
import requests
import hashlib
import hmac
import datetime

# 配置
CONFIG = {
    'access_key': 'AKLTNjZlZDdiODI5YTk4NGFkYzlmZGY3ZDUwOTczMzEXXXX',
    'secret_key': 'WldSa1pEVmpaVFV6TXpVek5ETTVNR0V6T0dNeU4yTTNORGMzWVRBdXXXX==',
    'image2video_req_key': 'jimeng_i2v_first_v30_1080',
    'text2video_req_key': 'jimeng_t2v_v30_1080p',
    'aigc_meta': {
        'producer_id': 'rgzn',
        'propagate_id': 'syh',
        'content_producer': '葡萄星球',
        'content_propagator': 'default'
    }
}

# 签名函数
def sign(key, msg):
    return hmac.new(key, msg.encode('utf-8'), hashlib.sha256).digest()

def get_signature_key(key, date_stamp, region_name, service_name):
    k_date = sign(key.encode('utf-8'), date_stamp)
    k_region = sign(k_date, region_name)
    k_service = sign(k_region, service_name)
    k_signing = sign(k_service, 'request')
    return k_signing

def sign_request(access_key, secret_key, region, service, host, method, canonical_querystring, req_body):
    t = datetime.datetime.utcnow()
    current_date = t.strftime('%Y%m%dT%H%M%SZ')
    datestamp = t.strftime('%Y%m%d')

    canonical_uri = '/'
    signed_headers = 'content-type;host;x-content-sha256;x-date'
    payload_hash = hashlib.sha256(req_body.encode('utf-8')).hexdigest()
    content_type = 'application/json'

    canonical_headers = (
        f'content-type:{content_type}\n'
        f'host:{host}\n'
        f'x-content-sha256:{payload_hash}\n'
        f'x-date:{current_date}\n'
    )

    canonical_request = (
        f'{method}\n'
        f'{canonical_uri}\n'
        f'{canonical_querystring}\n'
        f'{canonical_headers}\n'
        f'{signed_headers}\n'
        f'{payload_hash}'
    )

    algorithm = 'HMAC-SHA256'
    credential_scope = f'{datestamp}/{region}/{service}/request'
    string_to_sign = (
        f'{algorithm}\n'
        f'{current_date}\n'
        f'{credential_scope}\n'
        f'{hashlib.sha256(canonical_request.encode("utf-8")).hexdigest()}'
    )

    signing_key = get_signature_key(secret_key, datestamp, region, service)
    signature = hmac.new(signing_key, string_to_sign.encode('utf-8'), hashlib.sha256).hexdigest()

    authorization_header = (
        f'{algorithm} Credential={access_key}/{credential_scope}, '
        f'SignedHeaders={signed_headers}, Signature={signature}'
    )

    headers = {
        'X-Date': current_date,
        'Authorization': authorization_header,
        'X-Content-Sha256': payload_hash,
        'Content-Type': content_type
    }

    request_url = f'https://{host}?{canonical_querystring}'

    return request_url, headers

def query_task(task_id, mode='image2video'):
    """查询任务状态"""
    print(f"=== 查询任务状态 ===")
    print(f"任务ID: {task_id}")
    print(f"模式: {mode}")

    region = 'cn-north-1'
    service = 'cv'
    host = 'visual.volcengineapi.com'
    method = 'POST'

    # 确定req_key
    req_key = CONFIG['image2video_req_key'] if mode == 'image2video' else CONFIG['text2video_req_key']

    # 构建查询payload
    req_json_str = json.dumps({"aigc_meta": CONFIG['aigc_meta']}, ensure_ascii=False)
    payload = {
        "req_key": req_key,
        "task_id": task_id,
        "req_json": req_json_str
    }

    query_params = {
        'Action': 'CVSync2AsyncGetResult',
        'Version': '2022-08-31'
    }
    canonical_querystring = '&'.join([f'{k}={v}' for k, v in sorted(query_params.items())])

    req_body = json.dumps(payload, ensure_ascii=False)

    print(f"查询payload: {json.dumps(payload, ensure_ascii=False)}")

    # 签名并发送请求
    url, headers = sign_request(
        CONFIG['access_key'],
        CONFIG['secret_key'],
        region,
        service,
        host,
        method,
        canonical_querystring,
        req_body
    )

    print(f"\n发送查询请求...")

    try:
        response = requests.post(url, headers=headers, data=req_body.encode('utf-8'), timeout=30)
        print(f"响应状态码: {response.status_code}")

        if response.status_code == 200:
            result = response.json()
            print(f"响应内容: {json.dumps(result, indent=2, ensure_ascii=False)}")

            # 解析结果
            data = result.get('data', {})
            status = data.get('status', '').lower()

            if status in ['done', 'success']:
                video_url = data.get('video_url')
                print(f"\n🎉 视频生成成功!")
                print(f"视频URL: {video_url}")

                # 尝试下载视频
                if video_url:
                    try:
                        print("尝试下载视频...")
                        video_response = requests.get(video_url, timeout=30)
                        if video_response.status_code == 200:
                            # 根据任务ID生成文件名
                            video_filename = f"socks_video_{task_id}.mp4"
                            video_path = f"/home/rgzn/.openclaw/workspace/{video_filename}"

                            with open(video_path, 'wb') as f:
                                f.write(video_response.content)

                            print(f"✅ 视频已下载到: {video_path}")
                            return {
                                'status': 'success',
                                'video_url': video_url,
                                'local_path': video_path,
                                'task_id': task_id
                            }
                        else:
                            print(f"⚠️  视频下载失败: HTTP {video_response.status_code}")
                    except Exception as e:
                        print(f"⚠️  视频下载失败: {e}")

                return {
                    'status': 'success',
                    'video_url': video_url,
                    'task_id': task_id
                }

            elif status == 'failed':
                error_msg = data.get('error_msg', '任务失败')
                print(f"\n❌ 视频生成失败: {error_msg}")
                return {
                    'status': 'failed',
                    'error': error_msg,
                    'task_id': task_id
                }

            elif status in ['pending', 'processing', '']:
                print(f"\n⏳ 任务状态: {status}")
                print("任务仍在处理中,请稍后再试")
                return {
                    'status': 'processing',
                    'current_status': status,
                    'task_id': task_id
                }

            else:
                print(f"\n⚠️  未知状态: {status}")
                return {
                    'status': 'unknown',
                    'current_status': status,
                    'task_id': task_id
                }

        else:
            print(f"\n❌ HTTP错误: {response.status_code}")
            print(f"响应内容: {response.text[:500]}")
            return {
                'status': 'http_error',
                'error': f'HTTP {response.status_code}',
                'task_id': task_id
            }

    except Exception as e:
        print(f"\n❌ 查询异常: {e}")
        import traceback
        traceback.print_exc()
        return {
            'status': 'error',
            'error': str(e),
            'task_id': task_id
        }

def main():
    """主函数"""
    print("视频生成任务查询工具")
    print("=" * 60)

    # 任务ID列表
    task_ids = [
        '13115669908804938365',  # 袜子展示视频(最新)
        '18025223537097267780',  # 之前的测试任务
    ]

    results = []

    for task_id in task_ids:
        print(f"\n{'='*60}")
        print(f"查询任务: {task_id}")
        print('='*60)

        # 先尝试image2video模式
        result = query_task(task_id, 'image2video')
        results.append(result)

        # 如果状态未知,尝试text2video模式
        if result['status'] in ['unknown', 'http_error']:
            print(f"\n尝试text2video模式...")
            result = query_task(task_id, 'text2video')
            results.append(result)

        # 短暂延迟
        time.sleep(1)

    # 汇总结果
    print(f"\n{'='*60}")
    print("查询结果汇总:")
    print('='*60)

    success_tasks = []
    processing_tasks = []
    failed_tasks = []

    for result in results:
        if result['status'] == 'success':
            success_tasks.append(result)
        elif result['status'] == 'processing':
            processing_tasks.append(result)
        elif result['status'] == 'failed':
            failed_tasks.append(result)

    if success_tasks:
        print(f"\n✅ 成功任务 ({len(success_tasks)}个):")
        for task in success_tasks:
            print(f"  任务ID: {task['task_id']}")
            if 'local_path' in task:
                print(f"  本地文件: {task['local_path']}")
            if 'video_url' in task:
                print(f"  视频URL: {task['video_url'][:80]}...")

    if processing_tasks:
        print(f"\n⏳ 处理中任务 ({len(processing_tasks)}个):")
        for task in processing_tasks:
            print(f"  任务ID: {task['task_id']}")
            print(f"  当前状态: {task.get('current_status', 'unknown')}")

    if failed_tasks:
        print(f"\n❌ 失败任务 ({len(failed_tasks)}个):")
        for task in failed_tasks:
            print(f"  任务ID: {task['task_id']}")
            print(f"  错误: {task.get('error', '未知错误')}")

    print('='*60)

if __name__ == '__main__':

7. 通过对话发送给OpenClaw(AccessKeyId和SecretAccessKey替换成自己的)

python 复制代码
我需要你帮我通过脚本调用即梦API生成视频,

脚本已经编写
核心脚本内容:~/.openclaw/workspace/nano volcengine_jimeng.py
提交任务脚本:~/.openclaw/workspace/generate_socks_video.py
查询任务脚本:~/.openclaw/workspace/query_video_task.py

脚本中的AccessKeyId和SecretAccessKey替换成如下:
AccessKeyId: AKLTOTgyOTQ1NGRlM2RiNGU2YzlkYmY3MmRhNzQzNTQ0ODk
SecretAccessKey: TnpRMk9URmhORE5qTjJZd05EazNaR0U0TnpKbFkyWXhNbUU1WldZNE1tSQ==

生成视频有文生视频和图生视频两种模式,通过对话触发,两种模式对话格式如下:
文生视频
提示词:山穷水复疑无路 柳暗花明又一村(帮我优化)
时长f:10
视频比例:16:9

图生视频
提示词:让哪吒在图片背景中从天而降,大喊我乃哪吒三太子
图片路径:D:\image\1.jpg
时长:10

关键参数说明
prompt: 视频提示词(中文)
image_urls: 图片URL列表(支持多个图片)
seed: 随机种子,-1表示随机
frames: 视频帧数(默认121帧≈10秒)
aspect_ratio: 视频比例(默认"16:9")

备注说明:
1.视频时长: frames=121对应约10秒视频
  帧数应该是24的倍数加1(如:25, 49, 73, 97, 121, 145, 169, 193, 217, 241, 265, 289等)
  帧数范围应该在73到289之间
2.你当前已经接入deepseek,apiKey请查看openclaw.json,当提示词后面备注有"帮我优化"类似字样时请在生成前先调用deepseek的api帮我优化提示词,在用新的提示词生成视频。
3.任务成功提交后,创建定时任务,每个30秒查询1次,直到查询到生成视频生成成功,超过5分钟超时停止查询。
4. 视频保存到我的电脑D:\generated_videos目录下
相关推荐
是晴天呀。10 天前
火山引擎接入项目
java·火山引擎
weixin_4566469911 天前
基于火山引擎 Ubuntu 24.04 预制镜像 30 分钟部署 OpenClaw 飞书办公助手
ubuntu·飞书·火山引擎
山顶听风11 天前
火山引擎 ArkClaw 抢先体验
火山引擎·智能体
无人装备硬件开发爱好者25 天前
硬核技术解析|MCP 协议实现语音 AI 与 ESP32 软 / 硬件的标准化对接:从火山引擎豆包认证到全链路落地——中
人工智能·esp32·火山引擎·mcp
无人装备硬件开发爱好者25 天前
硬核技术解析|MCP 协议实现语音 AI 与 ESP32 软 / 硬件的标准化对接:从火山引擎豆包认证到全链路落地——上
人工智能·esp32·火山引擎·mcp
数据猿25 天前
火山引擎的AI与云,正互为“梯子”
人工智能·火山引擎
newbiai1 个月前
2026马年春晚:火山引擎驱动AI新体验?
人工智能·python·火山引擎
福大大架构师每日一题1 个月前
openclaw v2026.2.21版本正式发布:新增Gemini 3.1支持、火山引擎对接、全新Discord语音系统与超200项安全和性能升级
安全·火山引擎·openclaw
火山引擎开发者社区2 个月前
火山引擎记忆库Mem0发布,全面兼容Mem0开源社区生态
开源·火山引擎