跳到正文
FreshApp Demo

開發者文件

生成 API 文件

用生成 API,在你自己的程式裡呼叫本站的模型建立生成任務。每個請求寫明模型與它的輸入;回傳的是一個生成任務,你追蹤它直到結束,結果檔案從本站下載。本頁的模型、價格、限額與錯誤碼都是本站目前實際執行的。

透過 API 建立生成任務,需要購買過付費積分包或有有效的付費訂閱,而且只扣付費積分。帳號的任何金鑰都能查詢、列出與下載。

快速開始

在 API 金鑰頁建立一把金鑰,只放在你的伺服器上,並設成 API_KEY。下面的範例用 seed-audio-1.0 建立一個生成任務,查詢到它結束,再下載第一個檔案。

每個新請求送出一個新的 Idempotency-Key。請求沒有收到回應時,用同一個鍵和同樣的請求內容再送一次:你拿到的是第一次請求建立的任務,只扣一次費。

cURL

export API_ORIGIN='https://demo.freshapp.ai'
export API_KEY='sk_YOUR_API_KEY'

curl --fail-with-body "$API_ORIGIN/api/v1/generations" \
  -H "Authorization: Bearer $API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: order-1001' \
  -d '{"model":"seed-audio-1.0","input":{"prompt":"黎明時分懸崖上的燈塔,海面平靜,光線柔和。"}}'

# Read it every 5 to 10 seconds until its status ends.
curl --fail-with-body "$API_ORIGIN/api/v1/generations/GENERATION_ID" \
  -H "Authorization: Bearer $API_KEY"

# A delivered output's url is a signed link: no key needed.
curl --fail-with-body -o result "OUTPUT_URL"

TypeScript 用戶端

import { createClient } from './open-api-client';

const client = createClient({
  baseUrl: "https://demo.freshapp.ai",
  apiKey: process.env.API_KEY, // on your server only
});
const generation = await client.create(
  {
    "model": "seed-audio-1.0",
    "input": {
      "prompt": "黎明時分懸崖上的燈塔,海面平靜,光線柔和。"
    }
  },
  { idempotencyKey: "order-1001" }
);
const done = await client.wait(generation.id);
for (const output of done.outputs)
  if (output.status === 'delivered') {
    const file = await client.download(output);
    // file.body is the output, as output.content_type says
  }

React hook

import { createClient } from './open-api-client';
import { useGeneration } from './open-api-react';

// In a browser on this site: no key, the visitor's own session.
const client = createClient();

export function Progress({ id }: { id: string }) {
  const { generation, error, done } = useGeneration(client, id);
  if (error) return <p>{String(error)}</p>;
  return <p>{generation?.status ?? '…'}{done ? ' ✓' : ''}</p>;
}

金鑰與權限

每個請求都在 Authorization: Bearer 中帶上 API 金鑰頁建立的金鑰。金鑰是 sk_ 加上 43 個字母、數字、連字號或底線,只在建立與輪換時顯示一次。帶有 Authorization 的請求只依這把金鑰判斷,不會改用旁邊的登入狀態。

金鑰要嘛只讀(查清單、查任務、下載),要嘛也能生成(建立與取消)。只讀金鑰嘗試建立或取消時會得到 403 insufficient_scope,不會寫入任何資料。

金鑰可以帶一份由位址與網段組成的 IP 白名單:從其他位址送來的請求會得到 403 ip_not_allowed。給金鑰更多權限、調高上限或放寬白名單,需要最近重新登入過;收緊則不需要。

輪換金鑰會立刻產生新值,舊值馬上失效。撤銷金鑰後它永久失效:還沒送交模型的任務會被取消並退回積分,已經在執行的任務照常完成。

只有具付費資格的帳號才能透過 API 建立任務(否則是 403 not_eligible),而且 API 只扣付費積分(不足時是 402 insufficient_credits)。贈送積分與簽到積分只留給網站使用。

生成 API 介面

所有路徑都在本站上。請求與回應的內容都是 JSON,結果檔案除外。

