Esta API transcreve ficheiros de áudio finalizados através de tarefas em fila de espera. Envie um ficheiro, guarde o ID da tarefa devolvido e consulte a tarefa até o processamento terminar. Envie todos os pedidos por HTTPS com as credenciais da sua conta, sejam as credenciais HTTP Basic apresentadas nos exemplos ou um token API, conforme descrito em Autenticação. Mantenha as credenciais no seu servidor.
Pontos de acesso
Os dois servidores API, https://api.multi.tel e o servidor de compatibilidade https://api.multitel.net, partilham as tarefas, chaves de idempotência, limites e faturação associados à mesma conta. Diferem na codificação dos envios e no formato exterior das respostas; por isso, utilize sempre o mesmo servidor com um analisador adequado.
| Operação | Método e caminho |
|---|---|
| Informações do serviço | GET /v3/speech_to_text |
| Submeter uma tarefa | POST /v3/speech_to_text |
| Estimar sem criar uma tarefa | POST /v3/speech_to_text/estimate |
| Consultar uma tarefa | GET /v3/speech_to_text/JOB_ID |
| Liquidar uma tarefa a aguardar pagamento | POST /v3/speech_to_text/JOB_ID/settle |
| Utilização | GET /v3/speech_to_text/usage |
Em api.multi.tel, todos os caminhos também estão disponíveis com o prefixo /v1/speech-to-text em vez de /v3/speech_to_text, por exemplo POST /v1/speech-to-text/estimate. Em api.multitel.net, utilize os caminhos /v3/speech_to_text.
A resposta com as informações do serviço apresenta mode (batch), realtime (false), paidEnabled (se estão atualmente a ser aceites novas submissões pagas), pricePerMinuteUsd (0.005), billingUnit (audio_second), maxAudioSeconds (7200) e maxUploadBytes (26214400), juntamente com uma breve descrição em description. A consulta é gratuita e funciona enquanto as submissões pagas estão desativadas; só devolve 503 transcription_unavailable quando o serviço está indisponível na sua totalidade.
Preparar um ficheiro de áudio
Utilize um ficheiro de áudio finalizado com, no máximo, 25 MiB (26,214,400 bytes) e 2 horas (7,200 segundos). No momento da submissão, o ficheiro tem de ser reconhecido como um ficheiro multimédia MP3, WAV, Ogg, FLAC, MOV ou Matroska que contenha um fluxo de áudio, com uma duração nos metadados superior a zero e não superior a 7,200 segundos. Um ficheiro reconhecido que não passe estas verificações é rejeitado com 422 unsupported_audio. Um ficheiro que não possa ser lido como nenhum destes formatos pode, atualmente, ser rejeitado com um erro do servidor (500); não volte a submetê-lo sem alterações. A extensão do ficheiro, por si só, não comprova a compatibilidade.
Passar estas verificações não garante que o áudio possa ser descodificado. O áudio é processado com um ou dois canais. Um ficheiro com mais de dois canais de áudio, um ficheiro cujo áudio descodificado exceda 2 horas ou qualquer outro ficheiro cuja descodificação falhe durante o processamento resulta numa tarefa com o estado failed, normalmente com o código decode_failed, e não é cobrado. Converta o áudio multicanal em mono ou estéreo antes de o submeter.
A indicação opcional de idioma é um código de duas ou três letras minúsculas para o idioma falado, como en. Para não fornecer uma indicação, omita o campo; api.multi.tel rejeita uma cadeia vazia. A indicação orienta o processamento, mas não é verificada numa lista de idiomas suportados; por isso, utilize um código válido para o idioma falado.
Submeter uma tarefa de transcrição
Envie JSON com Content-Type: application/json para POST https://api.multi.tel/v3/speech_to_text. O corpo do pedido pode ter até 35 MiB, o que permite incluir um ficheiro de tamanho máximo após a codificação base64; um corpo maior é rejeitado com 413.
| Campo | Significado |
|---|---|
audioBase64 | Obrigatório. O ficheiro completo em base64 padrão (A–Z, a–z, 0–9, +, /) com preenchimento = quando necessário. Não adicione um prefixo de URL de dados, quebras de linha ou espaços, nem utilize o alfabeto seguro para URLs. O valor descodificado tem de ter entre 1 byte e 25 MiB, e a sua recodificação tem de produzir exatamente o mesmo texto. |
language | Indicação opcional de idioma, conforme descrito acima. |
Qualquer outra propriedade JSON, incluindo idempotency_key, é rejeitada com 400 invalid_transcription_request. Envie a chave num cabeçalho.
Chave de idempotência
Cada submissão exige um cabeçalho Idempotency-Key com 1 a 190 caracteres. Utilize letras ASCII, algarismos, -, _, . e :, sem espaços no início ou no fim: o servidor de compatibilidade remove os espaços em branco circundantes e mede a chave em bytes, pelo que outros caracteres podem ser contados de forma diferente em cada servidor. Uma chave em falta, ou uma chave com 191 ou mais caracteres, é rejeitada com 400.
As chaves são específicas da sua conta e da transcrição de áudio, abrangendo ambos os servidores e todas as credenciais da sua conta. Reenviar a mesma chave com o mesmo ficheiro e idioma devolve a tarefa existente com HTTP 200 e duplicate: true, independentemente do seu estado e mesmo que o processamento tenha sido atualizado desde a criação da tarefa, sem nova cobrança. Reutilizar uma chave com um ficheiro ou idioma diferente devolve 409 idempotency_conflict. Uma nova chave cria uma nova tarefa mesmo para um ficheiro idêntico, com uma cobrança separada se o processamento terminar com êxito.
API_USER="your-api-username"
API_PASSWORD="your-api-password"
node -e 'process.stdout.write(JSON.stringify({audioBase64:require("node:fs").readFileSync("completed-call.mp3").toString("base64"),language:"en"}))' > completed-call.json
curl --fail-with-body --silent --show-error --user "$API_USER:$API_PASSWORD" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: speech-call-001" \
--data-binary @completed-call.json \
-o speech-job.json \
https://api.multi.tel/v3/speech_to_text
node -p 'JSON.parse(require("node:fs").readFileSync("speech-job.json","utf8")).data.id'Uma nova tarefa devolve HTTP 202 com os campos abaixo, e a repetição do pedido devolve HTTP 200 com o objeto completo da tarefa descrito em Consultar a transcrição. Leia o ID da tarefa, um UUID, em data.id. A resposta de uma nova tarefa tem o seguinte aspeto (o identificador e os valores são exemplos):
{
"status": "success",
"data": {
"id": "3f6c1b2e-8a4d-4e7f-9c21-5b0d7e4a9f13",
"status": "queued",
"mode": "batch",
"realtime": false,
"source": "api",
"durationSeconds": 90.5,
"billedSeconds": 91,
"costUsd": "0.007583334",
"pricePerMinuteUsd": "0.005"
}
}Enquanto uma tarefa está em fila de espera ou em execução, durationSeconds, billedSeconds e costUsd são estimativas baseadas nos metadados do ficheiro. A cobrança final utiliza a duração descodificada.
Uma submissão também pode devolver 402 insufficient_balance quando o saldo pré-pago não cobre a tarefa em conjunto com as outras tarefas pendentes, 429 transcription_queue_full quando a sua conta ou o serviço tem demasiadas tarefas pendentes, 429 audio_validation_busy quando a validação de ficheiros atingiu a capacidade máxima, e 503 paid_transcription_not_enabled enquanto a transcrição paga está desativada. Perante respostas 429 e 503, tente novamente mais tarde com a mesma chave.
Estimar sem criar uma tarefa
Envie o mesmo corpo JSON para POST https://api.multi.tel/v3/speech_to_text/estimate. Não é necessária uma chave de idempotência. Uma estimativa valida e mede o ficheiro, mas não o transcreve, não cria uma tarefa, não reserva fundos, não verifica o saldo nem cobra a sua conta. É aceite uma indicação de idioma no campo language, mas esta não afeta a estimativa.
Uma estimativa bem-sucedida devolve HTTP 200 com estimate: true, charged: false, mode, realtime, durationSeconds, billedSeconds, pricePerMinuteUsd e costUsd em data. Utiliza a duração nos metadados do ficheiro, enquanto uma tarefa concluída é cobrada pela duração descodificada, que pode ser diferente. As estimativas aplicam as mesmas verificações de ficheiros que as submissões. Só estão disponíveis enquanto a transcrição paga está ativada (caso contrário, 503 paid_transcription_not_enabled). Podem devolver 429 audio_validation_busy quando a validação de ficheiros atingiu a capacidade máxima; tente novamente após uma breve espera.
Consultar a transcrição
Consulte periodicamente GET /v3/speech_to_text/JOB_ID conforme descrito no guia do fluxo de trabalho das tarefas. O objeto da tarefa contém estes campos:
| Campo | Significado |
|---|---|
id | O UUID da tarefa. |
status | queued, running, completed, failed ou awaiting_payment. |
progress | Uma percentagem de 0 a 99 durante a execução, quando disponível; 100 quando concluída; caso contrário, null. |
durationSeconds, billedSeconds | Duração do áudio e segundos inteiros faturados. São estimativas dos metadados enquanto a tarefa está em fila de espera ou em execução, e utilizam a duração descodificada quando a tarefa está concluída ou a aguardar pagamento. |
costUsd, costIsEstimate | O custo em dólares dos EUA, como uma cadeia decimal com nove casas decimais. costIsEstimate é true enquanto a tarefa está em fila de espera ou em execução. Uma tarefa falhada não é cobrada, embora o respetivo campo costUsd continue a apresentar a estimativa. |
pricePerMinuteUsd | 0.005 para tarefas API e 0.000 para tarefas gratuitas de gravações do Hosted PBX. |
failureCode | Para uma tarefa falhada: decode_failed (não foi possível descodificar o áudio, por exemplo, por ter mais de dois canais ou durar mais de 2 horas após a descodificação), inference_timeout (o processamento demorou demasiado), service_error ou worker_lease_lost (o processamento foi interrompido). Os códigos unsupported_audio e quality_check_failed também estão definidos. Uma tarefa a aguardar pagamento apresenta insufficient_balance, que pode permanecer após a liquidação da tarefa. |
source, modelVersion, createdAt | source é api para submissões API ou hpbx para uma tarefa de gravação do Hosted PBX da sua conta. modelVersion é uma cadeia opaca que identifica a versão do processamento. createdAt é a hora da submissão. |
duplicate | true nas respostas que devolvem uma tarefa existente. |
result | Presente apenas quando status é completed. |
| Campo do resultado | Significado |
|---|---|
text | A transcrição completa: os textos de todos os segmentos unidos por quebras de linha, pela ordem dos segmentos. |
segments | Um array de segmentos ordenados pela hora de início. Cada segmento abrange uma secção de áudio com uma duração máxima de cerca de 29 segundos. Os respetivos campos start e end (segundos desde o início do áudio) delimitam essa secção, e não palavras ou frases individuais, e as secções consecutivas podem sobrepor-se até 1 segundo. Cada segmento também tem text e language (um código de idioma, que pode estar vazio), além de channel nos resultados com dois canais. |
channelCount | 1 ou 2. Presente nos resultados atuais; pode estar ausente em resultados mais antigos. |
audioDurationMs | A duração descodificada em milissegundos. A faturação arredonda-a para cima, para segundos inteiros. |
qualityFlags | Vazio, ou review_recommended juntamente com repetition_detected (uma expressão repete-se com uma frequência anormal numa secção), no_speech (não foi transcrita qualquer fala), ou ambos. |
pipelineVersion | Pode estar presente. Um identificador opaco do processamento. |
As transcrições e as respetivas marcas temporais, etiquetas de idioma e de canal são produzidas automaticamente e a sua exatidão não é garantida. Considere qualquer indicador de qualidade um motivo para rever o resultado e compare os nomes, números e compromissos importantes com o áudio original. Os silêncios longos e as passagens de volume muito baixo são ignorados e não produzem segmentos. Os resultados não identificam os intervenientes individualmente. Quando um resultado indica um channelCount de 2, cada segmento tem um channel de A (o primeiro canal, ou canal esquerdo) ou B (o segundo canal, ou canal direito). Isto só separa os intervenientes quando cada um foi gravado num canal separado. O áudio com dois canais é faturado uma única vez pela sua duração decorrida, e não por canal. Os resultados mono não têm etiquetas de canal.
Utilizar api.multitel.net
O ponto de acesso de compatibilidade POST https://api.multitel.net/v3/speech_to_text aceita multipart/form-data com uma parte de ficheiro chamada audio e um campo opcional language, em vez de JSON com audioBase64. Um valor vazio de language é tratado como ausência de indicação. Envie o mesmo cabeçalho Idempotency-Key. Se o cabeçalho estiver ausente, este servidor também aceita um campo de formulário idempotency_key. Os campos com os nomes source, free, billing_source, realtime ou stream são rejeitados com 400 unsupported_transcription_option; os outros campos do formulário são ignorados. Este servidor também devolve estes erros:
- 400
idempotency_key_requiredpara uma chave em falta ou demasiado longa. - 400
audio_upload_requiredpara um envio em falta ou que não foi recebido na totalidade. - 400
invalid_languagepara um idioma inválido. - 413
invalid_audio_sizepara um ficheiro vazio ou demasiado grande. - 400
invalid_jobpara um ID de tarefa malformado.
As respostas do serviço de transcrição deste servidor utilizam o formato exterior {"status":{"code":HTTP_STATUS},"response":{...}}. Note que status é um objeto, não uma cadeia. Em caso de êxito, response contém o mesmo objeto que data no servidor principal, pelo que o ID da tarefa é response.id. Em caso de erro, response.code contém o código do erro; não é incluída qualquer mensagem nem ID do pedido. As falhas de autenticação (401) são devolvidas pela verificação geral de início de sessão do servidor e podem ter um corpo diferente; por isso, verifique o estado HTTP antes de analisar a resposta. Não troque a codificação dos envios nem o analisador de respostas entre servidores.
Para obter uma estimativa neste servidor, envie os mesmos campos multipart por POST para /v3/speech_to_text/estimate. Não é necessária uma chave de idempotência e a estimativa encontra-se em response.
API_USER="your-api-username"
API_PASSWORD="your-api-password"
curl --fail-with-body --silent --show-error --user "$API_USER:$API_PASSWORD" \
-H "Idempotency-Key: speech-call-001" \
-F "audio=@completed-call.mp3" -F "language=en" \
-o speech-job.json \
https://api.multitel.net/v3/speech_to_text
node -p 'JSON.parse(require("node:fs").readFileSync("speech-job.json","utf8")).response.id'