spicyapiDokumentacja
Przewodniki
Treść główna

Przewodnik: generowanie i edycja obrazów

Jak zachowują się endpointy obrazu jako grupa — dwie postacie żądania, trzy sposoby zapisu rozmiaru wyjścia, co dokłada do rachunku obraz referencyjny, wagi adaptera i jak czytać odmowę.

Ten przewodnik dotyczy grupy endpointów obrazu, a nie pojedynczego modelu. Opisuje to, co jest w nich wszystkich takie samo, i — co przydatniejsze — miejsca, w których różnią się na tyle, że ciało żądania napisane dla jednego nie przejdzie na kolejnym.

Celowo nie ma tu tabeli parametrów. Parametry mają dokładnie jedno źródło: inputSchema, który żywy katalog zwraca dla dokładnie tego modelu, który wywołujesz. Ta strona pokazuje, jak czytać ten schemat i czego on nie mówi wprost.

Jeśli szukaszPrzeczytaj zamiast tego
Pierwszego obrazu od klucza i salda aż po plikSzybki start
Tej samej drogi dla wideo, krok po krokuSamouczek: zamień zdjęcie w wideo
Wszystkich pól konkretnego modeluJego inputSchema — zobacz Katalog modeli i schematy
Przeniesienia twarzy lub głowy z jednego zdjęcia na drugiePodmiana obiektu

MODEL_ID_FROM_CATALOG to symbol zastępczy

We wszystkich przykładach poniżej MODEL_ID_FROM_CATALOG stoi tam, gdzie ma być prawdziwy identyfikator modelu. Weź go z uwierzytelnionego żywego katalogu — GET /api/v1/models?modality=image — i wymagaj zarówno enabled: true, jak i available: true, zanim cokolwiek wydasz. Czytanie katalogu jest bezpłatne. Wysłanie samego symbolu zastępczego zwróci tylko błąd „not found".

Dwie postacie żądania

Praca z obrazami przychodzi jako dwa zadania i katalog je rozdziela:

  • Endpointy generujące kończą się na /text-to-image. Wysyłasz słowa, dostajesz obraz.
  • Endpointy edytujące kończą się na /edit. Wysyłasz dodatkowo co najmniej jeden obraz.

Edycja ma dwie dopuszczalne pisownie i warto znać obie, zanim zaczniesz filtrować katalog: endpointy są publikowane z przyrostkiem edit, natomiast tablica tasks klasyfikuje je jako image-to-image. Parametr zapytania task przyjmuje każdą z nich. Zobacz Katalog modeli i schematy.

Obie postacie korzystają z tej samej koperty tworzenia, tego samego cyklu życia zadania i tego samego formatu wyniku co każdy inny model multimedialny. Różni się tylko input.

prompt jest wymagany w obu

Kusi, by założyć, że endpointowi edytującemu wystarczy sam obraz, a prompt jest tam opcjonalny. Na endpointach, które w ogóle przyjmują prompt, tak nie jest: prompt znajduje się na głównej liście required w obu postaciach, a jego pominięcie zostaje odrzucone, zanim cokolwiek zostanie naliczone.

Odrzucone przez endpoint edytujący
{
  "model": "MODEL_ID_FROM_CATALOG",
  "input": {
    "image_urls": ["spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3"]
  }
}
prompt: is required

Obraz mówi, od czego zaczynasz; prompt mówi, co z nim zrobić. Endpoint edytujący, który nie dostał polecenia, nie ma na czym działać.

Jest jeden wyjątek i jest nim cała rodzina, a nie pojedynczy przypadek: niektóre endpointy edytujące nie przyjmują żadnego prompt i biorą wyłącznie obrazy, bo operacja jest ustalona przez sam endpoint. Należą one do zestawu narzędzi podmiany obiektu i mają w katalogu pole toolkit, po którym je rozpoznasz; zobacz Podmiana obiektu. Dla nich prompt: is not a supported field to właściwa odpowiedź, a nie usterka.