https://demo.freshapp.ai

方法路徑需要的權限用途
POST/api/v1/generationsgenerations:write建立生成任務。必須帶 Idempotency-Key;回傳 202 與這個任務。
GET/api/v1/generationsgenerations:read帳號的生成任務,最新的在前,分頁回傳(limit、cursor、module)。文字任務只能依編號查詢。
GET/api/v1/generations/{id}generations:read帳號的一個生成任務,包括它的輸出、積分與結束原因。
POST/api/v1/generations/{id}/cancelgenerations:write取消還沒送交模型的任務,並退回它的積分。
GET, HEAD/api/media/{id}generations:read (或簽章連結)一個輸出的檔案,最多支援一個位元組範圍。簽章連結不需要金鑰,從任何位址都能開啟。

模型與價格

本站已啟用的模型,依 API 的寫法列出:把編號填入 model,把欄位填入 input。請求在建立時預留它最貴的可能結果,結束後依實際交付的部分收費。

模型編號名稱類型價格單次最多輸入欄位
seed-audio-1.0Seed Audio 1.0音訊每分鐘 75 積分; 交付結果時至少 10 積分150 積分prompt (必填), voice, audio_references, image_url, output_format, sample_rate, speed, volume, pitch, multilingual

冪等鍵

建立生成任務必須帶 Idempotency-Key 標頭,由 1 到 128 個字母、數字、句點、冒號、底線或連字號組成。建議使用你自己系統裡的編號,例如訂單編號,讓同一件事永遠使用同一個鍵。

同一個鍵加上同樣的請求,不論送幾次都回傳同一個任務,只扣一次費。同一個鍵加上不同的請求會得到 409 idempotency_conflict,不會建立任何任務。

逾時或連線中斷並不代表請求失敗。請用同一個鍵和同樣的請求內容再送一次,並在收到回應前一直保留這兩樣。5xx、429 和 408 也一樣處理:依 Retry-After 等待,然後原封不動再送一次。

狀態與輪詢

用 GET /api/v1/generations/{id} 查詢任務:一開始每 5 秒一次,之後最長每 10 秒一次,直到狀態結束。遇到 429 時,Retry-After 會告訴你何時再查。

狀態意思
queued已接受,等待送交模型。這時還可以取消。
processing已送交模型,或正在儲存檔案與結算。
succeeded所有輸出都已交付,積分已結算。
partially_succeeded部分輸出已交付並收費,其餘部分的積分已退回。
failed什麼都沒交付;error 說明原因,預留的積分已退回。
canceled送交前被取消(由你取消,或因為金鑰被撤銷);積分已退回。

billing.reserved_credits 是建立任務時預留的積分。結算後,charged_credits 是實際收取的積分,refunded_credits 是退回的積分;結算前兩者都是 null,held_credits 顯示正在佔用的積分。

等待人工核對的任務會在 review 中顯示核對開始的時間,核對結束前積分一直佔用;核對後任務繼續,或者積分退回。

結果檔案

每個已交付的輸出都有一個本站上的 url。用金鑰查詢時,它是一個簽章連結,一小時內不帶金鑰、從任何位址都能開啟,可以直接交給下載工具。超過一小時後,再查一次任務就能拿到新的連結。

用金鑰本身請求 GET /api/media/{id} 也能取得檔案,但受這把金鑰的白名單限制。兩種方式都支援 HEAD 和一個位元組範圍(Range: bytes=0-1023),而且不會轉址到其他網站。

輸入中引用的檔案(例如一段音訊樣本或一張圖片)必須是這個帳號在網站上上傳的、本站內建的樣本,或來自本站允許來源的連結;其他引用會在預留積分之前就被拒絕。

限額

