Proměňte zdrojovou fotografii ve full-color vlastní klávesu (keycap) pro mechanickou klávesnici
ve dvou fázích: prototype vygeneruje render designu „hotové klávesy“
z vaší vstupní fotografie. Jakmile tento render potvrdíte, build ho v rámci jediného běhu
promění na texturovaný 3D model klávesy — generování bílého modelu, automatické
usazení a řezání v kalibrované výchozí poloze, obarvení celého modelu a
finální sestavení proběhnou vše v jedné úloze sestavení. Obě fáze jsou propojeny
prostřednictvím input_task_id a candidate_id.
POST /openapi/creative-lab/keycap/v1/prototype
POST /openapi/creative-lab/keycap/v1/build
Oba endpointy POST vyžadují placené předplatné. Požadavky z
účtů s bezplatným plánem jsou odmítnuty s chybou 402 Payment Required.
Vygeneruje render finálního designu klávesy (keycap) ze zdrojové fotografie. Výsledek úlohy obsahuje pole image_urls (zobrazovací render finální klávesy) a paralelní pole candidate_ids; obě pole obsahují jednu položku.
Pokud výsledek není takový, jaký chcete, zavolejte tento koncový bod znovu pro další render — každé volání je účtováno samostatně. Předejte candidate_id společně s ID úlohy prototypu do koncového bodu pro sestavení.
Podobu odpovědi naleznete v
Objektu úlohy prototypu Keycap.
Parametry
Name
image_url
Type
string
Povinné
Description
Zdrojová fotografie, kterou Meshy převede na obrázky designu klávesy. Aktuálně podporujeme formáty .jpg, .jpeg, .png a .webp.
Formát je rozpoznán dekódováním obrazových dat, nikoli podle přípony souboru v URL — URL bez přípony nebo taková, která přesměrovává, funguje, pokud se bajty dekódují do podporovaného formátu. HTTP přesměrování jsou následována. Orientace EXIF je normalizována, takže otočená fotografie z telefonu je použita tak, jak vypadá.
Limity: alespoň 32 pixelů na každé straně, nejvýše 178 956 970 pixelů celkem a nejvýše 20 000 000 bajtů po stažení. U Data URI se limit vztahuje na dekódované bajty, takže samotný zdrojový soubor může mít až tuto velikost — je to base64 text, který je zhruba o třetinu větší, což je relevantní pro tělo vašeho požadavku, nikoli pro tento limit. Data URI musí deklarovat typ obsahu image/* a ;base64.
Obrázek lze poskytnout dvěma způsoby:
Veřejně přístupná URL: URL, která je přístupná z veřejného internetu.
Data URI: Obrázek zakódovaný v base64 jako data URI. Příklad data URI: data:image/jpeg;base64,<vaše obrazová data zakódovaná v base64>.
Name
name
Type
string
Description
Volitelný název úlohy pro zobrazovací účely. Maximálně 100 znaků.
Name
remove_background
Type
boolean
výchozí false
Description
Když je nastaveno na true, zobrazovací render vrácený v image_urls je transparentní RGBA PNG s odstraněným pozadím, takže jej můžete umístit na jakékoli pozadí.
Toto platí pouze pro zobrazovací render. Kandidát, který zpracovává koncový bod pro sestavení, není ovlivněn, takže 3D výsledek je v obou případech totožný.
Návratové hodnoty
Vlastnost result v odpovědi obsahuje id úlohy nově vytvořené úlohy prototypu Keycap. Dotazujte koncový bod Získat úlohu nebo se přihlaste k odběru streamu, dokud úloha nedosáhne stavu SUCCEEDED, poté vezměte položku z candidate_ids a předejte ji společně s ID úlohy do koncového bodu pro sestavení.
Režimy selhání
Name
400 - Bad Request
Description
Požadavek byl nepřijatelný. Běžné příčiny:
Chybějící parametr: image_url je povinný.
Neplatný formát obrázku: Poskytnutý image_url není v podporovaném formátu (.jpg, .jpeg, .png, .webp).
Rozměry obrázku mimo povolený rozsah: Obrázek je příliš malý, přesahuje maximální velikost souboru nebo přesahuje maximální počet pixelů.
Nedostupná URL: image_url se nepodařilo stáhnout (404 nebo timeout).
Neplatné Data URI: Řetězec base64 je poškozený.
Obsah označen: Vstupní obrázek byl označen moderací NSFW.
Name
401 - Unauthorized
Description
Autentizace selhala. Zkontrolujte prosím svůj API klíč.
Name
402 - Payment Required
Description
Účet má aktivní bezplatný plán (pro vytváření úloh je vyžadován placený plán) nebo nemá dostatek kreditů.
Name
403 - Forbidden
Description
Vstupní obrázek byl označen moderací duševního vlastnictví.
Name
429 - Too Many Requests
Description
Překročili jste svůj limit rychlosti.
Name
500 - Internal Server Error
Description
Došlo k neočekávané chybě na straně serveru — například služba moderace obsahu byla nedostupná, nepodařilo se připravit vstupní obrázek, nebo úlohu nebylo možné vytvořit. V tomto případě nedojde k vytvoření žádné úlohy, takže je bezpečné požadavek zopakovat.
Request
POST
/openapi/creative-lab/keycap/v1/prototype
# Stage 1: generate a finished-keycap design rendercurlhttps://api.meshy.ai/openapi/creative-lab/keycap/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>" }'
Vygeneruje finální texturovaný 3D model keycapu z úspěšné prototypové úlohy a jednoho z jejích kandidátů. Jediná úloha sestavení spustí celý proces od začátku do konce — generování bílého modelu ze zvoleného návrhu, automatické usazení a oříznutí na základně keycapu pomocí kalibrované výchozí polohy (bez nutnosti interaktivního doladění), obarvení celého modelu a finální sestavení a export. Sestavení obvykle trvá 3–7 minut, přičemž se blíží horní hranici, pokud běží více sestavení současně.
Podrobnosti o tvaru odpovědi najdete v Objekt úlohy sestavení keycapu.
Parametry
Name
input_task_id
Type
string
Povinné
Description
ID úlohy prototypu vytvořeného prostřednictvím stejného OpenAPI koncového bodu. Prototyp musel být vytvořen stejným účtem Meshy, musí mít stav SUCCEEDED a musí produkovat alespoň jednoho kandidáta.
Prototypové úlohy vytvořené přes webovou aplikaci nejsou akceptovány — koncový bod pro sestavení přijímá pouze prototypové úlohy vytvořené pomocí POST /openapi/creative-lab/keycap/v1/prototype a jakýkoli jiný zdroj odmítne s chybou 404.
Name
candidate_id
Type
string
Povinné
Description
Kandidát, který se má sestavit, převzatý z pole candidate_ids úspěšné prototypové úlohy. Musí patřit k dané úloze; jakákoli jiná hodnota je odmítnuta s chybou 400.
Name
name
Type
string
Description
Volitelný název úlohy pro zobrazení. Maximálně 100 znaků.
options
Volitelné doladění geometrie. Každé pole má kalibrovanou výchozí hodnotu — odešlete pouze ta, která chcete přepsat.
Name
base_model
Type
string
výchozí cherry-mx-1x1-r1
Description
Základna keycapu, na které se má sestavovat. Aktuálně je jedinou dostupnou hodnotou
cherry-mx-1x1-r1 — standardní keycap 1u v profilu Cherry MX. Plánováno je
3–5 dalších rozšířených standardních velikostí; vlastní velikosti
nejsou podporovány.
Name
head_size_mm
Type
number
výchozí 23
Description
Cílová velikost vymodelované hlavy v milimetrech: její nejdelší rozměr je škálován na tuto hodnotu. Rozsah: [10, 40]. Hodnoty nad zhruba 32,9 mohou být sníženy, aby hlava stále odpovídala ochrannému limitu základny; dodaný nejdelší rozměr tak může být menší, než bylo požadováno. Použitá hodnota se dnes v objektu úlohy nepromítá zpět — pokud potřebujete potvrdit skutečně obdrženou velikost, změřte ohraničující kvádr sítě keycap-head ve staženém modelu.
Name
vertical_offset_mm
Type
number
výchozí 0
Description
Svislý posun aplikovaný na hlavu před jejím usazením na základnu, v milimetrech. Rozsah: [-5, 5].
Návratové hodnoty
Vlastnost result v odpovědi obsahuje id úlohy nově vytvořené úlohy sestavení keycapu. Dotazujte se na koncový bod Získání úlohy nebo se přihlaste k odběru streamu, dokud úloha nedosáhne stavu SUCCEEDED, a poté stáhněte výstupy z model_urls.glb a model_urls.obj_zip.
GLB i balíček OBJ jsou exportovány v reálném měřítku
v milimetrech, se souřadnicovým systémem s osou Y nahoru a přední stranou
keycapu směřující ve směru +Z.
Chybové stavy
Name
400 - Bad Request
Description
Požadavek byl nepřijatelný. Časté příčiny:
Chybějící parametr: input_task_id a candidate_id jsou povinné.
Neplatné UUID: input_task_id není platné UUID.
Nadřazená úloha nedokončena úspěšně: Odkazovaná prototypová úloha ještě nedosáhla stavu SUCCEEDED.
Žádní kandidáti: Prototypová úloha byla úspěšná, ale neprodukovala žádné kandidáty.
Neznámý kandidát: candidate_id není mezi kandidáty vstupní úlohy.
Volby mimo rozsah: Jedno z polí options bylo mimo povolený rozsah nebo množinu povolených hodnot.
Name
401 - Unauthorized
Description
Autentizace selhala. Zkontrolujte prosím svůj API klíč.
Name
402 - Payment Required
Description
Účet má bezplatný plán (pro vytváření úloh je vyžadován placený plán) nebo nemá dostatek kreditů.
Name
404 - Not Found
Description
Odkazovaná prototypová úloha neexistuje, patří jinému uživateli nebo byla vytvořena přes webovou aplikaci (do sestavení lze zřetězit pouze prototypové úlohy vytvořené v API režimu).
Name
429 - Too Many Requests
Description
Překročili jste limit rychlosti.
Name
500 - Internal Server Error
Description
Došlo k neočekávané chybě na straně serveru — například byla nedostupná služba moderation obsahu, selhalo vložení vstupního obrázku do fronty nebo se nepodařilo úlohu vytvořit. V tomto případě není vytvořena žádná úloha, takže je bezpečné požadavek opakovat.
Request
POST
/openapi/creative-lab/keycap/v1/build
# Stage 2: build the chosen candidate into a 3D keycapcurlhttps://api.meshy.ai/openapi/creative-lab/keycap/v1/build \-XPOST \-H"Authorization: Bearer ${YOUR_API_KEY}" \-H'Content-Type: application/json' \-d'{ "input_task_id": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef", "candidate_id": "0198c1b2-33f5-7d21-a4b7-8e9d0c1f2a3b", "options": { "base_model": "cherry-mx-1x1-r1", "head_size_mm": 23, "vertical_offset_mm": 0 } }'
Načtěte úlohu prototypu nebo sestavení (build) na základě platného id úlohy. Cesta URL
musí odpovídat fázi úlohy — úloha sestavení načtená přes
/prototype/:id vrátí 404, a naopak.
Zruší úlohu keycap. Pokud je úloha stále ve stavu PENDING, kredity
spotřebované při vytvoření jsou vráceny. Úlohy, které jsou již ve stavu
IN_PROGRESS, jsou zrušeny bez vrácení kreditů (pracovní proces již může
spotřebovávat zdroje). Úlohy, které již dosáhly konečného stavu
(SUCCEEDED, FAILED, CANCELED), nelze zrušit.
Cesta URL musí odpovídat fázi úlohy — DELETE na
/prototype/:buildId vrací 404.
Parametry cesty
Name
id
Type
path
Description
Jedinečný identifikátor úlohy keycap, kterou chcete zrušit.
Návratová hodnota
V případě úspěchu vrací 204 No Content s prázdným tělem.
Režimy selhání
Name
400 - Bad Request
Description
Úloha je již v konečném stavu a nelze ji zrušit.
Name
404 - Not Found
Description
Úloha neexistuje, patří jinému uživateli, nebo její fáze neodpovídá cestě URL.
Name
500 - Internal Server Error
Description
Během rušení došlo k neočekávané chybě na straně serveru. Úloha mohla, ale nemusela být zrušena — před dalším pokusem si ji znovu načtěte pro ověření.
Streamuje aktualizace úlohy keycap v reálném čase pomocí Server-Sent Events (SSE).
Cesta URL musí odpovídat fázi úlohy — otevření streamu na
/prototype/:buildId/stream vyvolá jednotný event: error payload s
status_code: 404 a stream se uzavře.
Parametry
Name
id
Type
path
Description
Jedinečný identifikátor úlohy keycap, kterou chcete streamovat.
Návratová hodnota
Vrací stream objektů úlohy typu Keycap Prototype
nebo Keycap Build jako
Server-Sent Events. Každý rámec obsahuje celý objekt úlohy pro danou fázi — stejnou podobu, jakou vrací
koncový bod Get — takže dokud je úloha ve stavu PENDING nebo IN_PROGRESS,
výstupní pole zkrátka ještě nejsou vyplněná (null, [] nebo {}) a
finished_at je null.
// Error event example (wrong stage or task not found)event: errordata: {"status_code": 404,"message": "Task not found"}// Message event examples illustrate task progress.// Every frame is the full task object; fields not yet populated are null / empty.// The PENDING frame below is abbreviated to the fields that change.event: messagedata: {"id": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af","progress": 0,"status": "PENDING"}event: messagedata: {"id": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af","type": "creative-lab-keycap-build","status": "SUCCEEDED","progress": 100,"created_at": 1753142600000,"started_at": 1753142610000,"finished_at": 1753143050000,"expires_at": 1753402250000,"task_error": null,"consumed_credits": 50,"model_urls": {"glb":"https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model.glb?Expires=***","obj_zip":"https://assets.meshy.ai/***/tasks/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/output/model-obj.zip?Expires=***" },"process_image_urls": {"head_design":"https://assets.meshy.ai/***/head-design.png?Expires=***" }}
Načtěte stránkovaný seznam vašich úloh keycap pro jednu fázi. Cesta URL
vybírá fázi — /prototype vrací úlohy prototypu; /build
vrací úlohy sestavení. Úlohy z druhé fáze nejsou zahrnuty v žádné
z odpovědí.
Parametry cesty
Name
stage
Type
path
Povinné
Description
Buď prototype, nebo build. Kolekce vrací pouze úlohy,
jejichž fáze odpovídá URL — načtení /prototype nikdy nevrátí
úlohy sestavení a naopak.
Parametry dotazu
Name
page_num
Type
integer
výchozí 1
Description
Číslo stránky pro stránkování.
Name
page_size
Type
integer
výchozí 10
Description
Limit velikosti stránky. Maximální povolená hodnota je 100 položek.
Name
sort_by
Type
string
výchozí -created_at
Description
Pole, podle kterého se řadí. Dostupné hodnoty:
+created_at: Řazení podle času vytvoření vzestupně.
-created_at: Řazení podle času vytvoření sestupně.
Objekt úlohy prototypu keycapu je pracovní jednotka, kterou Meshy sleduje za účelem
vygenerování jednoho obrázku hotového designu keycapu ze zdrojové fotografie. Výstup
této fáze je navázán na fázi sestavení
pomocí input_task_id a candidate_id.
Vlastnosti
Name
id
Type
string
Description
Unikátní identifikátor úlohy. Ačkoli jako implementační detail používáme pro id úloh k-sortovatelné UUID, neměli byste dělat žádné předpoklady o formátu id.
Name
type
Type
string
Description
Typ úlohy. Hodnota je creative-lab-keycap-prototype.
Name
name
Type
string
Description
Název úlohy zadaný při jejím vytvoření. Prázdný řetězec, pokud nebyl název zadán.
Name
status
Type
string
Description
Stav úlohy. Možné hodnoty jsou jedna z PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED.
Name
progress
Type
integer
Description
Progress úlohy. Pokud úloha ještě nezačala, bude tato vlastnost 0. Jakmile úloha uspěje, hodnota se změní na 100.
Name
created_at
Type
timestamp
Description
Časové razítko okamžiku vytvoření úlohy, v milisekundách.
Časové razítko představuje počet milisekund, které uplynuly od 1. ledna 1970 UTC, podle
standardu RFC 3339.
Například pátek 1. září 2023 12:00:00 GMT je reprezentován jako 1693569600000. To platí
pro všechna časová razítka v Meshy API.
Name
started_at
Type
timestamp
Description
Časové razítko okamžiku zahájení úlohy, v milisekundách. Pokud úloha ještě nezačala, bude tato vlastnost 0.
Name
finished_at
Type
timestamp
Description
Časové razítko okamžiku dokončení úlohy, v milisekundách. Pokud úloha ještě není dokončena, bude tato vlastnost 0.
Name
expires_at
Type
timestamp
Description
Časové razítko okamžiku, kdy vyprší platnost výsledku úlohy, v milisekundách.
Name
preceding_tasks
Type
integer
Description
Počet předcházejících úloh.
Hodnota tohoto pole má smysl pouze v případě, že stav úlohy je PENDING.
Name
task_error
Type
object
Description
Podrobnosti o chybě u neúspěšných úloh. Úplný popis objektu task_error naleznete v části Chyby.
Name
consumed_credits
Type
integer
Description
Počet kreditů spotřebovaných touto úlohou. Úloze, která dosáhne stavu SUCCEEDED, je účtována plná částka za danou fázi. Úloha, která nikdy nebyla vytvořena (chyba 4xx v okamžiku požadavku, včetně zamítnutí při moderation), se neúčtuje vůbec. Úloha, která dosáhne stavu FAILED, vrací 0 — poplatek je vrácen, včetně případu asynchronního zablokování při moderation. Zrušení pomocí DELETE vrátí poplatek pouze tehdy, pokud je úloha stále ve stavu PENDING; úloha, která je již IN_PROGRESS, zůstává zpoplatněna, protože práce již byla vynaložena.
Name
image_urls
Type
array of strings
Description
Stažitelná URL adresa vykresleného designu hotového keycapu — jak bude kandidát vypadat jako hotový keycap. Obsahuje jednu položku; image_urls[i] odpovídá candidate_ids[i]. Prázdné, dokud úloha nedosáhne stavu SUCCEEDED. URL adresa slouží pouze k zobrazení; koncový bod pro sestavení používá candidate_ids, nikoli tyto URL adresy. Stejný životní cyklus URL jako u model_urls: podepsané, bez hlavičky Authorization, platné do expires_at a stabilní při opětovném načtení úlohy.
Name
candidate_ids
Type
array of strings
Description
Neprůhledné identifikátory kandidátů, paralelní k image_urls. Předejte položku odpovídající vámi zvolenému designu jako candidate_id v požadavku na sestavení. Nedělejte žádné předpoklady o formátu těchto id.
Objekt Keycap Build Task je pracovní jednotka, kterou Meshy sleduje za účelem
vygenerování finální texturované 3D klávesy (keycap) z úspěšně dokončené prototypové úlohy a
zvoleného kandidáta. Jedno sestavení (build) spouští celý pipeline — generování bílého modelu,
automatické usazení a ořezání, obarvení, sestavení a export.
Vlastnosti
Name
id
Type
string
Description
Jedinečný identifikátor úlohy.
Name
type
Type
string
Description
Typ úlohy. Hodnota je creative-lab-keycap-build.
Name
name
Type
string
Description
Název úlohy zadaný při jejím vytvoření. Prázdný řetězec, pokud nebyl název zadán.
Name
status
Type
string
Description
Stav úlohy. Možné hodnoty jsou jedna z PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED.
Name
progress
Type
integer
Description
Postup úlohy (progress). Pokud úloha ještě nebyla zahájena, bude tato hodnota 0. Jakmile úloha úspěšně skončí, hodnota bude 100.
Name
created_at
Type
timestamp
Description
Časové razítko vytvoření úlohy, v milisekundách.
Name
started_at
Type
timestamp
Description
Časové razítko zahájení úlohy, v milisekundách.
Name
finished_at
Type
timestamp
Description
Časové razítko dokončení úlohy, v milisekundách.
Name
expires_at
Type
timestamp
Description
Časové razítko vypršení platnosti výsledku úlohy, v milisekundách.
Name
preceding_tasks
Type
integer
Description
Počet předcházejících úloh. Má význam pouze tehdy, když je stav PENDING.
Name
task_error
Type
object
Description
Podrobnosti o chybě u neúspěšných úloh. Úplný referenční popis objektu task_error naleznete v části Chyby.
Name
consumed_credits
Type
integer
Description
Počet kreditů spotřebovaných touto úlohou. Úloha, která dosáhne stavu SUCCEEDED, je zpoplatněna plnou částkou za danou fázi. Úloha, která nikdy nebyla vytvořena (chyba 4xx v okamžiku požadavku, včetně zamítnutí moderací), není zpoplatněna vůbec. Úloha, která skončí ve stavu FAILED, vrací 0 — poplatek je vrácen, včetně případu asynchronního zablokování moderací. Zrušení pomocí DELETE vrací poplatek pouze tehdy, když je úloha stále ve stavu PENDING; úloha, která je již IN_PROGRESS, zůstává zpoplatněna, protože práce již byla vynaložena.
Name
model_urls
Type
object
Description
Stažitelné URL adresy pro vygenerované soubory modelu. Jak balíček GLB, tak balíček OBJ jsou exportovány v reálném měřítku v milimetrech, s orientací Y nahoru a přední stranou klávesy směřující ve směru +Z. Sítě (mesh) se jmenují keycap-head a keycap-base; pokud se základna vrátí k výplňovému vzoru, je přítomna i třetí síť keycap-base-interior pro dutinu pro stem. Nepředpokládejte, že jsou vždy přesně dvě sítě.
Jedná se o podepsané URL adresy: načítejte je bez hlavičky Authorization. Zůstávají platné až do expires_at, tedy 3 dny po finished_at, a opětovné načtení úlohy v tomto časovém okně vrací identickou URL adresu, nikoli nově podepsanou. Soubory si stáhněte a uložte sami před tímto termínem — vypršenou platnost odkazu nelze žádným způsobem obnovit.
Name
glb
Type
string
Description
Stažitelná URL adresa finálního texturovaného souboru model.glb.
Name
obj_zip
Type
string
Description
Stažitelná URL adresa zip balíčku obsahujícího model.obj, model.mtl a PNG textury, na které jeho MTL soubor skutečně odkazuje. Jednobarevná základna obsahuje pouze keycap-head.png; vzorovaná základna obsahuje navíc i keycap-base.png.
Name
process_image_urls
Type
object
Description
Stažitelné URL adresy pro mezistupňové obrázky procesu, klíčované podle druhu. Stejný životní cyklus URL adres jako u model_urls: podepsané, bez hlavičky Authorization, platné až do expires_at a stabilní při opětovném načtení úlohy. Aktuálně generované druhy:
head_design — obrázek návrhu zvoleného kandidáta, který sestavení použilo (vždy přítomen).
composite — vykreslený finální náhled hotové klávesy zvoleného kandidáta (přítomen, pokud je k dispozici).
base_canvas — vymalované plátno základny klávesy (přítomno, pokud je k dispozici).
Považujte množinu klíčů za otevřenou; nové druhy mohou být přidány bez zpětně nekompatibilní změny.
Kompletní postup: vytvořit prototyp z fotografie, dotazovat se na jeho stav (poll) až do stavu
SUCCEEDED, vybrat kandidáta z candidate_ids, vytvořit build s
tímto kandidátem, dotazovat se na stav buildu až do SUCCEEDED a poté stáhnout GLB a
balíček OBJ z model_urls.
Příklad programově vybírá prvního kandidáta. Ve skutečné
integraci byste zobrazili položku image_urls koncovému uživateli a
nechali ho vybrat; zvolený index se mapuje 1:1 na candidate_ids.
Complete flow
POST
/openapi/creative-lab/keycap/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://...:"${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">&2exit1fiBASE="https://api.meshy.ai/openapi/creative-lab/keycap/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'{"image_url":"data:%s;base64,'"$MIME"base64<"$IMAGE_PATH"|tr-d'\n'printf'"}' } >"$BODY"elseprintf'{"image_url":"%s"}'"$IMAGE_URL">"$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 design renderpollprototype"$PROTO_ID"# 3. Pick a candidate (first one here; show image_urls to a user in production)CANDIDATE_ID=$(apiGET"$BASE/prototype/$PROTO_ID"|jq-r'.candidate_ids[0]')# 4. Create the build taskjq-n--argp"$PROTO_ID"--argc"$CANDIDATE_ID" \'{input_task_id: $p, candidate_id: $c}'>"$BODY"BUILD_ID=$(apiPOST"$BASE/build" \-H'Content-Type: application/json'--data-binary@"$BODY"|jq-r'.result')# 5. Wait for the model (a build usually takes 3-7 minutes)pollbuild"$BUILD_ID"# 6. Download the artifacts. These are signed URLs: no Authorization header,# and they stay valid for 3 days after the task finishes.TASK=$(apiGET"$BASE/build/$BUILD_ID")curl--silent--show-error--fail--max-time900 \-okeycap.glb"$(jq-r '.model_urls.glb' <<<"$TASK")"curl--silent--show-error--fail--max-time900 \-okeycap-obj.zip"$(jq-r '.model_urls.obj_zip' <<<"$TASK")"echo"Done: keycap.glb + keycap-obj.zip"