Skip to content

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
  1. Yaratish. Model va parametrlar bilan POST /media/generate so‘rovini yuboring — javobda id va so‘rov yuborish havolasi qaytadi:
json
{ "id": "beefb531-…", "model": "image/nano-banana-2", "status": "processing",
  "poll": "https://nordrouter.com/media/job/beefb531-…" }
  1. Kutish. Vazifa processing → done (yoki failed) holatiga o‘tadi. Tasvirlar bir necha soniyada, video va musiqa esa o‘nlab soniyadan bir necha daqiqagacha tayyor bo‘ladi.

  2. Natija. Tugallangan vazifaning result_url maydoni to‘ldiriladi (nordrouter.com havolasi); fayl cheklangan vaqt saqlanadi (GET /media/models javobidagi retention_days) — uni saqlab qolish uchun yuklab oling.

GET /media/job/:id javobining formati (va vebhuk tanasi — quyida ko‘ring) bir xil:

json
{ "id": "beefb531-…", "status": "done",
  "result_url": "https://nordrouter.com/media/file/beefb531-…",
  "cost_usd": 0.052, "error": null }
  • status — processing | done | failed.
  • result_url — faqat done holatida to‘ldiriladi, aks holda null.
  • result_url_2 — musiqiy modellardagi ikkinchi trek (Suno) uchun, aks holda null.
  • 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 — failed holatidagi xato matni, aks holda null.

1-usul. So‘rov yuborish (polling) ​

Eng sodda usul — status done/failed bo‘lguncha davriy ravishda GET /media/job/:id so‘rovini yuborish:

bash
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:

bash
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:

json
{ "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) yoki media.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:

python
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 taqqoslash
javascript
import 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:

javascript
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:

python
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. 2xx bilan javob bering, aks holda qayta yuboriladi.
  • Yo‘naltirishlarga amal qilinmaydi — bevosita callback_url manzilida 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 yuborishVebhuk
Ommaviy https manzilikerak emaskerak
Natijani olish kechikishiso‘rov oralig‘igachadeyarli darhol
Kafolatnazorat sizdabest-effort + zaxira so‘rov
Qayerda qulayskriptlar, CI, noutbukserverlar, ishlab chiqarish backendlari

Tavsiya: backendda — vebhuk va zaxira sifatida so‘rov yuborish; skript/noutbukda — faqat so‘rov yuborish.