創意工坊 — 鍵帽 API
把你的照片變成全彩客製機械鍵盤鍵帽。整個流程分兩段:prototype 用源照片
生成 1 張「成品鍵帽」設計效果圖,確認後 build 一條龍生成帶貼圖的
3D 鍵帽模型 —— 白模生成、按校準好的預設姿態自動落座與切割、整體上色、組裝導出
全部在一個 build 任務內完成。兩段通過 input_task_id 加 candidate_id
串聯。
POST /openapi/creative-lab/keycap/v1/prototypePOST /openapi/creative-lab/keycap/v1/build
兩個 POST 端點均要求付費訂閱方案。免費方案帳號的請求會被拒絕並返回
402 Payment Required。
建立鍵帽 Prototype 任務
從源照片生成 1 張成品鍵帽設計效果圖。任務結果攜帶 image_urls
陣列(成品鍵帽的展示渲染圖)以及與之平行的 candidate_ids 陣列,各含 1 項。
若效果不滿意,可再次呼叫本介面重新生成(每次呼叫單獨計費)。把圖片展示
給用戶挑選後,將對應的 candidate_id 與 prototype 任務 ID 一起傳給
build 端點。響應結構詳見
Prototype 任務物件。
參數
- Name
- image_url
- Type
- string
- 必選
- Description
提供給 Meshy 用於生成鍵帽設計圖的源照片。目前支援
.jpg、.jpeg、.png、.webp格式。格式由解碼圖片資料判定,不看 URL 的檔案副檔名 —— 沒有副檔名、或會發生轉址的 URL 都可以,只要位元組能解碼成受支援的格式。HTTP 轉址會被跟隨。EXIF 方向會被正規化,所以手機拍的旋轉照片會按看起來的方向使用。
限制:每邊至少
32像素、總像素不超過178,956,970、下載後不超過20,000,000位元組。data URI 的上限按 base64 解碼後的位元組計算,所以源檔案本身可以達到該上限 —— 變大約三分之一的是 base64 文字,那影響的是請求體大小,不是這個上限。data URI 必須宣告image/*內容類型與;base64。可通過兩種方式提供圖片:
- 公網可存取 URL:可從公開網路存取的 URL。
- Data URI:圖片的 base64 編碼 data URI,範例:
data:image/jpeg;base64,<your base64-encoded image data>。
- Name
- name
- Type
- string
- Description
選填的任務名稱,僅用於顯示。最長 100 個字元。
返回值
響應的 result 欄位返回新建立的鍵帽 prototype 任務的 id。輪詢
查詢任務 或訂閱 流式更新
直到任務狀態變為 SUCCEEDED,再從 candidate_ids 中選定一個候選,
連同任務 ID 一起傳給 build 端點。
失敗情形
- Name
400 - Bad Request- Description
請求不可接受。常見原因:
- 缺少參數:
image_url為必填。 - 圖片格式不支援:
image_url不是受支援的格式(.jpg、.jpeg、.png、.webp)。 - 圖片尺寸超限:圖片過小、超出最大檔案體積或超出最大像素數。
- URL 無法存取:
image_url下載失敗(404 或逾時)。 - Data URI 無效:base64 字串格式錯誤。
- 內容被標記:輸入圖片被 NSFW 審核標記。
- 缺少參數:
- Name
401 - Unauthorized- Description
鑑權失敗。請檢查你的 API key。
- Name
402 - Payment Required- Description
帳號處於免費方案(建立任務需要付費方案),或積分不足。
- Name
403 - Forbidden- Description
輸入圖片被智慧財產權審核標記。
- Name
429 - Too Many Requests- Description
超出速率限制。
- Name
500 - Internal Server Error- Description
伺服器端發生未預期的錯誤,例如內容審核服務不可用、輸入圖片暫存失敗,或任務建立失敗。此時不會建立任務,可安全重試。
Request
# 第一段:生成 1 張成品鍵帽設計效果圖
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"
}
建立鍵帽 Build 任務
從一個已成功的 prototype 任務及其選定候選生成最終的帶貼圖 3D 鍵帽模型。 單個 build 任務一條龍跑完整條流水線 —— 用選定設計圖生成白模、按校準好的 預設姿態自動落座並切割到鍵帽底座(無需互動調整)、整體上色、最終組裝導出。 一次 build 通常需要 3–7 分鐘,多個 build 並發時接近上限。響應結構詳見 Build 任務物件。
參數
- Name
- input_task_id
- Type
- string
- 必選
- Description
通過本 OpenAPI 端點建立的 prototype 任務 ID。該 prototype 必須由同一個 Meshy 帳號建立、已達到
SUCCEEDED狀態,且至少產出一個候選。通過網頁版建立的 prototype 任務不被接受 —— build 端點只接受由
POST /openapi/creative-lab/keycap/v1/prototype產出的 prototype 任務,其他來源一律返回404。
- Name
- candidate_id
- Type
- string
- 必選
- Description
要構建的候選,取自已成功 prototype 任務的
candidate_ids陣列。必須是該任務的候選之一,否則返回400。
- Name
- name
- Type
- string
- Description
選填的任務名稱,僅用於顯示。最長 100 個字元。
options
選填的幾何調節參數。每個欄位都有校準好的預設值 —— 只發送需要覆蓋的欄位即可。
- 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-head網格的邊界框。
- Name
- vertical_offset_mm
- Type
- number
- 預設值 0
- Description
頭部落座到底座前施加的垂直偏移,單位毫米。範圍:
[-5, 5]。
返回值
響應的 result 欄位返回新建立的鍵帽 build 任務的 id。輪詢
查詢任務 或訂閱 流式更新
直到任務狀態變為 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。 - 父任務未成功:引用的 prototype 任務尚未達到
SUCCEEDED。 - 沒有候選:prototype 任務雖成功但未產出候選。
- 候選不存在:
candidate_id不是該 prototype 任務的候選之一。 - 參數超出範圍:
options中某欄位超出允許範圍或列舉集合。
- 缺少參數:
- Name
401 - Unauthorized- Description
鑑權失敗。請檢查你的 API key。
- Name
402 - Payment Required- Description
帳號處於免費方案(建立任務需要付費方案),或積分不足。
- Name
404 - Not Found- Description
引用的 prototype 任務不存在、屬於其他用戶,或由網頁版建立(只有 API 模式的 prototype 任務才能串聯 build)。
- Name
429 - Too Many Requests- Description
超出速率限制。
- Name
500 - Internal Server Error- Description
伺服器端發生未預期的錯誤,例如內容審核服務不可用、輸入圖片暫存失敗,或任務建立失敗。此時不會建立任務,可安全重試。
Request
# 第二段:把選定候選構建成 3D 鍵帽
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"
}
查詢鍵帽任務
通過有效的任務 id 查詢 prototype 或 build 任務。URL 路徑必須與任務所屬
階段匹配 —— 通過 /prototype/:id 查詢 build 任務會返回 404,反之亦然。
響應結構詳見 Prototype 任務物件 與 Build 任務物件。
參數
- Name
- id
- Type
- path
- Description
要查詢的鍵帽任務的唯一識別碼。
返回值
響應包含鍵帽任務物件,具體結構取決於所查詢的階段。
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=***"
}
}
刪除鍵帽任務
取消一個鍵帽任務。若任務仍處於 PENDING,建立時消耗的積分將退還;已進入
IN_PROGRESS 的任務會被取消但不退積分(worker 可能已經在消耗資源);已到達
終態(SUCCEEDED、FAILED、CANCELED)的任務無法取消。
URL 路徑必須與任務所屬階段匹配 —— 對 /prototype/:buildId 執行 DELETE
會返回 404。
路徑參數
- Name
- id
- Type
- path
- Description
要取消的鍵帽任務的唯一識別碼。
返回值
成功時返回 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
// 成功時返回 204 No Content(空響應體)。
流式訂閱鍵帽任務
通過 Server-Sent Events(SSE)即時訂閱鍵帽任務的狀態更新。URL 路徑必須與
任務所屬階段匹配 —— 在 /prototype/:buildId/stream 上開啟流會發出一條
event: error(status_code: 404)後關閉。
參數
- Name
- id
- Type
- path
- Description
要訂閱的鍵帽任務的唯一識別碼。
返回值
以 Server-Sent Events 形式返回
Prototype 任務物件 或
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: error
data: {
"status_code": 404,
"message": "Task not found"
}
// message 事件範例(任務進度)。
// 對 PENDING 或 IN_PROGRESS 的任務,流中不會包含全部欄位。
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=***"
}
}
列出鍵帽任務
分頁列出你在單一階段下的鍵帽任務。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 時為
Prototype 任務物件,列出 /build
時為 Build 任務物件。
Request
# 列出 prototype 任務
curl https://api.meshy.ai/openapi/creative-lab/keycap/v1/prototype?page_size=10 \
-H "Authorization: Bearer ${YOUR_API_KEY}"
# 列出 build 任務
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"
]
}
]
Prototype 任務物件
鍵帽 Prototype 任務物件是 Meshy 追蹤的一個工作單元,用於從源照片生成 1 張
成品鍵帽設計效果圖。此階段的產出通過 input_task_id 加 candidate_id
串聯進 build 階段。
屬性
- Name
- id
- Type
- string
- Description
任務的唯一識別碼。實作細節上我們使用 k-sortable 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
任務進度。任務尚未開始時為
0;任務成功後為100。
- Name
- created_at
- Type
- timestamp
- Description
任務建立時間的時間戳,單位毫秒。
時間戳表示自 1970 年 1 月 1 日 UTC 以來經過的毫秒數,遵循 RFC 3339
標準。 例如 2023 年 9 月 1 日星期五 12:00:00 PM GMT 表示為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物件參考見 Errors。
- Name
- consumed_credits
- Type
- integer
- Description
此任務消耗的積分數。進入
SUCCEEDED的任務按該階段全額計費。從未被建立的任務(請求時即回傳4xx,包括內容審核拒絕)完全不計費。進入FAILED的任務回傳0—— 費用會退還,非同步的內容審核攔截也一樣。透過DELETE取消僅在任務仍為PENDING時退款;已進入IN_PROGRESS的任務不退款,因為算力已經花掉了。
- Name
- image_urls
- Type
- array of strings
- Description
成品鍵帽設計效果圖的下載 URL —— 展示該候選做成成品鍵帽後的效果。陣列僅含 1 項,
image_urls[i]對應candidate_ids[i]。任務達到SUCCEEDED前為空陣列。該 URL 僅用於展示;build 端點消費的是candidate_ids,而不是這些 URL。URL 生命週期與model_urls相同:簽名連結、不需要Authorization標頭、有效至expires_at,重複讀取任務時保持不變。
- Name
- candidate_ids
- Type
- array of strings
- Description
與
image_urls平行的不透明候選識別碼。把你選中設計對應的條目作為 build 請求的candidate_id傳入。不要對這些 id 的格式做任何假設。
Prototype 任務物件範例
{
"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 任務物件
鍵帽 Build 任務物件是 Meshy 追蹤的一個工作單元,用於從已成功的 prototype 任務及選定候選生成最終的帶貼圖 3D 鍵帽。單個 build 一條龍跑完整條流水線 —— 白模生成、自動落座切割、上色、組裝、導出。
屬性
- 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,包括內容審核拒絕)完全不計費。進入FAILED的任務回傳0—— 費用會退還,非同步的內容審核攔截也一樣。透過DELETE取消僅在任務仍為PENDING時退款;已進入IN_PROGRESS的任務不退款,因為算力已經花掉了。
- Name
- model_urls
- Type
- object
- Description
生成模型產物的下載 URL。GLB 與 OBJ 產物均按真實毫米尺度導出,座標系為 Y 軸向上,鍵帽正面朝向 +Z。網格命名為
keycap-head與keycap-base;當底座回退為圖案填充時,還會多出第三個網格keycap-base-interior(軸孔內壁)。請勿假設固定為兩個網格。這些是簽名連結:請求時不要帶
Authorization標頭。它們在expires_at之前有效,也就是finished_at之後 3 天;在這個窗口內重複讀取任務會拿到完全相同的連結,而不是重新簽名的新連結。請在此之前自行下載並保存檔案 —— 過期的連結無法刷新。- Name
glb- Type
- string
- Description
最終帶貼圖
model.glb的下載 URL。
- Name
obj_zip- Type
- string
- Description
zip 包的下載 URL,內含
model.obj、model.mtl,以及 MTL 實際引用的貼圖 PNG。純色底座僅含keycap-head.png;帶圖案的底座還會包含keycap-base.png。
- Name
- process_image_urls
- Type
- object
- Description
過程圖的下載 URL,按 kind 作為鍵。URL 生命週期與
model_urls相同:簽名連結、不需要Authorization標頭、有效至expires_at,重複讀取任務時保持不變。目前會出現的 kind:head_design—— build 實際消費的選定候選設計圖(始終存在)。composite—— 選定候選的成品鍵帽展示渲染圖(存在時返回)。base_canvas—— 上色後的鍵帽底座畫布(存在時返回)。
請把鍵集合視為開放集合;後續可能在不破壞相容的前提下新增 kind。
Build 任務物件範例
{
"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=***"
}
}
端到端完整範例
完整流程:用照片建立 prototype,輪詢到 SUCCEEDED,從 candidate_ids
中選定一個候選,用它建立 build,輪詢 build 到 SUCCEEDED,最後從
model_urls 下載 GLB 與 OBJ 包。
範例中程式化地選擇了第一個候選。實際接入時應把 image_urls 裡的那一項
展示給最終用戶挑選;選中的索引與 candidate_ids 一一對應。
Complete flow
#!/usr/bin/env bash
set -euo pipefail
# 需要 curl 與 jq。把 IMAGE_PATH 指向本機照片,或把 IMAGE_URL 指向公網圖片:
# 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 參數...] -> 印出回應體,失敗時回傳非 0。
# 注意這裡不用 -f/--fail:它會把回應體丟掉,而原因只出現在回應體裡。
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"
}
# 每個任務各有自己的 40 分鐘預算。
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
}
# 把請求體寫進檔案。base64 data URI 絕對不能出現在命令列或匯出的環境變數裡 ——
# 任何真實尺寸的照片都會超過作業系統的參數長度上限。
BODY=$(mktemp)
trap 'rm -f "$BODY"' EXIT
if [[ -n "${IMAGE_PATH:-}" ]]; then
# 宣告真實型別:介面支援 JPEG、PNG、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. 建立 prototype 任務
PROTO_ID=$(api POST "$BASE/prototype" \
-H 'Content-Type: application/json' --data-binary @"$BODY" | jq -r '.result')
# 2. 等待設計效果圖
poll prototype "$PROTO_ID"
# 3. 選一個候選(這裡取第一個;生產環境應把 image_urls 展示給使用者選)
CANDIDATE_ID=$(api GET "$BASE/prototype/$PROTO_ID" | jq -r '.candidate_ids[0]')
# 4. 建立 build 任務
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. 等待模型(build 通常需要 3-7 分鐘)
poll build "$BUILD_ID"
# 6. 下載產物。這些是簽名連結:不需要 Authorization 標頭,
# 任務完成後 3 天內有效。
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"