# Transcrever áudio

Da documentação da API do Lero: https://lero.studio/docs#transcricao. Tudo num arquivo só: https://lero.studio/docs/llms-full.txt.

`POST /v1/stt`

Transforma o áudio em texto, no português falado do Brasil: gírias, siglas, números e nomes no lugar. Devolve o texto com parágrafos e as frases com o tempo de início e fim; se você pedir, o tempo de cada palavra ou a legenda pronta (SRT ou VTT).

Mande o arquivo no campo `audio`, em `multipart/form-data` (até 4 MB), ou um link https público em `url` (até 500 MB; link assinado de S3, GCS ou R2 serve). Arquivo maior que 4 MB vai por `url`, num JSON com as mesmas opções. Formatos: MP3, WAV, M4A, OGG, OPUS, WEBM, FLAC e vídeo MP4 (o Lero usa o áudio do vídeo).

Custa 150 créditos por minuto de áudio (2,5 por segundo), cobrado pelo segundo e arredondado para cima, só quando a transcrição dá certo: se falhar, nada é cobrado. Conta a duração do arquivo inteiro, silêncio incluído. Exemplo: 11 min de áudio custam 1.650 créditos.

Até 2 h de áudio por pedido. A transcrição sai em cerca de 30 vezes o tempo real (1 h de áudio em uns 2 min): use timeout de 300 s. O Lero não guarda o áudio nem o texto da transcrição: apaga tudo ao responder.

| `formato` | resposta |
|---|---|
| `json` (padrão) | JSON com o texto, as frases e o custo (ao lado) |
| `texto` | `text/plain`: só o texto, com parágrafos |
| `srt` | `application/x-subrip`: a legenda SRT |
| `vtt` | `text/vtt`: a legenda WebVTT |

No JSON, `texto` traz parágrafos (`\n\n`) nas pausas longas e `segmentos` traz as frases, com `inicio` e `fim` em segundos. Com `timestamps=palavra`, cada frase traz também `palavras`: `[{inicio, fim, palavra}]`. O `formatado` vem `true` quando a revisão de pontuação e maiúsculas cobriu o texto todo. Os formatos `texto`, `srt` e `vtt` vêm em UTF-8.

Autenticação: chave com o escopo Fala (o mesmo da fala).

Corpo do pedido (multipart/form-data ou application/json):

- `audio` (file, um dos dois): O arquivo de áudio, até 4 MB: MP3, WAV, M4A, OGG, OPUS, WEBM, FLAC ou vídeo MP4. Mande `audio` ou `url`, nunca os dois.
- `url` (string, um dos dois): Link https público do áudio, até 500 MB; o Lero baixa. Para arquivo maior que 4 MB, use `url` (link assinado de S3, GCS, R2 etc. serve).
- `formato` (string, opcional): `json` (padrão), `texto` (text/plain), `srt` ou `vtt` (legendas prontas).
- `timestamps` (string, opcional): `frase` (padrão) ou `palavra`: cada segmento ganha `palavras`, com o início e o fim de cada palavra. Só no `json`.
- `palavras_chave` (string[], opcional): Até 50 nomes, marcas, siglas e termos para reconhecer e manter a grafia, ex. `["Lero", "Unflat", "CNPJ"]`. No multipart, numa lista separada por vírgula: `Lero,Unflat,CNPJ`.
- `formatar` (boolean, opcional): A revisão de pontuação e maiúsculas, padrão `true`. Com `false`, volta mais rápido, com a pontuação do reconhecimento; o preço é o mesmo.
- `idioma` (string, opcional): `pt-BR`, o único por enquanto.
- `model` (string, opcional): `Lero v1`, o único de transcrição por enquanto.

Headers da resposta:

- `X-Pedido-Id` (string): O id do pedido. Mande junto se precisar de suporte.
- `X-Creditos-Custo` (integer): Os créditos cobrados por este pedido.
- `X-Creditos-Restantes` (integer): O saldo da conta depois do pedido.
- `X-Duracao` (number): A duração do áudio, em segundos.

Responses:

- `200`: A transcrição: o JSON ao lado (`formato=json`) ou o arquivo direto (`texto`, `srt`, `vtt`), com os headers acima.
- `400`: `audio_invalido`
- `400`: `url_invalida`
- `400`: `formato_invalido`
- `400`: `idioma_invalido`
- `400`: `modelo_invalido`
- `400`: `pedido_invalido`
- `401`: `sem_chave`
- `401`: `chave_invalida`
- `401`: `chave_vencida`
- `402`: `sem_credito`
- `402`: `teto_da_chave`
- `403`: `plano`
- `403`: `escopo`
- `403`: `bloqueado`
- `413`: `audio_grande`
- `413`: `audio_longo`
- `429`: `muitos_pedidos`
- `429`: `simultaneas`
- `429`: `ocupado`
- `503`: `motor_desligado`
- `502`: `falhou`
- `504`: `demorou`
- `500`: `interno`

cURL:

```bash
# arquivo local (até 4 MB)
curl -X POST "https://app.lero.studio/api/v1/stt" \
  -H "Authorization: Bearer $LERO_API_KEY" \
  -F "audio=@reuniao.mp3" \
  -F "palavras_chave=Lero,Unflat,CNPJ" \
  --max-time 300

# link https público (até 500 MB) e a legenda pronta
curl -X POST "https://app.lero.studio/api/v1/stt" \
  -H "Authorization: Bearer $LERO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://exemplo.com/reuniao.mp3", "formato": "srt"}' \
  --max-time 300 \
  --output legenda.srt
```

Python:

```python
import os

import requests

H = {"Authorization": f"Bearer {os.environ['LERO_API_KEY']}"}

# arquivo local (até 4 MB)
with open("reuniao.mp3", "rb") as f:
    r = requests.post(
        "https://app.lero.studio/api/v1/stt",
        headers=H,
        files={"audio": f},
        data={"palavras_chave": "Lero,Unflat,CNPJ"},
        timeout=300,
    )
r.raise_for_status()
t = r.json()
print(t["texto"])
for s in t["segmentos"]:
    print(s["inicio"], s["fim"], s["texto"])

# link https público (até 500 MB) e a legenda pronta
r = requests.post(
    "https://app.lero.studio/api/v1/stt",
    headers=H,
    json={"url": "https://exemplo.com/reuniao.mp3", "formato": "srt"},
    timeout=300,
)
r.raise_for_status()
with open("legenda.srt", "wb") as f:
    f.write(r.content)
```

JavaScript:

```javascript
import { readFile, writeFile } from "node:fs/promises";

const headers = { "Authorization": `Bearer ${process.env.LERO_API_KEY}` };

// arquivo local (até 4 MB)
const form = new FormData();
form.append("audio", new Blob([await readFile("reuniao.mp3")], { type: "audio/mpeg" }), "reuniao.mp3");
form.append("palavras_chave", "Lero,Unflat,CNPJ");
const res = await fetch("https://app.lero.studio/api/v1/stt", {
  method: "POST",
  headers,
  body: form,
  signal: AbortSignal.timeout(300_000),
});
const t = await res.json();
if (!res.ok) throw new Error(`${res.status} ${t.erro}`);
console.log(t.texto);
for (const s of t.segmentos) console.log(s.inicio, s.fim, s.texto);

// link https público (até 500 MB) e a legenda pronta
const srt = await fetch("https://app.lero.studio/api/v1/stt", {
  method: "POST",
  headers: { ...headers, "Content-Type": "application/json" },
  body: JSON.stringify({ url: "https://exemplo.com/reuniao.mp3", formato: "srt" }),
  signal: AbortSignal.timeout(300_000),
});
if (!srt.ok) throw new Error(`${srt.status} ${(await srt.json()).erro}`);
await writeFile("legenda.srt", await srt.text());
```

Resposta · formato=json (200):

```json
{
  "pedido": "3f9c1e0a7b2d4c6e8a1b3d5f7e9c0a2b",
  "custo": 1650,
  "saldo": 1498350,
  "model": "Lero v1",
  "idioma": "pt-BR",
  "duracao": 659.4,
  "formatado": true,
  "texto": "Bom dia, pessoal. Hoje a pauta é o lançamento da campanha de verão.\n\nPerfeito. Então...",
  "segmentos": [
    {
      "inicio": 0.0,
      "fim": 3.2,
      "texto": "Bom dia, pessoal."
    },
    {
      "inicio": 3.4,
      "fim": 7.9,
      "texto": "Hoje a pauta é o lançamento da campanha de verão."
    }
  ]
}
```
