Bir kaynak fotoğrafı, iki aşamada tam renkli özel mekanik klavye tuş başlığına dönüştürün: prototip, giriş fotoğrafınızdan "bitmiş tuş başlığı" tasarım renderı oluşturur. Bu renderı onayladıktan sonra, yapı onu tek bir çalışmada dokulu 3D tuş başlığı modeline dönüştürür — beyaz model oluşturma, kalibre edilmiş varsayılan pozda otomatik oturma ve kesme, tam model renklendirme ve nihai montaj hepsi bir yapı görevi içinde gerçekleşir. İki aşama input_task_id artı candidate_id ile bağlantılıdır.
POST /openapi/creative-lab/keycap/v1/prototype
POST /openapi/creative-lab/keycap/v1/build
Her iki POST endpoint'i de ücretli bir abonelik planı gerektirir. Ücretsiz plan hesaplarından gelen talepler 402 Payment Required ile reddedilir.
Kaynak fotoğraftan bitmiş bir keycap tasarım renderı oluşturun. Görev sonucu, image_urls dizisi (bitmiş keycap'in görüntü renderı) ve paralel bir candidate_ids dizisi taşır; her ikisi de tek bir giriş içerir. Sonuç istediğiniz gibi değilse başka bir render için bu uç noktayı tekrar çağırın — her çağrı ayrı olarak faturalandırılır. candidate_id'yi prototip görev kimliği ile birlikte build endpoint uç noktasına iletin. Yanıt yapısı için The Keycap Prototype Task Object bölümüne bakın.
Parametreler
Name
image_url
Type
string
Zorunlu
Description
Meshy'nin keycap tasarım görüntülerine dönüştüreceği kaynak fotoğraf. Şu anda .jpg, .jpeg, .png ve .webp formatlarını destekliyoruz.
Format, URL'nin dosya uzantısından değil, görüntü verilerini çözerek algılanır — uzantısı olmayan veya yönlendiren bir URL, baytlar desteklenen bir formata çözüldüğü sürece çalışır. HTTP yönlendirmeleri takip edilir. EXIF yönlendirmesi normalleştirilir, böylece döndürülmüş bir telefon fotoğrafı göründüğü gibi kullanılır.
Sınırlar: her bir kenarda en az 32 piksel, toplamda en fazla 178,956,970 piksel ve indirildikten sonra en fazla 20,000,000 bayt. Bir veri URI'si için sınır çözülen baytlara uygulanır, bu nedenle kaynak dosyanın kendisi bu boyuta kadar olabilir — base64 metni yaklaşık üçte bir daha büyüktür, bu da istek gövdeniz için önemlidir, bu sınır için değil. Bir veri URI'si image/* içerik türünü ve ;base64'ü belirtmelidir.
Görüntüyü sağlamak için iki yol vardır:
Herkese açık erişilebilir URL: Genel internetten erişilebilen bir URL.
Veri URI'si: Görüntünün base64 kodlu bir veri URI'si. Bir veri URI'si örneği: data:image/jpeg;base64,<base64 kodlu görüntü veriniz>.
Name
name
Type
string
Description
Görüntüleme amaçları için isteğe bağlı görev adı. Maksimum 100 karakter.
Name
remove_background
Type
boolean
varsayılan false
Description
true olarak ayarlandığında, image_urls içinde döndürülen görüntü renderı, arka planı kaldırılmış şeffaf bir RGBA PNG olur, böylece herhangi bir arka plana yerleştirebilirsiniz.
Bu yalnızca görüntü renderına uygulanır. Build endpoint'in tükettiği aday etkilenmez, bu nedenle 3D sonuç her iki şekilde de aynıdır.
Döndürülenler
Yanıtın result özelliği, yeni oluşturulan keycap prototip görevinin görev id'sini içerir. Görev SUCCEEDED durumuna ulaşana kadar Bir Görev Al uç noktasını sorgulayın veya akışa abone olun, ardından candidate_ids'den girişi alın ve görev kimliği ile birlikte build endpoint uç noktasına iletin.
Başarısızlık Modları
Name
400 - Bad Request
Description
İstek kabul edilemezdi. Yaygın nedenler:
Eksik parametre: image_url gereklidir.
Geçersiz görüntü formatı: Sağlanan image_url desteklenen bir formatta değil (.jpg, .jpeg, .png, .webp).
Görüntü boyutları aralık dışında: Görüntü çok küçük, maksimum dosya boyutunu aşıyor veya maksimum piksel sayısını aşıyor.
Erişilemeyen URL: image_url indirilemedi (404 veya timeout).
Geçersiz Veri URI'si: Base64 dizesi hatalı.
İçerik işaretlendi: Girdi görüntüsü NSFW moderation tarafından işaretlendi.
Name
401 - Unauthorized
Description
Kimlik doğrulama başarısız oldu. Lütfen API anahtarınızı kontrol edin.
Name
402 - Payment Required
Description
Hesap ücretsiz planda (görev oluşturmak için ücretli bir plan gereklidir) veya yetersiz krediye sahip.
Name
403 - Forbidden
Description
Girdi görüntüsü fikri mülkiyet moderation tarafından işaretlendi.
Name
429 - Too Many Requests
Description
Hız sınırınızı aştınız.
Name
500 - Internal Server Error
Description
Beklenmedik bir sunucu tarafı hatası oluştu — örneğin içerik-moderation hizmeti kullanılamıyordu, girdi görüntüsünün sahnelenmesi başarısız oldu veya görev oluşturulamadı. Bu durumda hiçbir görev oluşturulmaz, bu yüzden yeniden denemek güvenlidir.
İstek
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>" }'
Başarılı bir prototip görevinden ve adaylarından birinden nihai dokulu 3D keycap modelini oluşturun. Tek bir yapı görevi, tüm hattı baştan sona çalıştırır — seçilen tasarımdan beyaz model üretimi, kalibre edilmiş varsayılan poz kullanılarak keycap tabanına otomatik oturtma ve kesme (etkileşimli ayarlama gerekmez), tam model renklendirme ve nihai montaj ve dışa aktarma. Bir yapı genellikle 3–7 dakika sürer, birkaç yapı aynı anda çalıştığında üst sınıra doğru yaklaşır. Yanıt şekli için Keycap Yapı Görevi Nesnesi bölümüne bakın.
Parametreler
Name
input_task_id
Type
string
Zorunlu
Description
Bu aynı OpenAPI uç noktası aracılığıyla oluşturulmuş bir prototip görevinin görev kimliği. Prototip aynı Meshy hesabı tarafından oluşturulmuş olmalı, SUCCEEDED durumuna ulaşmış olmalı ve en az bir aday üretmiş olmalıdır.
Web uygulaması aracılığıyla oluşturulan prototip görevler kabul edilmez — yapı uç noktası yalnızca POST /openapi/creative-lab/keycap/v1/prototype tarafından üretilen prototip görevleri kabul eder ve başka herhangi bir kaynağı 404 ile reddeder.
Name
candidate_id
Type
string
Zorunlu
Description
Başarılı prototip görevinin candidate_ids dizisinden alınan oluşturulacak aday. Bu göreve ait olmalı; başka herhangi bir değer 400 ile reddedilir.
Name
name
Type
string
Description
Görüntüleme amacıyla isteğe bağlı görev adı. Maksimum 100 karakter.
options
İsteğe bağlı geometri ayarlamaları. Her alanın kalibre edilmiş bir varsayılanı vardır — yalnızca üzerine yazmak istediğiniz alanları gönderin.
Name
base_model
Type
string
varsayılan cherry-mx-1x1-r1
Description
Üzerine inşa edilecek keycap tabanı. Şu anda mevcut olan tek değer cherry-mx-1x1-r1 — standart bir Cherry MX profil 1u keycap. 3–5 ek ana akım standart boyut planlanmaktadır; özel boyutlar desteklenmez.
Name
head_size_mm
Type
number
varsayılan 23
Description
Heykel başının hedef boyutu, milimetre cinsinden: en uzun boyutu bu değere ölçeklenir. Aralık: [10, 40]. Yaklaşık 32.9 üzerindeki değerler, başın tabanın koruyucu ayak izi sınırına hala sığması için azaltılabilir, bu nedenle teslim edilen en uzun boyut istenenden daha küçük olabilir. Uygulanan değer bugün görev nesnesinde geri yansıtılmaz — aslında aldığınız boyutu doğrulamanız gerekiyorsa, indirilen modeldeki keycap-head ağının sınırlayıcı kutusunu ölçün.
Name
vertical_offset_mm
Type
number
varsayılan 0
Description
Başın tabana oturtulmadan önce uygulanan dikey kaydırma, milimetre cinsinden. Aralık: [-5, 5].
Dönüşler
Yanıtın result özelliği, yeni oluşturulan keycap yapı görevinin görev id'sini içerir. Görev SUCCEEDED durumuna ulaşana kadar Bir Görev Al uç noktasını sorgulayın veya akışa abone olun, ardından model_urls.glb ve model_urls.obj_zip'den eserleri indirin.
Hem GLB hem de OBJ paketi gerçek dünya milimetre ölçeğinde dışa aktarılır, Y-yukarı koordinat sistemi ile ve keycap'in önü +Z'ye bakar.
Başarısızlık Modları
Name
400 - Bad Request
Description
İstek kabul edilemezdi. Yaygın nedenler:
Eksik parametre: input_task_id ve candidate_id gereklidir.
Geçersiz UUID: input_task_id geçerli bir UUID değil.
Ebeveyn başarılı değil: Referans verilen prototip görev henüz SUCCEEDED durumuna ulaşmadı.
Aday yok: Prototip görevi başarılı oldu ancak aday üretmedi.
Bilinmeyen aday: candidate_id, giriş görevinin adaylarından biri değil.
Seçenekler aralık dışında: options alanlarından biri izin verilen aralığın veya enum setinin dışına çıktı.
Name
401 - Unauthorized
Description
Kimlik doğrulama başarısız oldu. Lütfen API anahtarınızı kontrol edin.
Name
402 - Payment Required
Description
Hesap ücretsiz planda (görev oluşturmak için ücretli bir plan gereklidir) veya yetersiz krediye sahip.
Name
404 - Not Found
Description
Referans verilen prototip görevi mevcut değil, farklı bir kullanıcıya ait veya web uygulaması aracılığıyla oluşturulmuş (yalnızca API-modu prototip görevleri yapıya zincirlenir).
Name
429 - Too Many Requests
Description
Hız sınırınızı aştınız.
Name
500 - Internal Server Error
Description
Beklenmedik bir sunucu tarafı hatası oluştu — örneğin içerik-moderasyon hizmeti kullanılamıyordu, giriş resmi sahnelenemedi veya görev oluşturulamadı. Bu durumda hiçbir görev oluşturulmaz, bu nedenle yeniden denemek güvenlidir.
İstek
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 } }'
Geçerli bir görev idsi verilen bir prototip veya inşa görevini getirir. URL yolu
görevin aşamasıyla eşleşmelidir — /prototype/:id üzerinden getirilen bir inşa görevi
404 döndürür ve tersi de geçerlidir.
Bir keycap görevini iptal et. Görev hala PENDING durumundaysa, oluşturma sırasında tüketilen krediler iade edilir. Zaten IN_PROGRESS durumunda olan görevler, iade yapılmadan iptal edilir (çalışan kaynakları tüketiyor olabilir). Zaten bir son duruma ulaşmış olan görevler (SUCCEEDED, FAILED, CANCELED) iptal edilemez.
URL yolu, görevin aşamasıyla eşleşmelidir — /prototype/:buildId üzerinde DELETE404 döndürür.
Başarı durumunda boş bir gövde ile 204 No Content döner.
Hata Modları
Name
400 - Bad Request
Description
Görev zaten bir son durumda ve iptal edilemez.
Name
404 - Not Found
Description
Görev mevcut değil, farklı bir kullanıcıya ait veya aşaması URL yoluyla eşleşmiyor.
Name
500 - Internal Server Error
Description
İptal sırasında beklenmeyen bir sunucu tarafı hatası oluştu. Görev iptal edilmiş veya edilmemiş olabilir — yeniden denemeden önce doğrulamak için tekrar okuyun.
Bir keycap görevi için gerçek zamanlı güncellemeleri Server-Sent Events (SSE) aracılığıyla yayınlayın.
URL yolu, görevin aşamasıyla eşleşmelidir — /prototype/:buildId/stream adresinde bir akış açmak,
status_code: 404 ile tek bir event: error yükü yayar ve akışı kapatır.
Parametreler
Name
id
Type
path
Description
Yayınlanacak keycap görevi için benzersiz tanımlayıcı.
Dönen Değerler
Keycap Prototype veya Keycap Build görev nesnelerinin
Server-Sent Events olarak bir akışını döndürür. PENDING veya IN_PROGRESS görevler için, yanıt akışı yalnızca gerekli progress ve status alanlarını içerecektir.
Tek bir aşama için anahtar tuş görevlerinizin sayfalı bir listesini alın. URL
yolu aşamayı seçer — /prototype prototip görevlerini döndürür; /build
yapım görevlerini döndürür. Diğer aşamadan görevler her iki yanıtın da içinde yer almaz.
Yol Parametreleri
Name
stage
Type
path
Zorunlu
Description
Ya prototype ya da build. Koleksiyon yalnızca
aşaması URL ile eşleşen görevleri döndürür — /prototype çağrısı asla
yapım görevlerini döndürmez ve tersi de geçerlidir.
Sorgu Parametreleri
Name
page_num
Type
integer
varsayılan 1
Description
Sayfalama için sayfa numarası.
Name
page_size
Type
integer
varsayılan 10
Description
Sayfa boyutu sınırı. İzin verilen maksimum 100 öğedir.
Name
sort_by
Type
string
varsayılan -created_at
Description
Sıralanacak alan. Mevcut değerler:
+created_at: Oluşturulma zamanına göre artan sırada sıralayın.
-created_at: Oluşturulma zamanına göre azalan sırada sıralayın.
Keycap Prototip Görev nesnesi, Meshy'nin bir kaynak fotoğraftan bir bitmiş keycap tasarım görüntüsü oluşturmak için takip ettiği bir iş birimidir. Bu aşamanın çıktısı, input_task_id ve candidate_id aracılığıyla yapı aşamasına zincirlenir.
Özellikler
Name
id
Type
string
Description
Görev için benzersiz tanımlayıcı. Görev kimlikleri için k-sıralanabilir UUID kullanıyoruz, ancak kimliğin formatı hakkında herhangi bir varsayımda bulunmamalısınız.
Name
type
Type
string
Description
Görevin türü. Değer creative-lab-keycap-prototype'dir.
Name
name
Type
string
Description
Görev oluşturulurken sağlanan görev adı. Eğer bir ad sağlanmadıysa boş dize.
Name
status
Type
string
Description
Görevin durumu. Olası değerler PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED'dan biridir.
Name
progress
Type
integer
Description
Görevin ilerlemesi. Görev henüz başlamadıysa, bu özellik 0 olacaktır. Görev başarıyla tamamlandığında, bu 100 olur.
Name
created_at
Type
timestamp
Description
Görevin oluşturulduğu zaman damgası, milisaniye cinsinden.
Bir zaman damgası, 1 Ocak 1970 UTC'den itibaren geçen milisaniye sayısını temsil eder ve
RFC 3339 standardını takip eder.
Örneğin, Cuma, 1 Eylül 2023 12:00:00 PM GMT, 1693569600000 olarak temsil edilir. Bu, Meshy API'deki tüm zaman damgaları için geçerlidir.
Name
started_at
Type
timestamp
Description
Görevin başladığı zaman damgası, milisaniye cinsinden. Görev henüz başlamadıysa, bu özellik 0 olacaktır.
Name
finished_at
Type
timestamp
Description
Görevin tamamlandığı zaman damgası, milisaniye cinsinden. Görev henüz tamamlanmadıysa, bu özellik 0 olacaktır.
Name
expires_at
Type
timestamp
Description
Görev sonucunun sona erdiği zaman damgası, milisaniye cinsinden.
Name
preceding_tasks
Type
integer
Description
Önceki görevlerin sayısı.
Bu alanın değeri yalnızca görev durumu PENDING ise anlamlıdır.
Name
task_error
Type
object
Description
Başarısız görevler için hata detayları. Tam task_error nesne referansı için Hatalar bölümüne bakın.
Name
consumed_credits
Type
integer
Description
Bu görev tarafından tüketilen kredi sayısı. SUCCEEDED durumuna ulaşan bir görev, aşaması için tam miktarda ücretlendirilir. Hiç oluşturulmayan bir görev (istek zamanında bir 4xx, moderasyon reddi dahil) hiç ücretlendirilmez. FAILED durumuna ulaşan bir görev 0 döndürür — ücret iade edilir, asenkron moderasyon engeli dahil. DELETE ile iptal etmek yalnızca görev hala PENDING iken iade edilir; zaten IN_PROGRESS olan bir görev ücretli kalır, çünkü iş harcanmıştır.
Name
image_urls
Type
array of strings
Description
Bitmiş keycap tasarım renderının indirilebilir URL'si — adayın bitmiş bir keycap olarak nasıl göründüğünü gösterir. Tek bir giriş tutar; image_urls[i], candidate_ids[i] ile eşleşir. Görev SUCCEEDED durumuna ulaşana kadar boş. URL yalnızca görüntüleme içindir; yapı uç noktası candidate_ids tüketir, bu URL'leri değil. model_urls ile aynı URL yaşam döngüsü: imzalı, Authorization başlığı yok, expires_at kadar geçerli ve görev yeniden okunduğunda sabit.
Name
candidate_ids
Type
array of strings
Description
image_urls ile paralel opak aday tanımlayıcıları. Seçtiğiniz tasarıma karşılık gelen girişi yapı isteğinin candidate_id olarak geçirin. Bu kimliklerin formatı hakkında herhangi bir varsayımda bulunmayın.
Keycap Oluşturma Görev nesnesi, Meshy'nin başarılı bir prototip görevinden ve seçilen bir adaydan nihai dokulu 3D keycap'i oluşturmak için takip ettiği bir iş birimidir. Tek bir oluşturma, tam boru hattını çalıştırır — beyaz model oluşturma, otomatik oturma ve kesme, renklendirme, montaj ve dışa aktarma.
Özellikler
Name
id
Type
string
Description
Görev için benzersiz tanımlayıcı.
Name
type
Type
string
Description
Görevin türü. Değer creative-lab-keycap-build'dir.
Name
name
Type
string
Description
Görev oluşturulduğunda sağlanan görev adı. Ad sağlanmadıysa boş dize.
Name
status
Type
string
Description
Görevin durumu. Olası değerler PENDING, IN_PROGRESS, SUCCEEDED, FAILED, CANCELED'den biridir.
Name
progress
Type
integer
Description
Görevin ilerlemesi. Görev henüz başlamadıysa, bu özellik 0 olacaktır. Görev başarıyla tamamlandığında, bu 100 olur.
Name
created_at
Type
timestamp
Description
Görevin oluşturulduğu zaman damgası, milisaniye cinsinden.
Name
started_at
Type
timestamp
Description
Görevin başladığı zaman damgası, milisaniye cinsinden.
Name
finished_at
Type
timestamp
Description
Görevin tamamlandığı zaman damgası, milisaniye cinsinden.
Name
expires_at
Type
timestamp
Description
Görev sonucunun süresinin dolduğu zaman damgası, milisaniye cinsinden.
Name
preceding_tasks
Type
integer
Description
Önceki görevlerin sayısı. Yalnızca durum PENDING olduğunda anlamlıdır.
Name
task_error
Type
object
Description
Başarısız görevler için hata detayları. Tam task_error nesne referansı için Hatalar bölümüne bakın.
Name
consumed_credits
Type
integer
Description
Bu görev tarafından tüketilen kredi sayısı. SUCCEEDED durumuna ulaşan bir görev, aşaması için tam ücretlendirilir. Hiç oluşturulmayan bir görev (istek zamanında bir 4xx, bir moderasyon reddi dahil) hiç ücretlendirilmez. FAILED durumuna ulaşan bir görev 0 döndürür — ücret iade edilir, asenkron bir moderasyon engeli dahil. DELETE ile iptal etmek yalnızca görev hala PENDING iken iade edilir; zaten IN_PROGRESS olan bir görev ücretli kalır, çünkü iş harcanmıştır.
Name
model_urls
Type
object
Description
Oluşturulan model varlıkları için indirilebilir URL'ler. Hem GLB hem de OBJ paketi gerçek dünya milimetre ölçeğinde, Y-yukarı, keycap'in önü +Z'ye bakacak şekilde dışa aktarılır. Ağlar keycap-head ve keycap-base olarak adlandırılır; taban bir desen dolgusuna geri döndüğünde, sap boşluğu için üçüncü bir ağ keycap-base-interior da mevcuttur. Tam olarak iki ağ varsaymayın.
Bunlar imzalı URL'lerdir: bunları Authorization başlığı olmadan alın. expires_at'a kadar geçerlidirler, bu da finished_at'tan 3 gün sonradır ve bu süre içinde görevi yeniden okuduğunuzda aynı URL döner, yeni imzalanmış bir tane değil. Dosyaları o zamana kadar kendiniz indirin ve saklayın — süresi dolmuş bir bağlantıyı yenilemenin bir yolu yoktur.
Name
glb
Type
string
Description
Nihai dokulu model.glb için indirilebilir URL.
Name
obj_zip
Type
string
Description
model.obj, model.mtl ve MTL'nin gerçekten referans verdiği doku PNG'lerini içeren bir zip paketi için indirilebilir URL. Tek renkli bir taban yalnızca keycap-head.png gönderir; desenli bir taban ayrıca keycap-base.png gönderir.
Name
process_image_urls
Type
object
Description
Türüne göre anahtarlanmış, ara işlem görüntüleri için indirilebilir URL'ler. model_urls ile aynı URL yaşam döngüsü: imzalı, Authorization başlığı yok, expires_at'a kadar geçerli ve görev yeniden okunduğunda sabit. Şu anda yayımlanan türler:
head_design — oluşturmanın tükettiği seçilen adayın tasarım görüntüsü (her zaman mevcut).
composite — seçilen adayın bitmiş keycap görüntü renderı (mevcut olduğunda mevcut).
Tam akış: bir fotoğraftan prototip oluşturun, SUCCEEDED durumuna kadar sorgulayın, candidate_ids'den bir aday seçin, bu adayla bir yapı oluşturun, yapıyı SUCCEEDED durumuna kadar sorgulayın, ardından model_urls'den GLB ve OBJ paketini indirin.
Örnek, programatik olarak ilk adayı seçer. Gerçek bir entegrasyonda image_urls girişini son kullanıcıya gösterir ve onların seçmesine izin verirsiniz; seçilen indeks candidate_ids ile birebir eşleşir.
Tam akış
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"