Przejdź do treści głównej

Edycja obrazu w Qwen Image 2.1 poprawia od jednego do dziesięciu obrazów referencyjnych według instrukcji i zwraca jeden kadr w 1k, 1.5k lub 2k. Robi też edycje lokalne z czarno-białą maską, w której biel jest przemalowywana.

Od $0.036/obraz

Obszar roboczy

Wyślij żądanie

Szybki start

Przykłady korzystają z publicznych definicji parametrów wybranego endpointu. Podmień klucz API i przykładowe media, a potem wyślij żądanie ze swojego serwera.

SDK i integracje
POSThttps://api.spicyapi.ai/api/v1/jobs/createTask

Uwierzytelnianie API

Klucz API trzymaj w zmiennej środowiskowej serwera SPICY_API_KEY. Dla żądań JSON używaj uwierzytelniania Bearer i Content-Type: application/json.

Authorization: Bearer $SPICY_API_KEY
Qwen Image 2.1 · Image Editing · Przykładowy wynik
Przykładowy wynikUżyj tego przykładu
# Generate the idempotency key once; reuse it when retrying after a lost response.
export SPICY_IDEMPOTENCY_KEY="${SPICY_IDEMPOTENCY_KEY:-$(uuidgen)}"
curl -X POST https://api.spicyapi.ai/api/v1/jobs/createTask \
  -H "Authorization: Bearer $SPICY_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $SPICY_IDEMPOTENCY_KEY" \
  -d '{
  "model": "alibaba/qwen-image-2.1/edit",
  "input": {
    "aspect_ratio": "1:1",
    "background": "opaque",
    "image_urls": [
      "https://example.com/reference.png"
    ],
    "output_format": "jpeg",
    "prompt": "A ceramic teapot on a linen cloth, soft window light, muted palette",
    "resolution": "1k"
  }
}'

# Copy data.taskId from the response into TASK_ID, then poll the status.
TASK_ID="TASK_ID_FROM_RESPONSE"
curl "https://api.spicyapi.ai/api/v1/jobs/recordInfo?taskId=$TASK_ID" \
  -H "Authorization: Bearer $SPICY_API_KEY"

Wygenerowane ze schematu wejścia tego modelu – tego samego, względem którego API waliduje każde żądanie.

Parametry wejściowe

Te pola umieść w obiekcie input w ciele żądania. Nazwy i typy odpowiadają API. Gdy wartości domyślnej nie podano, nie zakładaj żadnej.

image_urlsarray<string>WymaganeWpływa na cenę

Od jednego do dziesięciu obrazów referencyjnych. Model nie przypisuje ról samodzielnie, więc w prompcie nazwij, co wnosi każde źródło — które jest osobą, które scenerią, a które ubraniem. Każda dołożona referencja podnosi wycenę, więc wysyłaj tylko te, które naprawdę pracują.

Domyślnie
Nie określono
Ograniczenia
minItems:1
maxItems:10
promptstringWymagane

Do 5000 znaków. W tej rodzinie nie ma negatywnego promptu, więc wykluczenia też należą tutaj — nazwij, co jest w kadrze, a potem powiedz wprost, czego w nim być nie może. Jeden ciągły opis działa lepiej niż stos słów kluczowych.

Domyślnie
Nie określono
Ograniczenia
minLength:1
maxLength:5000
seedintegerOpcjonalne

Stabilizuje losowanie, dzięki czemu seria trzyma się tej samej okolicy. To nie jest gwarancja odtworzenia — wysłaliśmy ten sam prompt i ten sam seed dwa razy i dostaliśmy dwa różne kadry. Gdy potrzebujesz dokładnie tego obrazu ponownie, zachowaj zwrócony zasób.

Domyślnie
Nie określono
Ograniczenia
minimum:0
maximum:2147483647
output_formatstringOpcjonalne

Domyślnie JPEG. PNG, gdy kadr idzie dalej do składania, WebP, gdy trafia prosto na stronę. Kontener nie zmienia ani ceny, ani samego renderu.

