Creative Lab 鍵帽 API
透過兩個階段,將一張照片變成機械鍵盤的全彩客製化鍵帽。原型任務根據照片產生成品鍵帽的圖像。構建任務會將該圖像轉換為帶紋理的 3D 鍵帽模型。它會將原型任務的 ID 作為 input_task_id,並將圖像的候選 ID 作為 candidate_id。
POST /openapi/creative-lab/keycap/v1/prototypePOST /openapi/creative-lab/keycap/v1/build
兩個 POST 端點都需要付費方案。免費方案帳戶發出的請求將返回 402。
建立 Keycap prototype 任務
根據一張照片生成一張成品鍵帽的圖像。任務的 image_urls 中儲存該圖像,candidate_ids 中儲存其 ID,二者各有一筆記錄。如果你不喜歡這個設計,可以再建立一個 prototype 任務。Meshy 會對每個 prototype 任務單獨收費。
要建構 3D 鍵帽,請將此任務的 ID 作為 input_task_id 傳給 build endpoint,並將 candidate_ids 中的那筆記錄作為 candidate_id 傳入。有關該任務各欄位的說明,請參閱Keycap prototype 任務物件。
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"
}
參數
- Name
- image_url
- Type
- string
- 必選
- Description
要轉換為鍵帽設計的照片,可以是公開可存取的 URL,或是一個 data URI(
data:image/jpeg;base64,<your base64-encoded image data>)。圖片必須是 JPG、JPEG、PNG 或 WebP 檔案,且不超過 20 MB(20,000,000 位元組)。每條邊至少為 32 像素,圖片總像素數最多為 178,956,970。超出這些限制的圖片會回傳
400。Meshy 會根據圖像資料來偵測格式,而非依據 URL 中的副檔名。沒有副檔名的 URL 也可以正常運作,且 Meshy 會跟隨 HTTP 重新導向。Meshy 會套用 EXIF 方向資訊,因此旋轉過的手機照片會依照其實際顯示的方向呈現。
data URI 必須使用 base64 編碼,並帶有圖像類型,例如
data:image/png;base64,...,且解碼後的圖像必須是 JPEG、PNG 或 WebP 格式。20 MB 的限制適用於解碼後的圖像,因此 base64 文字本身可能會大約再大三分之一。
- Name
- name
- Type
- string
- Description
任務的名稱,最多 100 個字元。該名稱會在任務的
name欄位中回傳。超出長度限制會回傳400。
- Name
- remove_background
- Type
- boolean
- 預設值 false
- Description
是否從 prototype 圖像中移除背景。設為
true會回傳一張透明的 RGBA PNG,這樣你就可以將鍵帽放置在任意背景之上。如果 Meshy 無法移除背景,它會回傳帶有原背景的圖像,任務仍然會成功。無論如何,build 階段用於生成 3D 效果的頭部設計都會保留其背景。build 階段會根據
image_urls中的圖像來繪製鍵帽底座,如果你傳送了true,則不帶其背景。build 階段會將該圖像以process_image_urls.composite的形式回傳。
回傳值
result 欄位儲存新建立的 prototype 任務的 ID。取得該任務或對其進行串流取得,直到 status 變為 SUCCEEDED。然後將該 ID 作為 input_task_id 傳給 build endpoint,並將 candidate_ids 中的那筆記錄作為 candidate_id 傳入。
失敗情形
- Name
400 - Bad Request- Description
請求無法執行。例如:
- 缺少
image_url。 - 圖像不是 JPG、JPEG、PNG 或 WebP 檔案。
- 圖像過小、超過 20 MB,或超過最大像素數限制。
- Meshy 無法下載該圖像,例如因為該 URL 回傳
404或逾時。 - data URI 不是有效的 base64 編碼。
- 該圖像被標記為 NSFW(不適宜內容)。
錯誤訊息會說明具體發現的問題。修正請求後再重新傳送。
- 缺少
- Name
401 - Unauthorized- Description
API 金鑰缺失或無效。請檢查
Authorization請求標頭。
- Name
402 - Payment Required- Description
以下情況之一適用:
- 帳戶的積分不足。
- 該 API 金鑰、工作區或成員已達到其積分上限。
- 該帳戶處於免費方案。
請檢查你的積分和方案,然後重試。
- Name
403 - Forbidden- Description
你的團隊已開啟IP 過濾功能,且 Meshy 將該圖像標記為涉及第三方智慧財產權。請傳送你擁有使用權利的圖像。
- Name
429 - Too Many Requests- Description
已達到以下限制之一:
- 你傳送的請求數超過了速率限制所允許的數量。請等待幾秒後重試。請參閱速率限制。
- 排隊或正在執行的任務過多。請等待部分任務完成後再重試。
- 在沒有剩餘積分的無限制方案下,你已達到可在無積分情況下執行的任務數量上限。請等待某個任務完成,或增加積分。
- Name
500 - Internal Server Error- Description
Meshy 遇到了伺服器錯誤,例如由於內容審核(moderation)或智慧財產權檢查未能執行,或 Meshy 無法儲存該圖像。Meshy 不會建立該任務,並會退還其已扣除的任何積分。請重試該請求。
創建 Keycap build 任務
根據一個成功的 prototype 任務及其候選項之一,生成帶貼圖的 3D keycap。相關欄位請參閱 Keycap build 任務物件。
一個 build 任務會執行每一個步驟。它先根據設計生成一個 3D 模型並為其上色,然後以經過校準的預設姿態將模型嵌入並裁切到 keycap 底座上,因此你無需手動調整。最後,它會組裝 keycap 並匯出檔案。一次 build 通常需要 3 到 7 分鐘。
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"
}
參數
- Name
- input_task_id
- Type
- string
- 必選
- Description
要建構的 prototype 任務的 ID。它必須是你的帳戶透過
POST /openapi/creative-lab/keycap/v1/prototype創建的任務,且狀態為SUCCEEDED。如果 ID 不是你透過 API 創建的 Keycap prototype 任務之一,將返回
404,這也包括在網頁應用程式中創建的 prototype。
- Name
- candidate_id
- Type
- string
- 必選
- Description
要建構的候選項,來自 prototype 任務的
candidate_ids陣列。如果值不在該陣列中,將返回400。
- Name
- name
- Type
- string
- Description
任務的名稱,最多 100 個字元。它會在任務的
name欄位中返回。名稱過長將返回400。
options
可選的 geometry 設定。每個欄位都有經過校準的預設值,因此只需傳送你想更改的欄位。
- Name
- base_model
- Type
- string
- 預設值 cherry-mx-1x1-r1
- Description
用於建構的 keycap 底座。目前唯一可用的值是
cherry-mx-1x1-r1,即標準的 Cherry MX profile 1u keycap。不支援自訂尺寸,其他任何值都會返回400。
- Name
- head_size_mm
- Type
- number
- 預設值 23
- Description
頭部沿其最長維度的尺寸,單位為毫米,範圍為
10到40。Meshy 會縮放頭部,使其最長維度與該值匹配。超出範圍的值將返回400。當值大於約
32.9時,Meshy 可能會縮小尺寸,以使頭部符合底座的保護性占用面積限制。此時頭部生成的結果可能會比你要求的更小。任務物件不會返回 Meshy 實際套用的尺寸。要檢查該尺寸,請測量模型中keycap-headmesh 的包圍盒。
- Name
- vertical_offset_mm
- Type
- number
- 預設值 0
- Description
在 Meshy 將頭部嵌入底座之前對其施加的垂直偏移量,單位為毫米,範圍為
-5到5。超出範圍的值將返回400。
回傳值
result 欄位保存新 build 任務的 ID。取得任務或對其進行串流傳輸,直到 status 為 SUCCEEDED。然後從 model_urls.glb 下載 GLB 檔案,並從 model_urls.obj_zip 下載 OBJ 壓縮包。
Meshy 匯出的 GLB 檔案和 OBJ 壓縮包均按真實世界比例以毫米為單位。兩者均採用 Y 軸朝上的座標系,keycap 正面朝向 +Z 方向。
失敗模式
- Name
400 - Bad Request- Description
請求無法執行。例如:
input_task_id缺失或不是有效的任務 ID。- prototype 任務的狀態不是
SUCCEEDED。如果仍在執行,請等待後重試。如果已失敗或被取消,請創建一個新的 prototype 任務。 - prototype 任務成功了,但沒有候選項。請創建一個新的 prototype 任務。
candidate_id缺失,或不在 prototype 任務的candidate_ids中。請從該陣列中傳送一個值。options中的某個欄位超出範圍,或base_model不是可用的值。
錯誤訊息會說明發現的具體問題。
- Name
401 - Unauthorized- Description
API 金鑰缺失或無效。請檢查
Authorization請求標頭。
- Name
402 - Payment Required- Description
以下情況之一適用:
- 帳戶沒有足夠的積分。
- 該 API 金鑰、工作區或成員已達到其積分限額。
- 帳戶處於免費方案。
請檢查你的積分和方案,然後重試。
- Name
404 - Not Found- Description
input_task_id與你的帳戶透過 API 創建的任何 Keycap prototype 任務都不匹配。在網頁應用程式中創建的 prototype 同樣會返回404。請傳送來自 prototype 創建回應中的resultID。
- Name
429 - Too Many Requests- Description
達到以下限制之一:
- 你傳送的請求數超過了速率限制所允許的數量。請等待幾秒後重試。參見速率限制。
- 你排隊或正在執行的任務過多。請等待部分任務完成後重試。
- 在沒有積分的無限制方案下,你達到了在沒有積分時可執行的任務數量上限。請等待某個任務完成,或增加積分。
- Name
500 - Internal Server Error- Description
由於伺服器錯誤,Meshy 無法創建任務。Meshy 會退還其已扣除的所有積分。請重試該請求。
取得 Keycap 任務
返回一個 prototype 或 build 任務。路徑必須與任務所處的階段相符。透過 /prototype/:id 請求 build 任務會回傳 404,透過 /build/:id 請求 prototype 任務同樣會回傳 404。
欄位說明請參閱 Keycap prototype 任務物件 和 Keycap build 任務物件。
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=***"
}
}
參數
- Name
- id
- Type
- path
- Description
建立回應中返回的任務 ID。
回傳值
prototype 任務物件 或 build 任務物件,具體取決於路徑中指定的階段。
失敗情況
- Name
400 - Bad Request- Description
id不是一個有效的任務 ID。請傳送建立回應中返回的resultID。
- Name
403 - Forbidden- Description
你的團隊已開啟 IP Filtering,並且 Meshy 偵測到該 prototype 任務的圖片涉及第三方智慧財產權問題。Build 任務以及 Enterprise 方案團隊不會遇到此錯誤。請使用你擁有使用權的圖片來建立 prototype 任務。
- Name
404 - Not Found- Description
你的帳戶下沒有該 ID 對應的 Keycap 任務,或者該任務所處的階段與路徑不符。請檢查 ID,並使用
/prototype或/build來對應正確的任務。
- Name
500 - Internal Server Error- Description
Meshy 無法執行智慧財產權檢查。請重試該請求。
刪除 Keycap 任務
取消一個 Keycap 任務。取消 PENDING 任務會退還其積分。IN_PROGRESS 任務被取消時不會退款,因為工作程序已經開始處理它。已處於最終狀態(SUCCEEDED、FAILED 或 CANCELED)的任務無法取消。
路徑必須與任務所處的階段相符。例如,用 build 任務的 ID 對 /prototype/:id 執行 DELETE 會回傳 404。
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).
路徑參數
- Name
- id
- Type
- path
- Description
要取消的任務的 ID。
回傳值
204 No Content,回應內容為空。
失敗情況
- Name
400 - Bad Request- Description
以下情況之一適用:
id不是有效的任務 ID。請傳送建立回應中的resultID。- 該任務已處於最終狀態(
SUCCEEDED、FAILED或CANCELED),因此無法取消。
- Name
404 - Not Found- Description
你的帳戶下不存在該 ID 對應的 Keycap 任務,或任務所處的階段與路徑不符。請檢查 ID,並使用
/prototype或/build來符合該任務。
- Name
500 - Internal Server Error- Description
Meshy 在取消任務時遇到了伺服器錯誤,因此該任務可能已取消,也可能未取消。請先取得任務以檢查其
status,然後再重試。
串流取得 Keycap 任務
以伺服器發送事件(SSE)的形式,串流取得 Keycap 任務的更新。路徑必須與任務所處的階段匹配。如果不匹配,例如在 /prototype/:id/stream 中使用 build 任務的 ID,串流會發送一個 status_code: 404 的 error 事件,然後關閉連線。
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.
// Every frame is the full task object; fields not yet populated are null / empty.
// The following PENDING frame is shortened to the fields that change.
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=***"
}
}
參數
- Name
- id
- Type
- path
- Description
建立回應中返回的任務 ID。
返回值
一個由原型或建置任務物件組成的串流。每個事件都包含完整的任務物件,格式與取得 Keycap 任務返回的一致。當任務處於 PENDING 或 IN_PROGRESS 狀態時,其輸出欄位仍為空(null、[] 或 {}),且 finished_at 為 null。
如果IP 過濾功能攔截了任務的結果,串流會在該處發送一個 error 事件,其中的 status_code 與 get 請求所返回的一致。
取得 Keycap 任務列表
返回某一階段的 Keycap 任務列表,每次返回一頁。路徑決定階段:/prototype 僅返回 prototype 任務,/build 僅返回 build 任務。
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"
]
}
]
路徑參數
- Name
- stage
- Type
- path
- 必選
- Description
要列出的階段,
prototype或build。
查詢參數
- Name
- page_num
- Type
- integer
- 預設值 1
- Description
要返回的頁碼,範圍從
1到255。0返回第一頁。超出0到255的值將返回400。
- Name
- page_size
- Type
- integer
- 預設值 10
- Description
每頁返回的任務數量,最多
100。101到255之間的值將返回 100 個任務,0使用預設值。超出0到255的值將返回400。
- Name
- sort_by
- Type
- string
- 預設值 -created_at
- Description
排序方式。
可用值:
-created_at:最新的排在最前+created_at:最舊的排在最前
返回值
一個陣列,包含與路徑中階段相符的prototype 任務物件或build 任務物件。
Keycap prototype 任務物件
一個 prototype 任務會根據照片生成一張成品鍵帽的圖像。要將該設計轉為 3D 鍵帽,請將該任務的 ID 作為 input_task_id 傳給 build endpoint,並將其 candidate_ids 中的對應條目作為 candidate_id 傳入。
Properties
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"
]
}
- Name
- id
- Type
- string
- Description
任務 ID。請勿依賴其具體格式。
- Name
- type
- Type
- string
- Description
任務類型,恆為
creative-lab-keycap-prototype。
- Name
- name
- Type
- string
- Description
你在建立任務時傳送的
name;如果沒有傳送,則為""。
- Name
- status
- Type
- string
- Description
任務的狀態。
可用取值:
PENDING:在佇列中等待IN_PROGRESS:正在生成結果SUCCEEDED:最終狀態,已生成結果FAILED:最終狀態,失敗原因見task_errorCANCELED:最終狀態,沒有結果
- Name
- progress
- Type
- integer
- Description
已完成工作的百分比,範圍從
0到100。任務開始前為0,成功後為100。
- Name
- created_at
- Type
- timestamp
- Description
任務建立的時間,單位為 Unix 毫秒。
- Name
- started_at
- Type
- timestamp
- Description
某個 worker 開始處理該任務的時間,單位為 Unix 毫秒。在此之前為
null。
- Name
- finished_at
- Type
- timestamp
- Description
任務到達最終狀態的時間,單位為 Unix 毫秒。在此之前為
null。
- Name
- expires_at
- Type
- timestamp
- Description
任務結果過期的時間,單位為 Unix 毫秒。該時間為
finished_at之後 3 天;在任務完成之前,為created_at之後 3 天。對於可無限期保留 API 結果的 Enterprise 帳戶,該時間約為 100 年之後。另見資產保留期。
- Name
- preceding_tasks
- Type
- integer
- Description
任務處於
PENDING狀態時在佇列中的位置。1表示該任務將是下一個開始的任務。任務離開佇列後為0,在列表結果中也始終為0。
- Name
- task_error
- Type
- object
- Description
任務失敗的原因。除非
status為FAILED,否則為null。另見 Errors。
- Name
- consumed_credits
- Type
- integer
- Description
該任務在扣除任何退款後實際收取的積分數量。回傳錯誤的請求不會被扣費。失敗的任務為
0,因為 Meshy 會對其進行退款。取消任務僅在其處於PENDING狀態時才會退款。如果 Meshy 無法讀取扣費資訊,get 或 stream 回應會省略該欄位,而 list 請求會回傳500。在這種情況下,請重試該請求。
- Name
- image_urls
- Type
- array of strings
- Description
成品鍵帽圖像的下載 URL。任務成功後,該陣列包含一個 URL;在此之前為空陣列。
image_urls[i]展示的是candidate_ids[i]所對應的候選結果。這些 URL 僅用於展示。build endpoint 接收的是
candidate_ids中的某個條目,而不是 URL。這些是簽名 URL,取得時無需攜帶Authorization請求標頭。它們在expires_at之前始終有效,並且再次取得該任務會回傳相同的 URL。
- Name
- candidate_ids
- Type
- array of strings
- Description
候選結果的 ID,順序與
image_urls相同。要建構某個候選結果,請在 build 請求中將其 ID 作為candidate_id傳送。請勿依賴這些 ID 的具體格式。
鍵帽建構任務物件
建構任務會根據一個成功的原型任務及其候選項之一,產生帶紋理的 3D 鍵帽。它會產生 3D 模型、為其上色、將其嵌入並裁切到鍵帽底座上,然後組裝並匯出鍵帽。
屬性
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=***"
}
}
- Name
- id
- Type
- string
- Description
任務 ID。請勿依賴其格式。
- Name
- type
- Type
- string
- Description
任務類型,始終為
creative-lab-keycap-build。
- Name
- name
- Type
- string
- Description
你建立任務時傳送的
name,如果未傳送則為""。
- Name
- status
- Type
- string
- Description
任務的狀態。
可用值:
PENDING:在佇列中等待IN_PROGRESS:正在產生結果SUCCEEDED:最終狀態,附帶結果FAILED:最終狀態,原因見task_errorCANCELED:最終狀態,無結果
- Name
- progress
- Type
- integer
- Description
已完成工作的百分比,從
0到100。任務開始前為0,成功後為100。
- Name
- created_at
- Type
- timestamp
- Description
任務建立的時間,單位為 Unix 毫秒。
- Name
- started_at
- Type
- timestamp
- Description
工作程序開始處理任務的時間,單位為 Unix 毫秒。在此之前為
null。
- Name
- finished_at
- Type
- timestamp
- Description
任務達到最終狀態的時間,單位為 Unix 毫秒。在此之前為
null。
- Name
- expires_at
- Type
- timestamp
- Description
任務結果過期的時間,單位為 Unix 毫秒。該時間為
finished_at之後 3 天,或在任務完成前為created_at之後 3 天。對於會無限期保留 API 結果的企業帳戶,該時間約為 100 年後。參見資產保留期。
- Name
- preceding_tasks
- Type
- integer
- Description
任務處於
PENDING狀態時在佇列中的位置。1表示該任務將是下一個開始執行的任務。任務離開佇列後為0,在列表結果中始終為0。
- Name
- task_error
- Type
- object
- Description
任務失敗的原因。除非
status為FAILED,否則為null。參見錯誤。
- Name
- consumed_credits
- Type
- integer
- Description
該任務在退款後實際扣除的積分數量。回傳錯誤的請求不會被扣費。失敗的任務為
0,因為 Meshy 會退還費用。僅當任務處於PENDING狀態時取消才會退款。如果 Meshy 無法讀取扣費資訊,get 或 stream 回應會省略該欄位,而 list 請求會回傳500。遇到這種情況,請重試該請求。
- Name
- model_urls
- Type
- object
- Description
3D 模型的下載 URL。Meshy 匯出的 GLB 檔案和 OBJ 包按真實世界比例(以毫米為單位)、Y 軸朝上,鍵帽正面朝向 +Z 方向。
該模型包含名為
keycap-head和keycap-base的網格。當 Meshy 回退為底座使用圖案填充時,模型還會包含一個用於軸芯凹腔的keycap-base-interior網格。請勿假設模型一定只有兩個網格。這些是簽名 URL,因此擷取時無需攜帶
Authorization請求標頭。它們在expires_at之前保持有效,在此之前再次擷取該任務會回傳相同的 URL。過期的 URL 無法續期,因此請在到期前下載並儲存檔案。- Name
glb- Type
- string
- Description
帶紋理的 GLB 檔案
model.glb的下載 URL。
- Name
obj_zip- Type
- string
- Description
OBJ 包的下載 URL,這是一個包含
model.obj、model.mtl以及model.mtl所使用的 PNG 紋理的 ZIP 檔案。如果底座為純色,唯一的紋理是keycap-head.png。如果底座帶有圖案,該 ZIP 檔案還會包含keycap-base.png。
- Name
- process_image_urls
- Type
- object
- Description
建構過程各步驟產生圖片的下載 URL,按類型進行鍵值索引。與
model_urls一樣,它們也是簽名 URL,因此擷取時無需攜帶Authorization請求標頭。它們在expires_at之前保持有效,再次擷取該任務會回傳相同的 URL。它可能包含以下鍵:
head_design:所選候選項的設計圖像,建構任務據此產生 3D 內容。始終存在。composite:所選候選項完成後的鍵帽圖像,底座正是根據它繪製而成。可能缺失。base_canvas:繪製完成的鍵帽底座。可能缺失。
Meshy 可能會新增鍵,因此遇到不認識的鍵請直接忽略。
端到端範例
此範例會執行整個流程:
- 根據照片建立一個 prototype 任務。
- 取得任務,直到其
status為SUCCEEDED。 - 從
candidate_ids中選取一個候選項。 - 使用該候選項建立一個 build 任務。
- 取得 build 任務,直到其
status為SUCCEEDED。 - 從
model_urls下載 GLB 檔案和 OBJ 壓縮檔。
此範例選擇了第一個候選項。在您的應用程式中,可以向使用者展示 image_urls 項目,讓他們自行選擇。所選圖片在 image_urls 中的索引,就是其 ID 在 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"