Przejdź do treści

Приклади

Повні приклади інтеграції з використанням curl, JavaScript та Python.

На цій сторінці представлено повний робочий процес генерації фотосесії трьома мовами: curl, JavaScript (fetch) та Python (requests). Кожен приклад виконує однакові кроки:

  1. Перегляд продуктів для вибору одного для зйомки.
  2. Перегляд схвалених ШІ-моделей та декорацій.
  3. Реєстрація генерації фотосесії з комбінацією продукту, моделі та декорації.
  4. Опитування ендпоінта image-picker до готовності результатів.
  5. Перегляд та схвалення згенерованих зображень.

Загальне налаштування

Кожен запит вимагає дві речі:

  • Базова URL-адреса — https://qamera.ai (замініть на вашу власну URL-адресу для self-hosted розгортань).
  • Автентифікація — Передайте ваш API key у заголовку X-Api-Key.
X-Api-Key: mk_live_abc123.secret456

Ви можете згенерувати API key у Settings > API Keys вашого командного робочого простору. Ключ показується лише один раз, тому скопіюйте його негайно.

GET-ендпоінти безкоштовні та ніколи не витрачають кредити. POST-ендпоінти, що запускають генерацію контенту, резервують кредити наперед і витрачають їх після завершення обробки.


Приклади curl

Крок 1 — Перегляд продуктів

Отримайте всі продукти, завантажені до вашого акаунта.

curl -s -X GET "https://qamera.ai/api/external/products" \
  -H "X-Api-Key: mk_live_abc123.secret456"

Відповідь:

{
  "products": [
    {
      "id": "rec_product_001",
      "name": "White T-Shirt Front",
      "thumbnail": "https://cdn.example.com/products/thumb_001.jpg",
      "status": "UPLOADED",
      "createdAt": "2026-03-20T14:30:00.000Z"
    },
    {
      "id": "rec_product_002",
      "name": "Leather Handbag",
      "thumbnail": "https://cdn.example.com/products/thumb_002.jpg",
      "status": "UPLOADED",
      "createdAt": "2026-03-21T09:15:00.000Z"
    }
  ],
  "count": 2
}

Виберіть ID продукту для використання у фотосесії. У цих прикладах ми будемо використовувати rec_product_001.

Крок 2 — Перегляд схвалених моделей

Отримайте лише моделі, схвалені для використання.

curl -s -X GET "https://qamera.ai/api/external/models?statusFilter=approved" \
  -H "X-Api-Key: mk_live_abc123.secret456"

Відповідь:

{
  "models": [
    {
      "id": "rec_model_101",
      "name": "Sophie — Casual",
      "thumbnail": "https://cdn.example.com/models/thumb_101.jpg",
      "status": "DONE",
      "voting": "APPROVED",
      "createdAt": "2026-03-18T10:00:00.000Z"
    }
  ],
  "count": 1
}

Крок 3 — Перегляд схвалених декорацій

curl -s -X GET "https://qamera.ai/api/external/sceneries?statusFilter=approved" \
  -H "X-Api-Key: mk_live_abc123.secret456"

Відповідь:

{
  "sceneries": [
    {
      "id": "rec_scenery_201",
      "name": "Bright Studio",
      "thumbnail": "https://cdn.example.com/sceneries/thumb_201.jpg",
      "status": "DONE",
      "voting": "APPROVED",
      "createdAt": "2026-03-19T11:45:00.000Z"
    }
  ],
  "count": 1
}

Крок 4 — Реєстрація фотосесії

Скомбінуйте продукт, модель та декорацію для запуску генерації. Цей ендпоінт резервує кредити.

curl -s -X POST "https://qamera.ai/api/external/image-picker/register-ideas" \
  -H "X-Api-Key: mk_live_abc123.secret456" \
  -H "Content-Type: application/json" \
  -d '{
    "config": {
      "product": { "id": "rec_product_001" },
      "model": { "id": "rec_model_101" },
      "scenery": { "id": "rec_scenery_201" },
      "industry": "fashion",
      "suggestions": "bright lighting, clean composition"
    },
    "count": 4
  }'

Відповідь:

{
  "createdRecordIds": ["rec_gen_301", "rec_gen_302", "rec_gen_303", "rec_gen_304"],
  "batchId": "batch_abc123",
  "orderId": "ord_xyz789",
  "reservationId": "res_def456",
  "creditsReserved": 120
}