下面每一項都是本站目前執行的限額,每次拒絕都會說明碰到了哪一項。

  • 一次請求最多預留 150 積分,也就是已啟用模型中最貴一次請求的費用。可以替金鑰設得更低,請求中的 max_credits 能為這一次再調低;超過時回傳 400 request_limit_exceeded。
  • 每把金鑰每個 UTC 日最多花 5,000 積分,可以自行設定,最高 1,000,000;超過後這把金鑰會得到 429 key_daily_limit_exceeded,直到下一個 UTC 日。
  • 一個帳號的所有金鑰加上它授權的 AI 用戶端,每個 UTC 日合計最多花 10,000 積分,可以為帳號另設上限;超過後回傳 429 account_daily_limit_exceeded。
  • 每把金鑰與每個帳號每分鐘最多建立與取消 20 次、查詢與下載 240 次;超過後回傳 429 rate_limited,並附上 Retry-After。
  • 一個帳號同時執行的生成任務最多 2 個;再建立會得到 429 too_many_active。
  • 請求內容最多 32 KiB 的 JSON;更大的回傳 413 request_too_large。

錯誤碼

錯誤的格式是 {"error": {"code": …, "message": …}}。code 一定是下表中的一個,message 是寫給開發者的英文說明。429 和 503 會在 Retry-After 中給出需要等待的秒數。失敗或被取消的任務會在 error 欄位中帶上標示為任務錯誤的碼之一。

