SovrGPT Dokumentation
API

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.

providerStärkeStimmenSprachenEmotion / TagsCloningFormat
supertonicschnell, kein KaltstartM1–M5 / F1–F531, gewählt über language<breath>/<sigh>–wav/flac
cosyvoiceDeutsch mit Emotion und Cloningde-thorsten oder eigene Stimme9, folgt dem Textvolle Inline-Tags und Emotion in natürlicher Spracheja (Zero-Shot)wav (24 kHz)
mistral (Vorgabe)Vorgabe-Engine und Stimmenkatalog: entworfene deutsche Stimmenbib-m-40, bib-f-35, … (siehe Stimmen)9, folgt dem Text––mp3/wav/opus/flac
qweneigene Stimmen ohne Mistral, vorläufigrooom-f-01, rooom-f-02, rooom-m-01, rooom-m-0210, 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.wav

Request-Body

FeldTypGilt fürBeschreibung
inputstringallePflicht. Der zu sprechende Text, ≤ 4 000 Zeichen (bei qwen ≤ 2 000). Inline-Tags je nach Provider (s. u.).
voicestringalleKatalog-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.
providerstringallesupertonic | cosyvoice | mistral | qwen. Optional; sonst aus model/voice abgeleitet, sonst Server-Vorgabe (derzeit mistral).
response_formatstringSupertonic/Mistralwav/flac (Supertonic; jeder andere Wert ergibt wav), zusätzlich mp3/opus/aac (Mistral). CosyVoice und Qwen liefern immer wav.
languagestringSupertonic/QwenDie 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 / instructionstringCosyVoiceStil- oder Emotionsanweisung in natürlicher Sprache, z. B. "Sprich sehr traurig und langsam."
reference_audio_b64stringCosyVoiceBase64 wav/flac (≤ 30 s): klont diese Stimme (Zero-Shot). Überschreibt voice. Mit provider: qwen gibt es 400 cloning_not_supported.
prompt_textstringCosyVoiceTranskript des Referenzclips (beste Qualität). Für eingebaute Stimmen automatisch.
speednumberCosyVoice0,5–2,0 (Vorgabe 1,0). Supertonic/Mistral/Qwen: akzeptiert, derzeit ignoriert.
modelstringalleWä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.

StatusBedeutung
400input 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 / 403Schlü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).
422language_not_supported (qwen): die Sprache gehört nicht zu den zehn Qwen-Sprachen, siehe supported.
429busy (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.
502Fehler beim Anbieter; bei qwen auch ein vorzeitig abgebrochener Tonstrom (stream_incomplete). Eine halbe Ansage liefern wir nicht aus.
503TTS-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 legt mistral fest, eine rooom-*-Stimme qwen.
  • selectable: ob diese Organisation die Stimme wählen darf. Katalogstimmen hängen am Tarif (siehe access), 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 vier rooom-*-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.
  • languages bleibt aus Kompatibilitätsgründen die Liste der Mistral-Stimmen; languages_by_provider nennt die Sprachen je Engine.
  • origin: designed = aus einer Beschreibung entworfen, fiktiv (gehört keiner Person); preset = Systemstimme des Anbieters; cloned = aus einer Aufnahme.
  • languages je 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: false heißt, POST /v1/audio/speech antwortet für Katalog-Stimmen mit 403 voice_not_in_plan. via nennt den Grund der Freigabe (tier ab Starter, entitlement per Berechtigung „Stimmen“).
  • samples sind ö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 öffentlichen samples, weil die Proben-Route ohne Anmeldung erreichbar ist. Stattdessen gibt es eine signierte sample_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.mp3

Eigene 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.

MethodePfadWas es tut
GET/v1/audio/voices/design-optionsDie Sprecherkartei: Merkmale, Grenzen, ob es geschaltet ist
POST/v1/audio/voices/designsEntwurf bestellen (202, läuft weiter)
GET/v1/audio/voices/designsDie Entwürfe dieser Organisation
GET/v1/audio/voices/designs/{id}Stand abholen; treibt den Auftrag voran
POST/v1/audio/voices/designs/{id}/adoptKlonen und in den Katalog eintragen
DELETE/v1/audio/voices/designs/{id}Verwerfen, Referenzclip löschen
POST/v1/audio/voices/designs/suggestAus 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).

