Creative Lab — 鍵帽 API
將一張原始照片分兩個階段轉換為全彩客製化機械鍵盤鍵帽:prototype(原型) 階段會根據你輸入的照片產生
一張「成品鍵帽」設計效果圖。在確認該效果圖之後,build(構建) 階段會在一次執行中將其轉換為
帶貼圖的 3D 鍵帽模型——白模生成、在校準的預設姿態上自動就位與切割、全模型上色,
以及最終組裝,均在同一個構建任務內完成。這兩個階段透過 input_task_id
與 candidate_id 關聯在一起。
POST /openapi/creative-lab/keycap/v1/prototypePOST /openapi/creative-lab/keycap/v1/build
這兩個 POST endpoint 均需要付費 訂閱 方案。免費方案帳號發出的請求將被拒絕,
並回傳 402 Payment Required。
建立鍵帽原型任務
根據來源照片產生成品鍵帽設計渲染圖。任務結果會攜帶一個 image_urls 陣列(成品鍵帽的展示渲染圖)以及一個對應的 candidate_ids 陣列;兩者都只包含一個項目。如果結果不是你想要的,可以再次呼叫此 endpoint 來取得另一張渲染圖——每次呼叫都是單獨計費的。將 candidate_id 與原型任務 ID 一起傳給建置 endpoint。
有關回應結構,請參閱
鍵帽原型任務物件。
參數
- Name
- image_url
- Type
- string
- 必選
- Description
供 Meshy 轉換為鍵帽設計圖片的來源照片。我們目前支援
.jpg、.jpeg、.png和.webp格式。格式是透過解碼圖片資料來偵測的,而非根據 URL 的檔案副檔名——沒有副檔名的 URL,或會重新導向的 URL,只要位元組能解碼為支援的格式即可正常使用。系統會跟隨 HTTP 重新導向。EXIF 方向資訊會被正規化,因此旋轉過的手機照片會依其看起來的方向被使用。
限制條件:每邊至少
32像素,總像素數最多178,956,970,下載後大小最多20,000,000位元組。對於 data URI,該限制適用於解碼後的位元組數,因此來源檔案本身可以達到該大小上限——base64 文字大約會多出三分之一,這會影響你的請求體大小,但不影響此項限制。data URI 必須聲明image/*內容類型以及;base64。提供圖片的方式有兩種:
- 可公開存取的 URL:可從公開網際網路存取的 URL。
- Data URI:圖片的 base64 編碼 data URI。data URI 範例:
data:image/jpeg;base64,<your base64-encoded image data>。
- Name
- name
- Type
- string
- Description
用於顯示目的的選填任務名稱。最多 100 個字元。
- Name
- remove_background
- Type
- boolean
- 預設值 false
- Description
設為
true時,image_urls中回傳的展示渲染圖會是已移除背景的透明 RGBA PNG,因此你可以將其合成到任意背景上。此設定僅適用於展示渲染圖。建置 endpoint 所使用的候選項不受影響,因此無論如何設定,3D 結果都是相同的。
回傳值
回應的 result 屬性包含新建立的鍵帽原型任務的任務 id。輪詢取得任務 endpoint 或訂閱串流介面,直到任務達到 SUCCEEDED 狀態,然後取出 candidate_ids 中的項目,將其與任務 ID 一起傳給建置 endpoint。
失敗模式
- Name
400 - Bad Request- Description
請求無法被接受。常見原因:
- 缺少參數:
image_url為必填項目。 - 圖片格式無效:提供的
image_url不是支援的格式(.jpg、.jpeg、.png、.webp)。 - 圖片尺寸超出範圍:圖片過小、超過最大檔案大小,或超過最大像素數。
- URL 無法存取:無法下載
image_url(404 或 timeout)。 - Data URI 無效:base64 字串格式有誤。
- 內容被標記:輸入圖片被 NSFW moderation 標記。
- 缺少參數:
- Name
401 - Unauthorized- Description
身份驗證失敗。請檢查你的 API 金鑰。
- Name
402 - Payment Required- Description
該帳戶處於免費方案中(建立任務需要付費方案),或積分不足。
- Name
403 - Forbidden- Description
輸入圖片被智慧財產權 moderation 標記。
- Name
429 - Too Many Requests- Description
你已超出速率限制。
- Name
500 - Internal Server Error- Description
發生了非預期的伺服器端錯誤——例如內容審核服務無法使用、暫存輸入圖片失敗,或任務無法建立。在這種情況下不會建立任務,因此重試是安全的。
Request
# Stage 1: generate a finished-keycap design render
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype \
-X POST \
-H "Authorization: Bearer ${YOUR_API_KEY}" \
-H 'Content-Type: application/json' \
-d '{
"image_url": "<your publicly accessible image url or base64-encoded data URI>"
}'
Response
{
"result": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef"
}
創建鍵帽構建任務
從一個成功的原型任務及其某個候選方案生成最終的帶貼圖 3D 鍵帽模型。單個構建任務會端到端運行整個流程——根據所選設計生成白模、使用經過校準的預設姿態自動將其放置並裁切到鍵帽底座上(無需互動式調整)、全模型上色,以及最終裝配與匯出。構建通常需要 3–7 分鐘,在多個構建並發運行時會更接近上限。 回應結構請參閱鍵帽構建任務物件。
參數
- Name
- input_task_id
- Type
- string
- 必選
- Description
透過同一個 OpenAPI endpoint 創建的原型任務的任務 ID。該原型必須由同一個 Meshy 帳戶創建,必須已到達
SUCCEEDED狀態,並且必須至少產生一個候選方案。透過 webapp 創建的原型任務不被接受——構建 endpoint 僅接受由
POST /openapi/creative-lab/keycap/v1/prototype生成的原型任務,任何其他來源都會被拒絕並返回404。
- Name
- candidate_id
- Type
- string
- 必選
- Description
要構建的候選方案,取自成功的原型任務的
candidate_ids陣列。必須屬於該任務;任何其他值都會被拒絕並返回400。
- Name
- name
- Type
- string
- Description
可選的任務名稱,用於顯示目的。最多 100 個字元。
options
可選的 geometry 調整。每個欄位都有經過校準的預設值——只需傳送你想要覆寫的欄位。
- Name
- base_model
- Type
- string
- 預設值 cherry-mx-1x1-r1
- Description
用於構建的鍵帽底座。目前唯一可用的值是
cherry-mx-1x1-r1——一個標準 Cherry MX 輪廓的 1u 鍵帽。計劃支援 3–5 種其他主流標準尺寸;不支援自訂尺寸。
- Name
- head_size_mm
- Type
- number
- 預設值 23
- Description
雕刻頭部的目標尺寸,以毫米為單位:其最長維度會被縮放到該值。範圍:
[10, 40]。高於約32.9的值可能會被調低,以使頭部仍然符合底座的保護性佔位限制,因此最終交付的最長維度可能小於所請求的值。目前該應用後的值不會在任務物件中回顯——如果你需要確認實際獲得的尺寸,請在下載的模型中測量keycap-headmesh 的包圍盒。
- Name
- vertical_offset_mm
- Type
- number
- 預設值 0
- Description
在頭部安置到底座之前施加的垂直偏移量,以毫米為單位。範圍:
[-5, 5]。
返回值
回應的 result 屬性包含新創建的鍵帽構建任務的任務 id。輪詢取得任務 endpoint 或訂閱串流,直到任務到達 SUCCEEDED,然後從 model_urls.glb 和 model_urls.obj_zip 下載產物。
GLB 和 OBJ 壓縮包均以真實世界毫米比例匯出,採用 Y 軸向上的座標系,且鍵帽正面朝向 +Z。
失敗模式
- Name
400 - Bad Request- Description
請求不可接受。常見原因:
- 缺少參數:
input_task_id和candidate_id是必需的。 - 無效的 UUID:
input_task_id不是有效的 UUID。 - 父任務未成功:所引用的原型任務尚未到達
SUCCEEDED。 - 沒有候選方案:原型任務成功但未產生任何候選方案。
- 未知的候選方案:
candidate_id不是輸入任務的候選方案之一。 - 參數超出範圍:
options中的某個欄位超出了其允許的範圍或列舉集合。
- 缺少參數:
- Name
401 - Unauthorized- Description
身份驗證失敗。請檢查你的 API 金鑰。
- Name
402 - Payment Required- Description
該帳戶處於免費方案(創建任務需要付費方案)或積分不足。
- Name
404 - Not Found- Description
所引用的原型任務不存在、屬於其他使用者,或是透過 webapp 創建的(只有 API 模式的原型任務才能連結到構建)。
- Name
429 - Too Many Requests- Description
你已超出速率限制。
- Name
500 - Internal Server Error- Description
發生了意外的伺服器端錯誤——例如內容 moderation 服務不可用、暫存輸入圖片失敗,或無法創建任務。這種情況下不會創建任何任務,因此重試是安全的。
Request
# Stage 2: build the chosen candidate into a 3D keycap
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/build \
-X POST \
-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
}
}'
Response
{
"result": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af"
}
取得 Keycap 任務
根據有效的任務 id 取得原型(prototype)或構建(build)任務。URL 路徑必須與任務所處的階段相符——透過 /prototype/:id 取得構建任務會回傳 404,反之亦然。
有關回應結構,請參閱 Keycap 原型任務物件 和 Keycap 構建任務物件。
參數
- Name
- id
- Type
- path
- Description
要取得的 keycap 任務的唯一識別碼。
回傳
回應包含 keycap 任務物件。其結構取決於所請求的具體階段。
Request
# Prototype
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype/019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef \
-H "Authorization: Bearer ${YOUR_API_KEY}"
# Build
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/build/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af \
-H "Authorization: Bearer ${YOUR_API_KEY}"
Prototype Response
{
"id": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef",
"type": "creative-lab-keycap-prototype",
"name": "",
"status": "SUCCEEDED",
"progress": 100,
"created_at": 1753142456000,
"started_at": 1753142460000,
"finished_at": 1753142516000,
"expires_at": 1753401716000,
"preceding_tasks": 0,
"task_error": null,
"consumed_credits": 12,
"image_urls": [
"https://assets.meshy.ai/***/design-1.png?Expires=***"
],
"candidate_ids": [
"0198c1b2-33f5-7d21-a4b7-8e9d0c1f2a3b"
]
}
Build Response
{
"id": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af",
"type": "creative-lab-keycap-build",
"name": "",
"status": "SUCCEEDED",
"progress": 100,
"created_at": 1753142600000,
"started_at": 1753142610000,
"finished_at": 1753143050000,
"expires_at": 1753402250000,
"preceding_tasks": 0,
"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=***",
"composite": "https://assets.meshy.ai/***/composite.png?Expires=***",
"base_canvas": "https://assets.meshy.ai/***/base-canvas.png?Expires=***"
}
}
刪除 Keycap 任務
取消一個 keycap 任務。如果任務仍處於 PENDING 狀態,則會退還建立時消耗的
積分。已經處於 IN_PROGRESS 狀態的任務會被取消但不予退款(worker 可能已經在
消耗資源)。已經達到終態(SUCCEEDED、FAILED、CANCELED)的任務無法取消。
URL 路徑必須與任務所處的階段相符 —— 對 /prototype/:buildId 執行
DELETE 會回傳 404。
路徑參數
- Name
- id
- Type
- path
- Description
要取消的 keycap 任務的唯一識別碼。
回傳值
成功時回傳 204 No Content,回應內容為空。
失敗模式
- Name
400 - Bad Request- Description
該任務已處於終態,無法取消。
- Name
404 - Not Found- Description
該任務不存在、屬於其他使用者,或其所處階段與 URL 路徑不符。
- Name
500 - Internal Server Error- Description
取消過程中發生了意外的伺服器端錯誤。該任務可能已被取消,也可能未被取消 —— 請在重試前重新讀取以確認。
Request
curl --request DELETE \
--url https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype/019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef \
-H "Authorization: Bearer ${YOUR_API_KEY}"
Response
// Returns 204 No Content on success (empty body).
流式取得 Keycap 任務
透過 Server-Sent Events(SSE)流式取得 keycap 任務的即時更新。
URL 路徑必須與任務所處的階段相符 —— 在
/prototype/:buildId/stream 處開啟串流會發出一個帶有
status_code: 404 的 event: error payload,隨後關閉該串流。
參數
- Name
- id
- Type
- path
- Description
要進行流式傳輸的 keycap 任務的唯一識別碼。
回傳
以 Server-Sent Events 的形式回傳一個由
Keycap Prototype
或 Keycap Build 任務物件組成的串流。
對於 PENDING 或 IN_PROGRESS 狀態的任務,回應串流中將只包含必要的
progress 和 status 欄位。
Request
curl -N https://api.meshy.ai/openapi/creative-lab/keycap/v1/build/019c9a52-7d18-7e2b-9f01-6e3b98c4d2af/stream \
-H "Authorization: Bearer ${YOUR_API_KEY}"
Response Stream
// Error event example (wrong stage or task not found)
event: error
data: {
"status_code": 404,
"message": "Task not found"
}
// Message event examples illustrate task progress.
// For PENDING or IN_PROGRESS tasks, the response stream will not include all fields.
event: message
data: {
"id": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af",
"progress": 0,
"status": "PENDING"
}
event: message
data: {
"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=***"
}
}
List Keycap Tasks
取得單一階段中你的 keycap 任務的分頁列表。URL 路徑決定了階段——/prototype 回傳原型(prototype)任務;/build
回傳建置(build)任務。另一個階段的任務不會包含在任一種回應中。
路徑參數
- Name
- stage
- Type
- path
- 必選
- Description
prototype或build。此集合只會回傳階段與 URL 相符的任務——請求/prototype永遠不會回傳 build 任務,反之亦然。
查詢參數
- Name
- page_num
- Type
- integer
- 預設值 1
- Description
用於分頁的頁碼。
- Name
- page_size
- Type
- integer
- 預設值 10
- Description
每頁數量上限。最大允許值為
100項。
- Name
- sort_by
- Type
- string
- 預設值 -created_at
- Description
用於排序的欄位。可用值:
+created_at:依建立時間升冪排序。-created_at:依建立時間降冪排序。
回傳值
回傳依階段劃分的任務物件分頁列表——列出 /prototype 時回傳
keycap 原型任務物件,
列出 /build 時回傳
keycap 建置任務物件。
Request
# List prototype tasks
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype?page_size=10 \
-H "Authorization: Bearer ${YOUR_API_KEY}"
# List build tasks
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/build?page_size=10 \
-H "Authorization: Bearer ${YOUR_API_KEY}"
Response (List Prototype Tasks)
[
{
"id": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef",
"type": "creative-lab-keycap-prototype",
"name": "",
"status": "SUCCEEDED",
"progress": 100,
"created_at": 1753142456000,
"started_at": 1753142460000,
"finished_at": 1753142516000,
"expires_at": 1753401716000,
"preceding_tasks": 0,
"task_error": null,
"consumed_credits": 12,
"image_urls": [
"https://assets.meshy.ai/***/design-1.png?Expires=***"
],
"candidate_ids": [
"0198c1b2-33f5-7d21-a4b7-8e9d0c1f2a3b"
]
}
]
鍵帽原型任務物件
鍵帽原型任務(Keycap Prototype Task)物件是 Meshy 用於追蹤的一個工作單元,用於根據來源照片生成一張成品鍵帽設計圖。該階段的輸出會透過 input_task_id 和 candidate_id 串聯到建構階段。
屬性
- Name
- id
- Type
- string
- Description
任務的唯一識別碼。雖然我們在實作細節上使用 k-可排序的 UUID 作為任務 id,但你不應對 id 的格式做任何假設。
- Name
- type
- Type
- string
- Description
任務的類型。此值為
creative-lab-keycap-prototype。
- Name
- name
- Type
- string
- Description
建立任務時提供的任務名稱。如果未提供名稱,則為空字串。
- Name
- status
- Type
- string
- Description
任務的狀態。可能的取值為
PENDING、IN_PROGRESS、SUCCEEDED、FAILED、CANCELED之一。
- Name
- progress
- Type
- integer
- Description
任務的 progress。如果任務尚未開始,此屬性為
0。任務成功後,此值將變為100。
- Name
- created_at
- Type
- timestamp
- Description
任務建立時的時間戳,單位為毫秒。
時間戳表示自 1970 年 1 月 1 日 UTC 起經過的毫秒數,遵循 RFC 3339
標準。 例如,格林威治標準時間 2023 年 9 月 1 日星期五中午 12:00:00 表示為1693569600000。這適用於 Meshy API 中的所有時間戳。
- Name
- started_at
- Type
- timestamp
- Description
任務開始時的時間戳,單位為毫秒。如果任務尚未開始,此屬性為
0。
- Name
- finished_at
- Type
- timestamp
- Description
任務完成時的時間戳,單位為毫秒。如果任務尚未完成,此屬性為
0。
- Name
- expires_at
- Type
- timestamp
- Description
任務結果過期時的時間戳,單位為毫秒。
- Name
- preceding_tasks
- Type
- integer
- Description
前置任務的數量。
此欄位的值僅在任務狀態為
PENDING時才有意義。
- Name
- task_error
- Type
- object
- Description
失敗任務的錯誤詳情。完整的
task_error物件參考請參見 錯誤。
- Name
- consumed_credits
- Type
- integer
- Description
此任務消耗的積分數量。達到
SUCCEEDED狀態的任務將按該階段的全額收費。從未成功建立的任務(請求時出現4xx,包括 moderation 拒絕)完全不收費。達到FAILED狀態的任務回傳0——費用將被退還,包括非同步 moderation 攔截的情況。透過DELETE取消任務僅在任務仍為PENDING狀態時退款;已處於IN_PROGRESS狀態的任務仍會被收費,因為相應的算力已經消耗。
- Name
- image_urls
- Type
- array of strings
- Description
成品鍵帽設計渲染圖的可下載 URL——即該候選項作為成品鍵帽的效果圖。僅包含一個項目;
image_urls[i]對應於candidate_ids[i]。在任務達到SUCCEEDED之前為空。該 URL 僅用於展示;建構端點使用的是candidate_ids,而非這些 URL。其 URL 生命週期與model_urls相同:經過簽署、無需Authorization請求標頭、在expires_at之前有效,且在重新讀取任務時保持不變。
- Name
- candidate_ids
- Type
- array of strings
- Description
不透明的候選項識別碼,與
image_urls一一對應。請將與你所選設計相符的項目作為建構請求的candidate_id傳入。請勿對這些 id 的格式做任何假設。
Example Keycap Prototype Task Object
{
"id": "019c9a4e-2b31-7f6a-8c44-5d2a87b3c1ef",
"type": "creative-lab-keycap-prototype",
"name": "",
"status": "SUCCEEDED",
"progress": 100,
"created_at": 1753142456000,
"started_at": 1753142460000,
"finished_at": 1753142516000,
"expires_at": 1753401716000,
"preceding_tasks": 0,
"task_error": null,
"consumed_credits": 12,
"image_urls": [
"https://assets.meshy.ai/***/design-1.png?Expires=***"
],
"candidate_ids": [
"0198c1b2-33f5-7d21-a4b7-8e9d0c1f2a3b"
]
}
鍵帽構建任務物件
鍵帽構建任務物件是 Meshy 用於追蹤的一個工作單元,用來根據成功的原型任務和選定的候選方案生成最終的帶 texture 3D 鍵帽。單次構建會執行完整的流水線——白模生成、自動落座與切割、上色、裝配以及匯出。
屬性
- Name
- id
- Type
- string
- Description
任務的唯一識別碼。
- Name
- type
- Type
- string
- Description
任務的類型。其值為
creative-lab-keycap-build。
- Name
- name
- Type
- string
- Description
建立任務時提供的任務名稱。如果未提供名稱,則為空字串。
- Name
- status
- Type
- string
- Description
任務的狀態。可能的值為
PENDING、IN_PROGRESS、SUCCEEDED、FAILED、CANCELED之一。
- Name
- progress
- Type
- integer
- Description
任務的進度。如果任務尚未開始,此屬性將為
0。一旦任務成功,此值將變為100。
- Name
- created_at
- Type
- timestamp
- Description
任務建立時的時間戳,單位為毫秒。
- Name
- started_at
- Type
- timestamp
- Description
任務開始時的時間戳,單位為毫秒。
- Name
- finished_at
- Type
- timestamp
- Description
任務完成時的時間戳,單位為毫秒。
- Name
- expires_at
- Type
- timestamp
- Description
任務結果過期時的時間戳,單位為毫秒。
- Name
- preceding_tasks
- Type
- integer
- Description
排在前面的任務數量。僅當狀態為
PENDING時才有意義。
- Name
- task_error
- Type
- object
- Description
失敗任務的錯誤詳情。完整的
task_error物件參考請參見 Errors。
- Name
- consumed_credits
- Type
- integer
- Description
此任務消耗的積分數量。達到
SUCCEEDED狀態的任務將按其階段收取全額費用。從未成功建立的任務(請求時回傳4xx,包括 moderation 拒絕)完全不收費。達到FAILED狀態的任務回傳0——費用會被退還,包括非同步 moderation 攔截的情況。透過DELETE取消任務僅在任務仍處於PENDING狀態時才會退款;已處於IN_PROGRESS狀態的任務仍會被收費,因為相關工作已經耗費。
- Name
- model_urls
- Type
- object
- Description
生成的模型檔案的可下載 URL。GLB 和 OBJ 壓縮檔均以真實世界的毫米級比例、Y 軸朝上匯出,鍵帽正面朝向 +Z 方向。mesh 分別命名為
keycap-head和keycap-base;當底座回退為圖案填充時,還會存在第三個 meshkeycap-base-interior,用於表示卡柱空腔。請勿假定一定只有兩個 mesh。這些是簽名 URL:取得時無需攜帶
Authorization請求標頭。它們在expires_at(即finished_at之後 3 天)之前一直有效,在此期間重新讀取任務將回傳相同的 URL,而不是重新簽名的 URL。請在此之前自行下載並儲存這些檔案——過期的連結無法刷新。- Name
glb- Type
- string
- Description
最終帶 texture 的
model.glb的可下載 URL。
- Name
obj_zip- Type
- string
- Description
指向包含
model.obj、model.mtl以及其 MTL 實際引用的 texture PNG 檔案的壓縮檔的可下載 URL。純色底座只提供keycap-head.png;帶圖案的底座還會提供keycap-base.png。
- Name
- process_image_urls
- Type
- object
- Description
按種類分類的中間過程圖像的可下載 URL。與
model_urls具有相同的 URL 生命週期:已簽名、無需Authorization請求標頭、在expires_at之前有效,並且在重新讀取任務時保持不變。目前會輸出以下種類:head_design— 構建所使用的所選候選方案的設計圖(始終存在)。composite— 所選候選方案的成品鍵帽展示渲染圖(在可用時存在)。base_canvas— 繪製完成的鍵帽底座畫布(在可用時存在)。
請將該鍵集合視為開放式的;未來可能會新增種類,且不會構成破壞性變更。
Example Keycap Build Task Object
{
"id": "019c9a52-7d18-7e2b-9f01-6e3b98c4d2af",
"type": "creative-lab-keycap-build",
"name": "",
"status": "SUCCEEDED",
"progress": 100,
"created_at": 1753142600000,
"started_at": 1753142610000,
"finished_at": 1753143050000,
"expires_at": 1753402250000,
"preceding_tasks": 0,
"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=***",
"composite": "https://assets.meshy.ai/***/composite.png?Expires=***",
"base_canvas": "https://assets.meshy.ai/***/base-canvas.png?Expires=***"
}
}
端到端範例
完整流程:從一張照片建立原型,輪詢直到狀態變為
SUCCEEDED,從 candidate_ids 中選擇一個候選項,使用該候選項建立建置任務,
輪詢建置任務直到狀態變為 SUCCEEDED,然後從 model_urls 下載 GLB
和 OBJ 壓縮檔。
此範例以程式化方式選擇了第一個候選項。在實際整合中,你應當將 image_urls
中的項目展示給最終使用者,讓他們進行選擇;所選的索引與 candidate_ids 一一對應。
Complete flow
#!/usr/bin/env bash
set -euo pipefail
# 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:-}" ]]; then
echo "export IMAGE_PATH (local file) or IMAGE_URL (public url) first" >&2
exit 1
fi
BASE="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 body
shift 2
out=$(curl --silent --show-error --max-time 60 --write-out $'\n%{http_code}' \
-X "$method" "$url" -H "$AUTH" "$@") || return 1
http_code=${out##*$'\n'}
body=${out%$'\n'*}
if ((http_code >= 400)); then
echo "HTTP $http_code for $url: $body" >&2
return 1
fi
printf '%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 :; do
if (($(date +%s) >= deadline)); then
echo "gave up waiting for $kind $id" >&2
return 1
fi
task_status=$(api GET "$BASE/$kind/$id" | jq -r '.status')
echo "$kind: $task_status"
case "$task_status" in
SUCCEEDED) return 0 ;;
FAILED | CANCELED) return 1 ;;
esac
sleep "$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"' EXIT
if [[ -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')" in
png) 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"
else
printf '{"image_url":"%s"}' "$IMAGE_URL" >"$BODY"
fi
# 1. Create the prototype task
PROTO_ID=$(api POST "$BASE/prototype" \
-H 'Content-Type: application/json' --data-binary @"$BODY" | jq -r '.result')
# 2. Wait for the design render
poll prototype "$PROTO_ID"
# 3. Pick a candidate (first one here; show image_urls to a user in production)
CANDIDATE_ID=$(api GET "$BASE/prototype/$PROTO_ID" | jq -r '.candidate_ids[0]')
# 4. Create the build task
jq -n --arg p "$PROTO_ID" --arg c "$CANDIDATE_ID" \
'{input_task_id: $p, candidate_id: $c}' >"$BODY"
BUILD_ID=$(api POST "$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)
poll build "$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=$(api GET "$BASE/build/$BUILD_ID")
curl --silent --show-error --fail --max-time 900 \
-o keycap.glb "$(jq -r '.model_urls.glb' <<<"$TASK")"
curl --silent --show-error --fail --max-time 900 \
-o keycap-obj.zip "$(jq -r '.model_urls.obj_zip' <<<"$TASK")"
echo "Done: keycap.glb + keycap-obj.zip"