歌詞時間戳校正 API
這不是語音辨識。 文字永遠採用你給的歌詞原文,我們只負責把每個字放到正確的時間點上——所以不會出現「辨識錯字導致歌詞對不上」的情況。
介面說明
把已有的歌詞和音訊對齊,輸出逐行 + 逐字的時間戳,用於卡拉OK逐字高亮、滾動歌詞、字幕生成。
介面位址:POST /api/music/lyrics-align
驗證:見認證說明,請求標頭 Authorization: Bearer YOUR_API_KEY
計費:按次計費(目前預設 0.1 元/次);平台歌曲勾選人聲分離時,另按平台「人聲/伴奏分離」價格計一次。實際扣費以目前後台價格設定為準。
平均耗時:5–15 秒(視音訊長度、以及是否需要現場做人聲分離而定)
為什麼需要校正:生成側的時間戳並不總是準
時間軸歌詞 API 直接回傳生成側的逐詞時間戳,存在不準確性:
- 重唱、和聲重、說唱、長音段落容易出現整體偏移或個別字錯位;
- 部分歌曲開頭會缺一段(例如純前奏,第一個片段從十幾秒才開始);
- 某些歌詞行很難拿到明確的時間錨點。
歌詞時間戳校正是在你自己提供的歌詞基礎上重新做時間對齊:只校正時間,不改文字,適合對「能不能對上」要求高的場景(KTV 逐字高亮、逐字字幕、跟唱評分)。
建議做法(三步,效果最好)
- 先提取純人聲(人聲/伴奏分離),只把人聲軌拿去對齊——伴奏與和聲不再干擾。 實測依據:同一首歌的「全曲 vs 人聲軌」逐行對比裡,28 行有 5 行差異超過 0.25 秒(最大 2.64 秒); 兩個互相獨立的引擎在人聲軌上的平均差 0.239 秒、在全曲上 0.508 秒——一致度幾乎差一倍。 所以做逐字高亮(KTV/字幕)建議開啟。(具體提升幅度正在用新引擎重新測。)
- 提供完整歌詞:整首歌、按行、和音訊一一對應。漏句或段落缺失會讓後面的行整體錯位;歌詞裡不要帶
[00:23.82]這類時間戳(帶了會自動忽略)。 - 平台歌曲可以直接勾
vocal_separate: true,由我們一步完成「分離 + 對齊」。
三種用法
| 用法 | 傳什麼 | 歌詞從哪來 | 支援人聲分離 |
|---|---|---|---|
| 外部歌曲 · 公網位址 | audio_url + 歌詞 |
你自己提供 | ❌ 不支援 |
| 外部歌曲 · 本機檔案直傳(2026-10 新增) | audio_object_key + 歌詞 |
你自己提供 | ❌ 不支援 |
| 平台歌曲(本站生成的歌) | song_id |
我們從歌曲記錄裡取 | ✅ 可選 |
參數的關係(最容易搞錯,務必看清)
- 傳
song_id→ 走平台歌曲:不要再傳lyrics/audio_url/audio_object_key; - 傳
audio_url或audio_object_key→ 走外部歌曲:兩者只能傳一個,且不要再傳song_id; vocal_separate只對平台歌曲有效,外部歌曲傳了會被拒絕(音訊不在我們這邊,無法分離)。
新增:本機檔案直傳(音訊不經過我們的伺服器)
音訊在你本機、又不想先傳到自己的公網儲存時用這個。兩步:
POST /api/music/lyrics-align/upload-ticket,帶file_name/file_size/content_type, 拿到put_url(簽名 URL,不含任何長期憑證)與object_key;- 把檔案
PUT到put_url,必須原樣帶上回應裡的content_type(它參與簽名,改一個字就是 403); - 提交對齊時傳
audio_object_key而不是audio_url。
憑證是一次性的:對齊跑完(成功或失敗)伺服器會刪掉這個物件,同一個 key 再用會報錯。
新增:歌詞可以不傳了
原本外部歌曲必須給歌詞。現在不傳也能用——伺服器先做一次辨識,用辨識出來的文字當歌詞。
代價必須說清楚:文字以辨識結果為準,個別字可能不準。這類回應會明確標註
lyrics_source: "asr"、confidence: "low",並在 warnings[] 裡給
{"code":"no_reference_lyrics"}。
要做逐字高亮 / KTV,請務必提供歌詞原文。
請求參數
Headers
| 參數名 | 型別 | 必填 | 說明 |
|---|---|---|---|
| Authorization | string | 是 | Bearer YOUR_API_KEY |
| Content-Type | string | 是 | application/json |
Body 參數
| 參數名 | 型別 | 必填 | 預設值 | 說明 |
|---|---|---|---|---|
| song_id | string | 二選一 | - | 平台歌曲 ID(平台歌曲用法) |
| lyrics | string | 否 | - | 歌詞原文,\n 分行。現在可以不傳,見上文「歌詞可以不傳了」 |
| audio_url | string | 外部歌曲二選一 | - | 音訊位址,必須公網可下載 |
| audio_object_key | string | 外部歌曲二選一 | - | 直傳物件的 key(先呼叫 /lyrics-align/upload-ticket) |
| vocal_separate | boolean | 否 | false |
是否先做人聲分離(僅平台歌曲) |
| language | string | 否 | 自動判斷 | Chinese / English 等;不傳按歌詞內容猜 |
| granularity | string | 否 | both |
both / line(不回傳逐字)/ word |
| sections | string | 否 | keep |
keep 保留 [Chorus] 等段落標記(不參與時間軸)/ drop |
| format | string | 否 | json |
json / lrc / lrc-word(後兩者多回傳 lrc、lrc_word 文字) |
限制
| 項 | 限制 |
|---|---|
| 音訊長度 | ≤ 6 分鐘(超過回傳錯誤並全額退款) |
| 音訊來源 | 必須公網可下載,不接受需要登入態的位址 |
| 歌詞格式 | 純文字、\n 分行;[Verse]、【主歌】 等段落標記會原樣保留,但不參與時間軸 |
| 批次 | 一次一首;多首請自行迴圈呼叫 |
| 結果保存 | 本介面不落庫,請自行保存回傳結果 |
請求範例
外部歌曲(歌詞 + 音訊位址)
curl -X POST https://www.suno-api.io/api/music/lyrics-align \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"lyrics": "漫步在清冷的街頭\n夜風輕撫過眼眸\n歲月匆匆如水流",
"audio_url": "https://your-bucket.example.com/song.mp3"
}'
平台歌曲(不分離)
curl -X POST https://www.suno-api.io/api/music/lyrics-align \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"song_id": "17e52af7-b5df-4877-a98a-dce94e0e6aa2"}'
平台歌曲 + 人聲分離(做卡拉OK推薦這個)
curl -X POST https://www.suno-api.io/api/music/lyrics-align \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"song_id": "17e52af7-b5df-4877-a98a-dce94e0e6aa2", "vocal_separate": true}'
回應結果
成功回應
{
"success": true,
"lyrics_source": "platform",
"vocal_separate": false,
"coverage": 0.935,
"exact": 196,
"fuzzy": 4,
"total": 214,
"lines": [
{
"text": "漫步在清冷的街頭",
"start": 21.66,
"end": 24.06,
"chars": [
{"char": "漫", "start": 21.66, "end": 21.74, "word": true},
{"char": "步", "start": 21.98, "end": 22.22, "word": true}
]
}
]
}
欄位說明
| 欄位名 | 型別 | 說明 |
|---|---|---|
success |
boolean | 請求是否成功 |
lyrics_source |
string | platform = 歌詞取自平台歌曲;user = 歌詞由你提供;asr = 你沒給歌詞,文字來自辨識 |
vocal_separate |
boolean | 本次是否走人聲分離 |
confidence |
string | high / low(lyrics_source=asr 時一定是 low) |
warnings[] |
array | 降級提示;無歌詞時含 {"code":"no_reference_lyrics"} |
coverage |
number | 對齊品質:有明確時間錨點的字佔比(0–1) |
exact / fuzzy / total |
number | 精確命中字數 / 同音命中字數 / 歌詞有效字數 |
lines[].text |
string | 一行歌詞,逐字元等於你的原文 |
lines[].start / end |
number | 這一行的起止時間(秒) |
lines[].section |
boolean | 這行是段落標記(true 時沒有時間,不參與高亮) |
lines[].chars[] |
array | 逐字時間:char 字、start/end 秒、word 是否計入時間軸(標點為 false) |
words[] |
array | 扁平逐字清單:text / start / end / line;granularity=line 時不回傳 |
lrc |
string | 逐行 LRC 文字(format=lrc 或 lrc-word 時才有) |
lrc_word |
string | 增強逐字 LRC,行內 <mm:ss.xx> 標籤(format=lrc-word 時才有) |
coverage 怎麼用(三檔建議)
| coverage | 建議用法 |
|---|---|
| ≥ 0.9 | 可以做逐字高亮(卡拉OK) |
| 0.8 – 0.9 | 逐字 + 整行混用,或只做整行高亮,逐字僅作參考 |
| < 0.8 | 建議只做整行高亮(重唱、和聲重、方言、說唱容易偏低) |
狀態與耗時
| 場景 | 實測耗時 |
|---|---|
| 平台歌曲 · 不分離 | 約 4.5 秒 |
| 平台歌曲 · 分離(已有人聲軌) | 約 11 秒 |
| 平台歌曲 · 分離(需現場分離) | 約 25 秒,最長約 1 分鐘 |
| 外部歌曲 · 歌詞 + 音訊位址 | 約 5–15 秒(視音訊長度) |
伺服器單次執行上限 8 分鐘;建議用戶端逾時設定為 120 秒以上。
錯誤回應
{
"success": false,
"message": "音频超过 6 分钟上限(实际 7.2 分钟)"
}
| 場景 | 是否扣費 |
|---|---|
| 缺少音訊(三個都不傳) | 不扣費(未開始處理) |
audio_url 與 audio_object_key 同時傳 |
不扣費(未開始處理) |
| 直傳物件還沒落盤 / 已被刪除 | 不扣費(未開始處理) |
非法的 granularity / sections / format |
不扣費(未開始處理) |
| 平台歌曲不存在 / 不屬於目前帳號 | 不扣費(未開始處理) |
| 參數缺失或參數不合法 | 不扣費(未開始處理) |
| 音訊超過 6 分鐘上限 | 全額退款 |
| 音訊不可下載(非公網位址 / 需要登入) | 全額退款 |
| 不傳歌詞、但伺服器辨識失敗 | 全額退款 |
| 勾了人聲分離但沒有可用人聲軌 | 全額退款(含人聲分離費用) |
| 對齊服務異常或逾時 | 全額退款 |
原則:拿不到最終結果就全額退款。 只有真正回傳了逐字時間戳才扣費,退款自動完成、無需申請。
計費
| 項目 | 何時收 | 說明 |
|---|---|---|
| 歌詞時間戳校正(基準) | 每次都收 | 按次計費(目前預設 0.1 元/次),實際扣費以目前後台價格設定為準 |
| 轉寫附加費 | 只有不提供歌詞時加收 | 伺服器要先跑一次語音辨識,那是「有歌詞」檔沒有的成本,所以單獨計價 |
| 人聲分離(可選,僅平台歌曲) | 勾了 vocal_separate 時 |
按平台「人聲/伴奏分離」的現有價格計一次,與本介面一起結算 |
組合關係:
實付 = 基準價 + (不提供歌詞 ? 轉寫附加費 : 0) + (勾了分離 ? 分離價 : 0)
人聲分離費用只收一次:如果你已經做過分離、能直接拿到人聲軌,就由本介面收;如果需要現場分離,則由分離那一步收。
完整範例(Python)
import requests
API_KEY = "YOUR_API_KEY"
BASE = "https://www.suno-api.io"
def align_lyrics(song_id=None, lyrics=None, audio_url=None, vocal_separate=False):
payload = {}
if song_id:
payload["song_id"] = song_id
payload["vocal_separate"] = vocal_separate
else:
payload["lyrics"] = lyrics
payload["audio_url"] = audio_url
r = requests.post(
f"{BASE}/api/music/lyrics-align",
headers={"Authorization": f"Bearer {API_KEY}"},
json=payload,
timeout=600,
)
data = r.json()
if not data.get("success"):
raise RuntimeError(data.get("message"))
return data
res = align_lyrics(song_id="17e52af7-b5df-4877-a98a-dce94e0e6aa2", vocal_separate=True)
print("對齊品質 coverage =", res["coverage"])
for line in res["lines"]:
print(f'{line["start"]:7.2f} {line["text"]}')
# 逐字卡拉OK:line["chars"] 裡每個字都有自己的 start / end
常見問題
Q:回傳的是逐字還是逐行?
A:兩者都有。lines[].start 是逐行,lines[].chars[].start / end 是逐字,播放器按需取用。
Q:為什麼回傳的文字和我傳的一模一樣? A:設計如此。我們不做辨識改寫,只做時間對齊,所以歌詞永遠不會被「改錯字」。
Q:coverage 很高,但聽起來還是有點偏?
A:逐字對齊誤差通常在數十毫秒量級;如果整首歌都偏一個固定值,多半是音訊開頭有一段靜音,可以裁剪後再試。
Q:為什麼剛剛做了人聲分離能用,過一會兒就報「人聲軌不可用」? A:分離結果是短時效的臨時位址(實測約半小時後失效)。這種情況介面會嘗試自動重新分離;如果最終仍然失敗,會全額退款。所以「先分離、過一會兒再做校正」這種用法不可靠,建議在同一個流程裡連著做。
Q:平台歌曲需要我自己先做分離嗎?
A:不需要。勾 vocal_separate: true 後我們會檢查這首歌是否已有人聲軌;沒有可用人聲軌會報錯並退款,不會用原曲糊弄。
Q:可以批次嗎? A:一次請求一首。批次請迴圈呼叫;每次呼叫都會正常計費,建議本地快取結果。
Q:結果會被保存嗎? A:本介面不落庫,請自行保存回傳值(逐行 + 逐字時間戳都在回應裡)。