Claude Opus 5 is now live on CometAPI →

Bir SaaS uygulamasına yapay zekâ ile video oluşturma nasıl eklenir

CometAPI
AnnaJun 5, 2026
Bir SaaS uygulamasına yapay zekâ ile video oluşturma nasıl eklenir

Uygulamanıza video üretimi eklemek, görsel (image) üretimi eklemekle aynı değildir. API çağrısı anında döner — ancak video henüz hazır olmaz. Size bir görev kimliği (task ID) verilir ve bitene kadar “bitti mi?” diye sormaya devam etmeniz gerekir.

Çoğu geliştirici bir video API’sini ilk kez çağırdığında, yanıt gövdesinde bir video URL’si bekler ve bunun yerine bir görev kimliği alır. Bu kılavuz, tam akışı adım adım ele alır: bir görevi gönderme, sonuçları yoklama, hataları yönetme ve URL süresi dolmadan çıktıyı depolama.

Neler geliştireceksiniz

Bir metin istemi veya görsel kabul eden, bir video üretim görevini gönderen, tamamlanana kadar yoklama yapan ve nihai video URL’sini döndüren bir arka uç (backend) servis. Dört modelle çalışacaksınız — Veo 3 Fast, Sora 2, Kling Video ve Runway — hepsi tek bir API anahtarıyla.

Önkoşullar:

  • Python 3.8+ veya Node.js 18+
  • Bir CometAPI anahtarı
  • REST API’lere temel aşinalık

Video üretiminin neden farklı olduğunu anlayın

Görsel üretiminde bir istek gönderir ve aynı yanıtta görseli geri alırsınız. Video üretimi ise eşzamansız (async) bir görev kuyruğu kullanır:

  1. Üretim isteğini gönderin → size bir task_id döner
  2. Her birkaç saniyede bir bir durum (status) uç noktasını yoklayın
  3. Durum bir terminal duruma ulaştığında video URL’sini alırsınız
  4. Videoyu indirin ve depolayın — URL geçicidir

Video üretimini görsel üretimi gibi ele alır ve ilk yanıtta videonun gelmesini beklerseniz, isteğiniz her seferinde zaman aşımına uğrar.

Üretim ortamındaki bir web servisinde bu yoklama döngüsü, istek işleyicisinde değil bir arka plan işçisinde (Celery, Bull veya benzeri) çalışmalıdır. Aşağıdaki örnekler eşzamanlı (senkron) yoklama kullanır — betikler ve prototipler için uygundur, ancak eşzamanlı kullanıcıları yönetmek için uygun değildir.

Bir model seçin

ModelSağlayıcıMaksimum süreFiyat (CometAPI üzerinden)En uygun kullanım
Veo 3 FastGoogle8 sec$0.05/secHızlı prototipleme, sosyal klipler
Sora 2OpenAI (CometAPI model ID)~10 sec$0.08/secYüksek kaliteli yaratıcı kısa videolar
Kling VideoKuaishou10 sec$0.13–$2.64/taskPazarlama içeriği, ayrıntılı kontrol
Runway Gen-3A TurboRunway5 or 10 sec$0.32/taskGörüntüden videoya, ticari içerik

Kaynak**: CometAPI model sayfaları, Mayıs 2026. Not: "Sora 2", CometAPI’nin model tanımlayıcısıdır — temel model ayrıntıları için onların model sayfasına bakın.

  • Veo 3 Fast hem metinden videoya hem de görüntüden videoya destek verir. Saniye başına en ucuz, iyi bir başlangıç noktası.
  • Sora 2, videoyla birlikte sesi de yerel olarak üretir — ayrı bir TTS adımı olmadan diyalog, ortam sesi ve efektler.
  • Kling Video size negative_prompt, cfg_scale, kamera hareketi ayarları ve pro modu sunar. Dördü içinde en fazla kontrol.
  • Runway, CometAPI üzerinden yalnızca görüntüden videoya çalışır. Ona statik bir görsel ve bir hareket açıklaması verin; görseli canlandırır.

Bir Veo görevi gönderin

Veo, multipart/form-data kullanır. Python requests’te doğru göndermek için files= kullanın — data=dict, application/x-www-form-urlencoded gönderir ve bu aynı şey değildir:

import requestsimport osfrom dotenv import load_dotenv​load_dotenv()​def submit_veo_task(prompt: str, size: str = "16x9") -> str:    """Submit a Veo 3 Fast text-to-video task. Returns task_id."""    api_key = os.getenv("COMETAPI_KEY")    if not api_key:        raise ValueError("COMETAPI_KEY environment variable is not set")​    response = requests.post(        "https://api.cometapi.com/v1/videos",        headers={"Authorization": f"Bearer {api_key}"},        files={            "prompt": (None, prompt),            "model": (None, "veo3-fast"),            "size": (None, size)        },        timeout=30    )    response.raise_for_status()    return response.json()["id"]​​task_id = submit_veo_task("A paper kite drifting above a wheat field on a windy afternoon")print(f"Task submitted: {task_id}")

Sonuç için yoklama yapın

import time​def poll_veo_task(task_id: str, interval: int = 10, max_wait: int = 600) -> str:    """Poll until Veo task completes. Returns video URL."""    api_key = os.getenv("COMETAPI_KEY")    if not api_key:        raise ValueError("COMETAPI_KEY environment variable is not set")​    headers = {"Authorization": f"Bearer {api_key}"}    url = f"https://api.cometapi.com/v1/videos/{task_id}"    elapsed = 0​    while elapsed < max_wait:        response = requests.get(url, headers=headers, timeout=30)        response.raise_for_status()        result = response.json()        status = result.get("status")​        if status == "succeeded":            return result["output"][0]        elif status in ("failed", "cancelled"):            raise RuntimeError(                f"Task {task_id} failed with status '{status}': "                f"{result.get('error', 'no error detail returned')}"            )​        time.sleep(interval)        elapsed += interval​    raise TimeoutError(f"Task {task_id} did not complete within {max_wait} seconds")​​video_url = poll_veo_task(task_id)print(f"Video ready: {video_url}")

Daha fazla kontrol için Kling Video’yu kullanın

Kling’in farklı bir uç nokta yapısı vardır ve JSON kullanır. Kling’in terminal durum dizgesinin "succeed" ( "succeeded" değil) olduğuna dikkat edin — bu, API’nin fiili yanıt biçimiyle eşleşir:

def submit_kling_task(prompt: str, duration: str = "5", mode: str = "std") -> str:    """Submit a Kling text-to-video task. Returns task_id."""    api_key = os.getenv("COMETAPI_KEY")    if not api_key:        raise ValueError("COMETAPI_KEY environment variable is not set")​    response = requests.post(        "https://api.cometapi.com/kling/v1/videos/text2video",        headers={            "Authorization": f"Bearer {api_key}",            "Content-Type": "application/json"        },        json={            "model_name": "kling-v1-6",            "prompt": prompt,            "negative_prompt": "blurry, low quality, watermark",            "cfg_scale": 0.5,            "mode": mode,         # "std" or "pro"            "aspect_ratio": "16:9",            "duration": duration  # "5" or "10"        },        timeout=30    )    response.raise_for_status()    return response.json()["data"]["task_id"]​​def poll_kling_task(task_id: str, interval: int = 10, max_wait: int = 600) -> str:    """Poll Kling task until complete. Returns video URL."""    api_key = os.getenv("COMETAPI_KEY")    if not api_key:        raise ValueError("COMETAPI_KEY environment variable is not set")​    headers = {"Authorization": f"Bearer {api_key}"}    url = f"https://api.cometapi.com/kling/v1/videos/text2video/{task_id}"    elapsed = 0​    while elapsed < max_wait:        response = requests.get(url, headers=headers, timeout=30)        response.raise_for_status()        result = response.json()        status = result["data"]["task_status"]​        if status == "succeed":  # Kling uses "succeed", not "succeeded"            return result["data"]["task_result"]["videos"][0]["url"]        elif status == "failed":            error_detail = result.get("data", {}).get("task_result", "no detail")            raise RuntimeError(                f"Kling task {task_id} failed: {error_detail}"            )​        time.sleep(interval)        elapsed += interval​    raise TimeoutError(f"Kling task {task_id} timed out after {max_wait}s")

Kaynak**: CometAPI Kling Video belgeleri

Runway ile statik bir görüntüyü canlandırın

Runway yalnızca görüntüden videoya çalışır. Ayrıca ekstra bir başlık (X-Runway-Version) ister:

def submit_runway_task(image_url: str, motion_prompt: str, duration: int = 5) -> str:    """Submit a Runway image-to-video task. Returns task_id."""    api_key = os.getenv("COMETAPI_KEY")    if not api_key:        raise ValueError("COMETAPI_KEY environment variable is not set")​    response = requests.post(        "https://api.cometapi.com/runwayml/v1/image_to_video",        headers={            "Authorization": f"Bearer {api_key}",            "X-Runway-Version": "2024-11-06",            "Content-Type": "application/json"        },        json={            "model": "gen3a_turbo",            "promptImage": image_url,  # must be a stable HTTPS URL            "promptText": motion_prompt,            "duration": duration,            "ratio": "1280:720",            "watermark": False        },        timeout=30    )    response.raise_for_status()    return response.json()["id"]​​def poll_runway_task(task_id: str, interval: int = 5, max_wait: int = 600) -> str:    """Poll Runway task. Returns video URL when done."""    api_key = os.getenv("COMETAPI_KEY")    if not api_key:        raise ValueError("COMETAPI_KEY environment variable is not set")​    headers = {        "Authorization": f"Bearer {api_key}",        "X-Runway-Version": "2024-11-06"    }    url = f"https://api.cometapi.com/runwayml/v1/tasks/{task_id}"    elapsed = 0​    while elapsed < max_wait:        response = requests.get(url, headers=headers, timeout=30)        response.raise_for_status()        result = response.json()        status = result.get("status")​        if status == "task_not_exist":            # CometAPI-specific: task is still initializing, retry after a few seconds            time.sleep(interval)            elapsed += interval            continue        elif status == "succeeded":            return result["output"][0]        elif status in ("failed", "cancelled"):            raise RuntimeError(f"Runway task {task_id} failed: {result.get('error', 'no detail')}")​        time.sleep(interval)        elapsed += interval​    raise TimeoutError(f"Runway task {task_id} timed out after {max_wait}s")

Kaynak**: CometAPI Runway belgeleri

URL’nin süresi dolmadan videoyu kaydedin

Video üretim API’lerinden alınan video URL’leri geçicidir. Dosyayı hemen indirin ve kontrol ettiğiniz bir yerde depolayın:

import requestsimport pathlib​def download_video(url: str, output_path: str) -> None:    """Download video from URL to local file using streaming."""    out = pathlib.Path(output_path)    if out.parent != pathlib.Path("."):        out.parent.mkdir(parents=True, exist_ok=True)​    with requests.get(url, stream=True, timeout=60) as r:        r.raise_for_status()        with open(out, "wb") as f:            for chunk in r.iter_content(chunk_size=8192):                f.write(chunk)    print(f"Saved to {output_path}")​​# Full flowtask_id = submit_veo_task("A timelapse of clouds moving over a city skyline")video_url = poll_veo_task(task_id)download_video(video_url, "output/city_timelapse.mp4")

Üretimde, yerel dosyaya yazma aşamasını S3, Cloudflare R2 veya seçtiğiniz depolamaya yükleme ile değiştirin. Akış (streaming) deseni aynı kalır — tüm videoyu belleğe yüklemek yerine baytları doğrudan yönlendirin.

Hataları ele alın

BelirtiMuhtemel nedenÇözüm
Görev 10+ dakika boyunca queued’da kaldıSunucu yükü veya model kullanılamıyorFarklı bir modelle yeniden deneyin
İlk Runway yoklamasında task_not_existGörev hâlâ başlatılıyor5 sn bekleyip yeniden deneyin — CometAPI davranışı
Hata mesajı olmadan failedİstem içerik filtresini tetiklediİstemi yeniden ifade edin
Video URL’si 403 döndürüyorURL indirilmeden önce süresi dolduURL’yi aldıktan hemen sonra indirin
10 dakika sonra zaman aşımıÜretim çok uzun sürdümax_wait’i artırın veya Veo 3 Fast’e geçin
Kling "succeeded" değil "succeed" döndürüyorKling’in API’si standart dışı durum dizgesi kullanırBu doğrudur — yukarıdaki Kling yoklama koduna bakın

Kaynak: CometAPI video üretim belgeleri

Node.js sürümü

Node.js 18+ yerleşik olarak fetch ve FormData içerir. Bu örnek dört modelin tamamını kapsar:

// Node.js 18+ — no extra packages needed​const API_KEY = process.env.COMETAPI_KEY;if (!API_KEY) throw new Error('COMETAPI_KEY is not set');​// --- Veo 3 Fast ---async function submitVeoTask(prompt, size = '16x9') {  const form = new FormData();  form.append('prompt', prompt);  form.append('model', 'veo3-fast');  form.append('size', size);​  const res = await fetch('https://api.cometapi.com/v1/videos', {    method: 'POST',    headers: { 'Authorization': `Bearer ${API_KEY}` },    body: form  });  if (!res.ok) throw new Error(`Veo submit failed: ${res.status}`);  return (await res.json()).id;}​async function pollVeoTask(taskId, intervalMs = 10000, maxWaitMs = 600000) {  let elapsed = 0;  while (elapsed < maxWaitMs) {    const res = await fetch(`https://api.cometapi.com/v1/videos/${taskId}`, {      headers: { 'Authorization': `Bearer ${API_KEY}` }    });    if (!res.ok) throw new Error(`Poll failed: ${res.status}`);    const result = await res.json();​    if (result.status === 'succeeded') return result.output[0];    if (['failed', 'cancelled'].includes(result.status)) {      throw new Error(`Task ${taskId} failed: ${result.error ?? 'no detail'}`);    }    await new Promise(r => setTimeout(r, intervalMs));    elapsed += intervalMs;  }  throw new Error(`Task ${taskId} timed out`);}​// --- Kling Video ---async function submitKlingTask(prompt, duration = '5', mode = 'std') {  const res = await fetch('https://api.cometapi.com/kling/v1/videos/text2video', {    method: 'POST',    headers: {      'Authorization': `Bearer ${API_KEY}`,      'Content-Type': 'application/json'    },    body: JSON.stringify({      model_name: 'kling-v1-6',      prompt,      negative_prompt: 'blurry, low quality, watermark',      cfg_scale: 0.5,      mode,      aspect_ratio: '16:9',      duration    })  });  if (!res.ok) throw new Error(`Kling submit failed: ${res.status}`);  return (await res.json()).data.task_id;}​async function pollKlingTask(taskId, intervalMs = 10000, maxWaitMs = 600000) {  let elapsed = 0;  while (elapsed < maxWaitMs) {    const res = await fetch(      `https://api.cometapi.com/kling/v1/videos/text2video/${taskId}`,      { headers: { 'Authorization': `Bearer ${API_KEY}` } }    );    if (!res.ok) throw new Error(`Kling poll failed: ${res.status}`);    const result = await res.json();    const status = result.data.task_status;​    if (status === 'succeed') return result.data.task_result.videos[0].url;    if (status === 'failed') {      throw new Error(`Kling task ${taskId} failed: ${JSON.stringify(result.data.task_result ?? 'no detail')}`);    }    await new Promise(r => setTimeout(r, intervalMs));    elapsed += intervalMs;  }  throw new Error(`Kling task ${taskId} timed out`);}​// --- Runway (image-to-video) ---async function submitRunwayTask(imageUrl, motionPrompt, duration = 5) {  const res = await fetch('https://api.cometapi.com/runwayml/v1/image_to_video', {    method: 'POST',    headers: {      'Authorization': `Bearer ${API_KEY}`,      'X-Runway-Version': '2024-11-06',      'Content-Type': 'application/json'    },    body: JSON.stringify({      model: 'gen3a_turbo',      promptImage: imageUrl,      promptText: motionPrompt,      duration,      ratio: '1280:720',      watermark: false    })  });  if (!res.ok) throw new Error(`Runway submit failed: ${res.status}`);  return (await res.json()).id;}​async function pollRunwayTask(taskId, intervalMs = 5000, maxWaitMs = 600000) {  let elapsed = 0;  while (elapsed < maxWaitMs) {    const res = await fetch(      `https://api.cometapi.com/runwayml/v1/tasks/${taskId}`,      { headers: { 'Authorization': `Bearer ${API_KEY}`, 'X-Runway-Version': '2024-11-06' } }    );    if (!res.ok) throw new Error(`Runway poll failed: ${res.status}`);    const result = await res.json();    const status = result.status;​    if (status === 'task_not_exist') {      // CometAPI-specific: task still initializing      await new Promise(r => setTimeout(r, intervalMs));      elapsed += intervalMs;      continue;    }    if (status === 'succeeded') return result.output[0];    if (['failed', 'cancelled'].includes(status)) {      throw new Error(`Runway task ${taskId} failed: ${result.error ?? 'no detail'}`);    }    await new Promise(r => setTimeout(r, intervalMs));    elapsed += intervalMs;  }  throw new Error(`Runway task ${taskId} timed out`);}​// Usage exampleconst taskId = await submitVeoTask('A paper kite drifting above a wheat field');const videoUrl = await pollVeoTask(taskId);console.log('Video ready:', videoUrl);

Sırada ne var

Artık dört video modeli için çalışan kodunuz, hataları ele alan bir yoklama döngünüz ve üretilen içeriği kaybetmemenizi sağlayan bir indirme adımınız var.

Çoğu geliştiricinin bir sonraki karşılaştığı sorun: tek bir modeli sabitlemiş olmaları ve daha ucuz veya daha hızlı bir seçeneğe geçmek için birden çok dosyaya dokunmaları gerekmesi. Bir sonraki makale, kodunuzu yeniden yazmadan istekleri modeller arasında nasıl yönlendireceğinizi ele alıyor.

Sonraki: Kodunuzu Yeniden Yazmadan Yapay Zekâ Modelleri Arasında Nasıl Geçiş Yaparsınız

SSS

S: API yanıtında video yerine neden bir görev kimliği alıyorum?

Video üretimi eşzamansızdır — Veo, Sora, Kling ve Runway gibi modellerin oluşturması 2–5 dakika sürer. API, isteğinizin zaman aşımına uğramaması için hemen bir görev kimliği döndürür. Görev bir terminal duruma (succeeded, succeed, failed) ulaşana kadar ayrı bir durum uç noktasını yoklarsınız.

S: Oluşturulan bir video URL’si ne kadar süre geçerli kalır?

Video üretim API’lerinden gelen URL’ler geçicidir. URL’yi aldıktan hemen sonra dosyayı indirin ve kendi depolamanıza (S3, Cloudflare R2 vb.) kaydedin. URL’yi saklayıp saatler sonra çalışmasını beklemeyin.

S: Veo 3 Fast ile Kling Video arasındaki fark nedir?

Veo 3 Fast daha ucuzdur ($0.05/sec), daha hızlıdır ve çağırması daha basittir. Kling Video ise daha fazla kontrol sunar: negative_prompt, cfg_scale, kamera hareketi ayarları ve pro kalite modu. Çıktıyı ince ayarlarla yönlendirmeniz gerekiyorsa Kling’i kullanın. Hız ve düşük maliyet istiyorsanız Veo 3 Fast’i kullanın.

S: Metin istemi yerine bir görselden video üretebilir miyim?

Evet. Veo, bir input_reference dosyası geçirerek görüntüden videoya destekler. Kling, image parametresi (URL veya base64) ile /kling/v1/videos/image2video uç noktası üzerinden destekler. Runway yalnızca görüntüden videoya çalışır — CometAPI üzerinden metin-only istem kabul etmez.

S: Neden Runway ilk yoklamada task_not_exist döndürüyor?

Bu, belgelenmiş bir CometAPI davranışıdır — görev arka uçta hâlâ başlatılıyor. Birkaç saniye bekleyip yeniden deneyin. Bu bir hata değildir. Yukarıdaki yoklama kodu bunu otomatik olarak ele alır.

S: Kling neden "succeed" yerine "succeeded" kullanıyor?

Bu, Kling’in gerçek API yanıt biçimidir. Yazım hatası değildir. Veo ve Runway "succeeded" kullanır — Kling "succeed" kullanır. Birleştirilmiş bir yoklama sarmalayıcısı (wrapper) oluşturuyorsanız her iki dizgeyi de ele almanız gerekir.

S: Eşzamanlı (senkron) yoklama döngüsünü bir web sunucusunda kullanmak güvenli midir?

Hayır. Bu kılavuzdaki yoklama döngüsü, dakikalarca iş parçacığını bloke eder. Eşzamanlı kullanıcıları olan gerçek bir web servisinde, yoklamayı bir arka plan işçisinde çalıştırın (Python için Celery, Node.js için Bull). Görevi istek işleyicisinde gönderin, istemciye görev kimliğini döndürün ve video hazır olduğunda işçi istemciyi bilgilendirsin.

Yapay zeka geliştirme maliyetlerinizi %20 azaltmaya hazır mısınız?

Dakikalar içinde ücretsiz başlayın. Ücretsiz deneme kredileri dahildir. Kredi kartı gerekmez.

Devamını Oku