Pole obrazu wejściowego ma trzy nazwy

To, której używa dany endpoint, należy do jego schematu i nie da się tego wywnioskować z rodzaju zadania:

PolePostaćCo zwykle oznacza
image_urljedno odniesienie do obrazuJest dokładnie jeden obraz z obiektem, a endpoint nie zna pojęcia drugiego
image_urlstablica odniesień do obrazówObrazy są materiałem, który się edytuje lub łączy, w kolejności, do której odnosi się polecenie
reference_image_urlstablica odniesień do obrazówObrazy naprowadzają generowanie, które inaczej byłoby wyłącznie tekstowe — to wskazówka, nie obiekt

Zaskakuje właśnie reference_image_urls: pojawia się na endpointach generujących, więc endpoint /text-to-image jak najbardziej może przyjmować obrazy. Nie zakładaj, że „text-to-image" znaczy „w żądaniu nie ma obrazów".

Odniesienie do obrazu to publiczny adres HTTPS, zatwierdzony po przesłaniu identyfikator spicy:// albo mały identyfikator data:image/…;base64,…. O przesyłaniu zobacz Multimedia, a o kanonicznych nazwach pól — kontrakt Spicy Schema.

Ograniczenia tablic różnią się znacznie bardziej, niż można by sądzić

Powyższe tablice mają minItems i maxItems, serwer egzekwuje oba, a liczby różnią się w zależności od endpointu: dziś rozpiętość sięga od tablicy przyjmującej dokładnie jeden element po tablice przyjmujące dziesięć. Endpoint z tej samej rodziny, z tą samą nazwą pola, może mieć inny pułap.

image_urls: must contain at least 1 items
image_urls: must contain at most 3 items

Czytaj minItems i maxItems ze schematu modelu, który wywołujesz. Tabela parametrów pokazująca tablicę jako gołe array, bez postaci elementu i bez ograniczenia długości, to dokładnie ten wiersz, z którym czytelnik nie może nic zrobić — i właśnie dlatego ta strona takiej tabeli nie publikuje.

Rozmiar wyjścia zapisuje się na trzy sposoby

To pierwsza rzecz, o którą potyka się większość osób kierujących gotowe ciało żądania na drugi endpoint.

W katalogu obrazów funkcjonują trzy pisownie, a endpoint przyjmuje dokładnie jedną z nich:

PisowniaPolaUwagi
Rozdzielonaaspect_ratio i resolutionKształt kadru i stopień pikseli wybiera się osobno
Ustawienie gotowesizeJedna wartość wyliczenia ustala oba naraz
Jawnawidth i heightPiksele całkowite, każdy z własnym minimum i maximum

Na nowszych endpointach najczęstsza jest pisownia rozdzielona i to ona jest najprzydatniejsza z trzech: aspect_ratio komponuje kadr przed generowaniem, zamiast przycinać po nim, więc kształt zmienisz bez ruszania budżetu pikseli.

Pole z niewłaściwej pisowni zostaje odrzucone, a nie zignorowane

Każdy obrazowy inputSchema ustawia additionalProperties: false. Pole, którego endpoint nie wymienia, zostaje odrzucone, więc ciało żądania przeniesione z innego endpointu po prostu upada, zamiast po cichu wrócić do wartości domyślnej.

Upada w obie strony, a komunikat nazywa pole:

size: is not a supported field
aspect_ratio: is not a supported field

Żadne z nich nie jest naliczane. Kosztem nie są pieniądze, tylko założenie: nie napiszesz jednego obiektu input i nie skierujesz go na kilka endpointów obrazu, a pisowni „zgodnościowej", którą przyjęłyby wszystkie, nie ma.

Która wybiera próg cenowy

Na endpoincie z pisownią rozdzieloną oba pola zwykle pełnią w rachunku różne role:

  • resolution zwykle wybiera próg cenowy. Pojawia się w wycenie jako variant, a jego zmiana zmienia kwotę.
  • aspect_ratio zwykle nie. Przekadrowanie to nie przeskalowanie.

