SDK dla Go
Oficjalne SDK SpicyAPI dla Go (github.com/spicyapi-ai/spicy-go): instalacja, wycena i pierwsza generacja, wysyłanie plików z dysku, przeglądanie historii zadań i obsługa wszystkich kodów błędów.
spicy-go to oficjalne SDK SpicyAPI dla Go. Generowanie obrazów, wideo i dźwięku chowa za jednym *spicy.Client: dołącza twój klucz API, zamienia strukturę odpowiedzi na typowane struktury, czeka na zadanie z ograniczonym wydłużaniem odstępów, wysyła pliki z dysku jednym wywołaniem i nadaje każdemu niepowodzeniu jeden typ błędu, który dopasujesz przez errors.As.
Wymaga Go 1.23 lub nowszego i korzysta wyłącznie z biblioteki standardowej. To celowe: ten pakiet trafia do twojego grafu zależności, a każdy moduł, który by ze sobą przyciągnął, to kolejna rzecz do audytu po twojej stronie.
Czy to właściwe narzędzie?
| Chcesz… | Użyj |
|---|---|
| Wywoływać SpicyAPI z własnego kodu w Go | Tego SDK |
| Wywoływać je z Node.js albo TypeScriptu | SDK dla TypeScriptu |
| Wywoływać je z Pythona, PHP albo Javy | SDK dla Pythona, SDK dla PHP albo SDK dla Javy |
| Generować z terminala, bez pisania kodu | CLI |
| Pozwolić, żeby asystent AI wywoływał SpicyAPI za ciebie | Serwer MCP i Agent Skill |
| Korzystać z modelu czatu albo modelu tekstowego | Uznanego klienta Go dla formatów OpenAI, Anthropic albo Gemini – zobacz Tekst i streaming |
Instalacja
Go rozwiązuje moduły prosto z ich repozytorium, więc nie ma tu kroku z rejestrem ani na co czekać. To polecenie działa już dziś:
go get github.com/spicyapi-ai/spicy-goKlucz trzymaj w zmiennej środowiskowej, żeby nigdy nie pojawił się w twoim kodzie ani w pliku historii powłoki:
export SPICY_API_KEY="sk-spicy-..."Pierwszy wynik
Zapytaj o cenę, zdecyduj, utwórz zadanie, poczekaj, odczytaj pliki. Wycena jest bezpłatna i niczego nie blokuje.
client, err := spicy.New(spicy.Options{}) // odczytuje SPICY_API_KEY ze zmiennej środowiskowej
if err != nil {
return err
}
request := spicy.CreateTaskInput{
Model: "MODEL_ID_FROM_CATALOG",
Input: map[string]any{"prompt": "a lantern in fog"},
}
quote, err := client.Quote(ctx, request)
if err != nil {
return err
}
log.Printf("this will cost at most %s", quote.MaxCharge)
// Zapisz go obok własnego rekordu zlecenia, zanim wyślesz żądanie: cały sens
// tego klucza polega na tym, żeby przetrwał awarię, która zgubiła odpowiedź.
key, err := spicy.NewIdempotencyKey()
if err != nil {
return err
}
request.Model = quote.Model
request.QuoteID = quote.QuoteID
request.ExpectedCost = quote.EstimatedCost
task, err := client.CreateTask(ctx, request, key, spicy.CreateTaskOptions{})
if err != nil {
return err
}
final, err := client.WaitForTerminal(ctx, task.TaskID, spicy.WaitOptions{})
if err != nil {
return err
}
for _, asset := range final.ReadyAssets() {
log.Println(asset.URL)
}MODEL_ID_FROM_CATALOG to symbol zastępczy. Prawdziwy identyfikator bierz z uwierzytelnionego katalogu na żywo — client.ListModels, czyli GET /api/v1/models — a nigdy z pamięci ani ze starej strony: modele są dodawane, wstrzymywane i wycofywane. Input buduj na podstawie inputSchema tego konkretnego modelu, które zwraca ListModels; każdy model przyjmuje inne pola.
Kwoty to dziesiętne łańcuchy znaków w dolarach amerykańskich, nigdy liczby zmiennoprzecinkowe, bo binarne liczby zmiennoprzecinkowe nie potrafią dokładnie zapisać większości kwot dziesiętnych. W tym API nigdzie nie ma kredytów ani punktów.
Stan końcowy to jeszcze nie stan udany: czekanie kończą także failed, canceled i expired. Sprawdź final.State.
Pomiń pierwsze odpytanie
WaitSeconds prosi usługę, żeby trzymała połączenie otwarte aż do końca zadania, co przy szybkim modelu oznacza, że wynik przychodzi razem z potwierdzeniem zgłoszenia.
seconds := 30
task, err := client.CreateTask(ctx, request, key, spicy.CreateTaskOptions{WaitSeconds: &seconds})
if err != nil {
return err
}
// Task jest nil zawsze wtedy, gdy skończył się czas czekania. To zwykły wynik,
// a nie błąd — generacja nadal trwa, więc od tego miejsca odpytuj.
final := task.Task
if final == nil {
final, err = client.WaitForTerminal(ctx, task.TaskID, spicy.WaitOptions{})
if err != nil {
return err
}
}
log.Println(final.State, final.Cost)To optymalizacja, nigdy gwarancja. Kod, który czyta task.Task bez sprawdzenia nil, działa dokładnie do pierwszej generacji wolniejszej niż przyjęty budżet czasu, a wtedy wpada w panikę na produkcji.
Zacznij od pliku z dysku
Generowanie wideo z obrazu, podmiana osoby i edycja obrazu wymagają, żeby twój materiał najpierw trafił na naszą stronę. UploadFile wykonuje wysyłkę w trzech krokach — pozwolenie na wysyłkę, PUT do magazynu, commit — w jednym wywołaniu i zwraca URI spicy://. To właśnie ten URI trafia do Input.
uploaded, err := client.UploadFile(ctx, "/path/to/reference.png", "")
// uploaded.URI -> "spicy://f/fil_..."Publicznie dostępny adres HTTPS możesz podać w danych wejściowych wprost i wtedy nie musisz niczego wysyłać. Limit dla obrazów to 10 MiB, dla dźwięku i wideo – 90 MiB; zobacz Media.
Saldo, zużycie i historia
Wszystkie trzy dotyczą klucza API, którym wywołujesz: bratnie klucze z tego samego konta ani generacje uruchomione w konsoli się w nich nie mieszczą, a ich brak nie jest usterką.
balance, err := client.GetBalance(ctx)
if err != nil {
return err
}
log.Printf("%s available, %s held by accepted tasks", balance.Available, balance.Held)
usage, err := client.GetUsage(ctx, spicy.UsageOptions{From: "2026-09-01", To: "2026-09-08"})
if err != nil {
return err
}
log.Printf("%d calls, %s settled over [%s,%s)", usage.TotalCalls, usage.TotalSpend, usage.From, usage.To)
// EachTask powtarza każdy filtr na każdej stronie i przesuwa wyłącznie kursor.
if err := client.EachTask(ctx, spicy.ListTasksOptions{From: "2026-09-01", To: "2026-09-08"},
func(task spicy.TaskListItem) bool {
log.Println(task.TaskID, task.State, task.Cost)
return true // zwróć false, żeby przerwać wcześniej
}); err != nil {
return err
}Daty to dni kalendarzowe UTC w przedziale półotwartym [from, to), obejmującym najwyżej 92 dni. Przy każdym przeglądaniu, które może przekroczyć północ UTC, ustaw From i To na sztywno. Zostawione puste sprawiają, że serwer przy każdej stronie wylicza własne okno od nowa — to to jutro według UTC — więc przeglądanie zaczęte o 23:59 i kontynuowane o 00:01 zadaje dwa różne pytania i skleja odpowiedzi w jedno. Nic tego nie zgłasza.
GetUsage służy do uzgadniania rachunków, nie do śledzenia postępu. Stoi za nim budżet obowiązujący dla całego konta, wspólny dla wszystkich kluczy, a ten ogranicznik przy problemach domyka się zamiast otwierać — odpytywanie go potrafi odciąć każdy inny klucz od jego własnych raportów. Za pojedynczym zadaniem podążaj przez WaitForTerminal. Rozliczenie może też przyjść z opóźnieniem, więc liczba odczytana dziś nadal może się jutro zmienić.
Błędy
Niepowodzenia wracają jako *spicy.APIError, do którego dotrzesz przez errors.As:
var apiErr *spicy.APIError
if errors.As(err, &apiErr) {
log.Println(apiErr.Status, apiErr.Code, apiErr.RequestID, apiErr.RetryAfter)
}Rozgałęziaj logikę po Code, nigdy po komunikacie — komunikaty są tłumaczone, kody nie. Status HTTP 503 dzielą między siebie trzy różne kody aplikacyjne, więc sam status nie wystarczy, żeby zdecydować, co zrobić:
| Kod | Co to znaczy | Co zrobić |
|---|---|---|
40003 | przesłane bajty nie zgadzają się ze swoim pozwoleniem na wysyłkę | zacznij od nowa, od świeżego pozwolenia |
40004 | żadne wdrożenie nie obsługuje tej kombinacji parametrów | zmień parametr wskazany w komunikacie |
40201 | za niskie saldo | doładuj konto |
40901 | cena zmieniła się, zanim powstało zadanie | wyceń ponownie, zachowując ten sam klucz idempotentności |
503 | składnik, od którego zależymy, jest chwilowo niedostępny | odczekaj tyle, ile mówi RetryAfter |
50301 | nie ma teraz działającego wdrożenia ani ceny | odśwież katalog, nie bombarduj usługi |
50302 | generacja synchroniczna nie powiodła się podczas przetwarzania i została zwrócona | ponów z nowym kluczem idempotentności |
Wszystkie kody wymienia strona Błędy. Kontaktując się ze wsparciem, podaj RequestID.
Dwie rzeczy, które oszczędzą ci pieniędzy
Miej jeden klucz idempotentności na jedno zgłoszenie. Używaj go przy każdym ponownym wysłaniu, także po przekroczeniu czasu. Utracona odpowiedź nie dowodzi, że zadanie nie powstało — nowy klucz zamienia nieznany wynik w drugie płatne zadanie. Dokładnie dlatego CreateTask wymaga klucza. Zobacz Idempotentność.
Za udane zadanie płacisz, nawet jeśli wynik cię rozczaruje. Quote niczego nie blokuje, więc gdy cena ma znaczenie, najpierw wyceń.
Czego ten pakiet nie robi
- Modeli tekstowych. Mówią formatami OpenAI, Anthropic i Gemini — uznani klienci Go dla tych formatów działają z
https://api.spicyapi.ai/v1od ręki, z tym samym kluczem. Zobacz Tekst i streaming. - Aplikacji po stronie klienta. Nigdy nie umieszczaj tego klucza w pliku wykonywalnym, który rozdajesz. Wywołuj ze swojego serwera.
- Wyboru modelu ani wypełniania jego pól. Pakiet podaje ci katalog i schemat każdego modelu; o tym, co wysłać, decydujesz ty.
- Anulowania zadania. Przyjęte zadanie wykonuje się do końca. Anulowanie
contextkończy tylko twoje czekanie.
Kod źródłowy
Moduł jest na licencji MIT i powstaje otwarcie pod adresem github.com/spicyapi-ai/spicy-go. Jego README to najkrótsza kompletna wycieczka po kliencie; ta strona dokłada do tego pojęcia, które go otaczają.
Co dalej
Katalog modeli i schematy
Jak czytać inputSchema modelu i dobierać prawidłowe dane wejściowe
Zadania asynchroniczne
Stany zadań, odpytywanie i znaczenie każdego pola
Wyceny i zgodność protokołów
Poznaj dokładną cenę żądania, zanim za nie zapłacisz
Webhooki
Format dostarczeń, harmonogram ponowień i weryfikacja podpisu
Błędy
Wszystkie kody błędów i to, które z nich warto ponawiać
SDK dla Pythona
Ten sam proces w Pythonie, bez żadnych zależności w czasie działania
SDK dla Pythona
Oficjalne SDK SpicyAPI dla Pythona (spicyapi): instalacja, wycena i pierwsza generacja, wysyłanie plików z dysku, weryfikacja webhooków oraz wszystkie kody błędów.
SDK dla PHP
Oficjalne SDK SpicyAPI dla PHP (spicyapi/spicyapi): instalacja przez Composera, wycena i pierwsza generacja, wysyłanie plików z dysku, bezpieczna weryfikacja webhooków i obsługa wszystkich kodów błędów.

