Teknik
Vellria API'sini kendi kodundan çağırmak
Dört çağrı seni sıfırdan biten dosyaya götürüyor: anahtar oluştur, üretimi başlat, kaydı yokla ve çıktıyı süresi dolmadan indir. Bu, o döngünün baştan sona hâli; her adımın döndürdüğü hata ve bir istemcinin o hata karşısında ne yapması gerektiğiyle birlikte.
Anahtar oluştur, Bearer token olarak gönder
Anahtarlar konsolda, API anahtarları sayfasında üretiliyor ve tam anahtarın göründüğü tek yer o yanıt: anahtar listeni sonraki her okuyuşun bir kimlik, bir ad ve bir önek döndürüyor, sırrı bir daha değil. Hemen sakla. Önek, bir log satırının anahtarı içermeden onu adlandırabilmesi için var.
Her istekte Authorization başlığında, Bearer kelimesinin ardından anahtar olarak gönder. Sorgu dizesi biçimi yok. RFC 6750 şunu öneriyor: "Bearer tokens SHOULD NOT be passed in page URLs (for example, as query string parameters)". Sebebi açık: token taşıyan adresler tarayıcı geçmişine, referrer'a ve sunucu log'larına düşüyor.
Eksik ya da iptal edilmiş anahtar authentication_required koduyla 401 dönüyor. Her hata tek bir gövdeyi paylaşıyor: message, type, param ve code taşıyan bir error nesnesi. Dallanmayı code üzerinden yap; message bir insan için yazılmış ve sözcükleri değişecek.
Kataloğu gömmek yerine oku
GET /v1/models iki liste döndürüyor: image ve video. Bir görsel kaydı kendi geçerli boyutlarını her birinin kredi bedeliyle ve bir varsayılan boyutla taşıyor; bir video kaydı saniye başına bedelle çözünürlükleri, bir süre alt ve üst sınırını ve kabul ettiği oranları taşıyor. Boyut listesi kataloğa değil tek bir modele ait, varsayılan da öyle; yani hiçbir tek değeri her yere uygulamak güvenli değil. Model kataloğu ve fiyat sayfaları da aynı ucu okuyor.
kind alanı modelin nasıl bir gövde istediğini söylüyor: metinden görsele, görselden görsele, metinden videoya, görselden videoya. Aynı şeyi referans görsel nesnesinin varlığından çıkarmak yerine onu kullan; o çıkarım bugün doğru ve bir sonraki eklenen şeyde sessizce yanlış. Bilinmeyen model, geçersiz boyut ya da aralık dışı süre, alanı adlandıran bir param ile 400 dönüyor; aralık dışı süre sığdırmak için kırpılmıyor, reddediliyor.
Üretimi başlat, sonra kaydı yokla
Bir model kimliği, bir prompt ve o modelin kabul ettiği seçeneklerle /v1/generate/image ya da /v1/generate/video ucuna POST at. Geriye bir kimlik, processing durumu ve az önce alınan kredi bedeliyle 202 alıyorsun: krediler üretimin sonunda değil başında düşüyor. Sonra durum queued ve processing'ten çıkana kadar GET /v1/generations/{id} yokla. Tamamlanmış kayıt bizim dosya ucumuzu gösteren output_url taşıyor; düşen kayıt ise kapalı bir kümeden gelen bir error_code ile birlikte, log'ların için kısa bir özet olan error taşıyor.
Yoklamalar arasına gecikme, gecikmenin içine rastgelelik koy. Marc Brooker'ın AWS Architecture Blog'daki geri çekilme deneyi tek bir satır için yarışan istemcileri benzetiyor ve jitter eklendiğinde şunu bildiriyor: "in the case with 100 contending clients, we've reduced our call count by more than half". Yoklama, sonucu nasıl öğrendiğin; nasıl olduğu değil: üretimler kimse bakmasa da sunucu tarafında uzlaştırılıyor, yani kopan bir bağlantı sana sonucu değil sonucun üstündeki tutamağını kaybettiriyor.
Döngünün tamamı tek dosyada
Bunu bir .mjs dosyası olarak kaydet, VELLRIA_API_KEY'i ayarla ve güncel bir Node'da çalıştır. Hiçbir model kimliği, boyut ya da bedel gömülü değil.
```js import { writeFile } from "node:fs/promises"; const BASE = "https://vellria.com"; const AUTH = { Authorization: `Bearer ${process.env.VELLRIA_API_KEY}` }; const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); async function call(path, init) { const res = await fetch(BASE + path, { ...init, headers: { ...AUTH, ...init?.headers } }); if (res.status === 429) { await sleep(Number(res.headers.get("retry-after") ?? 5) * 1000); return call(path, init); } if (!res.ok) throw new Error((await res.json().catch(() => null))?.error?.code ?? res.status); return res.json(); } const catalog = await call("/v1/models"); const model = catalog.image.find((m) => m.kind === "text-to-image"); let rec = await call("/v1/generate/image", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ model: model.id, prompt: "a lighthouse in fog", size: model.default_size }), }); while (rec.status === "queued" || rec.status === "processing") { await sleep(2000 + Math.random() * 2000); rec = await call(`/v1/generations/${rec.id}`); } if (rec.status !== "completed") throw new Error(rec.error_code ?? "generation_failed"); const file = await fetch(rec.output_url, { headers: AUTH }); await writeFile(`${rec.id}.png`, Buffer.from(await file.arrayBuffer())); ```
Görsel alan bir model için önce dosyayı, baytlarla eşleşen bir Content-Type başlığıyla /v1/uploads ucuna POST at, sonra dönen adresi image_urls içinde geçir; görselden videoya kabul edilen biçimleri ve ret listesini taşıyor. Bir modelin görsel isteyip istemediği modelin özelliği ve yanlış şekildeki bir gövde sessizce düzeltilmiyor, reddediliyor; bunu karakteri tutarlı tutmak anlatıyor. Video gövdeleri size yerine duration ve resolution taşıyor; onu da çözünürlük ve süre seçimi anlatıyor.
Hatalar, geri basınç ve süre dolumu
Bir üretim başladıktan sonra düştüğünde, başta alınan krediler kayıt failed olarak işaretlendiği anda kendiliğinden geri dönüyor ve hem düşen üretim hem iade geçmişinde kalıyor. failed'i terminal ve kapanmış say: sebep için error_code üzerinden dallan ve bakiyeleri kendi tarafından asla uzlaştırma. İade, yalnız tek bir yazarın sağlayabileceği bir koşul altında yazılıyor, yani yeniden teslim edilen bir sağlayıcı bildirimi sana iki kez kredi yazamıyor ya da bir kez atlayamıyor.
Hız sınırını aşmak rate_limit_exceeded kodu ve bir Retry-After başlığıyla 429 döndürüyor. RFC 6585 o durumu tanımlıyor: "the 429 status code indicates that the user has sent too many requests in a given amount of time". RFC 9110 bölüm 10.2.3 de başlığı şöyle tanımlıyor: "indicates how long the user agent ought to wait before making a follow-up request". Tahmin etmek yerine onu oku; bir parti ateşlerken bunun ne demek olduğu için storyboard ve previz rehberine bak. Bakiye yetmezse 402 ve hiç kayıt oluşmuyor. Saklama süresinin sonunda silinen bir dosya 404 değil content_expired ile 410 dönüyor, çünkü silinmiş bir dosya ile hiç var olmamış bir dosya bir istemci için farklı şeyler. Tam ayrıntı API referansında.
Sık sorulan sorular
Bir üretimin bitmesi için yoklamaya devam etmek zorunda mıyım?
Hayır. Yoklama, sonucu nasıl öğrendiğin; nasıl olduğu değil. Üretimler bir istemci bağlı olsa da olmasa da bizim tarafımızda uzlaştırılıyor, yani sonra ölen bir sürecin başlattığı iş yine completed ya da failed'e ulaşıyor; kimliğiyle sonra al.
Bunu tarayıcı kodundan çağırabilir miyim?
Anahtarınla değil. Bir anahtar kredi harcıyor ve kapsamı daraltılamıyor, yani tarayıcıya gönderilen her şey yayımlanmış bir anahtar. Çağrıları kendi sunucunun arkasına koy, anahtarı onun ortamında tut ve ön yüzün onunla konuşsun.
Model kimliklerini, boyutları ve bedelleri koduma gömebilir miyim?
Gömebilirsin ve kayar. Model sayfalarının çizdiği ve sunucunun ücretlendirdiği şey katalog ucu, yani kopyalanmış bir değer kataloğun değiştiği gün eşleşmeyi bırakıyor. Onu açılışta çek ve sürecin ömrü boyunca önbellekte tut.
