Speech-to-text
POST /v1/audio/transcriptions
Trascrive l'audio in testo. Compatibile con l'API Audio Transcriptions di OpenAI — lo stesso endpoint serve i modelli OpenAI (Whisper / GPT-4o-transcribe), Google Cloud Chirp, BytePlus Seed ASR e Alibaba Qwen3-ASR, e il gateway instrada verso l'upstream corretto in base all'ID del modello. Accetta un upload multipart/form-data (compatibile con l'SDK OpenAI) oppure un corpo application/json con audio codificato in base64.
Corpo della richiesta
| Parametro | Tipo | Descrizione |
|---|---|---|
model* | string | ID del modello di trascrizione (es. whisper-1, gpt-4o-transcribe, chirp-3, seed-asr-bigmodel, fun-asr, qwen3-asr-flash). Vedi Modelli supportati più sotto. |
file* | file | solo multipart — il file audio da trascrivere. Obbligatorio a meno che non venga fornito input_audio (JSON). |
input_audio* | object | solo JSON — { "data": "<base64>", "format": "mp3" }, oppure { "url": "<fetchable URL>" } per i modelli offline (seed-asr-bigmodel). Da usare al posto di file per le richieste application/json. |
response_format | string | Formato di output: json (default; restituisce {text, usage}), text (stringa grezza della trascrizione), verbose_json (segmenti con timestamp), diarized_json (segmenti etichettati per parlante — diarizzazione). I valori consentiti dipendono dal modello; vedi Formati di risposta più sotto. |
language | string | Suggerimento ISO-639-1 facoltativo (es. "en") per migliorare accuratezza e latenza. |
prompt | string | Testo facoltativo per guidare lo stile della trascrizione / l'ortografia dei nomi propri. |
temperature | number | Temperatura di campionamento 0–1. Default: 0. |
stream | boolean | Se true, restituisce eventi SSE con trascrizioni parziali. Supportato solo su gpt-4o-transcribe / gpt-4o-mini-transcribe. Gli altri modelli (whisper-1, chirp-2, chirp-3, seed-asr-bigmodel, qwen3-asr-flash) NON supportano lo streaming e restituiscono 400 se stream=true. Default: false. |
provider | object | Configurazione pass-through del provider. Vedi Pass-through del provider più sotto. |
Modelli supportati
Non sai quale modello scegliere? Scegli in base a ciò che ti serve
| Cosa serve | Attivalo con | Modelli consigliati |
|---|---|---|
| Cinese / cantonese, basso costo | — | seed-asr-bigmodel fun-asr |
| Inglese, alta qualità | — | gpt-4o-transcribe chirp-3 |
| Diarizzazione dei parlanti — chi ha detto cosa | response_format=diarized_json | seed-asr-bigmodel chirp-3 gpt-4o-transcribe-diarize |
| Timestamp a livello di parola | response_format=verbose_json | whisper-1 |
| Sottotitoli in tempo reale (mentre parli) | stream=true | gpt-4o-transcribe |
| Registrazioni lunghe / riunioni | pass a public URL in input_audio.url | seed-asr-bigmodel fun-asr |
| Modello | Provider · fatturazione | Input | Diarizzazione | Stream | Ideale per |
|---|---|---|---|---|---|
whisper-1 | OpenAI · $0.006/min | file | — | — | Timestamp a livello di parola (verbose_json); la lingua deve essere ISO-639-1 |
gpt-4o-transcribe | OpenAI · token | file | — | ✓ | Inglese, alta precisione; supporta lo streaming |
gpt-4o-mini-transcribe | OpenAI · token | file | — | ✓ | Multilingue più economico; supporta lo streaming |
gpt-4o-transcribe-diarize | OpenAI · token | file | ✓ | — | Diarizzazione in inglese; known_speaker_names facoltativo |
chirp-3 | Google · $0.016/min | file | ✓ | — | Alta qualità; singola chiamata ≤60 s |
chirp-2 | Google · $0.016/min | file | — | — | USM multilingue; usa chirp-3 per la diarizzazione |
seed-asr-bigmodel | BytePlus · $0.002/min | URL / file | ✓ | — | Cinese, registrazioni lunghe; il più economico |
fun-asr | Alibaba · $0.0021/min | URL / file | ✓ | — | Cinese · cantonese · dialetti; registrazioni lunghe |
fun-asr-mtl | Alibaba · $0.0021/min | URL / file | ✓ | — | Multilingue + diarizzazione |
fun-asr-flash | Alibaba · $0.0021/min | file | — | — | Multilingue veloce; ≤10 MB, sincrono |
qwen3-asr-flash | Alibaba · $0.0021/min | file | — | — | Multilingue; ≤5 min/chiamata, fatturazione esatta |
Diarization = imposta response_format=diarized_json per ottenere segments[].speaker. Limite di caricamento predefinito 25 MB (vedi Formati audio).
La disponibilità dipende dai canali abilitati per il tuo workspace — chiama /v1/models per vedere cosa puoi usare.
Insidie comuni. (1) Lo streaming (stream=true) funziona solo su gpt-4o-transcribe / gpt-4o-mini-transcribe — tutti gli altri modelli restituiscono 400. (2) input_audio.url (input tramite URL) è supportato solo da seed-asr-bigmodel; tutti gli altri modelli richiedono un file o un upload base64. (3) Il parametro language sui modelli OpenAI (whisper-1, gpt-4o-*) deve essere un codice ISO-639-1 come en o zh — i codici locale come yue-CN vengono rifiutati; Chirp / Seed ASR / Qwen accettano codici locale, oppure ometti language per il rilevamento automatico. (4) Se l'audio supera il limite per richiesta di un modello, suddividilo in blocchi — oppure usa seed-asr-bigmodel (tramite URL) per le registrazioni lunghe (~20 min/richiesta). (5) Audio silenzioso / senza parlato restituisce 200 con una stringa vuota {"text":""}, non un errore.
Formati audio supportati
mp3wavoggflacm4a
Per gli upload multipart il formato viene dedotto dall'estensione del file. Per le richieste base64 (JSON), imposta input_audio.format esplicitamente. Dimensione massima di upload: 25 MB.
Formati di risposta
I valori di response_format accettati dipendono dal modello. json è il default per tutti i modelli (restituisce { text, usage }); text restituisce la stringa grezza della trascrizione.
whisper-1—json,text,verbose_jsongpt-4o-transcribe,gpt-4o-mini-transcribe—json,textchirp-3,chirp-2,seed-asr-bigmodel,qwen3-asr-flash,fun-asr-flash—json,textgpt-4o-transcribe-diarize,chirp-3,seed-asr-bigmodel,fun-asr,fun-asr-mtl— alsodiarized_json(segmenti etichettati per parlante; vedi sotto)
verbose_json (timestamp dei segmenti) è solo per whisper-1. Richiedere un formato non supportato restituisce un 400.
Diarizzazione dei parlanti
Imposta response_format=diarized_json per ottenere segmenti etichettati per parlante — la risposta aggiunge un array segments in cui ogni voce riporta un'etichetta speaker più i timestamp start/end (in secondi). Supportato su gpt-4o-transcribe-diarize (OpenAI), chirp-3 (Google), seed-asr-bigmodel (BytePlus — miglior rapporto qualità-prezzo per il cinese e le registrazioni lunghe) e fun-asr / fun-asr-mtl (Alibaba — file di registrazione offline, accetta un URL o un file). Altri modelli ignorano diarized_json e restituiscono testo semplice; chirp-2 lo rifiuta (usa chirp-3).
Le etichette dei parlanti sono native del provider (ad es. "0"/"1" per chirp-3 e seed-asr, "A"/"B" per gpt-4o-transcribe-diarize); identificano parlanti distinti ma non sono identità reali stabili. Su gpt-4o-transcribe-diarize puoi passare known_speaker_names per orientare l'etichettatura.
# Chinese meeting, cheapest diarization (BytePlus seed-asr):
curl https://synthorai.io/v1/audio/transcriptions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "seed-asr-bigmodel",
"input_audio": { "url": "https://your-bucket/signed/meeting.wav", "language": "zh" },
"response_format": "diarized_json"
}'
# English / highest quality (Google chirp-3, <=60 s per request):
curl https://synthorai.io/v1/audio/transcriptions \
-H "Authorization: Bearer YOUR_API_KEY" \
-F model=chirp-3 \
-F file=@call.wav \
-F response_format=diarized_json Esempio di risposta
{
"task": "transcribe",
"text": "喂 你好 我这边是客服 有什么可以帮您",
"duration": 6.2,
"segments": [
{ "id": 0, "start": 0.10, "end": 0.90, "speaker": "0", "text": "喂 你好" },
{ "id": 1, "start": 1.20, "end": 6.20, "speaker": "1", "text": "我这边是客服 有什么可以帮您" }
]
} Esempio di richiesta (multipart)
curl https://synthorai.io/v1/audio/transcriptions \
-H "Authorization: Bearer YOUR_API_KEY" \
-F model=gpt-4o-transcribe \
-F file=@meeting.mp3 \
-F response_format=json \
-F language=en Esempio di richiesta (JSON base64)
POST /v1/audio/transcriptions
Authorization: Bearer YOUR_API_KEY
Content-Type: application/json
{
"model": "gpt-4o-transcribe",
"input_audio": {
"data": "UklGRiQAAABXQVZFZm10I...",
"format": "wav"
},
"response_format": "json",
"language": "en"
} Esempio — ASR offline (seed-asr-bigmodel)
seed-asr-bigmodel (ASR offline overseas di BytePlus) accetta due input mutuamente esclusivi: un input_audio.url raggiungibile (consigliato — un tuo URL firmato a scadenza verso l'object storage; l'audio non tocca mai il nostro storage), oppure un upload diretto di file/byte (lo depositiamo in un bucket privato e lo eliminiamo subito dopo la trascrizione). Limitazioni: nessuno streaming (stream=true restituisce 400); upload di file fino a 25 MB (usa un URL per registrazioni più grandi); l'elaborazione per singola richiesta è limitata a ~20 minuti, quindi suddividi gli audio molto lunghi. Fatturato in base alla durata dell'audio ($0.002/min).
# ① Quick test — replace ONLY YOUR_API_KEY and run it (uses our hosted sample audio).
curl https://synthorai.io/v1/audio/transcriptions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "seed-asr-bigmodel",
"input_audio": {
"url": "https://synthorai-asr-sample-360831509259.s3.us-west-1.amazonaws.com/seed-asr-sample.wav",
"language": "zh"
}
}'
# → {"text":"..."}
# ② Your own audio file (<=25 MB) — replace key + file path.
curl https://synthorai.io/v1/audio/transcriptions \
-H "Authorization: Bearer YOUR_API_KEY" \
-F model=seed-asr-bigmodel \
-F language=zh \
-F file=@/path/to/your-audio.wav
# ③ Your own signed URL (recommended for large files / privacy) — replace key + URL.
curl https://synthorai.io/v1/audio/transcriptions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"seed-asr-bigmodel","input_audio":{"url":"https://your-bucket/signed/meeting.wav","language":"zh"}}' Note / avvertenze: (1) language è facoltativo — valori comuni sono zh (mandarino), yue-CN (cantonese), en-US; omettilo per il rilevamento automatico. (2) Quando usi input_audio.url, l'URL deve essere raggiungibile pubblicamente dal servizio di trascrizione — un URL privato/interno/protetto da autenticazione fallirà; un URL firmato a scadenza (pre-signed) verso l'object storage è il modo consigliato. (3) Upload di file e URL sono mutuamente esclusivi; scegline uno. (4) Un audio senza parlato riconoscibile (silenzio) restituisce 200 con una stringa vuota {"text":""}, non un errore.
Esempio — SDK OpenAI Python
L'endpoint è compatibile OpenAI, quindi l'SDK OpenAI ufficiale funziona direttamente sovrascrivendo base_url. Funziona allo stesso modo per whisper-1, gpt-4o-transcribe, chirp-3, seed-asr-bigmodel e qwen3-asr-flash — basta cambiare model.
from openai import OpenAI
client = OpenAI(
base_url="https://synthorai.io/v1",
api_key="YOUR_API_KEY",
)
with open("meeting.mp3", "rb") as f:
result = client.audio.transcriptions.create(
model="gpt-4o-transcribe",
file=f,
language="en",
# prompt="Synthorai, BYOK, transcribe", # optional vocabulary hint
response_format="json",
)
print(result.text)
# Token-level usage on gpt-4o-*:
if getattr(result, "usage", None):
print(result.usage) Esempio — SDK OpenAI Node.js
import OpenAI from "openai";
import fs from "node:fs";
const client = new OpenAI({
baseURL: "https://synthorai.io/v1",
apiKey: process.env.SYNTHORAI_API_KEY,
});
const result = await client.audio.transcriptions.create({
model: "gpt-4o-transcribe",
file: fs.createReadStream("meeting.mp3"),
language: "en",
response_format: "json",
});
console.log(result.text); Streaming (SSE)
Imposta stream=true su gpt-4o-transcribe, gpt-4o-mini-transcribe per ricevere eventi incrementali man mano che l'audio viene decodificato. Il Content-Type della risposta è text/event-stream e gli eventi terminano con data: [DONE]. whisper-1 non supporta lo streaming (restituisce 400 se stream=true).
Tipi di evento che vedrai per gpt-4o-transcribe:
data: {"type":"transcript.text.delta","delta":"Hello "}
data: {"type":"transcript.text.delta","delta":"world."}
data: {"type":"transcript.text.done","text":"Hello world."}
data: {"type":"usage","usage":{"type":"tokens","input_tokens":689,"output_tokens":287,"total_tokens":976,"input_token_details":{"audio_tokens":689,"text_tokens":0,"cached_tokens":0}}}
data: [DONE] Il gateway emette un oggetto canonico usage documentato sotto Esempio di risposta. L'evento finale usage contiene sempre la suddivisione completa di input_token_details per una fatturazione accurata basata sulla durata audio.
Errori
Tutti gli errori seguono l'envelope OpenAI: { error: { message, type, code, param? } }. Casi comuni:
400 model_not_found— il modello non ha capacità di trascrizione nei canali di questo workspace.400 byok_strict_no_key— il workspace è in BYOK rigoroso (byok_fallback_to_pool=false) e non ha alcuna chiave nel vault per il provider risolto.400 content_policy_violation— il campopromptha attivato una regola guardrail (es. fuga di una chiave BYOK).402 quota_exceeded— il costo stimato supera la quota residua del workspace. BYOK è esente.408— il corpo della richiesta non ha terminato l'upload entro il timeout di lettura del server. Comune con audio di grandi dimensioni su connessioni lente; riprova o invia un file più piccolo.413— l'audio supera il limite di 25 MB.502 upstream_error— errore di rete upstream o risposta non 2xx dal provider del modello.
Esempio di risposta
{
"text": "Thanks for joining today's call. Let's get started.",
"usage": {
"type": "tokens",
"input_tokens": 689,
"output_tokens": 287,
"total_tokens": 976,
"input_token_details": {
"audio_tokens": 689,
"text_tokens": 0,
"cached_tokens": 0
}
}
} Oggetto usage uniforme. I modelli di trascrizione fatturati a token (gpt-4o-transcribe / -mini) restituiscono un oggetto usage uniforme — tutti i campi sono sempre presenti, azzerati quando un sotto-conteggio non viene riportato. I modelli OpenAI riportano la suddivisione nativa dell'input audio/testo, quindi per la trascrizione di solo audio input_token_details.audio_tokens == input_tokens vale in genere. cached_tokens è la parte di input servita da una cache lato provider.
whisper-1 è l'unica eccezione: viene fatturato in base alla durata dell'audio, non ai token, quindi la sua risposta non contiene alcun oggetto usage con i token. Con response_format=text il corpo della risposta è la stringa grezza della trascrizione invece di un oggetto JSON.