To „zwykle" w obu zdaniach naprawdę pracuje. Odpowiedź czytelna dla maszyny znajduje się na samym polu: x-ui.affects_price: true oraz — gdy endpoint to deklaruje — przynależność do x-pricing.variantFields. Sprawdzaj schemat, a nie przyzwyczajenie. Zobacz Czytanie cen oraz opis adnotacji w kontrakcie Spicy Schema.

Dozwolone wartości także są właściwe dla endpointu. Odmowa je wylicza, co jest darmowym sposobem, by je zobaczyć:

aspect_ratio: must be one of: "1:1", "16:9", "9:16", "4:3", "3:4", "3:2", "2:3", "21:9"

Przydatne przy rozpoznaniu, ale nie zastępuje przeczytania enum, bo schemat niesie też default stosowany wtedy, gdy pole pominiesz.

Co obraz referencyjny dokłada do rachunku

To pozycja cicha i zasługuje na osobny rozdział, bo w odpowiedzi nic na nią nie wskazuje.

Zwykła arytmetyka modelu multimedialnego to cena × ilość, gdzie ilość to wartość quantityField w twoim wejściu albo jedna jednostka, gdy quantityField jest puste. Na endpointach obrazu quantityField to najczęściej num_outputs i zachowuje się dokładnie tak, jak się tego spodziewasz: poproś o cztery obrazy, a wycena pokaże quantity równe 4. Ten wymiar jest uczciwy — widać, jak się rusza.

Niektóre endpointy doliczają ponadto osobną opłatę za każdy obraz wejściowy — i tego ruchu już nie widać. Poproś o wycenę tego samego endpointu dwa razy, raz z jednym odniesieniem, raz z pełną tablicą, a dostaniesz:

  • tę samą unit;
  • tę samą quantity;
  • ten sam variant;
  • inną kwotę.

Trzy z czterech pól, z których zwykle buduje się szacunek, zostają dokładnie tam, gdzie były. Szacunek policzony jako cena × ilość wychodzi zaniżony i nic w odpowiedzi tego nie sygnalizuje.

Sygnatura czytelna dla maszyny

Pole oznaczone x-ui.affects_price: true, które nie jest quantityField ani nie figuruje w x-pricing.variantFields, rusza kwotę, nie wybierając progu. Przy takim endpoincie czytaj katalogowe pricing jako dolną granicę, a kwotę bierz z wyceny.

To ta sama reguła, którą formułuje Katalog modeli i schematy, a edycja obrazów to miejsce, w którym spotkasz ją najczęściej: tablica obrazów wejściowych bywa tak oznaczona bardzo często.

Ile dokładnie dokłada, zależy od endpointu i nie trzyma się żadnej stałej proporcji. W dzisiejszym katalogu są endpointy, na których wypełnienie tablicy kosztuje kilkakrotność pojedynczego odniesienia, i takie, na których dodatkowe odniesienia nie kosztują nic — a odróżnić je można wyłącznie pytając. Nie wyceniaj więc tablicy przez analogię z sąsiednim endpointem i nie wyprowadzaj ceny pełnej tablicy z wyceny na jedno odniesienie.

Wyceń to ciało, które naprawdę wyślesz

Wycena dokładnie tego żądania, zanim za nie zapłacisz
curl -sS https://api.spicyapi.ai/api/v1/jobs/quote \
  -H "Authorization: Bearer $SPICY_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"model":"MODEL_ID_FROM_CATALOG","input":{"prompt":"your instruction","image_urls":["spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3"]}}'

Wycena przeprowadza tę samą walidację co utworzenie zadania, nic nie kosztuje, niczego nie uruchamia i niczego nie blokuje. Zwraca estimatedCost, maxCharge, quantity i unit dla dokładnie tego ciała. Zmieniłeś tablicę — wyceń ponownie. Szczegóły oraz postępowanie przy utraconej odpowiedzi znajdziesz w Wyceny i zgodność, a miejsce wyceny w prawdziwej integracji — w Wdrożenie produkcyjne.