Збережіть createdRecordIds — ви будете використовувати їх для перевірки прогресу.

Крок 5 — Опитування результатів

Генерація відбувається асинхронно. Опитуйте ендпоінт image-picker, фільтруючи за вашим продуктом, поки зображення не отримають статус DONE.

curl -s -X GET "https://qamera.ai/api/external/image-picker?productId=rec_product_001" \
  -H "X-Api-Key: mk_live_abc123.secret456"

Відповідь (під час обробки):

{
  "images": [
    {
      "id": "rec_gen_301",
      "name": "White T-Shirt — Variant 1",
      "thumbnail": "",
      "status": "INPROGRESS",
      "voting": null,
      "createdAt": "2026-03-27T12:00:00.000Z"
    }
  ],
  "count": 1
}

Зачекайте хвилину та викличте той самий ендпоінт знову. Коли status стане DONE, поле thumbnail міститиме URL зображення.

Крок 6 — Схвалення або відхилення результатів

Ви можете схвалювати зображення за допомогою ендпоінта оновлення пакшотів. Для зображень фотосесії, які ви хочете зберегти, схваліть їх, щоб вони з'являлися у відфільтрованих переглядах.

# Схвалення зображення
curl -s -X POST "https://qamera.ai/api/external/packshots/update-packshot" \
  -H "X-Api-Key: mk_live_abc123.secret456" \
  -H "Content-Type: application/json" \
  -d '{
    "recordId": "rec_gen_301",
    "Voting": "APPROVED"
  }'

Відповідь:

{
  "success": true,
  "message": "Packshot voting updated successfully",
  "recordId": "rec_gen_301"
}

Для відхилення зображення (яке архівує його):

curl -s -X POST "https://qamera.ai/api/external/packshots/update-packshot" \
  -H "X-Api-Key: mk_live_abc123.secret456" \
  -H "Content-Type: application/json" \
  -d '{
    "recordId": "rec_gen_302",
    "Voting": "REJECTED"
  }'

Приклад JavaScript (fetch)

Наступний приклад використовує API fetch браузера/Node.js для виконання того самого робочого процесу.

Допоміжна функція

const BASE_URL = "https://qamera.ai";
const API_KEY = "mk_live_abc123.secret456";

async function qameraFetch(path, options = {}) {
  const url = new URL(path, BASE_URL);

  if (options.params) {
    Object.entries(options.params).forEach(([key, value]) =>
      url.searchParams.set(key, value)
    );
  }

  const response = await fetch(url.toString(), {
    method: options.method || "GET",
    headers: {
      "X-Api-Key": API_KEY,
      ...(options.body ? { "Content-Type": "application/json" } : {}),
    },
    ...(options.body ? { body: JSON.stringify(options.body) } : {}),
  });

  if (!response.ok) {
    const error = await response.json().catch(() => ({}));
    throw new Error(
      `API error ${response.status}: ${error.error || response.statusText}`
    );
  }

  return response.json();
}

Повний робочий процес

async function runPhotoShootWorkflow() {
  // 1. Перегляд продуктів
  const { products } = await qameraFetch("/api/external/products");
  console.log(`Found ${products.length} products`);

  const product = products[0];
  if (!product) throw new Error("No products found. Upload one first.");
  console.log(`Using product: ${product.name} (${product.id})`);

  // 2. Перегляд схвалених моделей
  const { models } = await qameraFetch("/api/external/models", {
    params: { statusFilter: "approved" },
  });
  console.log(`Found ${models.length} approved models`);

  // 3. Перегляд схвалених декорацій
  const { sceneries } = await qameraFetch("/api/external/sceneries", {
    params: { statusFilter: "approved" },
  });
  console.log(`Found ${sceneries.length} approved sceneries`);

  // 4. Реєстрація генерації фотосесії
  const registration = await qameraFetch(
    "/api/external/image-picker/register-ideas",
    {
      method: "POST",
      body: {
        config: {
          product: { id: product.id },
          model: models[0] ? { id: models[0].id } : undefined,
          scenery: sceneries[0] ? { id: sceneries[0].id } : undefined,
          industry: "fashion",
          suggestions: "bright lighting, clean composition",
        },
        count: 4,
      },
    }
  );

  console.log(`Generation started — order ${registration.orderId}`);
  console.log(`Credits reserved: ${registration.creditsReserved}`);

  // 5. Опитування до готовності результатів
  const generatedIds = new Set(registration.createdRecordIds);
  let attempts = 0;
  const maxAttempts = 30;

  while (attempts < maxAttempts) {
    await new Promise((resolve) => setTimeout(resolve, 10_000));
    attempts++;

    const { images } = await qameraFetch("/api/external/image-picker", {
      params: { productId: product.id },
    });

    const ours = images.filter((img) => generatedIds.has(img.id));
    const done = ours.filter((img) => img.status === "DONE");

    console.log(`Poll ${attempts}: ${done.length}/${ours.length} done`);

    if (done.length === ours.length && done.length > 0) {
      console.log("All images ready!");

      // 6. Схвалення першого результату
      await qameraFetch("/api/external/packshots/update-packshot", {
        method: "POST",
        body: {
          recordId: done[0].id,
          Voting: "APPROVED",
        },
      });
      console.log(`Approved image ${done[0].id}`);

      return done;
    }
  }

  throw new Error("Generation timed out after 5 minutes");
}

