Audio-API (TTS & STT)
OpenAI-kompatible Audio-API – Text-to-Speech mit deutschen Stimmen und Voice-Cloning, Transkription per Voxtral, Verarbeitung in EU-Rechenzentren.
Die Audio-API bietet Sprachausgabe (POST /v1/audio/speech) und Transkription
(POST /v1/audio/transcriptions) im OpenAI-Format. Bestehende OpenAI-Audio-Clients können
Sie weiterverwenden: baseURL umstellen und eine unserer Stimmen wählen. Sprache wird in
EU-Rechenzentren erzeugt und erkannt.
Beide Endpunkte verlangen einen API-Schlüssel mit passendem Scope: speech für TTS,
transcribe für STT (siehe Authentifizierung → Berechtigungen).
Für die Sprachausgabe gibt es vier Engines. Sie wählen sie je Anfrage über das OpenAI-übliche
Feld model (supertonic-3 / cosyvoice-3 / voxtral-mini-tts / qwen3-tts) oder über
provider. Ist beides nicht gesetzt, leitet der Server die Engine aus der Stimme ab, sonst
gilt die Vorgabe-Engine: seit 26.09.2026 Mistral (EU-Endpunkt, Frankreich), vorher
Supertonic. Wer weiter Supertonic will, setzt provider: "supertonic" bzw.
model: "supertonic-3" oder wählt eine Supertonic-Stimme (M1–M5/F1–F5).
Spricht Mistral die Sprache nicht (aus language oder, bei auto, aus dem Text erkannt),
übernimmt Qwen (u. a. ru, ja, ko, zh), sonst Supertonic (u. a. tr, uk, pl, ro).
Welche Engine gesprochen hat, steht in X-Voice-Provider.
provider | Stärke | Stimmen | Sprachen | Emotion / Tags | Cloning | Format |
|---|---|---|---|---|---|---|
supertonic | schnell, kein Kaltstart | M1–M5 / F1–F5 | 31, gewählt über language | <breath>/<sigh> | – | wav/flac |
cosyvoice | Deutsch mit Emotion und Cloning | de-thorsten oder eigene Stimme | 9, folgt dem Text | volle Inline-Tags und Emotion in natürlicher Sprache | ja (Zero-Shot) | wav (24 kHz) |
mistral (Vorgabe) | Vorgabe-Engine und Stimmenkatalog: entworfene deutsche Stimmen | bib-m-40, bib-f-35, … (siehe Stimmen) | 9, folgt dem Text | – | – | mp3/wav/opus/flac |
qwen | eigene Stimmen ohne Mistral, vorläufig | rooom-f-01, rooom-f-02, rooom-m-01, rooom-m-02 | 10, gewählt über language | – | – | wav (24 kHz) |
Die Sprachzahlen sind die Angaben der jeweiligen Modellkarte. Selbst geprüft
(Rücktranskription) haben wir vor allem Deutsch, dazu Englisch bei den Katalogstimmen und
Russisch bei qwen. Für die übrigen Sprachen gibt es keine eigene Messung.
Die Transkription (STT) läuft auf Mistral Voxtral über den EU-Endpunkt von Mistral AI
(Frankreich). Wahlweise transkribiert Whisper large-v3 mit 99 Sprachen
(model=whisper-large-v3, siehe unten); dieses Modell betreiben wir selbst, auf gemieteten
GPUs in EU-Rechenzentren (zusätzlich auch in Island oder Norwegen, EWR).
KI-Kennzeichnung: Synthetisch erzeugte Sprache ist als KI-Inhalt zu kennzeichnen (EU AI Act Art. 50). WAV-, FLAC-, MP3- und Opus-Ausgaben tragen dafür Metadaten, CosyVoice-Clips zusätzlich ein unhörbares Wasserzeichen (Details: KI-Kennzeichnung). Den Hinweis an Ihre Hörer gibt Ihre Anwendung. Supertonic-Gewichte stehen unter OpenRAIL-M.
POST /v1/audio/speech — Text-to-Speech
Erzeugt gesprochenes Audio aus Text. Die Antwort ist der rohe Audio-Body ohne JSON-Hülle, wie bei OpenAI.
curl https://sovrgpt.com/api/v1/audio/speech \
-H "Authorization: Bearer $SOVR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "supertonic-3",
"input": "Guten Tag <breath> willkommen bei SovrGPT.",
"voice": "F3",
"response_format": "wav"
}' --output hallo.wavRequest-Body
| Feld | Typ | Gilt für | Beschreibung |
|---|---|---|---|
input | string | alle | Pflicht. Der zu sprechende Text, ≤ 4 000 Zeichen (bei qwen ≤ 2 000). Inline-Tags je nach Provider (s. u.). |
voice | string | alle | Katalog-Stimme per Slug (bib-m-40, bib-f-35, …; Liste: GET /v1/audio/voices, Hörproben: Stimmen); eine Katalog-Stimme legt provider: mistral fest. Außerdem Supertonic: M1–M5/F1–F5. CosyVoice: de-thorsten. Qwen: rooom-f-01, rooom-f-02, rooom-m-01, rooom-m-02 (legt provider: qwen fest). Diese Stimmen gehören fest zu ihrer Engine: Mit einem anderen provider oder model gibt es 400 voice_provider_mismatch, auch mit Referenzclip. default-de/default-en ist die Systemvorgabe: gesprochen von der Vorgabe-Engine (derzeit eine Mistral-Stimme), mit provider: supertonic von Supertonic F1 bzw. M1. |
provider | string | alle | supertonic | cosyvoice | mistral | qwen. Optional; sonst aus model/voice abgeleitet, sonst Server-Vorgabe (derzeit mistral). |
response_format | string | Supertonic/Mistral | wav/flac (Supertonic; jeder andere Wert ergibt wav), zusätzlich mp3/opus/aac (Mistral). CosyVoice und Qwen liefern immer wav. |
language | string | Supertonic/Qwen | Die gesprochene Sprache als ISO-639-1 (de, en, fr, …; de-DE gilt als de) oder auto (aus dem Text erkennen). Ohne Angabe: de (bei default-en: en). Supertonic kennt 31 Codes (en ko ja ar bg cs da de el es et fi fr hi hr hu id it lt lv nl pl pt ro ru sk sl sv tr uk vi), ein anderer Code ergibt 400 language_not_supported. Qwen kennt 10 (de en fr es it pt ru ja ko zh), ein anderer ergibt 422 language_not_supported. Die Fehlerantwort nennt die gültigen Codes in supported. Mistral und CosyVoice haben keinen Sprachparameter: Dort folgt die Sprache dem Text, das Feld wird ignoriert. |
emotion / instruction | string | CosyVoice | Stil- oder Emotionsanweisung in natürlicher Sprache, z. B. "Sprich sehr traurig und langsam." |
reference_audio_b64 | string | CosyVoice | Base64 wav/flac (≤ 30 s): klont diese Stimme (Zero-Shot). Überschreibt voice. Mit provider: qwen gibt es 400 cloning_not_supported. |
prompt_text | string | CosyVoice | Transkript des Referenzclips (beste Qualität). Für eingebaute Stimmen automatisch. |
speed | number | CosyVoice | 0,5–2,0 (Vorgabe 1,0). Supertonic/Mistral/Qwen: akzeptiert, derzeit ignoriert. |
model | string | alle | Wählt die Engine (OpenAI-Weg): supertonic-3, cosyvoice-3, voxtral-mini-tts oder qwen3-tts. Sind model und provider gesetzt, gilt provider. Jeder andere Wert, auch tts-1 oder gpt-4o-mini-tts, wird nicht abgelehnt: Dann entscheiden voice oder die Vorgabe. Welches Modell gesprochen hat, steht in x-sovrgpt-model-served. |
Antwort
200 mit Audio-Bytes. Header:
Content-Type: audio/wav (bzw. audio/flac, audio/mpeg …)
X-Voice-Provider: supertonic (oder: cosyvoice / mistral / qwen)
X-Voice: bib-m-40 (Katalog-Slug, der gesprochen hat — oder: default)
X-Voice-Language: en (nur Supertonic/Qwen: die Sprache, die gesprochen wurde)
x-sovrgpt-model-served: voxtral-mini-tts (das Modell, das gesprochen hat)
x-sovrgpt-model-requested: tts-1 (nur, wenn `model` davon abweicht)Anders als bei Chat, Embeddings und Rerank lehnen die Audio-Endpunkte eine unbekannte
model-Angabe auch künftig nicht ab. Prüfen Sie x-sovrgpt-model-served, wenn Sie eine
bestimmte Engine erwarten.
| Status | Bedeutung |
|---|---|
| 400 | input fehlt oder ist zu lang (text_too_long bei qwen über 2 000 Zeichen); unknown_voice: Den Slug gibt es nicht, er ist abgeschaltet oder gehört nicht zu qwen; voice_provider_mismatch: Die Stimme gehört zu einer anderen Engine als provider/model, etwa rooom-f-01 mit model: "supertonic-3"; language_not_supported (Supertonic); cloning_not_supported (qwen mit Referenzclip). |
| 401 / 403 | Schlüssel oder Scope fehlt. 403 voice_not_in_plan: Die Organisation hat keine Stimmenauswahl (ab Starter oder per Berechtigung „Stimmen“, siehe access in GET /v1/audio/voices). |
| 422 | language_not_supported (qwen): die Sprache gehört nicht zu den zehn Qwen-Sprachen, siehe supported. |
| 429 | busy (qwen): alle Sprachströme sind belegt. Nach einer Sekunde erneut senden (Retry-After: 1). Ein 429 von Mistral reichen wir ohne Retry-After durch, weil Mistral keine Wartezeit nennt. |
| 502 | Fehler beim Anbieter; bei qwen auch ein vorzeitig abgebrochener Tonstrom (stream_incomplete). Eine halbe Ansage liefern wir nicht aus. |
| 503 | TTS-Anbieter nicht konfiguriert, oder der CosyVoice- bzw. Qwen-Worker ist im Kaltstart; nach etwa einer Minute erneut senden |
Fehler kommen als {"error": {"message", "type", "code"}}; bei language_not_supported
steht zusätzlich die Liste supported im error-Objekt. Bei einer Störung des Sprachdienstes
(upstream_error, nicht konfigurierter Dienst) steht in message ein fester Satz. Werten Sie
type und code aus, nicht den Wortlaut. Für eine Rückfrage beim Support genügt die Uhrzeit
der Anfrage.
GET /v1/audio/voices — der Stimmenkatalog
Welche Werte voice annehmen kann und ob diese Organisation sie wählen darf. Antwortet für
jeden gültigen Schlüssel, ohne Scope, wie GET /v1/models.
curl https://sovrgpt.com/api/v1/audio/voices -H "Authorization: Bearer $SOVR_KEY"{
"object": "list",
"data": [
{
"object": "voice",
"slug": "bib-m-40",
"label": "Männlich, Anfang 40",
"origin": "designed",
"gender": "m",
"age_group": "Anfang 40",
"description": "Warm und rund, weicher Stimmansatz, ruhige Satzmelodie.",
"primary_language": "de",
"languages": ["de", "en", "fr", "es", "it", "pt", "nl", "hi", "ar"],
"samples": { "de": "/api/voice/samples/bib-m-40?lang=de", "en": "/api/voice/samples/bib-m-40?lang=en" },
"scope": "platform",
"sample_url": null,
"provider": "mistral",
"model": "voxtral-mini-tts",
"selectable": true,
"available": true
},
{
"object": "voice",
"slug": "rooom-f-01",
"label": "Beraterin (vorläufig)",
"origin": "designed",
"gender": "f",
"age_group": "30–35",
"primary_language": "de",
"languages": ["de", "en", "fr", "es", "it", "pt", "ru", "ja", "ko", "zh"],
"provider": "qwen",
"model": "qwen3-tts",
"selectable": true,
"available": true,
"status": "preliminary",
"status_note": "vorläufig — die Hörfreigabe steht aus; Klang und Kennung können sich noch ändern."
}
],
"languages": ["de", "en", "fr", "es", "it", "pt", "nl", "hi", "ar"],
"languages_by_provider": {
"mistral": ["de", "en", "fr", "es", "it", "pt", "nl", "hi", "ar"],
"supertonic": ["en", "ko", "ja", "ar", "bg", "cs", "da", "de", "el", "es", "…"],
"cosyvoice": ["zh", "en", "ja", "ko", "de", "es", "fr", "it", "ru"],
"qwen": ["de", "en", "fr", "es", "it", "pt", "ru", "ja", "ko", "zh"]
},
"access": { "selectable": true, "via": "tier", "tier": "pro", "hint": null }
}(Gekürzt: data enthält alle Katalogstimmen und dazu die festen Stimmen der Engines, also
M1–M5/F1–F5 von Supertonic, de-thorsten von CosyVoice und die vier rooom-*
von Qwen.)
provider/model: welche Engine die Stimme spricht. Eine Katalogstimme legtmistralfest, einerooom-*-Stimmeqwen.selectable: ob diese Organisation die Stimme wählen darf. Katalogstimmen hängen am Tarif (sieheaccess), die festen Engine-Stimmen nicht.available: ob die Engine in dieser Umgebung eingerichtet ist. Das sagt nichts darüber, ob gerade ein Worker läuft (Kaltstart siehe unten).status: "preliminary": Die Stimme ist vorläufig. Die vierrooom-*-Stimmen warten noch auf die Hörfreigabe; bis dahin können sich Klang und Kennung ändern. Für Produktivanwendungen, die eine feste Stimme brauchen, ist das ein Grund, noch zu warten.languagesbleibt aus Kompatibilitätsgründen die Liste der Mistral-Stimmen;languages_by_providernennt die Sprachen je Engine.origin:designed= aus einer Beschreibung entworfen, fiktiv (gehört keiner Person);preset= Systemstimme des Anbieters;cloned= aus einer Aufnahme.languagesje Stimme: die Sprachen ihrer Engine laut Modellkarte. Bei den Katalogstimmen sind das die neun Mistral-Sprachen. Die entworfenen Stimmen sind für Deutsch entworfen. Deutsch und Englisch haben wir bei den Katalogstimmen geprüft (Rücktranskription wortgleich, kein Einschwing-Knacks); in anderen Sprachen bleibt laut Anbieter eine Färbung der Ausgangssprache hörbar.access.selectable:falseheißt,POST /v1/audio/speechantwortet für Katalog-Stimmen mit403 voice_not_in_plan.vianennt den Grund der Freigabe (tierab Starter,entitlementper Berechtigung „Stimmen“).samplessind öffentlich und ohne Schlüssel abspielbar (fester Probesatz, MP3).scope:platform= für jede Organisation mit Stimmenauswahl;org= eine selbst entworfene Stimme, die nur Ihre Organisation sieht. Org-Stimmen tragen keine öffentlichensamples, weil die Proben-Route ohne Anmeldung erreichbar ist. Stattdessen gibt es eine signiertesample_url, die eine Stunde gilt.
Beispiel mit Katalog-Stimme (provider ist dann überflüssig):
curl -X POST https://sovrgpt.com/api/v1/audio/speech -H "Authorization: Bearer $SOVR_KEY" -H "Content-Type: application/json" -d '{"input":"Guten Tag, hier spricht eine entworfene Stimme.","voice":"bib-f-35","response_format":"mp3"}' -o hallo.mp3Eigene Stimme entwerfen
Eine fiktive Stimme aus einer Beschreibung erzeugen lassen, als Referenzclip ablegen und in
den Katalog übernehmen. Alle Entwurfs-Endpunkte brauchen den Scope speech. Ausnahme sind
die Optionen: Sie brauchen wie GET /v1/models nur einen gültigen Schlüssel.
| Methode | Pfad | Was es tut |
|---|---|---|
GET | /v1/audio/voices/design-options | Die Sprecherkartei: Merkmale, Grenzen, ob es geschaltet ist |
POST | /v1/audio/voices/designs | Entwurf bestellen (202, läuft weiter) |
GET | /v1/audio/voices/designs | Die Entwürfe dieser Organisation |
GET | /v1/audio/voices/designs/{id} | Stand abholen; treibt den Auftrag voran |
POST | /v1/audio/voices/designs/{id}/adopt | Klonen und in den Katalog eintragen |
DELETE | /v1/audio/voices/designs/{id} | Verwerfen, Referenzclip löschen |
POST | /v1/audio/voices/designs/suggest | Aus freier Beschreibung Merkmale vorschlagen |
GET /v1/audio/voices/design-options sagt im Feld available, ob der Entwurfs-Dienst in
dieser Umgebung geschaltet ist. Steht dort false, antwortet POST …/designs mit
501 not_implemented.
Bestellen
curl -X POST https://sovrgpt.com/api/v1/audio/voices/designs \
-H "Authorization: Bearer $SOVR_KEY" -H "Content-Type: application/json" \
-d '{
"language": "de",
"gender": "f",
"age_years": 52,
"timbre": "warm",
"character": "calm",
"tempo": "even",
"use_case": "narration",
"free_text": "leicht rauchig, Grundton um 200 Hertz",
"label": "Erzählerin, ruhig",
"slug": "erzaehlerin-ruhig",
"auto_adopt": false
}'{
"object": "voice_design",
"id": "9f1c…",
"status": "pending",
"scope": "org",
"language": "de",
"gender": "f",
"age_years": 52,
"label": "Erzählerin, ruhig",
"instruct": "Eine Frauenstimme von etwa 52 Jahren, reif und erfahren: …",
"target_hz": 203,
"band_hz": [185, 255],
"auto_adopt": false,
"measurements": { "f0_hz": null, "in_band": null, "attempts_used": null, "seconds": null },
"sample_url": null,
"cost_micro_eur": 0,
"voice_slug": null,
"error": null
}Pflicht sind gender und eines von age_years (16–90) oder age_group. Alles andere ist
freiwillig. Was Sie nicht angeben, wird je Auftrag zufällig gezogen; zwei gleiche
Bestellungen können also verschiedene Stimmen ergeben. Die gültigen Merkmals-Kennungen
liefert design-options. Eine unbekannte Kennung beantwortet der Dienst mit
400 invalid_request_error und nennt die erlaubten.
Profi-Felder: instruct ersetzt die gebaute Beschreibung vollständig (max. 2000 Zeichen),
target_hz setzt die Stimmlage fest (60–400).
Abholen
curl https://sovrgpt.com/api/v1/audio/voices/designs/9f1c… \
-H "Authorization: Bearer $SOVR_KEY"Der Aufruf treibt den Auftrag zugleich voran: Er fragt den Worker, lädt einen fertigen Clip
ab und schließt den Auftrag ab. Fragen Sie ihn alle paar Sekunden ab, bis status nicht
mehr pending ist. Ein Auftrag, der nach 20 Minuten nicht fertig ist, wird auf failed
gesetzt.
{
"object": "voice_design",
"id": "9f1c…",
"status": "ready",
"measurements": {
"f0_hz": 208.4, "p25_hz": 196, "p75_hz": 221,
"voiced_windows": 340, "in_band": true, "attempts_used": 2, "seconds": 19.5
},
"sample_url": "https://…signiert… (1 h gültig)",
"duration_ms": 42000,
"cost_micro_eur": 7583,
"voice": null
}in_band: false heißt: Keine der Ziehungen traf die bestellte Stimmlage, die beste wurde
behalten. Das ist kein Fehler, aber ein guter Grund, die Probe vor dem Übernehmen zu hören.
Zustände: pending → ready → adopted, daneben discarded und failed.
Übernehmen
curl -X POST https://sovrgpt.com/api/v1/audio/voices/designs/9f1c…/adopt \
-H "Authorization: Bearer $SOVR_KEY" -H "Content-Type: application/json" \
-d '{"slug":"erzaehlerin-ruhig","label":"Erzählerin, ruhig"}'Antwortet mit der fertigen Katalogzeile (scope: "org"). Die Stimme ist ab sofort in
GET /v1/audio/voices und als voice in POST /v1/audio/speech benutzbar.
In einem Zug geht es mit auto_adopt: true beim Bestellen: Dann wechselt der Auftrag von
ready direkt nach adopted, ohne dass jemand die Probe hören muss. Das ist der Weg für
unbeaufsichtigte Integrationen; in der App gibt es ihn bewusst nicht.
Vorschlag aus einer Beschreibung
curl -X POST https://sovrgpt.com/api/v1/audio/voices/designs/suggest \
-H "Authorization: Bearer $SOVR_KEY" -H "Content-Type: application/json" \
-d '{"text":"ruhig, etwas älter, wie eine Erzählstimme im Hörbuch"}'Gibt Merkmals-Kennungen, age_years, gender, einen Anzeigenamen, eine Begründung und bis
zu drei Hinweise zurück. Das ist ein Vorschlag, den Sie unverändert in POST …/designs
stecken oder vorher anpassen können. Der Aufruf entwirft nichts und startet keinen Worker.
Keine realen Personen. Ein genannter Prominentenname wird in hörbare Merkmale übersetzt und nicht übernommen. Beschreiben Sie, was man hört, nichts über Aussehen oder Herkunft.
Grenzen und Fehlercodes
Je Organisation 10 übernommene Stimmen und 3 gleichzeitig laufende Entwürfe (die aktuellen
Werte stehen in design-options.limits).
| HTTP | code | Bedeutung |
|---|---|---|
| 400 | invalid_request_error | unbekannte Merkmals-Kennung, Alter außerhalb 16–90, ungültiger Slug |
| 402 | quota_exceeded | Ausgabengrenze der Organisation oder des Nutzers erreicht |
| 403 | voice_not_in_plan | Tarif unter Starter und keine Berechtigung „Stimmen“ |
| 409 | voice_limit_reached | Höchstzahl eigener Stimmen erreicht (oder Slug vergeben) |
| 409 | too_many_pending | zu viele Entwürfe laufen gleichzeitig |
| 501 | not_implemented | der Entwurfs-Dienst ist in dieser Umgebung nicht geschaltet |
| 502 | upstream_error | Worker oder Laufzeit nicht erreichbar |
Abgerechnet wird die reine Synthesezeit des Entwurfs (duration_ms), nicht der Kaltstart.
Sie steht als cost_micro_eur am Auftrag und als Zeile im Verbrauch
(voice-design:qwen3-tts).
CosyVoice: Deutsch mit Emotion, Tags und eigener Stimme
Für expressives Deutsch mit Betonung, Lachen, Atmen und Voice-Cloning wählen Sie den
Provider cosyvoice. Alle Fähigkeiten: Modelle → Voice.
Inline-Tags (direkt im input): [laughter], [breath], <laughter>…</laughter>
(lachend gesprochen), <strong>…</strong> (Betonung).
# Deutsch mit Tags + Betonung
curl https://sovrgpt.com/api/v1/audio/speech \
-H "Authorization: Bearer $SOVR_KEY" -H "Content-Type: application/json" \
-d '{
"provider": "cosyvoice",
"voice": "de-thorsten",
"input": "Und dann [breath] öffnete ich die Tür. [laughter] Das war <strong>unglaublich</strong>."
}' --output tags.wavEmotion in natürlicher Sprache über emotion (bzw. instruction):
curl https://sovrgpt.com/api/v1/audio/speech \
-H "Authorization: Bearer $SOVR_KEY" -H "Content-Type: application/json" \
-d '{
"provider": "cosyvoice",
"voice": "de-thorsten",
"input": "Diese Zeiten sind für immer vorbei.",
"emotion": "Sprich sehr traurig, leise und langsam."
}' --output traurig.wavEigene Stimme (Zero-Shot-Cloning): einen Referenzclip von 10–20 s als Base64
mitgeben, dazu für die beste Qualität dessen Transkript als prompt_text:
REF=$(base64 -w0 meine_stimme.wav)
curl https://sovrgpt.com/api/v1/audio/speech \
-H "Authorization: Bearer $SOVR_KEY" -H "Content-Type: application/json" \
-d "{
\"provider\": \"cosyvoice\",
\"input\": \"Ein neuer Satz, gesprochen in meiner geklonten Stimme.\",
\"reference_audio_b64\": \"$REF\",
\"prompt_text\": \"<wörtliches Transkript des Referenzclips>\"
}" --output geklont.wavEingebaute Stimme:
de-thorsten(Deutsch, männlich, ruhig; CC0). Eigene Stimmen jederzeit überreference_audio_b64(Zero-Shot, kein Training).Kaltstart: Der CosyVoice-GPU-Worker skaliert auf null. Warm liefert er in etwa 6 s, ein kalt anlaufender Worker kann Minuten brauchen. Dann kommt
503mit dem Hinweis „warming up“; senden Sie nach etwa einer Minute erneut. Mistral (Vorgabe) und Supertonic haben keinen Kaltstart.
Sprache wählen
Die Vorgabe-Engine Mistral hat keinen Sprachparameter: Dort folgt die Sprache dem Text.
Supertonic und Qwen sprechen die Sprache, die Sie in language nennen. Ohne Angabe gilt
Deutsch (bei voice: "default-en" Englisch); der Text allein ändert daran nichts. Mit "language": "auto" erkennen wir die
Sprache aus dem Text (Schrift und häufige Funktionswörter). Ist die Erkennung unsicher, etwa
bei sehr kurzen oder gemischten Texten, gilt Deutsch.
curl https://sovrgpt.com/api/v1/audio/speech \
-H "Authorization: Bearer $SOVR_KEY" -H "Content-Type: application/json" \
-d '{"model":"supertonic-3","voice":"F3","language":"fr","input":"Bonjour, je vous lis la réponse."}' \
--output bonjour.wavWelche Sprache gesprochen wurde, steht im Antwort-Header X-Voice-Language. Ein Code, den
die Engine nicht kennt, wird abgelehnt (Supertonic 400, Qwen 422, jeweils mit der Liste
supported) und nicht still durch Deutsch ersetzt. Mistral und CosyVoice haben keinen
Sprachparameter; sie sprechen die Sprache des Textes.
Qwen3-TTS: eigene Stimmen ohne Mistral (vorläufig)
Mit provider: "qwen" (oder model: "qwen3-tts", oder einer rooom-*-Stimme) spricht
Qwen3-TTS (0.6B, Apache 2.0). Das Modell betreiben wir selbst, auf gemieteten GPUs in
EU-Rechenzentren (zusätzlich auch in Island oder Norwegen, EWR); der Text geht an keinen
fremden Sprachdienst wie Mistral.
| Stimme | Name | Beschreibung |
|---|---|---|
rooom-f-01 | Beraterin | weiblich, 30–35, warm, freundlich, klar, ruhiges Tempo |
rooom-f-02 | Fachexpertin | weiblich, 45–50, sachlich, souverän, deutlich artikuliert |
rooom-m-01 | Berater | männlich, 30–35, freundlich, offen, lebendig |
rooom-m-02 | Fachexperte | männlich, 45–50, tief, ruhig, vertrauenswürdig |
Die Stimmen sind entworfen und fiktiv; sie gehören keiner realen Person. Ohne voice
spricht rooom-f-01.
curl https://sovrgpt.com/api/v1/audio/speech \
-H "Authorization: Bearer $SOVR_KEY" -H "Content-Type: application/json" \
-d '{"provider":"qwen","voice":"rooom-m-01","language":"en","input":"Good morning, here is your summary."}' \
--output qwen.wavVorläufig. Die vier Stimmen warten noch auf die Hörfreigabe. Bis dahin können sich Klang
und Kennung ändern; GET /v1/audio/voices kennzeichnet sie mit status: "preliminary".
Selbst geprüft (Rücktranskription) sind Deutsch und Russisch, für die übrigen acht Sprachen
gibt es noch keine eigene Messung.
- Sprachen:
de en fr es it pt ru ja ko zh. Ohnelanguagegiltde. Andere Codes ergeben422 language_not_supported, Polnisch zum Beispiel. - Länge: höchstens 2 000 Zeichen je Anfrage, sonst
400 text_too_long. Längere Texte teilen Sie in Absätze auf. - Ausgabe: immer WAV, 24 kHz, mono, mit KI-Kennzeichnung in den Metadaten. Kein
Wasserzeichen, kein Stimmklonen (
reference_audio_b64ergibt400), keine Emotion-Tags. - Kaltstart: Der Worker skaliert auf null. Gemessen haben wir 50 s bis zum ersten Ton,
wenn das Abbild schon auf dem Rechner liegt, und rund zehn Minuten beim allerersten Start
auf einem neuen Rechner. Wir warten bis zu 240 s. Dauert es länger, kommt
503; senden Sie dann nach etwa einer Minute erneut. Sind alle Sprachströme belegt, kommt429mitRetry-After: 1.
POST /v1/audio/transcriptions — Speech-to-Text
Transkribiert eine hochgeladene Audiodatei (multipart/form-data).
curl https://sovrgpt.com/api/v1/audio/transcriptions \
-H "Authorization: Bearer $SOVR_KEY" \
-F file=@aufnahme.webm \
-F language=de \
-F response_format=jsonForm-Felder
| Feld | Typ | Vorgabe | Beschreibung |
|---|---|---|---|
file | Datei | – | Audio (webm/ogg/mp3/wav/m4a …), ≤ 4,5 MiB, siehe Hinweis unten. Entweder file oder upload_id. |
upload_id | string | – | Kennung aus POST /v1/audio/uploads. Das Audio fährt dann nicht im Anfragerumpf: bis 100 MiB. Siehe „Große Dateien“ unten. |
language | string | – | ISO-639-1, z. B. de. Wird in der Antwort zurückgespiegelt. Ohne Angabe bleibt language in der Antwort null, denn eine automatische Spracherkennung gibt es bei Voxtral nicht. Die Transkription selbst funktioniert auch ohne Angabe. Mit model=whisper-large-v3 erkennt Whisper die Sprache selbst und meldet sie zurück. |
response_format | string | json | json ({ "text": … }), text (Klartext), verbose_json ({ text, language, duration }, mit segments, wenn angefordert). Mit Whisper zusätzlich srt und vtt. |
timestamp_granularities | string | – | segment oder word: fügt der verbose_json-Antwort ein segments-Feld mit Zeitmarken hinzu. Genau ein Wert; segment,word wird mit 400 abgelehnt. |
context_bias | string | – | Wiederholbar. Eigennamen und Fachbegriffe, zu denen die Erkennung gezogen werden soll, etwa Produkt- oder Kundennamen. Ein Begriff darf kein Leerzeichen enthalten (Bindestriche sind erlaubt); Begriffe mit Leerzeichen werden verworfen. Höchstens 100 Einträge. |
format_text | boolean | false | Formatiert das Transkript zusätzlich: Absätze, nummerierte Liste aus gesprochenem „erstens/zweitens/drittens“, Leerzeile nach der Anrede, abgesetzte Grußformel. Siehe unten. |
model | string | – | whisper-large-v3 wählt Whisper large-v3 (siehe unten). Jeder andere Wert, auch whisper-1, und keine Angabe bedeuten Voxtral (voxtral-mini-transcribe). Abgelehnt wird kein Wert; welches Modell transkribiert hat, steht in x-sovrgpt-model-served. |
prompt | string | – | Nur Whisper: Schreibweisen und Stil vorgeben (Whispers initial_prompt). Es wirken nur die letzten rund 220 Token. |
Im Anfragerumpf gilt eine Größengrenze von 4,5 MiB. Unsere Plattform kappt
Anfragerümpfe bei 4,5 MiB, bevor dieser Endpunkt läuft. Eine größere Datei erreicht uns
deshalb nicht; Sie bekommen den Plattformfehler FUNCTION_PAYLOAD_TOO_LARGE.
Nehmen Sie Opus oder MP3 statt WAV: 4,5 MiB Opus bei 32 kbit/s sind rund 20 Minuten
Sprache, unkomprimiertes WAV reicht keine drei Minuten. Für größere Dateien gibt es den Weg
über upload_id (bis 100 MiB, nächster Abschnitt).
Große Dateien: POST /v1/audio/uploads
Die 4,5 MiB sind eine Grenze unserer Plattform und lassen sich nicht im Code anheben. Sie legen das Audio deshalb an unserer Funktion vorbei ab: Sie holen eine signierte Adresse, laden direkt dorthin hoch und nennen bei der Transkription nur noch die Kennung.
# 1. Ticket holen — derselbe Schlüssel, derselbe Scope `transcribe`
curl -s -X POST https://sovrgpt.com/api/v1/audio/uploads \
-H "Authorization: Bearer $SOVR_KEY" \
-H "content-type: application/json" \
-d '{"mime":"audio/ogg","size":18234012}'{
"upload_id": "0f1c…",
"upload_url": "https://…/storage/v1/object/upload/sign/api-audio/…",
"token": "…",
"content_type": "audio/ogg",
"max_bytes": 104857600
}# 2. Bytes direkt hochladen — NICHT an uns
curl -s -X PUT "$upload_url" \
-H "content-type: audio/ogg" \
--data-binary @aufnahme.ogg
# 3. Transkribieren, ohne Datei im Rumpf
curl -s -X POST https://sovrgpt.com/api/v1/audio/transcriptions \
-H "Authorization: Bearer $SOVR_KEY" \
-H "content-type: application/json" \
-d '{"upload_id":"0f1c…","language":"de","response_format":"verbose_json","timestamp_granularities":"segment"}'| Feld | Typ | Beschreibung |
|---|---|---|
mime | string | Pflicht. audio/mpeg, audio/mp4, audio/x-m4a, audio/aac, audio/wav, audio/webm, audio/ogg, audio/opus, audio/flac. Ein anderer Typ wird mit 415 abgelehnt, und zwar vor dem Hochladen. |
size | number | Pflicht. Größe in Bytes. Über 100 MiB → 413. |
- Ein Ticket ist Einwegware. Nach der Transkription wird die Datei gelöscht, auch wenn die Transkription fehlgeschlagen ist. Ein erneuter Versuch braucht ein neues Ticket. So entsteht bei uns kein Audioarchiv, das niemand bestellt hat.
- Abgerechnet wird die Transkription, nicht das Ticket. Ein Ticket, das Sie nie einlösen, kostet nichts.
- Der Ticket-Weg verlangt denselben Scope (
transcribe) wie die Transkription.
100 MiB ist unsere Grenze, nicht die unseres Anbieters. Welche Dateigröße und Laufzeit der Erkennungsdienst annimmt, haben wir nicht gemessen. Bei sehr langen Aufnahmen kann es sinnvoll sein zu schneiden; 100 MiB Opus bei 32 kbit/s wären rund sieben Stunden.
context_bias nur für Eigennamen. Der Parameter zieht den Text zu den gelisteten
Begriffen hin und verbiegt bei Allgemeinwortschatz korrekt erkannte Wörter. Beispiel: Ein
gelistetes „Refactoring“ hat ein richtig transkribiertes „refactoren“ zu „refactoring“
gemacht.
Antwort
{ "text": "Hallo, dies ist ein Test." }Mit response_format=verbose_json und timestamp_granularities:
{
"text": "Die Bundeswehr braucht eine souveräne Plattform. Der letzte Satz ist genau der, den wir prüfen wollen.",
"language": "de",
"duration": 7,
"segments": [
{ "text": "Die Bundeswehr braucht eine souveräne Plattform.", "start": 0.5, "end": 3.3, "speakerId": null },
{ "text": "Der letzte Satz ist genau der, den wir prüfen wollen.", "start": 3.6, "end": 6.9, "speakerId": null }
]
}segments steht nur in der Antwort, wenn timestamp_granularities gesetzt war; ein leeres
Feld wäre von „nichts erkannt“ nicht zu unterscheiden. Die Zeitmarken beziehen sich immer
auf den unformatierten Text. format_text ist ein zweiter Modelldurchgang mit eigener
Wortwahl, für den es keine Zeitmarken gibt. speakerId ist derzeit immer null.
Jede erfolgreiche Antwort trägt x-sovrgpt-model-served (voxtral-mini-transcribe oder
whisper-large-v3). Weicht Ihr model davon ab, etwa whisper-1, steht es zusätzlich in
x-sovrgpt-model-requested.
| Status | Bedeutung |
|---|---|
| 400 | weder file noch upload_id, oder zwei Werte in timestamp_granularities |
| 401 / 403 | Schlüssel oder Scope fehlt |
| 404 | upload_id unbekannt, oder die Bytes wurden nie hochgeladen |
| 413 | mehr als 4,5 MiB im Rumpf-Weg |
| 502 | Fehler beim Anbieter |
| 503 | Transkription in dieser Umgebung nicht konfiguriert. Bei Whisper auch: der Worker fährt gerade hoch oder lädt noch das Modell, in 1–2 Minuten erneut senden. Mit upload_id ist das Ticket dann verbraucht: Audio neu hochladen (POST /v1/audio/uploads) und die neue upload_id senden |
| 504 | Whisper: der Worker rechnete bei Ablauf der Wartezeit schon mindestens zwei Minuten an der Aufnahme; teilen Sie sie. Voxtral: der Erkennungsdienst hat nicht innerhalb von 270 Sekunden geantwortet; erneut senden |
format_text — Transkript mit Struktur
Ein Rohtranskript hat Satzzeichen und Großschreibung, aber keine Absätze, keine Aufzählungen
und keine Leerzeile nach der Anrede. Mit format_text=1 läuft deshalb zusätzlich ein zweiter
Durchlauf über ein Modell mit Audio-Verständnis, das diese Struktur setzt. Beide Durchläufe
starten gleichzeitig; die Antwortzeit ist die des langsameren.
curl https://sovrgpt.com/api/v1/audio/transcriptions \
-H "Authorization: Bearer $SOVR_KEY" \
-F file=@diktat.webm \
-F format_text=1 \
-F response_format=verbose_json{
"text": "Sehr geehrte Frau Dr. Schmitt,\n\nvielen Dank …\n\n1. Die Übertragung …\n2. Die Antwortzeiten …\n\nMit freundlichen Grüßen\nMax Mustermann",
"text_raw": "Sehr geehrte Frau Dr. Schmitt, vielen Dank … Erstens die Übertragung …",
"language": null,
"duration": 101,
"formatting": { "applied": true, "verdict": "ok", "coverage": 0.996 }
}Der Wortlaut ist geschützt. Ein Modell, das formatieren soll, kann dabei umformulieren oder kürzen, und das Ergebnis sieht trotzdem tadellos aus. Deshalb prüfen wir jede formatierte Fassung vor der Auslieferung gegen das Rohtranskript:
formatting.verdict | Bedeutung | Was Sie bekommen |
|---|---|---|
ok | Nur die Gliederung hat sich geändert. | die formatierte Fassung |
auffaellig | Einzelne Wörter weichen ab. | die formatierte Fassung; text_raw gegenlesen |
— (applied: false) | Der Wortlaut wurde verändert oder der Durchlauf schlug fehl. | das Rohtranskript, dazu formatting.reason |
text_raw ist bei format_text=1 immer dabei, auch wenn die Formatierung angewendet wurde.
Wer auf den wörtlichen Text angewiesen ist, liest text_raw und ignoriert text.
format_text ist standardmäßig aus; Bestandsintegrationen bekommen dieselben Bytes wie
bisher.
Grenzen des formatierten Pfads. Er nutzt ein anderes Modell als der Rohpfad und kennt
deshalb context_bias, Sprechertrennung und Wort-Zeitstempel nicht; diese wirken nur auf
text_raw. Außerdem verarbeitet er höchstens etwa 20 Minuten Audio je Anfrage (der
Rohpfad deutlich mehr). Für Diktate reicht das, für Mitschnitte langer Besprechungen nicht.
Whisper large-v3 — 99 Sprachen im Selbstbetrieb
Mit model=whisper-large-v3 transkribiert Whisper large-v3 statt Voxtral. Das Modell
betreiben wir selbst, auf gemieteten GPUs in EU-Rechenzentren (zusätzlich auch in Island oder
Norwegen, EWR); das Audio geht an keinen externen Sprachdienst.
curl https://sovrgpt.com/api/v1/audio/transcriptions \
-H "Authorization: Bearer $SOVR_KEY" \
-F model=whisper-large-v3 \
-F file=@interview.ogg \
-F response_format=vtt- 99 Sprachen plus Kantonesisch (
yue). Ohnelanguageerkennt Whisper die Sprache selbst,verbose_jsonmeldet sie inlanguage;language=autobedeutet dasselbe. Regionszusätze wiede-DEwerden aufdegekürzt, und Schreibweisen, die Whisper anders führt, setzen wir um (nb/nb-NO→no,jv→jw,fil→tl, die Altcodesiw,in,ji→he,id,yi). Ein unbekannter Code ergibt400. - Antwortformate:
json,text,verbose_json,srt,vtt.verbose_jsonenthält bei Whisper immersegmentsin der Whisper-Form (id,start,end,text,avg_logprob,no_speech_prob…); ein leeres Feld heißt hier wirklich „keine Sprache erkannt“. Mittimestamp_granularities=wordkommtwordsdazu, beide Stufen gleichzeitig sind erlaubt. durationist das Ende des letzten erkannten Abschnitts, nicht die Länge der Datei. Stille am Ende zählt nicht mit. Nach dieser Dauer wird abgerechnet.context_biaswird bei Whisper zumprompt, wenn Sie keinen eigenenpromptschicken.format_textgibt es mit Whisper nicht (400). Der Formatierungsdurchgang läuft bei einem anderen Anbieter; wer Whisper wählt, damit das Audio beim selbst betriebenen Modell bleibt, soll es nicht ungefragt dorthin geschickt bekommen.- Die Vorgabe bleibt Voxtral. Auch
model=whisper-1, das OpenAI-Clients oft fest eintragen, geht an Voxtral. - Große Dateien über
upload_id(bis 100 MiB): Der Worker liest das Audio dann selbst über eine kurzlebige Adresse aus unserem Speicher. Das Ticket wird danach wie immer gelöscht.
Kaltstart. Der Whisper-Worker skaliert auf null. Der erste Aufruf nach einer Pause kann
mit 503 („warming up“) enden; senden Sie nach 1–2 Minuten erneut. Das gilt auch, wenn der
Worker den Auftrag schon angenommen hat und noch das Modell lädt: dieser Auftrag läuft weiter
und macht das Modell für Ihren nächsten Versuch warm. Mit upload_id ist das Ticket danach
verbraucht: laden Sie das Audio neu hoch (POST /v1/audio/uploads) und senden Sie die neue
upload_id; die Fehlermeldung sagt das ebenfalls. Die Kaltstartzeit haben wir noch nicht
gemessen. Eine Anfrage wartet höchstens rund vier Minuten auf das Ergebnis; rechnet der Worker dann schon
mindestens zwei Minuten an der Aufnahme, endet sie mit 504, und Sie teilen sie. Wie lang
eine Aufnahme dafür sein darf, haben wir ebenfalls noch nicht gemessen.
whisper-large-v3 erscheint in GET /v1/models, sobald das Modell auf der Umgebung
eingerichtet ist. Solange das nicht so ist, antwortet dieser Endpunkt dafür mit 503.
SDK-Beispiel (OpenAI-Client)
from openai import OpenAI
client = OpenAI(base_url="https://sovrgpt.com/api/v1", api_key=SOVR_KEY)
# Text-to-Speech (Supertonic, schnell)
client.audio.speech.create(
model="supertonic-3", voice="F3", response_format="wav",
input="Hallo Welt <sigh> das war ein langer Tag.",
).stream_to_file("hallo.wav")
# Text-to-Speech (CosyVoice, deutsch + Emotion)
# model="cosyvoice-3" wählt die Engine; emotion (SovrGPT-Extension) via extra_body
client.audio.speech.create(
model="cosyvoice-3", voice="de-thorsten", response_format="wav",
input="Was für ein wunderbarer Tag!",
extra_body={"emotion": "Sprich fröhlich und aufgeregt."},
).stream_to_file("froehlich.wav")
# Speech-to-Text
with open("aufnahme.webm", "rb") as f:
tr = client.audio.transcriptions.create(
model="voxtral-mini-transcribe", file=f, language="de",
)
print(tr.text)
# Speech-to-Text mit Whisper large-v3 (99 Sprachen, Sprache wird erkannt)
with open("interview.ogg", "rb") as f:
tr = client.audio.transcriptions.create(
model="whisper-large-v3", file=f, response_format="verbose_json",
)
print(tr.language, tr.text)Im Chat
Im Chat geht Sprache ohne API: Das Mikrofon-Symbol im Eingabefeld diktiert (STT), der Lautsprecher-Button an jeder Assistenten-Antwort liest vor (TTS). Die Stimme wählt jeder Nutzer unter Einstellungen → Stimmen (ab Starter oder per Berechtigung); Hörproben unter Stimmen. Siehe auch Modelle → Voice.
Vorgelesen wird in der Sprache der Antwort: Sie wird aus dem Antworttext erkannt
(language: "auto", Codeblöcke und Links zählen dabei nicht mit). Ist der Text dafür zu
kurz oder gemischt, gilt die Sprache der Oberfläche, sonst Deutsch.
Im Chat liest die Standardstimme (derzeit Mistral, in anderen Sprachen Supertonic), eine gewählte
Katalogstimme oder eine gewählte Supertonic-Stimme vor, alle ohne Kaltstart. CosyVoice
und Qwen3-TTS laufen auf GPU-Workern, die auf null skalieren; sie sind deshalb nur über
POST /v1/audio/speech erreichbar.