Wagi adaptera

Niektóre endpointy pozwalają nałożyć własne dostrojone wagi na model bazowy. Kanoniczne pole to loras albo high_noise_loras i low_noise_loras, gdy endpoint wystawia swoje etapy osobno.

Tablica obiektów z własnymi regułami w środku

Te pola noszą x-ui.widget: "object-list": tablicę, której items jest pełnoprawnym schematem obiektu sam w sobie. Ma własne required, własne additionalProperties: false oraz własny typ, zakres i default dla każdego podpola. Typowy element nazywa jeden zestaw wag i siłę, z jaką go zastosować.

Dwa elementy zastosowane razem
{
  "model": "MODEL_ID_FROM_CATALOG",
  "input": {
    "prompt": "your scene",
    "loras": [
      { "path": "https://weights.example.com/style.safetensors", "scale": 1 },
      { "path": "https://weights.example.com/character.safetensors", "scale": 0.6 }
    ]
  }
}

Postać elementu nie jest stała między endpointami. To, co liczy się jako plik wag — bezpośredni adres czy klucz z wbudowanej biblioteki — zawęża własny podschemat items danego endpointu, podobnie jak nazwy podpól, liczbę mieszczących się elementów i to, które są wymagane. Czytaj items, a nie ten przykład. Widżet opisuje kontrakt Spicy Schema; jak zamienić go w zagnieżdżoną tabelę, pokazuje Katalog modeli i schematy.

Jedną regułę wewnątrz tych elementów łatwo przeczytać opacznie: wartości domyślne sięgają do wnętrza elementów tablicy. Podpole, które jest w items.required i ma default, jest w praktyce opcjonalne — pomiń je, a wartość domyślna zostanie wstawiona przed walidacją. Podpole bez wartości domyślnej, gdy go brakuje, jest odrzucane. items.required nie znaczy więc „musi znaleźć się w JSON-ie, który wysyłam".

Skąd pochodzą wagi

Pole path przyjmuje jedną z trzech rzeczy:

  • Publiczny link do pliku .safetensors albo, gdy endpoint to dopuszcza, identyfikator repozytorium Hugging Face w rodzaju owner/repo. Model pobiera go w chwili generowania, więc pierwsze wywołanie z nowymi wagami jest wyraźnie wolniejsze od kolejnych.
  • Przesłany plik. Prześlij plik jako application/octet-stream przez bezpośrednie przesyłanie, do 2 GiB, i użyj zwróconego URI spicy://f/…. Commit sprawdza, czy to kompletny plik safetensors.
  • Import. Dla pliku wymagającego logowania, na przykład z prywatnego lub objętego ograniczeniem dostępu repozytorium Hugging Face albo pliku Civitai za kluczem API, wyślij link i token dostępu na POST /api/v1/files/import. SpicyAPI pobiera plik jeden raz i zwraca URI spicy://f/…. Token służy tylko do tego pobrania i nigdy nie jest zapisywany.
Import LoRA z prywatnego repozytorium Hugging Face
curl -sS https://api.spicyapi.ai/api/v1/files/import \
  -H "Authorization: Bearer $SPICY_API_KEY" \
  -H "Content-Type: application/json" \
  --data "$(jq -n --arg url "https://huggingface.co/OWNER/REPO/blob/main/your_lora.safetensors" --arg token "$HF_TOKEN" '{url: $url, token: $token}')"

url może być także identyfikatorem repozytorium (OWNER/REPO) albo stroną repozytorium, o ile zawiera dokładnie jeden plik .safetensors. Odpowiedź ma taką samą postać jak odpowiedź commit; wstaw data.uri do loras[].path. Przesłane i zaimportowane wagi są przechowywane przez jeden dzień, jak każdy inny przesłany plik, i nigdy nie są udostępniane innym kontom. Potem prześlij je lub zaimportuj ponownie.