Domyślnie
"jpeg"
Dozwolone wartości
"jpeg""png""webp"
backgroundstringOpcjonalne

Domyślnie opaque. transparent zwraca sam obiekt na prawdziwym kanale alfa: połącz to z wyjściem png lub webp (jpeg nie ma kanału alfa i żądanie zostaje odrzucone) i opisz wyłącznie obiekt, bo wspomnienie pokoju, powierzchni czy sceny może przywrócić tło. Dostępne w 1k i 2k, niedostępne w 1.5k. Nie zmienia ceny. Nie łączy się z mask_url.

Domyślnie
"opaque"
Dozwolone wartości
"opaque""transparent"
enable_prompt_expansionbooleanOpcjonalne

Domyślnie włączone: przed generowaniem prompt jest przepisywany na pełniejszy opis sceny. Wyłącz, jeśli chcesz, żeby użyto twojego sformułowania bez zmian. Wyłączenie jest dostępne w 1k i 2k, nie w 1.5k. Nie zmienia ceny. Nie działa, gdy podano mask_url.

Domyślnie
true
resolutionstringOpcjonalneWpływa na cenę

Poziom, który ustala rozmiar wyjścia i cenę: 1k jest domyślny i najtańszy, 1.5k leży pomiędzy, a na 2k utrzymują się faktura skóry, włosy i splot tkaniny. Iteruj na 1k i przenieś najlepszy kadr na 2k.

Domyślnie
"1k"
Dozwolone wartości
"1k""1.5k""2k"
aspect_ratiostringOpcjonalne

Komponuje kadr jeszcze przed generowaniem, zamiast przycinać go potem, więc wybierz kształt, w którym będziesz publikować. Piętnaście opcji, od pasów 3:1 i 21:9 po kolumny 1:3 i 9:21. Wszystkie proporcje kosztują tyle samo.

Domyślnie
"1:1"
Dozwolone wartości
"1:1""16:9""9:16""4:3""3:4""3:2""2:3""21:9""9:21""2:1""1:2""3:1""1:3""5:4""4:5"
mask_urlstringOpcjonalne

Opcjonalny czarno-biały obraz, który przełącza edycję w tryb lokalny: biel oznacza obszar do przemalowania, czerń zostaje bez zmian, a kilka pikseli miękkiej krawędzi pomaga w przejściu. Używaj go z dokładnie jednym obrazem referencyjnym o tych samych proporcjach (maska o innym rozmiarze jest skalowana) i opisz w prompcie, co ma się pojawić w białym obszarze. Wynik zachowuje kształt obrazu referencyjnego, więc aspect_ratio jest pomijany, a maski nie da się połączyć z przezroczystym tłem. Dostępne w 1k i 2k, niedostępne w 1.5k. Nie zmienia ceny.

Domyślnie
Nie określono
Ograniczenia
format:"uri"
contentMediaType:["image/jpeg","image/png","image/webp","image/gif"]

Śledź zadanie

HTTP 202 oznacza, że zadanie zostało przyjęte, a nie ukończone. Zapisz zwrócone taskId i odpytuj właśnie to zadanie. Nie twórz kolejnego zadania, czekając na jego wynik.

Odpowiedź o przyjęciu
HTTP/1.1 202 Accepted
Location: /api/v1/jobs/recordInfo?taskId=job_01k3m8x9q2z4v7n5p6r8s0t1w3

{
  "code": 200,
  "msg": "success",
  "request_id": "req_example_create",
  "data": {
    "taskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3",
    "state": "queued",
    "estimatedCost": "0.750000"
  }
}

Odpowiedź o przyjęciu zawiera szacunek, dzięki czemu twoja aplikacja pokaże tę samą kwotę w historii zadań i w rozliczeniach.

Odczytaj zadanie
curl --get "https://api.spicyapi.ai/api/v1/jobs/recordInfo" \
  --data-urlencode "taskId=$TASK_ID" \
  -H "Authorization: Bearer $SPICY_API_KEY"

