Generating Videos Using Runway
Learn how to generate AI-powered videos using RunwayML's Gen-4 models available through the AvalAI API.
Introduction
The AvalAI Video API provides endpoints for video generation using RunwayML's cutting-edge Gen-4 models, including the new gen4.5 - their most advanced video generation model to date. These state-of-the-art models can create realistic and imaginative videos from text descriptions combined with reference images, with support for:
- Image-to-Video: Generate dynamic videos starting from a reference image
- Text-Guided Generation: Control video content with detailed text prompts
- Flexible Duration: Create videos from 2 to 10 seconds
- Asynchronous Processing: Generate videos with status polling
- Multiple Resolutions: Support for various aspect ratios and resolutions
This guide covers using these capabilities via AvalAI to create compelling video content with RunwayML's Gen-4 technology.
⚠️ IMPORTANT: Connection Interruptions
Video generation operations are asynchronous - the server begins processing your request immediately upon submission. If your connection is interrupted during or after submission, DO NOT immediately retry with a new generation request, as this may result in duplicate charges.
What to do if your connection is interrupted:
Use the List Videos endpoint to retrieve all your videos:
curl -X GET https://api.avalai.ir/v1/videos/
-H "Authorization: Bearer $AVALAI_API_KEY"Check the
statusfield of your most recent video:
- If
status == "failed": The video did not start generating, and no costs will apply. You can safely submit a new request.- If
statusis anything other than"failed"(e.g.,"queued","processing","completed"): The generation has started or completed, and costs will be charged. Wait for this video to complete instead of creating a duplicate request.This practice helps you avoid unnecessary credit usage and duplicate video generations.
About gen4.5 (NEW)
RunwayML's gen4.5 is their most advanced video generation model, representing a new frontier for video generation:
- Exceptional Realism: Industry-leading visual quality with natural physics and lighting
- Superior Coherence: Advanced temporal consistency for smooth, believable motion
- Duration: Up to 10 seconds of generated video
- Pricing: $0.12 per second of generated video
- Input Support: Text-to-video with optional reference image
- Use Cases: Professional content creation, cinematic sequences, creative productions
- Processing: Asynchronous with status polling
Gen4.5 excels at creating highly realistic video content with exceptional attention to physics, lighting, and natural motion.
About gen4_turbo
RunwayML's gen4_turbo is a high-performance video generation model optimized for speed and quality:
- Resolution Support: Multiple resolutions from 720x720 to 2112x912
- Duration: 2 to 10 seconds (flexible)
- Pricing: $0.10 per second of generated video
- Input Requirement: Requires a reference image (
input_reference) - Use Cases: Creative content, social media videos, product demos, storytelling
- Processing: Asynchronous with status polling
The model excels at creating smooth, coherent video sequences that extend and animate reference images based on your text prompts.
⚠️ Important: Prompt Character Limit
The
promptfield has a maximum limit of 1000 characters. If your prompt exceeds this limit, the API will return an error and the video generation will fail. Keep your prompts concise and focused on the most important visual and motion elements.
Basic Video Generation
To generate a video with RunwayML, you need to provide both a text prompt and a reference image. The model will use the image as a starting point and animate it according to your prompt.
Example Reference Image: Download monster_original_720p.jpeg
from openai import OpenAI
import time
client = OpenAI(api_key="your-avalai-api-key", base_url="https://api.avalai.ir/v1")
# Create video generation request with image reference
video = client.videos.create(
model="gen4_turbo",
prompt="The fridge door opens. A cute, chubby purple monster comes out of it.",
input_reference=open("monster_original_720p.jpeg", "rb"),
size="1280x720",
seconds="2",
safety_identifier="project_demo_001", # Optional: for internal tracking
)
print(f"Video generation started: {video.id}")
print(f"Request ID: {video.request_id}") # Use for cost tracking
# Poll for completion
while True:
video_status = client.videos.retrieve(video.id)
if video_status.status == "completed":
print(f"Video ready! ID: {video.id}")
# Download the video content
with client.with_streaming_response.videos.retrieve_content(
video.id
) as response:
with open("runway_output.mp4", "wb") as f:
for chunk in response.iter_bytes():
f.write(chunk)
print("Video downloaded to runway_output.mp4")
break
elif video_status.status == "failed":
print(f"Generation failed: {video_status.error}")
break
time.sleep(10)# Create video generation request with image reference and safety_identifier
curl -X POST "https://api.avalai.ir/v1/videos" \
-H "Authorization: Bearer $AVALAI_API_KEY" \
-H "Content-Type: multipart/form-data" \
-F "prompt=The fridge door opens. A cute, chubby purple monster comes out of it." \
-F "model=gen4_turbo" \
-F "size=1280x720" \
-F "seconds=2" \
-F "safety_identifier=project_demo_001" \
-F "input_reference=@monster_original_720p.jpeg;type=image/jpeg"
# Check generation status
curl -X GET https://api.avalai.ir/v1/videos/video_45d4cf58-6c37-43f1-b7ca-8f349f280a3e \
-H "Authorization: Bearer $AVALAI_API_KEY"
# Download completed video
curl -X GET https://api.avalai.ir/v1/videos/video_45d4cf58-6c37-43f1-b7ca-8f349f280a3e/content \
-H "Authorization: Bearer $AVALAI_API_KEY" \
--output runway_video.mp4import OpenAI from 'openai';
import fs from 'fs';
const client = new OpenAI({
apiKey: process.env.AVALAI_API_KEY,
baseURL: 'https://api.avalai.ir/v1'
});
async function generateVideo() {
// Create video generation request with image reference
const video = await client.videos.create({
model: 'gen4_turbo',
prompt: 'The fridge door opens. A cute, chubby purple monster comes out of it.',
input_reference: fs.createReadStream('monster_original_720p.jpeg'),
size: '1280x720',
seconds: '2',
safety_identifier: 'project_demo_001' // Optional: for internal tracking
});
console.log(`Video generation started: ${video.id}`);
console.log(`Request ID: ${video.request_id}`); // Use for cost tracking
// Poll for completion
while (true) {
const videoStatus = await client.videos.retrieve(video.id);
if (videoStatus.status === 'completed') {
console.log(`Video ready! ID: ${video.id}`);
// Download the video content
const response = await client.videos.retrieveContent(video.id);
const buffer = Buffer.from(await response.arrayBuffer());
fs.writeFileSync('runway_output.mp4', buffer);
console.log('Video downloaded to runway_output.mp4');
break;
} else if (videoStatus.status === 'failed') {
console.log(`Generation failed: ${videoStatus.error}`);
break;
}
await new Promise(resolve => setTimeout(resolve, 10000));
}
}
generateVideo();Supported Resolutions
RunwayML's gen4_turbo model supports a wide range of resolutions to fit various use cases:
Standard Resolutions
- 1024x1024 - Square (default)
- 1080x1080 - Square HD
- 720x720 - Small square
Landscape Resolutions
- 1920x1080 - Full HD landscape
- 1280x720 - HD landscape
- 1808x768 - Ultrawide landscape
- 2112x912 - Cinematic landscape
- 1680x720 - Wide landscape
- 1168x880 - Wide landscape
- 1360x768 - Standard landscape
Portrait Resolutions
- 1080x1920 - Full HD portrait
- 720x1280 - HD portrait
- 1080x1440 - Tall portrait
- 720x960 - Standard portrait
Choose the resolution that best matches your content platform and aspect ratio requirements.
Checking Video Status
For production applications, polling provides a reliable way to check when video generation completes.
from openai import OpenAI
import time
client = OpenAI(api_key="your-avalai-api-key", base_url="https://api.avalai.ir/v1")
def check_video_status(video_id):
"""Poll for video completion with exponential backoff"""
max_attempts = 60
wait_time = 10
for attempt in range(max_attempts):
video_status = client.videos.retrieve(video_id)
if video_status.status == "completed":
print(f"Video {video_id} completed!")
print(f"Usage: {video_status.usage}")
print(f"Estimated cost: {video_status.estimated_cost}")
# Download the video
with client.with_streaming_response.videos.retrieve_content(
video_id
) as response:
with open(f"runway_{video_id}.mp4", "wb") as f:
for chunk in response.iter_bytes():
f.write(chunk)
return True
elif video_status.status == "failed":
print(f"Video generation failed: {video_status.error}")
return False
print(f"Status: {video_status.status}, Progress: {video_status.progress}%")
time.sleep(wait_time)
print("Timeout waiting for video completion")
return False
# Example usage
video = client.videos.create(
model="gen4_turbo",
prompt="Smooth camera movement through a futuristic cityscape at night",
input_reference=open("city_image.jpg", "rb"),
size="1920x1080",
seconds="5",
)
check_video_status(video.id)# Poll for video status
VIDEO_ID="video_45d4cf58-6c37-43f1-b7ca-8f349f280a3e"
while true; do
STATUS=$(curl -s -X GET https://api.avalai.ir/v1/videos/$VIDEO_ID \
-H "Authorization: Bearer $AVALAI_API_KEY" | jq -r '.status')
if [ "$STATUS" = "completed" ]; then
echo "Video completed! Downloading..."
curl -X GET https://api.avalai.ir/v1/videos/$VIDEO_ID/content \
-H "Authorization: Bearer $AVALAI_API_KEY" \
--output runway_$VIDEO_ID.mp4
break
elif [ "$STATUS" = "failed" ]; then
echo "Video generation failed"
break
else
echo "Status: $STATUS - Waiting..."
sleep 10
fi
doneimport OpenAI from 'openai';
import fs from 'fs';
const client = new OpenAI({
apiKey: process.env.AVALAI_API_KEY,
baseURL: 'https://api.avalai.ir/v1'
});
async function checkVideoStatus(videoId) {
const maxAttempts = 60;
const waitTime = 10000;
for (let attempt = 0; attempt < maxAttempts; attempt++) {
const videoStatus = await client.videos.retrieve(videoId);
if (videoStatus.status === 'completed') {
console.log(`Video ${videoId} completed!`);
console.log(`Usage: ${JSON.stringify(videoStatus.usage)}`);
console.log(`Estimated cost: ${JSON.stringify(videoStatus.estimated_cost)}`);
// Download the video
const response = await client.videos.retrieveContent(videoId);
const buffer = Buffer.from(await response.arrayBuffer());
fs.writeFileSync(`runway_${videoId}.mp4`, buffer);
return true;
} else if (videoStatus.status === 'failed') {
console.log(`Video generation failed: ${videoStatus.error}`);
return false;
}
console.log(`Status: ${videoStatus.status}, Progress: ${videoStatus.progress}%`);
await new Promise(resolve => setTimeout(resolve, waitTime));
}
console.log('Timeout waiting for video completion');
return false;
}
// Example usage
const video = await client.videos.create({
model: 'gen4_turbo',
prompt: 'Smooth camera movement through a futuristic cityscape at night',
input_reference: fs.createReadStream('city_image.jpg'),
size: '1920x1080',
seconds: '5'
});
await checkVideoStatus(video.id);Best Practices for Prompting
Creating effective prompts is crucial for generating high-quality videos with RunwayML. Follow these guidelines:
Be Descriptive and Specific
Provide detailed descriptions including:
- Visual elements: Colors, lighting, composition
- Motion: Camera movements, subject actions, animation style
- Style: Cinematic, realistic, artistic, dramatic
- Mood: Atmospheric, energetic, calm, mysterious
Good Example:
The fridge door slowly swings open, revealing a soft purple glow from inside.
A cute, chubby purple monster emerges cautiously, looking around with curious
eyes. Smooth animation with subtle lighting changes.Poor Example:
Monster comes outDescribe Motion and Transformation
RunwayML excels at animating static images, so focus on motion:
- "Camera slowly pushes forward into the scene..."
- "Subject turns to face the camera with a smile..."
- "Water begins to flow and ripple across the surface..."
- "Clouds drift across the sky with changing light..."
Set the Scene Context
Establish atmosphere and timing:
- Time of day (dawn, golden hour, night)
- Weather and environment (windy, foggy, sunny)
- Lighting direction (backlit, dramatic shadows, soft glow)
- Pacing (slow and smooth, dynamic and energetic)
Use Temporal Descriptions
Describe how the scene evolves over time:
- "Starting from stillness, gradually building movement..."
- "The subject slowly turns towards the light..."
- "Gentle camera drift to reveal more of the environment..."
- "Elements come to life one by one in sequence..."
Duration and Pricing Guidelines
Choosing the Right Duration
RunwayML's gen4_turbo supports flexible durations from 2 to 10 seconds:
- 2-3 seconds: Quick loops, social media clips, transitions
- 4-6 seconds: Standard content, product showcases, story segments
- 7-10 seconds: Extended sequences, detailed animations, narrative content
Cost Optimization
At $0.05 per second, optimize your costs:
# 2 seconds = $0.10
# 5 seconds = $0.25
# 10 seconds = $0.50
# Start with shorter durations for testing
test_video = client.videos.create(
model="gen4_turbo",
prompt="Your test prompt",
input_reference=open("test_image.jpg", "rb"),
size="1280x720",
seconds="2", # Test with minimum duration
)
# Use longer durations only when needed
final_video = client.videos.create(
model="gen4_turbo",
prompt="Your final prompt",
input_reference=open("final_image.jpg", "rb"),
size="1920x1080",
seconds="10", # Full duration for final output
)Image Reference Best Practices
Since gen4_turbo requires an input image, follow these guidelines for best results:
Image Quality
- Use high-quality source images (at least 720p)
- Ensure good lighting and clear composition
- Avoid heavily compressed or artifacted images
Image Content
- Clear focal subjects work best
- Well-defined foreground and background
- Good contrast and color separation
- Composition that allows for motion
File Formats and Size
- Supported formats: JPEG, PNG
- Recommended size: Under 10MB for faster upload
- Resolution: Match or exceed your target video resolution
# Good practice: Match image and video resolution
with open("high_quality_image.jpg", "rb") as image_file:
video = client.videos.create(
model="gen4_turbo",
prompt="Camera slowly zooms into the scene with subtle parallax effect",
input_reference=image_file,
size="1920x1080", # Matches image aspect ratio
seconds="5",
)Error Handling and Troubleshooting
Common Issues and Solutions
Generation Timeout
If generation takes longer than expected:
- Increase polling timeout duration
- Check video status for error messages
- Use exponential backoff in polling logic
Invalid Image Reference
If image upload fails:
- Ensure file format is JPEG or PNG
- Check file size (keep under 10MB)
- Verify file is not corrupted
- Use binary mode when opening files (
"rb")
Unsupported Resolution
Ensure resolution is in the supported list:
- Refer to supported resolutions
- Common resolutions: 1280x720, 1920x1080, 1024x1024
- Avoid custom or unusual aspect ratios
Prompt Rejection
If prompts are rejected or fail:
- Character limit: Ensure prompt is under 1000 characters (the API will fail if exceeded)
- Remove explicit content or violence
- Avoid copyrighted character references
- Use descriptive rather than branded terms
- Focus on visual and motion descriptions
Retry Logic Example
import requests
import time
def generate_video_with_retry(prompt, image_path, max_retries=3):
for attempt in range(max_retries):
try:
with open(image_path, "rb") as image_file:
response = requests.post(
"https://api.avalai.ir/v1/videos",
headers={"Authorization": "Bearer YOUR_API_KEY"},
files={
"input_reference": image_file,
"model": (None, "gen4_turbo"),
"prompt": (None, prompt),
"size": (None, "1280x720"),
"seconds": (None, "5"),
},
timeout=30,
)
if response.status_code == 200:
return response.json()
elif response.status_code == 429: # Rate limit
wait_time = 2**attempt # Exponential backoff
print(f"Rate limited. Waiting {wait_time}s...")
time.sleep(wait_time)
else:
print(f"Error {response.status_code}: {response.text}")
return None
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
if attempt < max_retries - 1:
time.sleep(2**attempt)
return None
result = generate_video_with_retry("A serene landscape comes to life", "landscape.jpg")async function generateVideoWithRetry(prompt, imagePath, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const formData = new FormData();
formData.append('model', 'gen4_turbo');
formData.append('prompt', prompt);
formData.append('size', '1280x720');
formData.append('seconds', '5');
formData.append('input_reference', fs.createReadStream(imagePath));
const response = await fetch('https://api.avalai.ir/v1/videos', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY'
},
body: formData
});
if (response.ok) {
return await response.json();
} else if (response.status === 429) {
const waitTime = Math.pow(2, attempt) * 1000;
console.log(`Rate limited. Waiting ${waitTime/1000}s...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
} else {
console.error(`Error ${response.status}: ${await response.text()}`);
return null;
}
} catch (error) {
console.error(`Request failed: ${error}`);
if (attempt < maxRetries - 1) {
await new Promise(resolve =>
setTimeout(resolve, Math.pow(2, attempt) * 1000)
);
}
}
}
return null;
}
const result = await generateVideoWithRetry(
'A serene landscape comes to life',
'landscape.jpg'
);Advanced Use Cases
Creating Video Sequences
Generate related videos from different images that form a sequence:
import requests
scenes = [
{
"image": "scene1_establishing.jpg",
"prompt": "Slow camera push into the futuristic city establishing shot",
"seconds": 5,
},
{
"image": "scene2_street.jpg",
"prompt": "Dynamic movement through busy street with flying vehicles passing by",
"seconds": 6,
},
{
"image": "scene3_character.jpg",
"prompt": "Character turns to look at camera with city lights reflecting in background",
"seconds": 4,
},
]
generation_ids = []
for i, scene in enumerate(scenes):
with open(scene["image"], "rb") as image_file:
response = requests.post(
"https://api.avalai.ir/v1/videos",
headers={"Authorization": "Bearer YOUR_API_KEY"},
files={
"input_reference": image_file,
"model": (None, "gen4_turbo"),
"prompt": (None, scene["prompt"]),
"size": (None, "1920x1080"),
"seconds": (None, str(scene["seconds"])),
},
)
generation_ids.append(response.json()["id"])
print(f"Scene {i+1} generation started: {generation_ids[-1]}")
print(f"Generated sequence with {len(generation_ids)} scenes")Product Demonstration Videos
Create engaging product demos from product photography:
product_shots = {
"hero": {
"image": "product_hero.jpg",
"prompt": "Smooth 360-degree rotation of the product with dramatic lighting, showcasing all angles",
"seconds": 8,
},
"feature_close": {
"image": "product_detail.jpg",
"prompt": "Slow camera push into product details, highlighting premium materials and craftsmanship",
"seconds": 5,
},
"lifestyle": {
"image": "product_lifestyle.jpg",
"prompt": "Product comes to life in real-world setting, subtle environmental movement",
"seconds": 6,
},
}
for key, shot in product_shots.items():
with open(shot["image"], "rb") as image_file:
requests.post(
"https://api.avalai.ir/v1/videos",
"input_reference": image_file,
"model": (None, "gen4_turbo"),
"prompt": (None, shot["prompt"]),
"size": (None, "1920x1080"),
"seconds": (None, str(shot["seconds"])),
},
)
print(f"Generated {key} shot")Social Media Content
Optimize for different platforms with appropriate resolutions:
social_configs = {
"instagram_story": {
"size": "1080x1920", # Vertical
"seconds": 4,
"prompt": "Energetic product showcase with dynamic camera movement and vibrant atmosphere",
"image": "product_vertical.jpg",
},
"youtube_short": {
"size": "1080x1920", # Vertical
"seconds": 8,
"prompt": "Compelling narrative with smooth transitions and engaging visual flow",
"image": "content_vertical.jpg",
},
"landscape_post": {
"size": "1920x1080", # Landscape
"seconds": 5,
"prompt": "Professional presentation with cinematic camera movement",
"image": "content_landscape.jpg",
},
"square_post": {
"size": "1080x1080", # Square
"seconds": 4,
"prompt": "Attention-grabbing visual with centered composition and dynamic elements",
"image": "content_square.jpg",
},
}
for platform, config in social_configs.items():
with open(config["image"], "rb") as image_file:
requests.post(
"https://api.avalai.ir/v1/videos",
headers={"Authorization": "Bearer YOUR_API_KEY"},
files={
"input_reference": image_file,
"model": (None, "gen4_turbo"),
"prompt": (None, config["prompt"]),
"size": (None, config["size"]),
"seconds": (None, str(config["seconds"])),
},
)
print(f"Generated {platform} content")Architectural Visualization
Bring architectural renderings to life:
architectural_scenes = [
{
"image": "exterior_render.jpg",
"prompt": "Slow camera orbit around the building exterior, showcasing architecture from multiple angles with subtle lighting changes",
"size": "1920x1080",
"seconds": 10,
},
{
"image": "interior_render.jpg",
"prompt": "Smooth camera walkthrough of interior space, highlighting design elements and spatial flow",
"size": "1920x1080",
"seconds": 8,
},
]
for scene in architectural_scenes:
with open(scene["image"], "rb") as image_file:
client.videos.create(
model="gen4_turbo",
prompt=scene["prompt"],
input_reference=image_file,
size=scene["size"],
seconds=str(scene["seconds"]),
)Comparison with Other Video Models
RunwayML vs Sora
RunwayML gen4_turbo:
- ✅ Requires reference image (image-to-video)
- ✅ More control over visual style through input image
- ✅ Lower cost at $0.05/second
- ✅ Flexible durations (2-10 seconds)
- ✅ Wide resolution support
- ✅ Text-to-video (no image required)
- ✅ Can use optional image reference
- ✅ Higher cost ($0.10-$0.50/second)
- ✅ Fixed durations (4 or 8 seconds)
- ✅ Specialized in pure text-to-video generation
When to use RunwayML:
- You have reference images or concept art
- You want precise control over visual style
- Budget optimization is important
- You need flexible video durations
When to use Sora:
- Pure text-to-video generation needed
- No reference images available
- Higher quality/resolution requirements
- Professional cinematic output needed
Integration Tips
With OpenAI SDK
RunwayML models work seamlessly with the OpenAI SDK:
from openai import OpenAI
client = OpenAI(api_key="YOUR_AVALAI_API_KEY", base_url="https://api.avalai.ir/v1")
# Same interface as other video models
video = client.videos.create(
model="gen4_turbo",
prompt="Your animation prompt",
input_reference=open("reference.jpg", "rb"),
size="1920x1080",
seconds="5",
)Batch Processing
Process multiple videos efficiently:
import concurrent.futures
from openai import OpenAI
client = OpenAI(api_key="your-avalai-api-key", base_url="https://api.avalai.ir/v1")
def generate_video(image_path, prompt, duration):
with open(image_path, "rb") as img:
video = client.videos.create(
model="gen4_turbo",
prompt=prompt,
input_reference=img,
size="1280x720",
seconds=str(duration),
)
return video.id
# Submit multiple generations in parallel
video_requests = [
("image1.jpg", "Scene 1 animation", 4),
("image2.jpg", "Scene 2 animation", 5),
("image3.jpg", "Scene 3 animation", 6),
]
with concurrent.futures.ThreadPoolExecutor(max_workers=3) as executor:
futures = [executor.submit(generate_video, *req) for req in video_requests]
video_ids = [f.result() for f in concurrent.futures.as_completed(futures)]
print(f"Submitted {len(video_ids)} video generations")Webhook Integration
For production systems, consider webhook notifications:
import requests
# Note: AvalAI may support webhooks - check documentation
response = requests.post(
"https://api.avalai.ir/v1/videos",
headers={"Authorization": "Bearer YOUR_API_KEY"},
files={
"input_reference": open("image.jpg", "rb"),
},
data={
"model": "gen4_turbo",
"prompt": "Your prompt",
"size": "1280x720",
"seconds": "5",
# Uncomment if webhooks are supported:
# "webhook_url": "https://yourapp.com/webhook/video-completed",
},
)
# Your webhook endpoint would receive completion notification
# allowing you to process videos without pollingPerformance Optimization
Minimize Polling Frequency
Balance responsiveness with API efficiency:
import time
def smart_polling(video_id, initial_wait=15, max_wait=60):
"""Intelligent polling with adaptive intervals"""
wait_time = initial_wait
while True:
video_status = client.videos.retrieve(video_id)
if video_status.status in ["completed", "failed"]:
return video_status
# Adaptive wait time based on progress
if hasattr(video_status, "progress") and video_status.progress:
if video_status.progress > 80:
wait_time = 10 # Check frequently near completion
elif video_status.progress > 50:
wait_time = 20
else:
wait_time = min(wait_time * 1.5, max_wait)
time.sleep(wait_time)Caching and Reuse
Cache generated videos to avoid regeneration:
import hashlib
import json
import os
def get_cache_key(prompt, image_path, size, seconds):
"""Generate cache key from generation parameters"""
with open(image_path, "rb") as f:
image_hash = hashlib.md5(f.read()).hexdigest()
params = f"{prompt}|{image_hash}|{size}|{seconds}"
return hashlib.md5(params.encode()).hexdigest()
def generate_with_cache(prompt, image_path, size="1280x720", seconds="5"):
cache_key = get_cache_key(prompt, image_path, size, seconds)
cache_file = f"cache/{cache_key}.mp4"
if os.path.exists(cache_file):
print(f"Using cached video: {cache_file}")
return cache_file
# Generate new video
with open(image_path, "rb") as img:
video = client.videos.create(
model="gen4_turbo",
prompt=prompt,
input_reference=img,
size=size,
seconds=seconds,
)
# Wait for completion and cache
# ... polling logic ...
return cache_fileTracking and Identification
Using safety_identifier for Internal Tracking
The safety_identifier parameter allows you to associate video requests with your internal tracking systems. This is useful for:
- Department tracking: Identify which team or department generated a video
- Project management: Associate videos with specific projects or campaigns
- Cost allocation: Track spending across different business units
- Audit trails: Maintain records for compliance purposes
# Example: Using safety_identifier for project tracking
video = client.videos.create(
model="gen4_turbo",
prompt="Product showcase with dynamic camera movement",
input_reference=open("product_image.jpg", "rb"),
size="1920x1080",
seconds="8",
safety_identifier="marketing_dept_q4_campaign",
)Filtering Videos by Identifier
You can filter your video list using the safety_identifier parameter:
# List all videos for a specific project
curl -X GET "https://api.avalai.ir/v1/videos?safety_identifier=marketing_dept_q4_campaign" \
-H "Authorization: Bearer $AVALAI_API_KEY"Using request_id for Cost Tracking
Every video response includes a request_id (UUID v7) that you can use for precise cost tracking:
video = client.videos.create(
model="gen4_turbo",
prompt="Your video prompt",
input_reference=open("reference.jpg", "rb"),
size="1920x1080",
seconds="8",
)
# Store the request_id for cost lookup
request_id = video.request_id
print(f"Request ID for cost tracking: {request_id}")
# Later, use /user/v1/transactions/lookup to get exact costsYou can also filter videos by request_id to find a specific video:
curl -X GET "https://api.avalai.ir/v1/videos?request_id=019b4797-14a2-79a0-8635-2cf8dd84820c" \
-H "Authorization: Bearer $AVALAI_API_KEY"For more details on cost tracking, see the Response Headers and User API documentation.
Related Resources
- Video API Reference - Complete API documentation
- RunwayML Models - Detailed model specifications
- Pricing Guide - Cost information and optimization
- Generate Videos Using Sora - Alternative video generation approach
- Generate Videos Using Veo - Google's video generation models
- Image Generation - Create reference images for video generation
- Best Practices - General API usage guidelines
- Error Handling - Comprehensive error handling strategies
Official Documentation
For more information about RunwayML's Gen-4 technology and capabilities, visit the official RunwayML API documentation.