Przy wysyłce sprawdzany jest link, a nie wagi w środku

Zanim zadanie powstanie, każdy link do wag jest sondowany. Link wymagający logowania, zwracający 404 lub otwierający stronę WWW jest odrzucany błędem 400 i nic nie jest naliczane, a komunikat wskazuje element. Reszta przechodzi, więc host, który padnie później, albo wagi, których nie uda się wczytać, nadal dotrą do ciebie jako niepowodzenie zadania.

Problemy, których sonda nie widzi, wracają później, jako niepowodzenie zadania z errorCode z dziewięciu publicznych klas platformy i komunikatem wyjaśniającym, co poszło nie tak; kwota zarezerwowana na zadanie jest zwracana. Zobacz Błędy.

Najgorszy przypadek jest jeszcze cichszy: wagi zbudowane pod inny model bazowy mogą wczytać się bez błędu i nie zmienić wyniku prawie wcale. Nie ma żadnego błędu do przeczytania, jest tylko obraz wyglądający jak ten z modelu bazowego.

Sprawdzaj więc na etapie wdrożenia

Wynieś sprawdzenie ze ścieżki żądania do tego, co uruchamia się przy wydaniu:

  1. Osiągalność. Żądanie HEAD na każdy adres wag, który zamierzasz wypuścić na produkcję. Platforma sonduje każdy link przy tworzeniu zadania, ale link działający dziś może przestać działać za tydzień, a sprawdzenie przy wdrożeniu wychwyci to, zanim zrobi to twój ruch.
  2. Skutek. Jedno generowanie na każdy nowy plik wag, porównane z tym samym promptem i tym samym ziarnem bez niego. Jeśli obu nie da się odróżnić, plik nie robi tego, co myślisz — upewnij się, zanim zaufa mu cała partia.
  3. Trwałość. Twoje adresy muszą działać tak długo, jak długo są na produkcji. Zniknięty plik wag zamienia się w niepowodzenia zadań bez oczywistej przyczyny, kilka dni po wdrożeniu, któremu zostaną przypisane.

Porady właściwe konkretnemu endpointowi dotyczące tych pól — względem czego naprawdę mierzona jest wartość, które ustawienie zauważalnie spowalnia wywołanie, jakie dane wejściowe schemat przyjmie, a ty ich pożałujesz — mieszkają w paramNotes w katalogu publicznym, kluczowane nazwą parametru i dostępne we wszystkich dziesięciu językach dokumentacji. To proza, nigdy reguła; o tym, co zostanie przyjęte, wciąż decyduje inputSchema. Zobacz Katalog modeli i schematy.

Asynchroniczne jak każdy inny model multimedialny

Endpointy obrazu to zadania, a nie wywołania żądanie-odpowiedź. Tworzysz zadanie, a wynik odbierasz odpytywaniem albo webhookiem; queued i running nie są stanami końcowymi, a succeeded, failed i expired są. Źródłem prawdy o stanach jest Zadania asynchroniczne.

Obrazy kończą się szybciej niż wideo, co kusi, by napisać wywołanie tak, jakby było synchroniczne. Oprzyj się temu: ograniczone odpytywanie jest tu na tyle krótkie, że sprawia takie wrażenie, ale kod i tak musi obsłużyć zadanie wciąż trwające w chwili wyczerpania budżetu oczekiwania — a oddanie tego webhookowi skaluje się lepiej niż trzymanie otwartego żądania. Odpytywanie korzysta z osobnego limitu odczytów konta i nie zużywa limitu wysyłania zadań. Zbyt częste odpytywanie może spowodować ograniczenie zapytań o stan; zobacz Limity.

Odczyt wyniku

