Zamień zdjęcie źródłowe w wielokolorową, drukowalną w 3D planszę fidget w stylu pixel-art w
dwóch etapach: prototype przekształca Twoje zdjęcie w obraz pixel-art, a
build próbkuje ten obraz na siatce 16×16 lub 32×32 i zamienia każdy piksel
w blokujący się kwadratowy lub sześciokątny element, dostarczany jako pojedynczy plik 3MF,
którego obiekty niosą swoje kolory, dzięki czemu slicer obsługujący wiele filamentów drukuje każdy element
w odpowiednim kolorze. Oba etapy są połączone za pomocą input_task_id.
POST /openapi/creative-lab/fidget-pixel/v1/prototype
POST /openapi/creative-lab/fidget-pixel/v1/build
Oba endpointy POST wymagają płatnego planu subskrypcji. Żądania z
kont na planie bezpłatnym są odrzucane z kodem 402 Payment Required.
Wygeneruj pojedynczy obraz pixel-art ze źródłowego zdjęcia. Zwrócony identyfikator zadania to wartość, którą przekazujesz jako input_task_id do punktu końcowego budowania. Wywołaj ten
punkt końcowy ponownie, aby uzyskać kolejną próbę, jeśli wynik nie jest tym, czego oczekujesz — każde
wywołanie jest rozliczane osobno. Zobacz
Obiekt zadania prototypu Fidget Pixel
dla struktury odpowiedzi.
Parametry
Name
image_url
Type
string
Wymagane
Description
Zdjęcie źródłowe, które Meshy ma zamienić w piksele. Obecnie obsługujemy formaty .jpg, .jpeg, .png i .webp.
Format jest wykrywany poprzez dekodowanie danych obrazu, nie na podstawie rozszerzenia pliku w adresie URL — adres URL bez rozszerzenia lub taki, który przekierowuje, działa, o ile bajty dają się zdekodować do obsługiwanego formatu. Przekierowania HTTP są śledzone.
Istnieją dwa sposoby dostarczenia obrazu:
Publicznie dostępny adres URL: Adres URL dostępny z publicznego internetu.
Data URI: Zakodowany w base64 identyfikator Data URI obrazu. Przykład Data URI: data:image/jpeg;base64,<twoje zakodowane w base64 dane obrazu>.
Name
type
Type
string
Wymagane
Description
Co przedstawia zdjęcie. Wybiera styl pikselizacji, więc wybieraj świadomie — te dwie opcje dają wyraźnie różne rezultaty. Dostępne wartości:
person — obiektem jest osoba (portret lub cała sylwetka). Tworzy sprite'a w stylu chibi pixel-art przedstawiającego dany podmiot.
other — cokolwiek innego: zwierzęta domowe, przedmioty, maskotki, logo, krajobrazy. Tworzy ikonę pikselową w stylu bead-art przedstawiającą dany podmiot.
Name
name
Type
string
Description
Opcjonalna nazwa zadania do celów wyświetlania. Maksymalnie 100 znaków.
Zwracane wartości
Właściwość result odpowiedzi zawiera id zadania nowo utworzonego zadania prototypu fidget pixel. Odpytuj punkt końcowy Pobierz zadanie lub subskrybuj strumień, dopóki zadanie nie osiągnie statusu SUCCEEDED, a następnie przekaż ten identyfikator do punktu końcowego budowania jako input_task_id.
Tryby awarii
Name
400 - Bad Request
Description
Żądanie było niepoprawne. Typowe przyczyny:
Brakujący parametr: image_url i type są wymagane.
Nieprawidłowy typ: type musi mieć wartość person lub other.
Nieprawidłowy format obrazu: Podany image_url nie jest w obsługiwanym formacie (.jpg, .jpeg, .png, .webp).
Wymiary obrazu poza zakresem: Obraz jest zbyt mały, przekracza maksymalny rozmiar pliku lub przekracza maksymalną liczbę pikseli.
Nieosiągalny adres URL: Nie udało się pobrać image_url (404 lub timeout).
Nieprawidłowy Data URI: Ciąg base64 jest nieprawidłowo sformatowany.
Treść oznaczona: Obraz wejściowy został oznaczony przez moderation NSFW.
Name
401 - Unauthorized
Description
Uwierzytelnianie nie powiodło się. Sprawdź swój klucz API.
Name
402 - Payment Required
Description
Niewystarczająca liczba kredytów do wykonania tego zadania lub klucz API należy do konta na darmowym planie.
Name
403 - Forbidden
Description
Obraz wejściowy został oznaczony przez moderation własności intelektualnej (Content flagged for intellectual property violation). Blokowane są wyłącznie konta Enterprise z włączonym filtrowaniem własności intelektualnej; nic nie jest naliczane.
Name
429 - Too Many Requests
Description
Przekroczono limit szybkości.
Name
500 - Internal Server Error
Description
Nie udało się przeprowadzić samej kontroli własności intelektualnej (Unable to perform intellectual property check, please try again). Konta Enterprise z włączonym filtrowaniem własności intelektualnej zawodzą w trybie zamkniętym przy tej kontroli; nic nie jest naliczane — ponów żądanie.
Request
POST
/openapi/creative-lab/fidget-pixel/v1/prototype
# Stage 1: pixelize the source photocurlhttps://api.meshy.ai/openapi/creative-lab/fidget-pixel/v1/prototype \-XPOST \-H"Authorization: Bearer ${YOUR_API_KEY}" \-H'Content-Type: application/json' \-d'{ "image_url": "<your publicly accessible image url or base64-encoded data URI>", "type": "person" }'
Generuje elementy gotowe do druku 3D na podstawie zakończonego powodzeniem zadania prototypu. Proces budowania próbkuje obraz pixel-art prototypu na żądaną siatkę, kwantyzuje go do maksymalnie color_count kolorów i generuje jeden zazębiający się element na każdą komórkę siatki. Wynikiem jest pojedynczy plik 3MF, w którym każdy element jest osobnym obiektem oznaczonym swoim kolorem, gotowym do użycia w slicerze obsługującym wiele filamentów. Zapoznaj się z sekcją
Obiekt zadania budowania Fidget Pixel,
aby poznać kształt odpowiedzi.
Parametry
Name
input_task_id
Type
string
Wymagane
Description
Identyfikator zadania prototypu utworzonego za pomocą tego samego punktu końcowego OpenAPI. Prototyp musi zostać utworzony przez to samo konto Meshy i musi osiągnąć status SUCCEEDED.
Zadania prototypów utworzone za pośrednictwem aplikacji webowej nie są akceptowane — punkt końcowy budowania akceptuje wyłącznie zadania prototypów wygenerowane przez POST /openapi/creative-lab/fidget-pixel/v1/prototype i odrzuca każde inne źródło, zwracając 404.
Name
name
Type
string
Description
Opcjonalna nazwa zadania do celów wyświetlania. Maksymalnie 100 znaków.
options
Opcjonalna geometria elementu. Każde pole ma wartość domyślną — wysyłaj tylko te, które chcesz zmienić. Są to te same ustawienia, które udostępnia aplikacja webowa Creative Lab; wysokość zatyczki, skala nakładki i pozostałe ustawienia produkcyjne są wyprowadzane z shape i piece_size_mm i nie są udostępniane bezpośrednio.
Name
shape
Type
string
domyślne square
Description
Kształt podstawy każdego elementu. Dostępne wartości:
square (domyślnie) — kwadratowe elementy na kwadratowej siatce.
hex — sześciokątne elementy na sześciokątnej siatce. Elementy heksagonalne są dostępne wyłącznie w rozmiarach 6 i 8 mm.
Name
grid_size
Type
integer
domyślne 32
Description
Liczba elementów wzdłuż każdego boku planszy. Dostępne wartości: 16 lub 32. Siatka 32 zachowuje więcej szczegółów; siatka 16 oznacza mniej, ale większe elementy dla tego samego motywu.
Name
piece_size_mm
Type
integer
domyślne 8
Description
Długość krawędzi każdego elementu, w milimetrach. Dostępne wartości: 6, 8 lub 10. W połączeniu z grid_size ustala to rozmiar wydrukowanej planszy — na przykład 32 × 8 mm ≈ 26 cm na bok. Wartość 10 nie jest dostępna dla shape: "hex" (nachylona ścianka heksagonalna powoduje nawisy na większości konsumenckich drukarek FDM).
Name
color_count
Type
integer
domyślne 8
Description
Maksymalna liczba kolorów w palecie, do której kwantyzowany jest obraz. Zakres: [1, 8]. Każdy kolor staje się jednym filamentem w Twoim slicerze.
Name
piece_height_mm
Type
integer
domyślne 15
Description
Wysokość każdego elementu, w milimetrach. Zakres: [10, 80].
output
Opcjonalny selektor formatu danych wyjściowych. Domyślnie 3mf, co obecnie jest jedyną obsługiwaną wartością.
Name
format
Type
string
domyślne 3mf
Description
Artefakt zwracany przez proces budowania. Dostępne wartości:
3mf (domyślnie) — zwraca pojedynczy plik model.3mf pod adresem model_urls.3mf, z jednym obiektem na element i kolorem elementu przypisanym do każdego obiektu.
Zwracane wartości
Właściwość result odpowiedzi zawiera id zadania nowo utworzonego zadania budowania Fidget Pixel. Odpytuj punkt końcowy Pobierz zadanie lub zasubskrybuj strumień, aż zadanie osiągnie status SUCCEEDED, a następnie pobierz artefakt z model_urls.3mf.
Tryby awarii
Name
400 - Bad Request
Description
Żądanie było nieprawidłowe. Typowe przyczyny:
Brakujący parametr: input_task_id jest wymagane.
Nieprawidłowy UUID: input_task_id nie jest prawidłowym identyfikatorem UUID.
Zadanie nadrzędne nie zakończyło się powodzeniem: Wskazane zadanie prototypu nie osiągnęło jeszcze statusu SUCCEEDED.
Brak kandydata: Zadanie prototypu zakończyło się powodzeniem, ale nie wygenerowało obrazu pixel-art; utwórz nowy prototyp.
Opcje poza zakresem: Jedno z pól options znajduje się poza dozwolonym zbiorem lub zakresem — na przykład options.grid_size must be 16 or 32 lub options.piece_size_mm=10 is not supported for shape=hex; hex pieces are available in 6 and 8 mm.
Nieobsługiwany format: output.format musi mieć wartość 3mf.
Name
401 - Unauthorized
Description
Uwierzytelnianie nie powiodło się. Sprawdź swój klucz API.
Name
402 - Payment Required
Description
Niewystarczająca liczba kredytów do wykonania tego zadania lub klucz API należy do konta na planie darmowym.
Name
403 - Forbidden
Description
Obraz wskazanego prototypu został oznaczony przez moderation własności intelektualnej. Blokowane są wyłącznie konta Enterprise z włączonym filtrowaniem własności intelektualnej; nic nie zostaje naliczone.
Name
404 - Not Found
Description
Wskazane zadanie prototypu nie istnieje, należy do innego użytkownika lub zostało utworzone za pośrednictwem aplikacji webowej (tylko zadania prototypów utworzone w trybie API mogą być łączone w łańcuch z budowaniem).
Name
429 - Too Many Requests
Description
Przekroczono limit szybkości.
Name
500 - Internal Server Error
Description
Nie udało się ustalić werdyktu dotyczącego własności intelektualnej dla wskazanego prototypu (Unable to perform intellectual property check, please try again). Konta Enterprise z włączonym filtrowaniem własności intelektualnej traktują taką sytuację jako niepowodzenie tego sprawdzenia; nic nie zostaje naliczone — spróbuj ponowić żądanie.
Pobierz zadanie prototypu lub kompilacji na podstawie prawidłowego id zadania. Ścieżka URL
musi odpowiadać etapowi zadania — zadanie kompilacji pobrane przez
/prototype/:id zwraca 404, i odwrotnie.
Unikalny identyfikator zadania fidget pixel do pobrania.
Zwraca
Odpowiedź zawiera obiekt zadania fidget pixel. Kształt zależy od
tego, o który etap zapytano.
Tryby awarii
Name
400 - Bad Request
Description
id nie jest prawidłowym UUID (Invalid ID).
Name
403 - Forbidden
Description
Obraz zadania został oznaczony przez moderację własności intelektualnej. Blokowane są tylko konta Enterprise z włączonym filtrowaniem własności intelektualnej.
Name
404 - Not Found
Description
Zadanie nie istnieje, należy do innego użytkownika lub jego etap nie odpowiada ścieżce URL.
Name
500 - Internal Server Error
Description
Nie udało się przeprowadzić weryfikacji własności intelektualnej (Unable to perform intellectual property check, please try again); konta Enterprise z włączonym filtrowaniem własności intelektualnej stosują zasadę „fail closed”. Ponów żądanie.
Anuluje zadanie fidget pixel. Jeśli zadanie ma nadal status PENDING,
kredyty zużyte w momencie tworzenia zostają zwrócone. Zadania, które są już
w stanie IN_PROGRESS, są anulowane bez zwrotu kredytów (worker mógł już
zużywać zasoby). Zadań, które osiągnęły już stan końcowy
(SUCCEEDED, FAILED, CANCELED), nie można anulować.
Ścieżka URL musi odpowiadać etapowi zadania — wywołanie DELETE na
/prototype/:buildId zwraca 404.
Parametry ścieżki
Name
id
Type
path
Description
Unikalny identyfikator zadania fidget pixel do anulowania.
Zwraca
Zwraca 204 No Content w przypadku powodzenia, z pustą treścią odpowiedzi.
Tryby niepowodzenia
Name
400 - Bad Request
Description
Żądanie było nieprawidłowe. Typowe przyczyny:
Nieprawidłowe ID: id nie jest prawidłowym identyfikatorem UUID.
Stan końcowy: Zadanie ma już status SUCCEEDED, FAILED lub CANCELED i nie może zostać anulowane.
Name
404 - Not Found
Description
Zadanie nie istnieje, należy do innego użytkownika lub jego etap nie odpowiada ścieżce URL.
Strumieniuj aktualizacje w czasie rzeczywistym dla zadania fidget pixel za pomocą Server-Sent Events (SSE).
Ścieżka URL musi odpowiadać etapowi zadania — otwarcie strumienia pod adresem
/prototype/:buildId/stream emituje pojedynczy ładunek event: error z
status_code: 404 i zamyka strumień; nieprawidłowo sformułowany id powoduje to samo z
status_code: 400 (Invalid ID).
Parametry
Name
id
Type
path
Description
Unikalny identyfikator zadania fidget pixel do strumieniowania.
Zwraca
Zwraca strumień obiektów zadań Fidget Pixel Prototype
lub Fidget Pixel Build jako
zdarzenia Server-Sent Events. Każda ramka zawiera pełny obiekt zadania dla danego etapu — tę samą strukturę, jaką
zwraca punkt końcowy Get — więc dopóki zadanie ma status PENDING lub IN_PROGRESS,
pola wyjściowe po prostu nie są jeszcze wypełnione (null, [] lub {}), a
finished_at ma wartość null.
Pobierz stronicowaną listę Twoich zadań fidget pixel dla pojedynczego etapu.
Ścieżka URL wybiera etap — /prototype zwraca zadania prototypu;
/build zwraca zadania budowy. Zadania z drugiego etapu nie są uwzględnione
w żadnej z odpowiedzi.
Parametry ścieżki
Name
stage
Type
path
Wymagane
Description
Wartość prototype lub build. Kolekcja zwraca tylko zadania,
których etap odpowiada adresowi URL — pobranie /prototype nigdy nie zwraca
zadań budowy i odwrotnie.
Parametry zapytania
Name
page_num
Type
integer
domyślne 1
Description
Numer strony do stronicowania.
Name
page_size
Type
integer
domyślne 10
Description
Limit rozmiaru strony. Maksymalna dozwolona wartość to 100 elementów.
Name
sort_by
Type
string
domyślne -created_at
Description
Pole do sortowania. Dostępne wartości:
+created_at: Sortuj według czasu utworzenia rosnąco.
-created_at: Sortuj według czasu utworzenia malejąco.
Obiekt zadania prototypu Fidget Pixel to jednostka pracy, którą Meshy śledzi
w celu przekształcenia zdjęcia źródłowego w obraz w stylu pixel-art. Wynik tego
etapu jest przekazywany do etapu budowy
za pomocą input_task_id.
Właściwości
Name
id
Type
string
Description
Unikalny identyfikator zadania. Choć jako szczegół implementacyjny używamy dla identyfikatorów zadań UUID z możliwością sortowania k-sortable, nie należy zakładać niczego co do formatu tego identyfikatora.
Name
type
Type
string
Description
Typ zadania. Wartość to creative-lab-fidget-pixel-prototype.
Name
name
Type
string
Description
Nazwa zadania podana podczas jego tworzenia. Pusty ciąg znaków, jeśli nie podano nazwy.
Name
status
Type
string
Description
Status zadania. Możliwe wartości to jedna z: PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED.
Name
progress
Type
integer
Description
Postęp zadania (progress). Jeśli zadanie jeszcze się nie rozpoczęło, ta wartość wynosi 0. Gdy zadanie zakończy się powodzeniem, wartość ta zmieni się na 100.
Name
created_at
Type
timestamp
Description
Znacznik czasu utworzenia zadania, w milisekundach.
Znacznik czasu reprezentuje liczbę milisekund, która upłynęła od 1 stycznia 1970 UTC, zgodnie ze
standardem RFC 3339.
Na przykład piątek, 1 września 2023, 12:00:00 czasu GMT jest reprezentowany jako 1693569600000. Dotyczy to
wszystkich znaczników czasu w Meshy API.
Name
started_at
Type
timestamp
Description
Znacznik czasu rozpoczęcia zadania, w milisekundach. Jeśli zadanie jeszcze się nie rozpoczęło, ta wartość to null.
Name
finished_at
Type
timestamp
Description
Znacznik czasu zakończenia zadania, w milisekundach. Jeśli zadanie jeszcze się nie zakończyło, ta wartość to null.
Name
expires_at
Type
timestamp
Description
Znacznik czasu wygaśnięcia wyniku zadania, w milisekundach — 3 dni po zakończeniu zadania. Konta enterprise przechowują wyniki API bezterminowo (zobacz Przechowywanie zasobów); dla nich ten znacznik czasu jest ustawiony na około 100 lat naprzód.
Name
preceding_tasks
Type
integer
Description
Liczba poprzedzających zadań.
Wartość tego pola ma znaczenie tylko wtedy, gdy status zadania to PENDING.
Name
task_error
Type
object
Description
Szczegóły błędu dla nieudanych zadań. Pełny opis obiektu task_error znajdziesz w sekcji Błędy.
Name
consumed_credits
Type
integer
Description
Liczba kredytów zużytych przez to zadanie. Zadanie, które osiągnie status SUCCEEDED, jest obciążane pełną kwotą za swój etap. Zadanie, które nigdy nie zostało utworzone (4xx w momencie żądania, w tym odrzucenie przez moderation), w ogóle nie jest obciążane. Zadanie, które zakończy się statusem FAILED, zwraca 0 — opłata jest zwracana. Anulowanie za pomocą DELETE powoduje zwrot środków tylko wtedy, gdy zadanie wciąż ma status PENDING; zadanie, które jest już IN_PROGRESS, pozostaje obciążone, ponieważ praca została już wykonana.
Name
image_urls
Type
array of strings
Description
Adresy URL umożliwiające pobranie obrazu pixel-art wygenerowanego przez to zadanie prototypu. Obecnie API zawsze zwraca dokładnie jeden obraz; pole jest tablicą, aby przyszłe wersje mogły udostępniać wiele kandydatów bez wprowadzania zmian niekompatybilnych wstecz. Puste, dopóki zadanie nie osiągnie statusu SUCCEEDED.
Są to podpisane adresy URL: pobieraj je bez nagłówka Authorization. Pozostają ważne do momentu expires_at, czyli 3 dni po finished_at, a ponowne odczytanie zadania w tym okresie zwraca identyczny adres URL, a nie nowo podpisany. Pobierz i zapisz pliki samodzielnie przed upływem tego terminu — nie ma możliwości odświeżenia wygasłego linku.
Obiekt zadania budowy Fidget Pixel to jednostka pracy śledzona przez Meshy w celu
wygenerowania drukowalnych elementów na podstawie pomyślnie zakończonego zadania prototypu. Budowa
próbkuje obraz pixel-art prototypu na żądaną siatkę i publikuje
pojedynczy plik 3MF oznaczony kolorami.
Właściwości
Name
id
Type
string
Description
Unikalny identyfikator zadania.
Name
type
Type
string
Description
Typ zadania. Wartość to creative-lab-fidget-pixel-build.
Name
name
Type
string
Description
Nazwa zadania podana podczas jego tworzenia. Pusty ciąg znaków, jeśli nie podano nazwy.
Name
status
Type
string
Description
Status zadania. Możliwe wartości to jedna z: PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED.
Name
progress
Type
integer
Description
Postęp zadania. Jeśli zadanie nie zostało jeszcze rozpoczęte, ta właściwość będzie miała wartość 0. Gdy zadanie zakończy się powodzeniem, wartość ta zmieni się na 100.
Name
created_at
Type
timestamp
Description
Znacznik czasu utworzenia zadania, w milisekundach.
Name
started_at
Type
timestamp
Description
Znacznik czasu rozpoczęcia zadania, w milisekundach. null dopóki zadanie się nie rozpocznie.
Name
finished_at
Type
timestamp
Description
Znacznik czasu zakończenia zadania, w milisekundach. null dopóki zadanie się nie zakończy.
Name
expires_at
Type
timestamp
Description
Znacznik czasu wygaśnięcia wyniku zadania, w milisekundach — 3 dni po zakończeniu zadania. Konta Enterprise przechowują wyniki API bezterminowo (zobacz Przechowywanie zasobów); dla nich ten znacznik czasu jest ustawiony na około 100 lat w przyszłość.
Name
preceding_tasks
Type
integer
Description
Liczba zadań poprzedzających. Ma znaczenie tylko wtedy, gdy status to PENDING.
Name
task_error
Type
object
Description
Szczegóły błędu dla zadań zakończonych niepowodzeniem. Zobacz Błędy, aby poznać pełną specyfikację obiektu task_error.
Name
consumed_credits
Type
integer
Description
Liczba kredytów zużytych przez to zadanie. Zadanie, które osiąga status SUCCEEDED, jest obciążane pełną kwotą za swój etap. Zadanie, które nigdy nie zostało utworzone (błąd 4xx w momencie żądania, w tym odrzucenie przez moderation) w ogóle nie jest obciążane. Zadanie, które osiąga status FAILED, zwraca 0 — opłata jest zwracana. Anulowanie za pomocą DELETE zwraca opłatę tylko wtedy, gdy zadanie nadal ma status PENDING; zadanie już w stanie IN_PROGRESS pozostaje obciążone, ponieważ praca została już wykonana.
Name
model_urls
Type
object
Description
Adresy URL do pobrania wygenerowanego artefaktu, kluczowane według formatu. Zawiera dokładnie jeden wpis — format żądany za pomocą pola output.format żądania budowy. Puste, dopóki zadanie nie osiągnie statusu SUCCEEDED.
Są to podpisane adresy URL: pobieraj je bez nagłówka Authorization. Pozostają ważne do momentu expires_at, czyli 3 dni po finished_at, a ponowne odczytanie zadania w tym okresie zwraca identyczny adres URL zamiast nowo podpisanego. Pobierz i zapisz pliki samodzielnie przed tym terminem — nie ma sposobu na odświeżenie wygasłego linku.
Name
3mf
Type
string
Description
Adres URL do pobrania pliku 3MF. Jeden obiekt na element, każdy oznaczony kolorem z palety, dzięki czemu wielofilamentowy slicer przypisuje filamenty według koloru. Obecny, gdy output.format miało wartość 3mf (domyślną).
Pełny przepływ: utwórz prototyp ze zdjęcia, sprawdzaj jego status aż do
SUCCEEDED, utwórz na jego podstawie build, sprawdzaj jego status aż do
SUCCEEDED, a następnie pobierz plik 3MF z model_urls.
Prototyp zwykle kończy się w ciągu kilku minut; build zazwyczaj kończy się
w znacznie mniej niż minutę. W prawdziwej integracji pokazałbyś użytkownikowi
końcowemu wpis image_urls prototypu i pozwolił mu potwierdzić (lub ponownie
uruchomić prototyp) przed wydaniem kredytów na build.
Complete flow
POST
/openapi/creative-lab/fidget-pixel/v1
#!/usr/bin/env bashset-euopipefail# Requires curl and jq. Point IMAGE_PATH at a local photo, or IMAGE_URL at a public one:# export MESHY_API_KEY=msy_...# export IMAGE_PATH=./portrait.jpg # or: export IMAGE_URL=https://...# export PIXEL_TYPE=person # or: other:"${MESHY_API_KEY:?export MESHY_API_KEY first}"if [[ -z"${IMAGE_PATH:-}"&&-z"${IMAGE_URL:-}" ]]; thenecho"export IMAGE_PATH (local file) or IMAGE_URL (public url) first">&2exit1fiPIXEL_TYPE=${PIXEL_TYPE:-person}BASE="https://api.meshy.ai/openapi/creative-lab/fidget-pixel/v1"AUTH="Authorization: Bearer $MESHY_API_KEY"# api METHOD URL [curl args...] -> prints the response body, non-zero on failure.# Note we do not use -f/--fail: it discards the body, and the body is the only# place the reason appears.api() {local method=$1 url=$2 out http_code bodyshift2 out=$(curl--silent--show-error--max-time60--write-out$'\n%{http_code}' \-X"$method""$url"-H"$AUTH""$@") ||return1 http_code=${out##*$'\n'} body=${out%$'\n'*}if ((http_code >=400)); thenecho"HTTP $http_code for $url: $body">&2return1fiprintf'%s'"$body"}# Each task gets its own 40-minute budget.poll() {local kind=$1 id=$2 delay=5 task_status deadline deadline=$(($(date+%s) + 2400))while:; doif (($(date +%s) >= deadline)); thenecho"gave up waiting for $kind $id">&2return1fi task_status=$(apiGET"$BASE/$kind/$id"|jq-r'.status')echo"$kind: $task_status"case"$task_status"inSUCCEEDED)return0 ;;FAILED|CANCELED)return1 ;;esacsleep"$delay" delay=$((delay*2>30?30:delay*2))done}# Build the request body in a file. A base64 data URI must never go on the# command line or into an exported variable - a photo of any real size will# exceed the OS argument limit.BODY=$(mktemp)trap'rm -f "$BODY"'EXITif [[ -n"${IMAGE_PATH:-}" ]]; then# Declare the real type: the API accepts JPEG, PNG and WebP.case"$(printf '%s' "${IMAGE_PATH##*.}" |tr 'A-Z' 'a-z')"inpng) MIME=image/png ;;webp) MIME=image/webp ;;*) MIME=image/jpeg ;;esac {printf'{"type":"%s","image_url":"data:%s;base64,'"$PIXEL_TYPE""$MIME"base64<"$IMAGE_PATH"|tr-d'\n'printf'"}' } >"$BODY"elsejq-n--argt"$PIXEL_TYPE"--argu"$IMAGE_URL" \'{type: $t, image_url: $u}'>"$BODY"fi# 1. Create the prototype taskPROTO_ID=$(apiPOST"$BASE/prototype" \-H'Content-Type: application/json'--data-binary@"$BODY"|jq-r'.result')# 2. Wait for the pixel-art image (show image_urls[0] to a user in production)pollprototype"$PROTO_ID"# 3. Create the build task (defaults: square pieces, 32x32 grid, 8 mm, 8 colors, 15 mm tall)jq-n--argp"$PROTO_ID" \'{input_task_id: $p, options: {shape: "square", grid_size: 32, piece_size_mm: 8, color_count: 8, piece_height_mm: 15}, output: {format: "3mf"}}'>"$BODY"BUILD_ID=$(apiPOST"$BASE/build" \-H'Content-Type: application/json'--data-binary@"$BODY"|jq-r'.result')# 4. Wait for the piecespollbuild"$BUILD_ID"# 5. Download the 3MF. This is a signed URL: no Authorization header,# and it stays valid for 3 days after the task finishes.TASK=$(apiGET"$BASE/build/$BUILD_ID")curl--silent--show-error--fail--max-time900 \-ofidget-pixel.3mf"$(jq-r '.model_urls["3mf"]' <<<"$TASK")"echo"Done: fidget-pixel.3mf"