API de calibração de marcas de tempo da letra
Isto não é reconhecimento de fala. O texto usa sempre a letra original que você fornece; nós apenas colocamos cada caractere no instante correto — então nunca acontece de "caracteres mal ouvidos desalinharem a letra".
Descrição do endpoint
Alinha uma letra existente com um áudio e devolve marcas de tempo por linha e por caractere, para realce caractere a caractere no estilo karaokê, letra com rolagem e geração de legendas.
Endpoint: POST /api/music/lyrics-align
Autenticação: veja Autenticação; o cabeçalho é Authorization: Bearer YOUR_API_KEY
Cobrança: cobrada por chamada (atualmente ¥0,1 por chamada por padrão); numa música da plataforma com separação de voz marcada, cobra-se mais uma vez ao preço de "separação de voz/acompanhamento". O valor realmente cobrado segue a configuração de preços do back-office.
Tempo médio: 5–15 segundos (dependendo da duração do áudio e de haver separação de voz na hora)
Por que é preciso calibrar: as marcas do lado gerador nem sempre são exatas
A API de letras com marcas de tempo devolve diretamente as marcas palavra a palavra do lado gerador e elas têm imprecisões:
- repetições, harmonias densas, rap e notas longas costumam desviar no conjunto ou deslocar caracteres isolados;
- algumas músicas perdem um trecho no início (por exemplo uma introdução pura, com o primeiro fragmento começando só lá pelos quinze segundos);
- algumas linhas são difíceis de ancorar num instante claro.
A calibração refaz o alinhamento temporal sobre a letra que você fornece: só o tempo é corrigido, nunca o texto, o que serve para casos em que "bater" importa (realce por caractere no KTV, legendas por caractere, pontuação de canto).
Abordagem recomendada (três passos, melhor resultado)
- Extraia primeiro a voz (separação voz/acompanhamento) e alinhe apenas a faixa de voz: o acompanhamento e as harmonias deixam de interferir. Base medida: numa comparação linha a linha de "mixagem completa vs faixa de voz" da mesma música, 5 de 28 linhas divergiam mais de 0,25 s (a maior, 2,64 s); dois motores independentes divergiam em média 0,239 s na faixa de voz e 0,508 s na mixagem completa — quase metade da concordância. Por isso, para realce por caractere (KTV/legendas) recomendamos ativar. (O ganho exato está sendo medido de novo com o motor novo.)
- Forneça a letra completa: a música inteira, linha a linha, correspondendo um a um com o áudio. Uma frase ou seção em falta desloca todas as linhas seguintes; não inclua marcas como
[00:23.82]na letra (são ignoradas automaticamente). - Numa música da plataforma basta marcar
vocal_separate: truee fazemos "separação + alinhamento" num passo só.
Três formas de usar
| Uso | O que enviar | De onde vem a letra | Separação de voz |
|---|---|---|---|
| Música externa · URL público | audio_url + letra |
Você fornece | ❌ Não suportado |
| Música externa · envio directo de ficheiro local (novo em 2026-10) | audio_object_key + letra |
Você fornece | ❌ Não suportado |
| Música da plataforma (gerada neste site) | song_id |
Nós tiramos do registo da música | ✅ Opcional |
Como os parâmetros se relacionam (é o que mais se erra: leia com atenção)
- Enviar
song_id→ rota de música da plataforma: não envie tambémlyrics/audio_url/audio_object_key; - Enviar
audio_urlouaudio_object_key→ rota de música externa: apenas um dos dois e não enviesong_id; vocal_separatesó funciona em músicas da plataforma; se o enviar numa música externa é rejeitado (o áudio não está do nosso lado, não há como separar).
Novo: envio directo de ficheiro local (o áudio não passa pelos nossos servidores)
Use quando o áudio está na sua máquina e prefere não o enviar primeiro para o seu próprio armazenamento público. Dois passos:
POST /api/music/lyrics-align/upload-ticketcomfile_name/file_size/content_typee recebe umput_url(URL assinado, sem credenciais de longa duração) e umobject_key;- Faça
PUTdo ficheiro paraput_url, levando ocontent_typeda resposta tal como veio (participa na assinatura; um caractere alterado dá 403); - Ao enviar o alinhamento, mande
audio_object_keyem vez deaudio_url.
A credencial é de uso único: ao terminar o alinhamento (sucesso ou falha) o servidor apaga o objeto e reutilizar a mesma chave dá erro.
Novo: a letra passou a ser opcional
Antes, uma música externa exigia letra. Agora pode omiti-la: o servidor faz um reconhecimento e usa o texto reconhecido como letra.
O custo tem de ficar claro: o texto passa a depender do resultado do reconhecimento, pelo que algum caractere pode estar errado. Essas respostas são marcadas com
lyrics_source: "asr", confidence: "low" e, em warnings[],
{"code":"no_reference_lyrics"}.
Para realce por caractere / KTV, forneça sempre a letra original.
Parâmetros da requisição
Headers
| Parâmetro | Tipo | Obrigatório | Observações |
|---|---|---|---|
| Authorization | string | sim | Bearer YOUR_API_KEY |
| Content-Type | string | sim | application/json |
Parâmetros do body
| Parâmetro | Tipo | Obrigatório | Padrão | Observações |
|---|---|---|---|---|
| song_id | string | um de dois | - | ID de música da plataforma |
| lyrics | string | não | - | Letra original, linhas separadas por \n. Agora pode ser omitida |
| audio_url | string | um de dois para externas | - | Endereço do áudio; precisa ser publicamente descarregável |
| audio_object_key | string | um de dois para externas | - | Chave do objeto enviado diretamente (chame antes /lyrics-align/upload-ticket) |
| vocal_separate | boolean | não | false |
Se separar a voz primeiro (só músicas da plataforma) |
| language | string | não | automático | Chinese / English etc.; se não enviar, deduzido da letra |
| granularity | string | não | both |
both / line (sem saída por caractere) / word |
| sections | string | não | keep |
keep mantém marcas como [Chorus] (não entram na linha do tempo) / drop |
| format | string | não | json |
json / lrc / lrc-word (os dois últimos devolvem também o texto lrc e lrc_word) |
Limites
| Item | Limite |
|---|---|
| Duração do áudio | ≤ 6 minutos (mais devolve erro e reembolso total) |
| Origem do áudio | Precisa ser publicamente descarregável; endereços que exijam sessão não são aceites |
| Formato da letra | Texto simples, linhas com \n; marcas de seção como [Verse] ou 【主歌】 são mantidas mas não entram na linha do tempo |
| Lotes | Uma música por chamada; para várias, faça o seu próprio ciclo |
| Guardar o resultado | Este endpoint não persiste nada; guarde você o resultado |
Exemplos de requisição
Música externa (letra + endereço do áudio)
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": "Caminhando por ruas frias\nA brisa da noite roça meus olhos\nO tempo corre como a água",
"audio_url": "https://your-bucket.example.com/song.mp3"
}'
Música da plataforma (sem separação)
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"}'
Música da plataforma + separação de voz (recomendado para karaokê)
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}'
Resposta
Resposta de sucesso
{
"success": true,
"lyrics_source": "platform",
"vocal_separate": false,
"coverage": 0.935,
"exact": 196,
"fuzzy": 4,
"total": 214,
"lines": [
{
"text": "Caminhando por ruas frias",
"start": 21.66,
"end": 24.06,
"chars": [
{"char": "C", "start": 21.66, "end": 21.74, "word": true},
{"char": "a", "start": 21.98, "end": 22.22, "word": true}
]
}
]
}
Referência dos campos
| Campo | Tipo | Observações |
|---|---|---|
success |
boolean | Se a requisição foi bem-sucedida |
lyrics_source |
string | platform = letra tirada da música da plataforma; user = letra fornecida por você; asr = não deu letra e o texto veio do reconhecimento |
vocal_separate |
boolean | Se desta vez passou por separação de voz |
confidence |
string | high / low (sempre low quando lyrics_source=asr) |
warnings[] |
array | Avisos de degradação; contém {"code":"no_reference_lyrics"} quando não houve letra |
coverage |
number | Qualidade do alinhamento: proporção de caracteres com âncora temporal clara (0–1) |
exact / fuzzy / total |
number | Caracteres exatos / homófonos / caracteres válidos da letra |
lines[].text |
string | Uma linha da letra, caractere a caractere igual ao seu original |
lines[].start / end |
number | Início e fim da linha (segundos) |
lines[].section |
boolean | Se a linha é marca de seção (true = sem tempo e sem realce) |
lines[].chars[] |
array | Tempos por caractere: char, start/end em segundos, word se entra na linha do tempo (pontuação é false) |
words[] |
array | Lista plana por caractere: text / start / end / line; não é devolvida com granularity=line |
lrc |
string | Texto LRC por linha (só com format=lrc ou lrc-word) |
lrc_word |
string | LRC por caractere melhorado, com etiquetas <mm:ss.xx> na linha (só com format=lrc-word) |
Como usar o coverage (três faixas)
| coverage | Uso sugerido |
|---|---|
| ≥ 0,9 | Dá para realce por caractere (karaokê) |
| 0,8 – 0,9 | Mistura por caractere e por linha, ou realce só por linha com o caractere como referência |
| < 0,8 | Apenas realce por linha (repetições, harmonias densas, dialetos e rap tendem a sair baixo) |
Estado e tempos
| Cenário | Tempo medido |
|---|---|
| Música da plataforma · sem separação | cerca de 4,5 s |
| Música da plataforma · separação (já há faixa de voz) | cerca de 11 s |
| Música da plataforma · separação (é preciso separar na hora) | cerca de 25 s, até cerca de 1 minuto |
| Música externa · letra + endereço do áudio | cerca de 5–15 s (conforme a duração) |
O limite de uma execução no servidor é 8 minutos; defina o timeout do cliente em 120 segundos ou mais.
Respostas de erro
{
"success": false,
"message": "音频超过 6 分钟上限(实际 7.2 分钟)"
}
| Cenário | Cobra? |
|---|---|
| Falta o áudio (nenhum dos três) | Não cobra (processamento não iniciado) |
audio_url e audio_object_key ao mesmo tempo |
Não cobra (processamento não iniciado) |
| O objeto do envio directo ainda não está ou já foi apagado | Não cobra (processamento não iniciado) |
granularity / sections / format inválidos |
Não cobra (processamento não iniciado) |
| A música da plataforma não existe / não é da conta atual | Não cobra (processamento não iniciado) |
| Parâmetros em falta ou inválidos | Não cobra (processamento não iniciado) |
| Áudio acima do limite de 6 minutos | Reembolso total |
| Áudio não descarregável (endereço não público / exige login) | Reembolso total |
| Sem letra e o reconhecimento do servidor falhou | Reembolso total |
| Marcou separação de voz mas não há faixa utilizável | Reembolso total (incluindo o preço da separação) |
| Falha ou timeout do serviço de alinhamento | Reembolso total |
Princípio: sem resultado final, reembolso total. Só se cobra quando as marcas por caractere são realmente devolvidas, e o reembolso é automático, sem pedido.
Cobrança
| Item | Quando é cobrado | Observações |
|---|---|---|
| Calibração das marcas da letra (base) | Em cada chamada | Por chamada (atualmente ¥0,1 por chamada por padrão); o valor real segue a configuração de preços do back-office |
| Taxa adicional de transcrição | Só quando não fornece letra | O servidor tem de correr um reconhecimento de fala, um custo que o escalão "com letra" não tem, por isso é tarifado à parte |
| Separação de voz (opcional, só músicas da plataforma) | Ao marcar vocal_separate |
É cobrada uma vez ao preço atual de "separação de voz/acompanhamento" e liquidada junto com este endpoint |
A combinação:
a pagar = preço base + (sem letra ? taxa de transcrição : 0) + (separação marcada ? preço da separação : 0)
A separação de voz é cobrada uma só vez: se já separou e tem a faixa de voz disponível, cobra-a este endpoint; se for preciso separar na hora, cobra-a o passo de separação.
Exemplo completo (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("qualidade do alinhamento coverage =", res["coverage"])
for line in res["lines"]:
print(f'{line["start"]:7.2f} {line["text"]}')
# karaokê por caractere: cada caractere em line["chars"] tem o seu start / end
Perguntas frequentes
P: A saída é por caractere ou por linha?
R: Ambas. lines[].start é por linha e lines[].chars[].start / end por caractere; o reprodutor usa a que precisar.
P: Porque é que o texto devolvido é igual ao que enviei? R: É o desenho. Não reconhecemos nem reescrevemos, só alinhamos tempos, por isso a letra nunca é "corrigida para gralha".
P: O coverage é alto mas ainda soa ligeiramente desviado.
R: O erro por caractere costuma andar nas dezenas de milissegundos; se a música toda estiver desviada um valor fixo, é provável que haja um trecho de silêncio no início do áudio: corte-o e tente de novo.
P: Porque é que há pouco a separação servia e agora diz "faixa de voz indisponível"? R: Os resultados da separação são endereços temporários de vida curta (medido: caducam por volta de meia hora depois). Nesse caso o endpoint tenta separar outra vez; se mesmo assim falhar, há reembolso total. Portanto "separar agora e calibrar depois" não é fiável: faça as duas coisas no mesmo fluxo.
P: Preciso de separar eu próprio uma música da plataforma?
R: Não. Com vocal_separate: true verificamos se a música já tem faixa de voz; se não houver uma utilizável, dá erro e reembolsa em vez de despachar a mixagem completa.
P: Dá para fazer lotes? R: Uma música por pedido. Para lotes, faça um ciclo; cada chamada é cobrada normalmente, por isso recomenda-se guardar os resultados em cache.
P: O resultado fica guardado? R: Este endpoint não persiste nada; guarde você o valor devolvido (as marcas por linha e por caractere vão na resposta).
Obter uma chave de API
Crie uma chave de API no console após o cadastro. Cada geração custa ¥0,6 e devolve 2 faixas, os downloads são ilimitados e não é preciso número de telefone.
Obter chave de API Voltar à visão geral