HTTP錯誤碼意思怎麼處理
401invalid_credentialAPI 金鑰缺少、格式錯誤、不存在、已撤銷或已被取代。檢查 API 金鑰、它的權限與白名單。
401credential_revoked請求進行中金鑰被撤銷或輪換;被撤銷金鑰排隊中的任務會被取消並退回積分。檢查 API 金鑰、它的權限與白名單。
403insufficient_scope這把金鑰不能做這件事:錯誤中的 required_scope 寫明了需要的權限。檢查 API 金鑰、它的權限與白名單。
403ip_not_allowed不能從這個位址使用這把金鑰:它不在金鑰的 IP 白名單中。檢查 API 金鑰、它的權限與白名單。
401unauthorized網站的登入已失效:請重新登入。修改請求後再送出。
403invalid_origin網站請求必須來自本站本身。修改請求後再送出。
403forbidden請求沒有可信的用戶端位址。聯絡本站客服。
400invalid_request請求格式錯誤:JSON、標頭(Idempotency-Key、Content-Type)或查詢參數有誤。修改請求後再送出。
400invalid_input輸入不符合模型的欄位,或模型無法使用它。修改請求後再送出。
413request_too_large請求內容太大。修改請求後再送出。
409idempotency_conflict這個 Idempotency-Key 已經用於另一個不同的請求。修改請求後再送出。
404model_unavailable模型不存在或目前無法使用。修改請求後再送出。
404not_found這個帳號下沒有這個路徑、任務或檔案。修改請求後再送出。
405method_not_allowed這個路徑不支援該方法;Allow 列出了支援的方法。修改請求後再送出。
409not_cancelable任務已經送交模型,或已經結束。修改請求後再送出。
409not_ready檔案還沒準備好。依 Retry-After 等待後再送出。
410expired檔案已過保存期,已被刪除。修改請求後再送出。
400request_limit_exceeded這個請求的費用會超過它的 max_credits,或超過金鑰或本站的單次上限。修改請求後再送出。
403not_eligible透過 API 生成需要付費帳號。購買積分包或方案:API 只扣付費積分。
403email_unverified需要先驗證帳號的電子郵件才能生成。修改請求後再送出。
402insufficient_credits積分不足:API 只扣付費積分。購買積分包或方案:API 只扣付費積分。
403generation_restricted因多次內容違規,這個帳號的生成已暫停;ends_at 寫明暫停到何時。聯絡本站客服。
403trial_paused這個帳號有幾次試用輸出超出了試用限制,網站試用已暫停;ends_at 寫明暫停到何時。不用試用的請求照常進行。修改請求後再送出。
429key_daily_limit_exceeded已達到這把金鑰的每日花費上限。依 Retry-After 等待後再送出。 Retry-After:到下一個 UTC 日。
429account_daily_limit_exceeded已達到帳號透過 API 的每日花費上限。依 Retry-After 等待後再送出。 Retry-After:到下一個 UTC 日。
429rate_limited短時間內請求太多。依 Retry-After 等待後再送出。 Retry-After:限流時段的剩餘時間。
429too_many_active帳號正在執行的任務太多。依 Retry-After 等待後再送出。 Retry-After:30 秒。
429too_many_under_review帳號有部分任務正在等待人工核對。依 Retry-After 等待後再送出。 Retry-After:3,600 秒。
503busy本站目前執行的任務太多。依 Retry-After 等待後再送出。 Retry-After:30 秒。
503paused生成暫時停止。依 Retry-After 等待後再送出。 Retry-After:60 秒。
503temporarily_unavailable請求暫時無法完成。用同一個 Idempotency-Key 原封不動再送一次。 Retry-After:60 秒。
503api_unavailable本站暫未開放生成。依 Retry-After 等待後再送出。 Retry-After:60 秒。
503retry請求進行中有內容發生變化,例如金鑰的設定。用同一個 Idempotency-Key 原封不動再送一次。 Retry-After:60 秒。
503unavailable檔案暫時無法存取。依 Retry-After 等待後再送出。 Retry-After:60 秒。
500internal_error本站出了問題。用同一個 Idempotency-Key 原封不動再送一次。
400request_failed請求被拒絕,但沒有對應的專屬錯誤碼。聯絡本站客服。
400captcha_required請完成網站的安全驗證。修改請求後再送出。
403captcha_failed網站的安全驗證沒有通過。修改請求後再送出。
503captcha_unavailable網站的安全驗證暫時無法使用。依 Retry-After 等待後再送出。 Retry-After:60 秒。
400reference_unavailable引用的上傳檔案已不存在,或不屬於這個帳號。修改請求後再送出。
413reference_too_large引用的上傳檔案合計不能超過 10 MB。修改請求後再送出。
503reference_storage_unavailable引用檔案的儲存空間暫時無法使用。依 Retry-After 等待後再送出。 Retry-After:60 秒。
409storage_quota_exceeded帳號的儲存空間已滿。聯絡本站客服。
任務中canceled任務在送交前被取消;積分已退回。修改請求後再送出。
任務中submission_expired任務沒能及時送交;積分已退回。用同一個 Idempotency-Key 原封不動再送一次。
任務中model_busy模型忙碌中;積分已退回。依 Retry-After 等待後再送出。
任務中content_rejected內容安全檢查拒絕了輸入或輸出。修改請求後再送出。
任務中result_expired結果沒能及時儲存。聯絡本站客服。
任務中generation_failed生成失敗。聯絡本站客服。
任務中delivery_failed結果沒能交付;積分已退回。聯絡本站客服。
任務中trial_limit_exceeded網站試用的輸出超出了試用限制,沒有交付;積分已退回。修改請求後再送出。

TypeScript 用戶端與 React hook

TypeScript 用戶端 open-api-client.ts 不需要任何其他套件,可以在伺服器、Worker 和瀏覽器中執行。在伺服器上傳入 baseUrl 和 apiKey;在本站的瀏覽器頁面中兩者都不傳,請求會使用訪客自己的登入狀態。

create 會送出 Idempotency-Key(你提供的,或新產生的隨機值),遇到連線中斷、5xx、429 或 408 時用同一個請求重送,並依 Retry-After 等待。放棄時,錯誤中帶著這個鍵,你可以稍後用它重送。傳入 store(例如 localStorage)後,重新整理頁面也會沿用第一次的鍵。

wait 會一直查詢任務直到結束:一開始間隔 5 秒,之後最長 10 秒,中止時立刻停下。download 下載一個輸出的檔案,只對本站自己的未簽章連結帶上金鑰。

React hook open-api-react.ts 用用戶端的 wait 追蹤一個任務,元件卸載時停止。下載這兩個檔案,放在同一個目錄中,並把副檔名改成 .ts。

檔案下載