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 szukasz | Przeczytaj zamiast tego |
|---|---|
| Pierwszego obrazu od klucza i salda aż po plik | Szybki start |
| Tej samej drogi dla wideo, krok po kroku | Samouczek: zamień zdjęcie w wideo |
| Wszystkich pól konkretnego modelu | Jego inputSchema — zobacz Katalog modeli i schematy |
| Przeniesienia twarzy lub głowy z jednego zdjęcia na drugie | Podmiana 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.
{
"model": "MODEL_ID_FROM_CATALOG",
"input": {
"image_urls": ["spicy://f/fil_01k3m8x9q2z4v7n5p6r8s0t1w3"]
}
}prompt: is requiredObraz 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:
| Pole | Postać | Co zwykle oznacza |
|---|---|---|
image_url | jedno odniesienie do obrazu | Jest dokładnie jeden obraz z obiektem, a endpoint nie zna pojęcia drugiego |
image_urls | tablica odniesień do obrazów | Obrazy są materiałem, który się edytuje lub łączy, w kolejności, do której odnosi się polecenie |
reference_image_urls | tablica odniesień do obrazów | Obrazy 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 itemsCzytaj 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:
| Pisownia | Pola | Uwagi |
|---|---|---|
| Rozdzielona | aspect_ratio i resolution | Kształt kadru i stopień pikseli wybiera się osobno |
| Ustawienie gotowe | size | Jedna wartość wyliczenia ustala oba naraz |
| Jawna | width i height | Piksele 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:
resolutionzwykle wybiera próg cenowy. Pojawia się w wycenie jakovariant, a jego zmiana zmienia kwotę.aspect_ratiozwykle 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
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ć.
{
"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
.safetensorsalbo, gdy endpoint to dopuszcza, identyfikator repozytorium Hugging Face w rodzajuowner/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-streamprzez bezpośrednie przesyłanie, do 2 GiB, i użyj zwróconego URIspicy://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 URIspicy://f/…. Token służy tylko do tego pobrania i nigdy nie jest zapisywany.
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:
- Osiągalność. Żądanie
HEADna 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. - 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.
- 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_outputsjest większe od jednego, dostajesz po jednym zasobie na obraz. Pisz obsługę jako pętlę od początku; obsługa czytającaassets[0]po cichu wyrzuca wszystko inne, za co zapłaciłeś. - O rozszerzeniu decyduje
mime, a nie nazwa endpointu ani prompt. Gdy endpoint wystawiaoutput_format, to właśnie to pole wybiera kodowanie; gdy nie wystawia, kodowanie należy do endpointu, amimejest jedynym sposobem, by dowiedzieć się, co dostałeś. - Plik wciąż kopiowany ma
pending: truei nie maurl. 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 fieldProblem 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 4Przekaż 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:
| Komunikat | Co znaczy | Co zrobić |
|---|---|---|
X: is required | X jest na głównej liście required | Dodaj. Na endpointach edytujących to zwykle prompt albo pole obrazu |
X: is not a supported field | X nie ma w properties; nieznane pola są odrzucane, nigdy ignorowane | Usuń albo użyj pisowni tego endpointu — zobacz Rozmiar wyjścia |
X: must be one of: … | Wartość poza enum | Komunikat wylicza dozwolone wartości; enum i default są w schemacie |
X: must contain at least N items | Poniżej minItems | Tablicy, której endpoint wymaga, nie wyślesz pustej |
X: must contain at most N items | Powyżej maxItems | Sprawdź pułap tego endpointu; nie wszędzie jest taki sam |
X: must be an array | Wartość nie jest zadeklarowanego typu | Opakuj pojedynczy element w listę |
X: must be at most N characters | Powyżej maxLength | Prompty też mają pułap zależny od endpointu |
X.<n>.<sub>: is required | Podpole elementu <n> jest wymagane i nie ma wartości domyślnej | Dodaj je tylko w tym elemencie |
X.<n>.<sub>: is not a supported field | Schemat elementu ustawia additionalProperties: false | Usuń ten klucz z tego elementu |
X.<n>.<sub>: must be at most N | Podpole wyszło poza własny zakres | Ogranicz 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
Katalog modeli i schematy
Żywy katalog, progi cenowe i własna tabela parametrów z inputSchema
Kontrakt Spicy Schema
Kanoniczne nazwy pól, adnotacje x-ui, pola warunkowe i format wyniku
Multimedia
Przesłanie obrazu i zamiana go w odniesienie spicy://
Wyceny i zgodność
Wycena dokładnie tego żądania, zanim za nie zapłacisz
Podmiana obiektu
Endpointy edytujące, które biorą obrazy i żadnego promptu
Samouczek: zamień zdjęcie w wideo
Ta sama droga dla wideo: CLI, SDK i czysty HTTP
Błędy
Wszystkie kody błędów i to, gdzie ponowienie naprawdę pomaga
Wdrożenie produkcyjne
Co dodać, zanim zaczną na tym polegać prawdziwi użytkownicy
Samouczek: z obrazu do wideo
Zacznij od jednego obrazu na swoim komputerze, a skończ na pobranym pliku wideo. Każdy krok pokazuje CLI, SDK dla TypeScriptu i zwykłe HTTP.
Podmiana osoby
Jeden zestaw narzędzi, dwie postaci. Modele jednowywołaniowe podmieniają twarz albo głowę w pojedynczym żądaniu; modele dwuwywołaniowe najpierw analizują klip, żebyś to ty wskazał, kto ma się zmienić.