Udane zadanie wypisuje swoje pliki w output.assets[]. Trzy rzeczy o tej liście na endpointach obrazu:

  • Może zawierać więcej niż jeden plik. Gdy num_outputs jest większe od jednego, dostajesz po jednym zasobie na obraz. Pisz obsługę jako pętlę od początku; obsługa czytająca assets[0] po cichu wyrzuca wszystko inne, za co zapłaciłeś.
  • O rozszerzeniu decyduje mime, a nie nazwa endpointu ani prompt. Gdy endpoint wystawia output_format, to właśnie to pole wybiera kodowanie; gdy nie wystawia, kodowanie należy do endpointu, a mime jest jedynym sposobem, by dowiedzieć się, co dostałeś.
  • Plik wciąż kopiowany ma pending: true i nie ma url. Wyniki trafiają najpierw do własnego magazynu SpicyAPI, zanim zostaną wydane, co zajmuje kilka sekund po tym, jak zadanie zgłosi sukces. Odczytaj zadanie ponownie, zamiast traktować brak odnośnika jak niepowodzenie.

Odnośniki do pobrania żyją około dwudziestu minut i nie wymagają klucza API; po świeży odczytaj zadanie ponownie. Wygenerowane pliki przechowujemy najwyżej czternaście dni, krócej, jeśli retencja twojego konta jest krótsza. Zobacz Wyniki i pobieranie oraz Przechowywanie i usuwanie.

Czytanie odmowy

Odrzucone żądanie nic nie kosztuje i niczego nie tworzy, więc endpoint wyceny służy zarazem jako darmowy walidator ciała, które masz zamiar wysłać.

Zgłaszane są wszystkie problemy, nie tylko pierwszy. Komunikat łączy je przez ; , więc jedna odrzucona wycena potrafi wymienić wszystko, co jest nie tak:

prompt: is required; loras.0.path: is required; loras.0.scale: must be at most 4; bogus: is not a supported field

Problem wewnątrz tablicy wskazuje konkretny element. Wskaźnik ma postać pole.indeks.podpole, a indeks liczy się od zera:

loras.1.scale: must be at most 4

Przekaż ten wskaźnik temu, kto będzie poprawiał. Gdy w grze jest kilka elementów, wiedza o tym, który wyszedł poza zakres, to różnica między poprawką w jednym wierszu a wyszukiwaniem połówkowym.

Postacie, które spotkasz:

KomunikatCo znaczyCo zrobić
X: is requiredX jest na głównej liście requiredDodaj. Na endpointach edytujących to zwykle prompt albo pole obrazu
X: is not a supported fieldX nie ma w properties; nieznane pola są odrzucane, nigdy ignorowaneUsuń albo użyj pisowni tego endpointu — zobacz Rozmiar wyjścia
X: must be one of: …Wartość poza enumKomunikat wylicza dozwolone wartości; enum i default są w schemacie
X: must contain at least N itemsPoniżej minItemsTablicy, której endpoint wymaga, nie wyślesz pustej
X: must contain at most N itemsPowyżej maxItemsSprawdź pułap tego endpointu; nie wszędzie jest taki sam
X: must be an arrayWartość nie jest zadeklarowanego typuOpakuj pojedynczy element w listę
X: must be at most N charactersPowyżej maxLengthPrompty też mają pułap zależny od endpointu
X.<n>.<sub>: is requiredPodpole elementu <n> jest wymagane i nie ma wartości domyślnejDodaj je tylko w tym elemencie
X.<n>.<sub>: is not a supported fieldSchemat elementu ustawia additionalProperties: falseUsuń ten klucz z tego elementu
X.<n>.<sub>: must be at most NPodpole wyszło poza własny zakresOgranicz je; zakresy są na podpole, nie na tablicę

Jeśli odmowa przychodzi tam, gdzie spodziewałeś się powodzenia, zwykłą przyczyną jest nieaktualny schemat. Po 400 przeczytaj katalog ponownie i nigdy nie trzymaj trwałej migawki — Buforowanie katalogu mówi, jak długo kopia jest dobra. Resztę omawia Rozwiązywanie problemów.

Następne kroki

Na tej stronie