Fluxo de cadastro
- Cadastra nome/email em
/cadastro.html - Confirma o email pelo link mágico que chega na caixa de entrada
- Aguarda o admin aprovar o cadastro
- Entra em
/painel.html(login por link, sem senha) e cria suas chaves de API por lá
Autenticação
Todo request precisa do header:
Authorization: Bearer SUA_CHAVE
(ou X-API-Key: SUA_CHAVE).
| código | motivo |
|---|---|
401 | chave ausente ou inválida |
403 | email não verificado, ou cadastro aguardando aprovação do admin |
402 | créditos insuficientes |
Créditos e uso
Cada chave de API (criada no /painel.html) tem seu próprio saldo de créditos, definido pelo admin. Consumo:
| endpoint | custo |
|---|---|
/api/tts | 1 crédito por caractere do texto enviado (checado antes de gerar; estornado se falhar) |
/api/transcricao | 1 crédito por token retornado pelo provedor (checado depois de transcrever, exige saldo > 0 antes de começar) |
POST /api/tts
{
"texto": "texto a narrar",
"engine": "edge",
"voz": "antonio",
"rate": "+0%",
"pitch": "+0Hz"
}
Resposta: audio/mpeg (mp3).
| engine | voz | obs |
|---|---|---|
edge | antonio | masculina, pt-BR |
francisca | feminina, pt-BR | |
thalita | feminina, pt-BR | |
duarte | masculina, pt-PT | |
piper | cadu | masculina, offline, empacotada (resposta rápida) |
faber | masculina, offline, baixada sob demanda | |
jeff | masculina, offline, baixada sob demanda | |
edresson | masculina, offline, baixada sob demanda |
rate e pitch só valem pra engine edge.
POST /api/transcricao
Body: bytes crus do áudio. Headers opcionais:
| header | default |
|---|---|
X-Audio-Filename | audio.mp3 |
X-Idioma | pt |
curl -X POST https://ttsapi-delta.vercel.app/api/transcricao \ -H "Authorization: Bearer SUA_CHAVE" \ -H "X-Audio-Filename: fala.mp3" \ --data-binary @fala.mp3
Provedor usado, em ordem de prioridade (o primeiro configurado no servidor):
| provedor | modelo |
|---|---|
| Groq | whisper-large-v3-turbo |
| OpenAI | whisper-1 |
| OpenRouter | openai/whisper-large-v3 (padrão, configurável via OPENROUTER_STT_MODEL) |
Outros modelos de transcrição disponíveis no OpenRouter (preço por minuto de áudio):
| modelo | preço/min |
|---|---|
qwen/qwen3-asr-flash | $0.000035 |
nvidia/parakeet-tdt-0.6b-v3 | $0.0015 |
openai/whisper-large-v3 | $0.0015 |
mistralai/voxtral-mini-transcribe | $0.003 |
openai/whisper-1 | $0.016 |
google/chirp-3 | $0.016 |
Textos longos (evitar timeout)
/api/tts não quebra o texto sozinho. Se a síntese passar do timeout da function, ela é encerrada à força e o crédito já debitado não volta (o estorno automático só roda se o próprio código Python falhar, não quando a Vercel mata o processo por tempo).
Quebre o texto no seu lado, respeitando fim de frase, em pedaços de até ~3000 caracteres, chame /api/tts uma vez por pedaço, e concatene os .mp3 recebidos (colar os bytes um atrás do outro já funciona pra tocar em sequência).
import re, requests
def dividir_em_pedacos(texto, tamanho_max=3000):
frases = re.split(r'(?<=[.!?])\s+', texto)
pedacos, atual = [], ''
for frase in frases:
if len(atual) + len(frase) + 1 > tamanho_max:
pedacos.append(atual.strip())
atual = frase
else:
atual = f'{atual} {frase}'.strip()
if atual:
pedacos.append(atual)
return pedacos
audio_completo = bytearray()
for pedaco in dividir_em_pedacos(texto_longo):
resposta = requests.post(
'https://SEU-DEPLOY.vercel.app/api/tts',
headers={'Authorization': 'Bearer SUA_CHAVE'},
json={'texto': pedaco, 'engine': 'edge', 'voz': 'antonio'},
)
resposta.raise_for_status()
audio_completo.extend(resposta.content)
Custo em créditos é por caractere, cobrado em cada pedaço — quebrar não aumenta o custo total, só evita o timeout.