Video Generation by answerzhao/agent-skills
npx skills add https://github.com/answerzhao/agent-skills --skill 'Video Generation'本技能指导使用 z-ai-web-dev-sdk 包实现视频生成功能,使 AI 模型能够通过异步任务处理从文本描述或图像创建视频。
技能位置 : {project_path}/skills/video-generation
此技能位于您项目的上述路径中。
参考脚本 : 示例测试脚本位于 {技能位置}/scripts/ 目录中,用于快速测试和参考。请参阅 {技能位置}/scripts/video.ts 以获取工作示例。
视频生成允许您构建能够从文本提示或图像创建视频内容的应用程序,并具有可自定义的参数,如分辨率、帧率、持续时间和质量设置。API 使用异步任务模型,您需要创建任务并轮询结果。
重要提示 : z-ai-web-dev-sdk 必须仅在后端代码中使用。切勿在客户端代码中使用。
z-ai-web-dev-sdk 包已安装。请按照以下示例所示导入。
对于简单的视频生成任务,您可以使用 z-ai CLI 而不是编写代码。CLI 会自动处理任务创建和轮询,非常适合快速测试和简单自动化。
# 生成视频并自动轮询
z-ai video --prompt "A cat playing with a ball" --poll
# 使用短选项
z-ai video -p "Beautiful landscape with mountains" --poll
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
# 质量模式(速度或质量)
z-ai video -p "Ocean waves at sunset" --quality quality --poll
# 自定义分辨率和 FPS
z-ai video \
-p "City timelapse" \
--size "1920x1080" \
--fps 60 \
--poll
# 自定义持续时间(5 或 10 秒)
z-ai video -p "Fireworks display" --duration 10 --poll
# 从单个图像生成视频
z-ai video \
--image-url "https://example.com/image.png" \
--prompt "Make the scene come alive" \
--poll
# 使用短选项
z-ai video \
-i "https://example.com/photo.jpg" \
-p "Add motion to this scene" \
--poll
# 在两帧之间生成视频
z-ai video \
--image-url "https://example.com/start.png,https://example.com/end.png" \
--prompt "Smooth transition between frames" \
--poll
# 生成带有 AI 生成音频效果的视频
z-ai video \
-p "Thunder storm approaching" \
--with-audio \
--poll
# 将任务结果保存到 JSON 文件
z-ai video \
-p "Sunrise over mountains" \
--poll \
-o video_result.json
# 自定义轮询行为
z-ai video \
-p "Dancing robot" \
--poll \
--poll-interval 10 \
--max-polls 30
# 创建任务而不轮询(获取任务 ID)
z-ai video -p "Abstract art animation" -o task.json
--prompt, -p <text>: 可选 - 视频的文本描述--image-url, -i <URL>: 可选 - 图像 URL(单个或以逗号分隔的对)--quality, -q <mode>: 可选 - 输出模式:speed 或 quality(默认:speed)--with-audio: 可选 - 生成 AI 音频效果(默认:false)--size, -s <resolution>: 可选 - 视频分辨率(例如,"1920x1080")--fps <rate>: 可选 - 帧率:30 或 60(默认:30)--duration, -d <seconds>: 可选 - 持续时间:5 或 10 秒(默认:5)--model, -m <model>: 可选 - 要使用的模型名称--poll: 可选 - 自动轮询直到任务完成--poll-interval <seconds>: 可选 - 轮询间隔(默认:5)--max-polls <count>: 可选 - 最大轮询尝试次数(默认:60)--output, -o <path>: 可选 - 输出文件路径(JSON 格式)1024x1024768x1344864x11521344x7681152x8641440x720720x14401920x1080(以及其他标准分辨率)如果您创建任务时未使用 --poll,可以稍后检查其状态:
# 从初始响应中获取任务 ID
z-ai async-result --id "task-id-here" --poll
使用 CLI 用于:
使用 SDK 用于:
视频生成遵循两步异步模式:
import ZAI from 'z-ai-web-dev-sdk';
async function generateVideo(prompt) {
try {
const zai = await ZAI.create();
// 创建视频生成任务
const task = await zai.video.generations.create({
prompt: prompt,
quality: 'speed', // 'speed' 或 'quality'
with_audio: false,
size: '1920x1080',
fps: 30,
duration: 5
});
console.log('Task ID:', task.id);
console.log('Task Status:', task.task_status);
// 轮询结果
let result = await zai.async.result.query(task.id);
let pollCount = 0;
const maxPolls = 60;
const pollInterval = 5000; // 5 秒
while (result.task_status === 'PROCESSING' && pollCount < maxPolls) {
pollCount++;
console.log(`Polling ${pollCount}/${maxPolls}: Status is ${result.task_status}`);
await new Promise(resolve => setTimeout(resolve, pollInterval));
result = await zai.async.result.query(task.id);
}
if (result.task_status === 'SUCCESS') {
// 从多个可能的字段中获取视频 URL
const videoUrl = result.video_result?.[0]?.url ||
result.video_url ||
result.url ||
result.video;
console.log('Video URL:', videoUrl);
return videoUrl;
} else {
console.log('Task failed or still processing');
return null;
}
} catch (error) {
console.error('Video generation failed:', error.message);
throw error;
}
}
// 用法
const videoUrl = await generateVideo('A cat is playing with a ball.');
console.log('Generated video:', videoUrl);
import ZAI from 'z-ai-web-dev-sdk';
async function generateVideoFromImage(imageUrl, prompt) {
const zai = await ZAI.create();
// 单个图像作为起始帧
const task = await zai.video.generations.create({
image_url: imageUrl,
prompt: prompt,
quality: 'quality',
duration: 5,
fps: 30
});
return task;
}
// 用法
const task = await generateVideoFromImage(
'https://example.com/image.jpg',
'Animate this scene with gentle motion'
);
import ZAI from 'z-ai-web-dev-sdk';
async function generateVideoWithKeyframes(startImageUrl, endImageUrl, prompt) {
const zai = await ZAI.create();
// 用于起始和结束帧的两个图像
const task = await zai.video.generations.create({
image_url: [startImageUrl, endImageUrl],
prompt: prompt,
quality: 'quality',
duration: 10,
fps: 30
});
console.log('Task created with keyframes:', task.id);
return task;
}
// 用法
const task = await generateVideoWithKeyframes(
'https://example.com/start.jpg',
'https://example.com/end.jpg',
'Smooth transition between these scenes'
);
import ZAI from 'z-ai-web-dev-sdk';
async function checkTaskStatus(taskId) {
try {
const zai = await ZAI.create();
const result = await zai.async.result.query(taskId);
console.log('Task Status:', result.task_status);
if (result.task_status === 'SUCCESS') {
// 从结果中提取视频 URL
const videoUrl = result.video_result?.[0]?.url ||
result.video_url ||
result.url ||
result.video;
if (videoUrl) {
console.log('Video URL:', videoUrl);
return { success: true, url: videoUrl };
}
} else if (result.task_status === 'PROCESSING') {
console.log('Task is still processing');
return { success: false, status: 'processing' };
} else if (result.task_status === 'FAIL') {
console.log('Task failed');
return { success: false, status: 'failed' };
}
} catch (error) {
console.error('Query failed:', error.message);
throw error;
}
}
// 用法
const status = await checkTaskStatus('your-task-id-here');
import ZAI from 'z-ai-web-dev-sdk';
async function pollWithBackoff(taskId) {
const zai = await ZAI.create();
let pollInterval = 5000; // 从 5 秒开始
const maxInterval = 30000; // 最大 30 秒
const maxPolls = 40;
let pollCount = 0;
while (pollCount < maxPolls) {
const result = await zai.async.result.query(taskId);
pollCount++;
if (result.task_status === 'SUCCESS') {
const videoUrl = result.video_result?.[0]?.url ||
result.video_url ||
result.url ||
result.video;
return { success: true, url: videoUrl };
}
if (result.task_status === 'FAIL') {
return { success: false, error: 'Task failed' };
}
// 指数退避
console.log(`Poll ${pollCount}: Waiting ${pollInterval / 1000}s...`);
await new Promise(resolve => setTimeout(resolve, pollInterval));
pollInterval = Math.min(pollInterval * 1.5, maxInterval);
}
return { success: false, error: 'Timeout' };
}
import ZAI from 'z-ai-web-dev-sdk';
class VideoGenerationQueue {
constructor() {
this.tasks = new Map();
}
async initialize() {
this.zai = await ZAI.create();
}
async createVideo(params) {
const task = await this.zai.video.generations.create(params);
this.tasks.set(task.id, {
taskId: task.id,
status: task.task_status,
params: params,
createdAt: new Date()
});
return task.id;
}
async checkTask(taskId) {
const result = await this.zai.async.result.query(taskId);
const taskInfo = this.tasks.get(taskId);
if (taskInfo) {
taskInfo.status = result.task_status;
taskInfo.lastChecked = new Date();
if (result.task_status === 'SUCCESS') {
taskInfo.videoUrl = result.video_result?.[0]?.url ||
result.video_url ||
result.url ||
result.video;
}
}
return result;
}
async pollTask(taskId, options = {}) {
const maxPolls = options.maxPolls || 60;
const pollInterval = options.pollInterval || 5000;
let pollCount = 0;
while (pollCount < maxPolls) {
const result = await this.checkTask(taskId);
if (result.task_status === 'SUCCESS' || result.task_status === 'FAIL') {
return result;
}
pollCount++;
await new Promise(resolve => setTimeout(resolve, pollInterval));
}
throw new Error('Task polling timeout');
}
getTask(taskId) {
return this.tasks.get(taskId);
}
getAllTasks() {
return Array.from(this.tasks.values());
}
}
// 用法
const queue = new VideoGenerationQueue();
await queue.initialize();
const taskId = await queue.createVideo({
prompt: 'A sunset over the ocean',
quality: 'quality',
duration: 5
});
const result = await queue.pollTask(taskId);
console.log('Video ready:', result.video_result?.[0]?.url);
import ZAI from 'z-ai-web-dev-sdk';
async function generateMultipleVideos(prompts) {
const zai = await ZAI.create();
const tasks = [];
// 创建所有任务
for (const prompt of prompts) {
const task = await zai.video.generations.create({
prompt: prompt,
quality: 'speed',
duration: 5
});
tasks.push({ taskId: task.id, prompt: prompt });
}
console.log(`Created ${tasks.length} video generation tasks`);
// 轮询所有任务
const results = [];
for (const task of tasks) {
const result = await pollTaskUntilComplete(zai, task.taskId);
results.push({
prompt: task.prompt,
taskId: task.taskId,
...result
});
}
return results;
}
async function pollTaskUntilComplete(zai, taskId) {
let pollCount = 0;
const maxPolls = 60;
while (pollCount < maxPolls) {
const result = await zai.async.result.query(taskId);
if (result.task_status === 'SUCCESS') {
return {
success: true,
url: result.video_result?.[0]?.url ||
result.video_url ||
result.url ||
result.video
};
}
if (result.task_status === 'FAIL') {
return { success: false, error: 'Generation failed' };
}
pollCount++;
await new Promise(resolve => setTimeout(resolve, 5000));
}
return { success: false, error: 'Timeout' };
}
// 用法
const prompts = [
'A cat playing with yarn',
'A dog running in a park',
'A bird flying in the sky'
];
const videos = await generateMultipleVideos(prompts);
videos.forEach(video => {
console.log(`${video.prompt}: ${video.success ? video.url : video.error}`);
});
| 参数 | 类型 | 必需 | 描述 | 默认值 |
|---|---|---|---|---|
prompt | string | 可选* | 视频的文本描述 | - |
image_url | string | string[] | 可选* | 用于生成的图像 URL |
quality | string | 可选 | 输出模式:'speed' 或 'quality' | 'speed' |
with_audio | boolean | 可选 | 生成 AI 音频效果 | false |
size | string | 可选 | 视频分辨率(例如,'1920x1080') | - |
fps | number | 可选 | 帧率:30 或 60 | 30 |
duration | number | 可选 | 持续时间(秒):5 或 10 | 5 |
model | string | 可选 | 模型名称 | - |
*注意:必须提供 prompt 或 image_url 中的至少一个。
// 单个图像(起始帧)
image_url: 'https://example.com/image.jpg'
// 多个图像(起始和结束帧)
image_url: [
'https://example.com/start.jpg',
'https://example.com/end.jpg'
]
PROCESSING:任务正在处理中SUCCESS:任务成功完成FAIL:任务失败{
"id": "task-12345",
"task_status": "PROCESSING",
"model": "video-model-v1"
}
{
"task_status": "SUCCESS",
"model": "video-model-v1",
"request_id": "req-67890",
"video_result": [
{
"url": "https://cdn.example.com/generated-video.mp4"
}
]
}
{
"task_status": "PROCESSING",
"id": "task-12345",
"model": "video-model-v1"
}
// 推荐的轮询实现
async function smartPoll(zai, taskId) {
// 立即检查(某些任务完成很快)
let result = await zai.async.result.query(taskId);
if (result.task_status !== 'PROCESSING') {
return result;
}
// 以合理的间隔开始轮询
let interval = 5000; // 5 秒
let maxPolls = 60; // 总共 5 分钟
for (let i = 0; i < maxPolls; i++) {
await new Promise(resolve => setTimeout(resolve, interval));
result = await zai.async.result.query(taskId);
if (result.task_status !== 'PROCESSING') {
return result;
}
}
throw new Error('Task timeout');
}
async function safeVideoGeneration(params) {
try {
const zai = await ZAI.create();
// 验证参数
if (!params.prompt && !params.image_url) {
throw new Error('Either prompt or image_url is required');
}
const task = await zai.video.generations.create(params);
const result = await smartPoll(zai, task.id);
if (result.task_status === 'SUCCESS') {
const videoUrl = result.video_result?.[0]?.url ||
result.video_url ||
result.url ||
result.video;
if (!videoUrl) {
throw new Error('Video URL not found in response');
}
return {
success: true,
url: videoUrl,
taskId: task.id
};
} else {
return {
success: false,
error: 'Video generation failed',
taskId: task.id
};
}
} catch (error) {
console.error('Video generation error:', error);
return {
success: false,
error: error.message
};
}
}
// 用于预览或高容量的快速生成
const quickVideo = await zai.video.generations.create({
prompt: 'A cat playing',
quality: 'speed',
duration: 5,
fps: 30
});
// 用于最终生产的高质量
const qualityVideo = await zai.video.generations.create({
prompt: 'A cat playing',
quality: 'quality',
duration: 10,
fps: 60,
size: '1920x1080'
});
import express from 'express';
import ZAI from 'z-ai-web-dev-sdk';
const app = express();
app.use(express.json());
let zaiInstance;
async function initZAI() {
zaiInstance = await ZAI.create();
}
// 创建视频生成任务
app.post('/api/video/create', async (req, res) => {
try {
const { prompt, image_url, quality, duration } = req.body;
if (!prompt && !image_url) {
return res.status(400).json({
error: 'Either prompt or image_url is required'
});
}
const task = await zaiInstance.video.generations.create({
prompt,
image_url,
quality: quality || 'speed',
duration: duration || 5,
fps: 30
});
res.json({
success: true,
taskId: task.id,
status: task.task_status
});
} catch (error) {
res.status(500).json({
success: false,
error: error.message
});
}
});
// 查询任务状态
app.get('/api/video/status/:taskId', async (req, res) => {
try {
const { taskId } = req.params;
const result = await zaiInstance.async.result.query(taskId);
const response = {
taskId: taskId,
status: result.task_status
};
if (result.task_status === 'SUCCESS') {
response.videoUrl = result.video_result?.[0]?.url ||
result.video_url ||
result.url ||
result.video;
}
res.json(response);
} catch (error) {
res.status(500).json({
success: false,
error: error.message
});
}
});
initZAI().then(() => {
app.listen(3000, () => {
console.log('Video generation API running on port 3000');
});
});
import WebSocket from 'ws';
import ZAI from 'z-ai-web-dev-sdk';
const wss = new WebSocket.Server({ port: 8080 });
let zaiInstance;
async function initZAI() {
zaiInstance = await ZAI.create();
}
wss.on('connection', (ws) => {
ws.on('message', async (message) => {
try {
const data = JSON.parse(message);
if (data.action === 'generate') {
// 创建任务
const task = await zaiInstance.video.generations.create(data.params);
ws.send(JSON.stringify({
type: 'task_created',
taskId: task.id
}));
// 轮询结果并发送更新
pollAndNotify(ws, task.id);
}
} catch (error) {
ws.send(JSON.stringify({
type: 'error',
message: error.message
}));
}
});
});
async function pollAndNotify(ws, taskId) {
let pollCount = 0;
const maxPolls = 60;
while (pollCount < maxPolls) {
const result = await zaiInstance.async.result.query(taskId);
ws.send(JSON.stringify({
type: 'status_update',
taskId: taskId,
status: result.task_status
}));
if (result.task_status === 'SUCCESS') {
ws.send(JSON.stringify({
type: 'complete',
taskId: taskId,
videoUrl: result.video_result?.[0]?.url ||
result.video_url ||
result.url ||
result.video
}));
break;
}
if (result.task_status === 'FAIL') {
ws.send(JSON.stringify({
type: 'failed',
taskId: taskId
}));
break;
}
pollCount++;
await new Promise(resolve => setTimeout(resolve, 5000));
}
}
initZAI();
问题:"SDK 必须用于后端"
问题:任务无限期保持在 PROCESSING 状态
问题:响应中未找到视频 URL
问题:任务立即失败
问题:视频生成缓慢
问题:轮询超时
每周安装次数
0
仓库
GitHub 星标数
24
首次出现时间
1970年1月1日
安全审计
This skill guides the implementation of video generation functionality using the z-ai-web-dev-sdk package, enabling AI models to create videos from text descriptions or images through asynchronous task processing.
Skill Location : {project_path}/skills/video-generation
This skill is located at the above path in your project.
Reference Scripts : Example test scripts are available in the {Skill Location}/scripts/ directory for quick testing and reference. See {Skill Location}/scripts/video.ts for a working example.
Video Generation allows you to build applications that can create video content from text prompts or images, with customizable parameters like resolution, frame rate, duration, and quality settings. The API uses an asynchronous task model where you create a task and poll for results.
IMPORTANT : z-ai-web-dev-sdk MUST be used in backend code only. Never use it in client-side code.
The z-ai-web-dev-sdk package is already installed. Import it as shown in the examples below.
For simple video generation tasks, you can use the z-ai CLI instead of writing code. The CLI handles task creation and polling automatically, making it ideal for quick tests and simple automation.
# Generate video with automatic polling
z-ai video --prompt "A cat playing with a ball" --poll
# Using short options
z-ai video -p "Beautiful landscape with mountains" --poll
# Quality mode (speed or quality)
z-ai video -p "Ocean waves at sunset" --quality quality --poll
# Custom resolution and FPS
z-ai video \
-p "City timelapse" \
--size "1920x1080" \
--fps 60 \
--poll
# Custom duration (5 or 10 seconds)
z-ai video -p "Fireworks display" --duration 10 --poll
# Generate video from single image
z-ai video \
--image-url "https://example.com/image.png" \
--prompt "Make the scene come alive" \
--poll
# Using short option
z-ai video \
-i "https://example.com/photo.jpg" \
-p "Add motion to this scene" \
--poll
# Generate video between two frames
z-ai video \
--image-url "https://example.com/start.png,https://example.com/end.png" \
--prompt "Smooth transition between frames" \
--poll
# Generate video with AI-generated audio effects
z-ai video \
-p "Thunder storm approaching" \
--with-audio \
--poll
# Save task result to JSON file
z-ai video \
-p "Sunrise over mountains" \
--poll \
-o video_result.json
# Customize polling behavior
z-ai video \
-p "Dancing robot" \
--poll \
--poll-interval 10 \
--max-polls 30
# Create task without polling (get task ID)
z-ai video -p "Abstract art animation" -o task.json
--prompt, -p <text>: Optional - Text description of the video--image-url, -i <URL>: Optional - Image URL (single or comma-separated pair)--quality, -q <mode>: Optional - Output mode: speed or quality (default: speed)--with-audio: Optional - Generate AI audio effects (default: false)--size, -s <resolution>: Optional - Video resolution (e.g., "1920x1080")--fps <rate>: Optional - Frame rate: 30 or 60 (default: 30)--duration, -d <seconds>: Optional - Duration: 5 or 10 seconds (default: 5)1024x1024768x1344864x11521344x7681152x8641440x720720x14401920x1080 (and other standard resolutions)If you create a task without --poll, you can check its status later:
# Get the task ID from the initial response
z-ai async-result --id "task-id-here" --poll
Use CLI for:
Use SDK for:
Video generation follows a two-step asynchronous pattern:
import ZAI from 'z-ai-web-dev-sdk';
async function generateVideo(prompt) {
try {
const zai = await ZAI.create();
// Create video generation task
const task = await zai.video.generations.create({
prompt: prompt,
quality: 'speed', // 'speed' or 'quality'
with_audio: false,
size: '1920x1080',
fps: 30,
duration: 5
});
console.log('Task ID:', task.id);
console.log('Task Status:', task.task_status);
// Poll for results
let result = await zai.async.result.query(task.id);
let pollCount = 0;
const maxPolls = 60;
const pollInterval = 5000; // 5 seconds
while (result.task_status === 'PROCESSING' && pollCount < maxPolls) {
pollCount++;
console.log(`Polling ${pollCount}/${maxPolls}: Status is ${result.task_status}`);
await new Promise(resolve => setTimeout(resolve, pollInterval));
result = await zai.async.result.query(task.id);
}
if (result.task_status === 'SUCCESS') {
// Get video URL from multiple possible fields
const videoUrl = result.video_result?.[0]?.url ||
result.video_url ||
result.url ||
result.video;
console.log('Video URL:', videoUrl);
return videoUrl;
} else {
console.log('Task failed or still processing');
return null;
}
} catch (error) {
console.error('Video generation failed:', error.message);
throw error;
}
}
// Usage
const videoUrl = await generateVideo('A cat is playing with a ball.');
console.log('Generated video:', videoUrl);
import ZAI from 'z-ai-web-dev-sdk';
async function generateVideoFromImage(imageUrl, prompt) {
const zai = await ZAI.create();
// Single image as starting frame
const task = await zai.video.generations.create({
image_url: imageUrl,
prompt: prompt,
quality: 'quality',
duration: 5,
fps: 30
});
return task;
}
// Usage
const task = await generateVideoFromImage(
'https://example.com/image.jpg',
'Animate this scene with gentle motion'
);
import ZAI from 'z-ai-web-dev-sdk';
async function generateVideoWithKeyframes(startImageUrl, endImageUrl, prompt) {
const zai = await ZAI.create();
// Two images for start and end frames
const task = await zai.video.generations.create({
image_url: [startImageUrl, endImageUrl],
prompt: prompt,
quality: 'quality',
duration: 10,
fps: 30
});
console.log('Task created with keyframes:', task.id);
return task;
}
// Usage
const task = await generateVideoWithKeyframes(
'https://example.com/start.jpg',
'https://example.com/end.jpg',
'Smooth transition between these scenes'
);
import ZAI from 'z-ai-web-dev-sdk';
async function checkTaskStatus(taskId) {
try {
const zai = await ZAI.create();
const result = await zai.async.result.query(taskId);
console.log('Task Status:', result.task_status);
if (result.task_status === 'SUCCESS') {
// Extract video URL from result
const videoUrl = result.video_result?.[0]?.url ||
result.video_url ||
result.url ||
result.video;
if (videoUrl) {
console.log('Video URL:', videoUrl);
return { success: true, url: videoUrl };
}
} else if (result.task_status === 'PROCESSING') {
console.log('Task is still processing');
return { success: false, status: 'processing' };
} else if (result.task_status === 'FAIL') {
console.log('Task failed');
return { success: false, status: 'failed' };
}
} catch (error) {
console.error('Query failed:', error.message);
throw error;
}
}
// Usage
const status = await checkTaskStatus('your-task-id-here');
import ZAI from 'z-ai-web-dev-sdk';
async function pollWithBackoff(taskId) {
const zai = await ZAI.create();
let pollInterval = 5000; // Start with 5 seconds
const maxInterval = 30000; // Max 30 seconds
const maxPolls = 40;
let pollCount = 0;
while (pollCount < maxPolls) {
const result = await zai.async.result.query(taskId);
pollCount++;
if (result.task_status === 'SUCCESS') {
const videoUrl = result.video_result?.[0]?.url ||
result.video_url ||
result.url ||
result.video;
return { success: true, url: videoUrl };
}
if (result.task_status === 'FAIL') {
return { success: false, error: 'Task failed' };
}
// Exponential backoff
console.log(`Poll ${pollCount}: Waiting ${pollInterval / 1000}s...`);
await new Promise(resolve => setTimeout(resolve, pollInterval));
pollInterval = Math.min(pollInterval * 1.5, maxInterval);
}
return { success: false, error: 'Timeout' };
}
import ZAI from 'z-ai-web-dev-sdk';
class VideoGenerationQueue {
constructor() {
this.tasks = new Map();
}
async initialize() {
this.zai = await ZAI.create();
}
async createVideo(params) {
const task = await this.zai.video.generations.create(params);
this.tasks.set(task.id, {
taskId: task.id,
status: task.task_status,
params: params,
createdAt: new Date()
});
return task.id;
}
async checkTask(taskId) {
const result = await this.zai.async.result.query(taskId);
const taskInfo = this.tasks.get(taskId);
if (taskInfo) {
taskInfo.status = result.task_status;
taskInfo.lastChecked = new Date();
if (result.task_status === 'SUCCESS') {
taskInfo.videoUrl = result.video_result?.[0]?.url ||
result.video_url ||
result.url ||
result.video;
}
}
return result;
}
async pollTask(taskId, options = {}) {
const maxPolls = options.maxPolls || 60;
const pollInterval = options.pollInterval || 5000;
let pollCount = 0;
while (pollCount < maxPolls) {
const result = await this.checkTask(taskId);
if (result.task_status === 'SUCCESS' || result.task_status === 'FAIL') {
return result;
}
pollCount++;
await new Promise(resolve => setTimeout(resolve, pollInterval));
}
throw new Error('Task polling timeout');
}
getTask(taskId) {
return this.tasks.get(taskId);
}
getAllTasks() {
return Array.from(this.tasks.values());
}
}
// Usage
const queue = new VideoGenerationQueue();
await queue.initialize();
const taskId = await queue.createVideo({
prompt: 'A sunset over the ocean',
quality: 'quality',
duration: 5
});
const result = await queue.pollTask(taskId);
console.log('Video ready:', result.video_result?.[0]?.url);
import ZAI from 'z-ai-web-dev-sdk';
async function generateMultipleVideos(prompts) {
const zai = await ZAI.create();
const tasks = [];
// Create all tasks
for (const prompt of prompts) {
const task = await zai.video.generations.create({
prompt: prompt,
quality: 'speed',
duration: 5
});
tasks.push({ taskId: task.id, prompt: prompt });
}
console.log(`Created ${tasks.length} video generation tasks`);
// Poll all tasks
const results = [];
for (const task of tasks) {
const result = await pollTaskUntilComplete(zai, task.taskId);
results.push({
prompt: task.prompt,
taskId: task.taskId,
...result
});
}
return results;
}
async function pollTaskUntilComplete(zai, taskId) {
let pollCount = 0;
const maxPolls = 60;
while (pollCount < maxPolls) {
const result = await zai.async.result.query(taskId);
if (result.task_status === 'SUCCESS') {
return {
success: true,
url: result.video_result?.[0]?.url ||
result.video_url ||
result.url ||
result.video
};
}
if (result.task_status === 'FAIL') {
return { success: false, error: 'Generation failed' };
}
pollCount++;
await new Promise(resolve => setTimeout(resolve, 5000));
}
return { success: false, error: 'Timeout' };
}
// Usage
const prompts = [
'A cat playing with yarn',
'A dog running in a park',
'A bird flying in the sky'
];
const videos = await generateMultipleVideos(prompts);
videos.forEach(video => {
console.log(`${video.prompt}: ${video.success ? video.url : video.error}`);
});
| Parameter | Type | Required | Description | Default |
|---|---|---|---|---|
prompt | string | Optional* | Text description of the video | - |
image_url | string | string[] | Optional* | Image URL(s) for generation |
quality | string | Optional | Output mode: 'speed' or 'quality' |
*Note: At least one of prompt or image_url must be provided.
// Single image (starting frame)
image_url: 'https://example.com/image.jpg'
// Multiple images (start and end frames)
image_url: [
'https://example.com/start.jpg',
'https://example.com/end.jpg'
]
PROCESSING: Task is being processedSUCCESS: Task completed successfullyFAIL: Task failed{
"id": "task-12345",
"task_status": "PROCESSING",
"model": "video-model-v1"
}
{
"task_status": "SUCCESS",
"model": "video-model-v1",
"request_id": "req-67890",
"video_result": [
{
"url": "https://cdn.example.com/generated-video.mp4"
}
]
}
{
"task_status": "PROCESSING",
"id": "task-12345",
"model": "video-model-v1"
}
// Recommended polling implementation
async function smartPoll(zai, taskId) {
// Check immediately (some tasks complete fast)
let result = await zai.async.result.query(taskId);
if (result.task_status !== 'PROCESSING') {
return result;
}
// Start polling with reasonable intervals
let interval = 5000; // 5 seconds
let maxPolls = 60; // 5 minutes total
for (let i = 0; i < maxPolls; i++) {
await new Promise(resolve => setTimeout(resolve, interval));
result = await zai.async.result.query(taskId);
if (result.task_status !== 'PROCESSING') {
return result;
}
}
throw new Error('Task timeout');
}
async function safeVideoGeneration(params) {
try {
const zai = await ZAI.create();
// Validate parameters
if (!params.prompt && !params.image_url) {
throw new Error('Either prompt or image_url is required');
}
const task = await zai.video.generations.create(params);
const result = await smartPoll(zai, task.id);
if (result.task_status === 'SUCCESS') {
const videoUrl = result.video_result?.[0]?.url ||
result.video_url ||
result.url ||
result.video;
if (!videoUrl) {
throw new Error('Video URL not found in response');
}
return {
success: true,
url: videoUrl,
taskId: task.id
};
} else {
return {
success: false,
error: 'Video generation failed',
taskId: task.id
};
}
} catch (error) {
console.error('Video generation error:', error);
return {
success: false,
error: error.message
};
}
}
// Fast generation for previews or high volume
const quickVideo = await zai.video.generations.create({
prompt: 'A cat playing',
quality: 'speed',
duration: 5,
fps: 30
});
// High quality for final production
const qualityVideo = await zai.video.generations.create({
prompt: 'A cat playing',
quality: 'quality',
duration: 10,
fps: 60,
size: '1920x1080'
});
import express from 'express';
import ZAI from 'z-ai-web-dev-sdk';
const app = express();
app.use(express.json());
let zaiInstance;
async function initZAI() {
zaiInstance = await ZAI.create();
}
// Create video generation task
app.post('/api/video/create', async (req, res) => {
try {
const { prompt, image_url, quality, duration } = req.body;
if (!prompt && !image_url) {
return res.status(400).json({
error: 'Either prompt or image_url is required'
});
}
const task = await zaiInstance.video.generations.create({
prompt,
image_url,
quality: quality || 'speed',
duration: duration || 5,
fps: 30
});
res.json({
success: true,
taskId: task.id,
status: task.task_status
});
} catch (error) {
res.status(500).json({
success: false,
error: error.message
});
}
});
// Query task status
app.get('/api/video/status/:taskId', async (req, res) => {
try {
const { taskId } = req.params;
const result = await zaiInstance.async.result.query(taskId);
const response = {
taskId: taskId,
status: result.task_status
};
if (result.task_status === 'SUCCESS') {
response.videoUrl = result.video_result?.[0]?.url ||
result.video_url ||
result.url ||
result.video;
}
res.json(response);
} catch (error) {
res.status(500).json({
success: false,
error: error.message
});
}
});
initZAI().then(() => {
app.listen(3000, () => {
console.log('Video generation API running on port 3000');
});
});
import WebSocket from 'ws';
import ZAI from 'z-ai-web-dev-sdk';
const wss = new WebSocket.Server({ port: 8080 });
let zaiInstance;
async function initZAI() {
zaiInstance = await ZAI.create();
}
wss.on('connection', (ws) => {
ws.on('message', async (message) => {
try {
const data = JSON.parse(message);
if (data.action === 'generate') {
// Create task
const task = await zaiInstance.video.generations.create(data.params);
ws.send(JSON.stringify({
type: 'task_created',
taskId: task.id
}));
// Poll for results and send updates
pollAndNotify(ws, task.id);
}
} catch (error) {
ws.send(JSON.stringify({
type: 'error',
message: error.message
}));
}
});
});
async function pollAndNotify(ws, taskId) {
let pollCount = 0;
const maxPolls = 60;
while (pollCount < maxPolls) {
const result = await zaiInstance.async.result.query(taskId);
ws.send(JSON.stringify({
type: 'status_update',
taskId: taskId,
status: result.task_status
}));
if (result.task_status === 'SUCCESS') {
ws.send(JSON.stringify({
type: 'complete',
taskId: taskId,
videoUrl: result.video_result?.[0]?.url ||
result.video_url ||
result.url ||
result.video
}));
break;
}
if (result.task_status === 'FAIL') {
ws.send(JSON.stringify({
type: 'failed',
taskId: taskId
}));
break;
}
pollCount++;
await new Promise(resolve => setTimeout(resolve, 5000));
}
}
initZAI();
Issue : "SDK must be used in backend"
Issue : Task stays in PROCESSING status indefinitely
Issue : Video URL not found in response
Issue : Task fails immediately
Issue : Slow video generation
Issue : Polling timeout
Weekly Installs
0
Repository
GitHub Stars
24
First Seen
Jan 1, 1970
Security Audits
AI Elements:基于shadcn/ui的AI原生应用组件库,快速构建对话界面
60,400 周安装
--model, -m <model>: Optional - Model name to use--poll: Optional - Auto-poll until task completes--poll-interval <seconds>: Optional - Polling interval (default: 5)--max-polls <count>: Optional - Maximum poll attempts (default: 60)--output, -o <path>: Optional - Output file path (JSON format)'speed' |
with_audio | boolean | Optional | Generate AI audio effects | false |
size | string | Optional | Video resolution (e.g., '1920x1080') | - |
fps | number | Optional | Frame rate: 30 or 60 | 30 |
duration | number | Optional | Duration in seconds: 5 or 10 | 5 |
model | string | Optional | Model name | - |