Zacznij odpytywać mniej więcej co 2 sekundy i stopniowo wydłużaj odstęp. Zatrzymaj się na stanie końcowym. Po zerwaniu połączenia odpytaj pierwotne taskId. Tworzenie ponawiaj wyłącznie z pierwotnym kluczem idempotentności i pierwotnym ciałem żądania.

Albo odbierz wynik przez callback
import { verifyWebhook } from "@spicyapi/sdk";

// express.raw keeps the bytes we signed; express.json never matches.
app.post("/hooks/spicy", express.raw({ type: "application/json" }), (req, res) => {
  const { payload } = verifyWebhook({
    rawBody: req.body,
    timestamp: req.header("X-Webhook-Timestamp"),
    signature: req.header("X-Webhook-Signature"),
    payloadVersion: Number(req.header("X-Webhook-Payload-Version")),
    secret: process.env.SPICY_WEBHOOK_SECRET,
  });
  res.status(200).end();
  void handleFinishedTask(payload);
});

Podaj callBackUrl przy tworzeniu zadania, a gotowy rekord przyjdzie do ciebie metodą POST – bez żadnej pętli odpytywania. Każda dostawa niesie X-Webhook-Timestamp, X-Webhook-Signature i X-Webhook-Payload-Version. Podpis to HMAC-SHA256 w base64 z taskId.timestamp.sha256(body), więc trzeba go sprawdzać na surowych bajtach: sparsowanie JSON-a i ponowne zserializowanie zmienia je i weryfikacja się nie powiedzie. Nieudane dostawy są ponawiane, więc to samo taskId może przyjść dwa razy – zrób obsługę idempotentną. Najpierw odpowiedz kodem 2xx, a pracę wykonaj potem; wolna obsługa jest traktowana jak nieudana dostawa.

Odczytaj wynik

Wynik wykorzystuj dopiero przy stanie succeeded. Przy niepowodzeniu skorzystaj z errorCode, errorMessage i request_id. Przykładowe koszty i stany nie odpowiadają rzeczywistemu rozliczeniu.

Przykład odpowiedzi po zakończeniu
{
  "code": 200,
  "msg": "success",
  "request_id": "req_example_record",
  "data": {
    "taskId": "job_01k3m8x9q2z4v7n5p6r8s0t1w3",
    "model": "alibaba/qwen-image-2.1/edit",
    "state": "succeeded",
    "output": {
      "assets": [
        {
          "key": "tasks/2026/08/28/job_01k3m8x9q2z4v7n5p6r8s0t1w3/3f7a1c9e5b2d48f0a6c1e3d5b7f9a1c3.png",
          "mime": "image/png",
          "url": "https://example.r2.cloudflarestorage.com/results/job_01k3m8x9q2z4v7n5p6r8s0t1w3/result.png?X-Amz-Signature=SIGNATURE_FROM_RESPONSE",
          "expiresAt": "2026-08-28T12:20:08.000Z"
        }
      ]
    },
    "cost": "0.750000",
    "settled": true,
    "createdAt": "2026-08-28T12:00:00Z",
    "completedAt": "2026-08-28T12:00:30Z"
  }
}

Każdy dostępny materiał otwieraj lub pobieraj bezpośrednio spod assets[].url, bez nagłówka Authorization. Podpisany adres wygasa o expiresAt; odpytaj zadanie ponownie, żeby go odświeżyć, dopóki materiał mieści się w okresie przechowywania. Materiał oczekujący lub niedostępny nie ma adresu. Podpisane adresy traktuj jako prywatne.

SDK i integracje

Korzystaj ze SpicyAPI w aplikacji, terminalu, asystencie AI lub wizualnym przepływie pracy. Wybierz instrukcję konfiguracji.

Użyj w ComfyUI

Zainstaluj węzły SpicyAPI przez ComfyUI Manager albo poleceniem poniżej, a potem wyszukaj na płótnie Qwen Image 2.1 · Image Editing. Węzeł ma te same opcje co ta strona i pokazuje cenę, zanim ruszy.

cd ComfyUI/custom_nodes
git clone https://github.com/spicyapi-ai/comfyui-spicyapi