Vazifalar va vebhuklar
Media yaratish (video, tasvirlar, musiqa) asinxron amalga oshiriladi: siz vazifa (job) yaratasiz va natija tayyor bo‘lganda uni olasiz. Vazifa tugaganini bilishning ikki usuli bor: so‘rov yuborish (polling) va vebhuk (push). Quyida vazifa qanday ishlashi va natijani ishonchli olish usullari keltirilgan.
Vazifa hayotiy sikli
POST /media/generate → status: processing ──► done (result_url tayyor)
│ └─► failed (error, mablag‘ qaytariladi)
└── (ixtiyoriy) callback_url → done/failed holatida push-vebhuk- Yaratish. Model va parametrlar bilan
POST /media/generateso‘rovini yuboring — javobdaidva so‘rov yuborish havolasi qaytadi:
{ "id": "beefb531-…", "model": "image/nano-banana-2", "status": "processing",
"poll": "https://nordrouter.com/media/job/beefb531-…" }Kutish. Vazifa
processing→done(yokifailed) holatiga o‘tadi. Tasvirlar bir necha soniyada, video va musiqa esa o‘nlab soniyadan bir necha daqiqagacha tayyor bo‘ladi.Natija. Tugallangan vazifaning
result_urlmaydoni to‘ldiriladi (nordrouter.comhavolasi); fayl cheklangan vaqt saqlanadi (GET /media/modelsjavobidagiretention_days) — uni saqlab qolish uchun yuklab oling.
GET /media/job/:id javobining formati (va vebhuk tanasi — quyida ko‘ring) bir xil:
{ "id": "beefb531-…", "status": "done",
"result_url": "https://nordrouter.com/media/file/beefb531-…",
"cost_usd": 0.052, "error": null }status—processing|done|failed.result_url— faqatdoneholatida to‘ldiriladi, aks holdanull.result_url_2— musiqiy modellardagi ikkinchi trek (Suno) uchun, aks holdanull.results— vazifaning barcha fayllari:[{ "index": 1, "name": "Natija 1", "ext": "png", "url": "…" }](3D uchun model va ko‘rib chiqish tasviri, trekni ajratishda esa «Vokal», «Instrumental» kabi yo‘laklar).cost_usd— haqiqiy narx (mablag‘ sarflanganiga qarab yechiladi; muvaffaqiyatsiz generatsiyalar hisoblanmaydi — zaxiralangan mablag‘ qaytariladi).error—failedholatidagi xato matni, aks holdanull.
1-usul. So‘rov yuborish (polling)
Eng sodda usul — status done/failed bo‘lguncha davriy ravishda GET /media/job/:id so‘rovini yuborish:
curl https://nordrouter.com/media/job/beefb531-…Har 2–3 soniyada so‘rov yuboring. So‘rov yuborish doim ishlaydi va ommaviy manzilni talab qilmaydi — skriptlar, noutbuklar va CI uchun mos.
2-usul. Vebhuklar (push)
Doimiy so‘rov yubormaslik uchun callback_url ni POST /media/generate so‘roviga qo‘shing. Vazifa tugagach, manzilingizga o‘zimiz POST yuboramiz:
curl https://nordrouter.com/media/generate \
-H "Authorization: Bearer sk-nr-YOUR-KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "image/nano-banana-2",
"input": { "prompt": "…" },
"callback_url": "https://your-server.com/webhooks/nordrouter",
"callback_secret": "любая-ваша-строка"
}'callback_url qabul qilinsa, vazifa yaratilgani haqidagi javobda "webhook": "registered" bo‘ladi. callback_url vazifa yaratilishi bilanoq tekshiriladi: manzil yaroqsiz bo‘lsa (https bo‘lmasa yoki xususiy/mahalliy manzil bo‘lsa), so‘rov sabab ko‘rsatilgan 400 xatosini qaytaradi ({ "error": "callback_url отклонён: …", "code": "invalid_callback" }), vazifa yaratilmaydi.
Vebhuk tanasi
Vazifa done/failed holatiga yetganda, callback_url manzilingizga GET /media/job/:id bilan bir xil tana va qo‘shimcha event maydoni bo‘lgan POST so‘rovi keladi:
{ "event": "media.completed", "id": "beefb531-…", "status": "done",
"result_url": "https://nordrouter.com/media/file/beefb531-…",
"cost_usd": 0.052, "error": null }event—media.completed(muvaffaqiyat) yokimedia.failed(xato).
Imzoni tekshirish
Agar callback_secret belgilagan bo‘lsangiz, X-NR-Signature sarlavhasida sha256=<hmac> bo‘ladi. Bu so‘rovning xom tanasi va kalit sifatida sizning maxfiy kalitingiz bilan hisoblangan HMAC-SHA256. So‘rov bizdan kelganiga va soxtalashtirilmaganiga ishonch hosil qilish uchun imzoni tekshiring:
import hmac, hashlib
def verify(raw_body: bytes, header: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header) # o‘zgarmas vaqt ichida taqqoslashimport crypto from "node:crypto";
function verify(rawBody, header, secret) {
const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(header));
}HMACni JSON tahlilidan oldin, kelganicha aynan o‘sha baytlar bo‘yicha hisoblang, aks holda imzo mos kelmaydi.
10 qatorda tayyor qabul qilgich
Vebhukni qabul qiladigan, imzoni tekshiradigan va 2xx bilan javob beradigan ishlaydigan server. Maxfiy kalit — callback_secret ga uzatgan kalitingiz bilan bir xil.
Node.js / Express:
import express from "express";
import crypto from "node:crypto";
const SECRET = "любая-ваша-строка"; // = ваш callback_secret
const app = express();
app.post("/webhooks/nordrouter",
express.raw({ type: "application/json" }), // сырое тело — обязательно для подписи
(req, res) => {
const expected = "sha256=" + crypto.createHmac("sha256", SECRET).update(req.body).digest("hex");
const got = req.headers["x-nr-signature"] || "";
if (expected.length !== got.length || !crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(got)))
return res.sendStatus(401); // подпись не сошлась — не наш запрос
const job = JSON.parse(req.body);
if (job.event === "media.completed") console.log("готово:", job.result_url, "$" + job.cost_usd);
res.sendStatus(200); // ответьте 2xx, иначе будет повтор
});
app.listen(3000);Python / FastAPI:
import hmac, hashlib
from fastapi import FastAPI, Request, Response
SECRET = b"любая-ваша-строка" # = ваш callback_secret
app = FastAPI()
@app.post("/webhooks/nordrouter")
async def hook(request: Request):
raw = await request.body() # сырые байты — обязательно для подписи
expected = "sha256=" + hmac.new(SECRET, raw, hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, request.headers.get("X-NR-Signature", "")):
return Response(status_code=401) # подпись не сошлась — не наш запрос
job = await request.json()
if job["event"] == "media.completed":
print("готово:", job["result_url"], "$", job["cost_usd"])
return Response(status_code=200) # ответьте 2xx, иначе будет повторMahalliy muhitda tekshirish
callback_url ommaviy https manzili bo‘lishi kerak. Noutbukda ishlab chiqish uchun tunnel oching, masalan ngrok http 3000, va u bergan https manzilini callback_url sifatida uzating.
Yetkazish va ishonchlilik
- 4 tagacha urinish ortib boruvchi tanaffus bilan (≈3 → 6 → 9 soniya), har bir urinish uchun kutish vaqti — 15 soniya.
2xxbilan javob bering, aks holda qayta yuboriladi. - Yo‘naltirishlarga amal qilinmaydi — bevosita
callback_urlmanzilida javob bering. - Yetkazish — best-effort: 4 urinishning barchasi muvaffaqiyatsiz bo‘lsa (serveringiz ishlamagan bo‘lsa), vebhuk keyinroq qayta yuborilmaydi. Shuning uchun:
Vebhuklar so‘rov yuborish o‘rnini bosmaydi
Vebhuk — tezlashtirish vositasi, kafolat emas. Zaxira yo‘l sifatida GET /media/job/:id ni saqlang: push oqilona vaqt ichida kelmasa, holatni o‘zingiz so‘rang. Idempotentlik siz tomonda: bir vazifa vebhuk orqali ham kelishi, ham so‘rovda aniqlanishi mumkin — id bo‘yicha tekshiring.
callback_url talablari
- Faqat
https://. - Faqat ommaviy manzil. Mahalliy va xususiy manzillar (
localhost,*.local,10.x,172.16–31.x,192.168.x,127.x,169.254.x,100.64–127.x, IPv6 loopback/ULA/link-local) rad etiladi — bu SSRF hujumlaridan himoya. Manzil har bir yuborishdan oldin ham qayta tekshiriladi (DNS-rebindingdan himoya).
Qaysi usulni tanlash kerak
| So‘rov yuborish | Vebhuk | |
|---|---|---|
Ommaviy https manzili | kerak emas | kerak |
| Natijani olish kechikishi | so‘rov oralig‘igacha | deyarli darhol |
| Kafolat | nazorat sizda | best-effort + zaxira so‘rov |
| Qayerda qulay | skriptlar, CI, noutbuk | serverlar, ishlab chiqarish backendlari |
Tavsiya: backendda — vebhuk va zaxira sifatida so‘rov yuborish; skript/noutbukda — faqat so‘rov yuborish.