HTTPcodeBedeutung
400invalid_request_errorunbekannte Merkmals-Kennung, Alter außerhalb 16–90, ungültiger Slug
402quota_exceededAusgabengrenze der Organisation oder des Nutzers erreicht
403voice_not_in_planTarif unter Starter und keine Berechtigung „Stimmen“
409voice_limit_reachedHöchstzahl eigener Stimmen erreicht (oder Slug vergeben)
409too_many_pendingzu viele Entwürfe laufen gleichzeitig
501not_implementedder Entwurfs-Dienst ist in dieser Umgebung nicht geschaltet
502upstream_errorWorker 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.wav

Emotion 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.wav

Eigene 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.wav

Eingebaute Stimme: de-thorsten (Deutsch, männlich, ruhig; CC0). Eigene Stimmen jederzeit über reference_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 503 mit 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.wav

Welche 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.

StimmeNameBeschreibung
rooom-f-01Beraterinweiblich, 30–35, warm, freundlich, klar, ruhiges Tempo
rooom-f-02Fachexpertinweiblich, 45–50, sachlich, souverän, deutlich artikuliert
rooom-m-01Beratermännlich, 30–35, freundlich, offen, lebendig
rooom-m-02Fachexpertemä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.wav

Vorlä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. Ohne language gilt de. Andere Codes ergeben 422 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_b64 ergibt 400), 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, kommt 429 mit Retry-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=json

Form-Felder

FeldTypVorgabeBeschreibung
fileDatei–Audio (webm/ogg/mp3/wav/m4a …), ≤ 4,5 MiB, siehe Hinweis unten. Entweder file oder upload_id.
upload_idstring–Kennung aus POST /v1/audio/uploads. Das Audio fährt dann nicht im Anfragerumpf: bis 100 MiB. Siehe „Große Dateien“ unten.
languagestring–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_formatstringjsonjson ({ "text": … }), text (Klartext), verbose_json ({ text, language, duration }, mit segments, wenn angefordert). Mit Whisper zusätzlich srt und vtt.
timestamp_granularitiesstring–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_biasstring–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_textbooleanfalseFormatiert das Transkript zusätzlich: Absätze, nummerierte Liste aus gesprochenem „erstens/zweitens/drittens“, Leerzeile nach der Anrede, abgesetzte Grußformel. Siehe unten.
modelstring–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.
promptstring–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"}'
FeldTypBeschreibung
mimestringPflicht. 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.
sizenumberPflicht. 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.

StatusBedeutung
400weder file noch upload_id, oder zwei Werte in timestamp_granularities
401 / 403Schlüssel oder Scope fehlt
404upload_id unbekannt, oder die Bytes wurden nie hochgeladen
413mehr als 4,5 MiB im Rumpf-Weg
502Fehler beim Anbieter
503Transkription 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
504Whisper: 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.verdictBedeutungWas Sie bekommen
okNur die Gliederung hat sich geändert.die formatierte Fassung
auffaelligEinzelne 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). Ohne language erkennt Whisper die Sprache selbst, verbose_json meldet sie in language; language=auto bedeutet dasselbe. Regionszusätze wie de-DE werden auf de gekürzt, und Schreibweisen, die Whisper anders führt, setzen wir um (nb/nb-NO → no, jv → jw, fil → tl, die Altcodes iw, in, ji → he, id, yi). Ein unbekannter Code ergibt 400.
  • Antwortformate: json, text, verbose_json, srt, vtt. verbose_json enthält bei Whisper immer segments in der Whisper-Form (id, start, end, text, avg_logprob, no_speech_prob …); ein leeres Feld heißt hier wirklich „keine Sprache erkannt“. Mit timestamp_granularities=word kommt words dazu, beide Stufen gleichzeitig sind erlaubt.
  • duration ist 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_bias wird bei Whisper zum prompt, wenn Sie keinen eigenen prompt schicken.
  • format_text gibt 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.

Audio-API (TTS & STT)