runPhotoShootWorkflow()
  .then((images) => console.log("Completed:", images))
  .catch((err) => console.error("Failed:", err.message));

Приклад Python (requests)

Наступний приклад використовує бібліотеку requests (pip install requests).

Налаштування сесії

import time
import requests

BASE_URL = "https://qamera.ai"
API_KEY = "mk_live_abc123.secret456"

session = requests.Session()
session.headers.update({"X-Api-Key": API_KEY})

Повний робочий процес

def run_photo_shoot_workflow():
    # 1. Перегляд продуктів
    resp = session.get(f"{BASE_URL}/api/external/products")
    resp.raise_for_status()
    products = resp.json()["products"]
    print(f"Found {len(products)} products")

    if not products:
        raise RuntimeError("No products found. Upload one first.")

    product = products[0]
    print(f"Using product: {product['name']} ({product['id']})")

    # 2. Перегляд схвалених моделей
    resp = session.get(
        f"{BASE_URL}/api/external/models",
        params={"statusFilter": "approved"},
    )
    resp.raise_for_status()
    models = resp.json()["models"]
    print(f"Found {len(models)} approved models")

    # 3. Перегляд схвалених декорацій
    resp = session.get(
        f"{BASE_URL}/api/external/sceneries",
        params={"statusFilter": "approved"},
    )
    resp.raise_for_status()
    sceneries = resp.json()["sceneries"]
    print(f"Found {len(sceneries)} approved sceneries")

    # 4. Реєстрація генерації фотосесії
    config = {
        "product": {"id": product["id"]},
        "industry": "fashion",
        "suggestions": "bright lighting, clean composition",
    }
    if models:
        config["model"] = {"id": models[0]["id"]}
    if sceneries:
        config["scenery"] = {"id": sceneries[0]["id"]}

    resp = session.post(
        f"{BASE_URL}/api/external/image-picker/register-ideas",
        json={"config": config, "count": 4},
    )
    resp.raise_for_status()
    registration = resp.json()

    print(f"Generation started — order {registration['orderId']}")
    print(f"Credits reserved: {registration['creditsReserved']}")

    # 5. Опитування до готовності результатів
    generated_ids = set(registration["createdRecordIds"])
    max_attempts = 30

    for attempt in range(1, max_attempts + 1):
        time.sleep(10)

        resp = session.get(
            f"{BASE_URL}/api/external/image-picker",
            params={"productId": product["id"]},
        )
        resp.raise_for_status()
        images = resp.json()["images"]

        ours = [img for img in images if img["id"] in generated_ids]
        done = [img for img in ours if img["status"] == "DONE"]

        print(f"Poll {attempt}: {len(done)}/{len(ours)} done")

        if len(done) == len(ours) and done:
            print("All images ready!")

            # 6. Схвалення першого результату
            resp = session.post(
                f"{BASE_URL}/api/external/packshots/update-packshot",
                json={
                    "recordId": done[0]["id"],
                    "Voting": "APPROVED",
                },
            )
            resp.raise_for_status()
            print(f"Approved image {done[0]['id']}")

            return done

    raise TimeoutError("Generation timed out after 5 minutes")


if __name__ == "__main__":
    try:
        results = run_photo_shoot_workflow()
        for img in results:
            print(f"  {img['name']}: {img['thumbnail']}")
    except Exception as e:
        print(f"Error: {e}")