whisper-large-v3-turbo ist über denselben /v1/audio/transcriptions-Endpunkt wie die OpenAI Whisper API zugänglich, sodass jeder für OpenAI geschriebene Code durch Änderung der base_url direkt übernommen werden kann. Unterstützte Formate, Sprachcodes und Inferenzparameter auf der Whisper-Modellseite.
Für Sprechertrennung, Wort-Zeitstempel, Untertitel oder Aufnahmen über 30 Minuten siehe Spracherkennung mit Cohere Transcribe.
Einrichtung
user@local $ pip install openai
user@local $ export OPENAI_API_KEY="sk-…"
Für das Aufteilen langer oder großer Dateien (über 30 Minuten oder über 25 MB):
user@local $ pip install pydub
# pydub benötigt ffmpeg
user@local $ brew install ffmpeg # macOS
user@local $ apt-get install ffmpeg # Debian/Ubuntu
Grundlegende Transkription
import os
from openai import OpenAI
client = OpenAI(base_url="https://llm.aihosting.mittwald.de/v1")
with open("aufnahme.mp3", "rb") as f:
result = client.audio.transcriptions.create(
model="whisper-large-v3-turbo",
file=f,
language="de", # Immer explizit setzen — Standard ist "de"
response_format="json",
temperature=0,
)
print(result.text)
Mehrere Sprachen
dateien_und_sprachen = [
("meeting_de.mp3", "de"),
("interview_fr.wav", "fr"),
("podcast_en.ogg", "en"),
("vortrag_ja.flac", "ja"),
]
for dateiname, sprache in dateien_und_sprachen:
with open(dateiname, "rb") as f:
result = client.audio.transcriptions.create(
model="whisper-large-v3-turbo",
file=f,
language=sprache,
response_format="json",
temperature=0,
)
print(f"[{sprache}] {result.text[:120]}")
Lange oder große Dateien (> 30 Minuten oder > 25 MB)
Die API akzeptiert Dateien bis zu 25 MB und bis zu 30 Minuten Audio. Beide Limits gelten unabhängig voneinander. Welches zuerst greift, hängt von der Bitrate ab: In 25 MB passen rund 52 Minuten mp3 mit 64 kbit/s mono, aber nur rund 27 Minuten mit 128 kbit/s stereo. Das Beispiel teilt längere Aufnahmen mit pydub an Stille-Stellen, fasst die Stücke wieder zu Abschnitten bis 25 Minuten zusammen und kodiert jeden Abschnitt neu als mp3 in mono. So bleibt jede Anfrage unter beiden Limits, und kein Wort wird mittendrin geschnitten:
from io import BytesIO
from pydub import AudioSegment
from pydub.silence import split_on_silence
MAX_CHUNK_MS = 25 * 60 * 1000 # Unter dem 30-Minuten-Limit bleiben
def grosse_datei_transkribieren(path: str, language: str = "de") -> str:
"""Datei beliebiger Größe und Länge transkribieren durch Aufteilen an Stille-Stellen."""
audio = AudioSegment.from_file(path)
# An Pausen von mehr als 700 ms mit Stille unter -40 dBFS aufteilen
stuecke = split_on_silence(
audio,
min_silence_len=700,
silence_thresh=-40,
keep_silence=300, # 300 ms Stille an jeder Kante für Kontext beibehalten
seek_step=10, # Alle 10 ms statt jede Millisekunde prüfen, rund zehnmal schneller
) or [audio]
# Eine Passage ohne Pausen kann das Limit trotzdem überschreiten: hart schneiden
begrenzt: list[AudioSegment] = []
for stueck in stuecke:
begrenzt.extend(stueck[i: i + MAX_CHUNK_MS] for i in range(0, len(stueck), MAX_CHUNK_MS))
# Aufeinanderfolgende Stücke zu möglichst wenigen Anfragen zusammenfassen
chunks: list[AudioSegment] = []
for stueck in begrenzt:
if chunks and len(chunks[-1]) + len(stueck) <= MAX_CHUNK_MS:
chunks[-1] += stueck
else:
chunks.append(stueck)
transkripte: list[str] = []
for chunk in chunks:
buf = BytesIO()
# Mono mit 64 kbit/s: 25 Minuten ergeben rund 12 MB, weit unter 25 MB
chunk.set_channels(1).export(buf, format="mp3", bitrate="64k")
buf.seek(0)
buf.name = "chunk.mp3" # openai SDK liest das .name-Attribut für den MIME-Typ
result = client.audio.transcriptions.create(
model="whisper-large-v3-turbo",
file=buf,
language=language,
response_format="json",
temperature=0,
)
transkripte.append(result.text)
return " ".join(transkripte)
volltext = grosse_datei_transkribieren("langes_interview.mp3", language="de")
print(volltext)
Transkription + Zusammenfassungs-Pipeline
Whisper mit einem Chat-Modell verknüpfen, um direkt von Audio zu einer schriftlichen Zusammenfassung zu gelangen:
def transkribieren_und_zusammenfassen(audio_path: str, language: str = "de") -> dict:
# Schritt 1: Transkribieren
with open(audio_path, "rb") as f:
result = client.audio.transcriptions.create(
model="whisper-large-v3-turbo",
file=f,
language=language,
response_format="json",
temperature=0,
)
transkript = result.text
# Schritt 2: Zusammenfassen
zusammenfassung_resp = client.chat.completions.create(
model="Qwen3.6-35B-A3B-FP8",
messages=[
{
"role": "system",
"content": "Fasse das Transkript prägnant zusammen. Verwende Stichpunkte für die wichtigsten Themen.",
},
{"role": "user", "content": transkript},
],
temperature=0.7,
max_tokens=512,
extra_body={"chat_template_kwargs": {"enable_thinking": False}},
)
return {
"transkript": transkript,
"zusammenfassung": zusammenfassung_resp.choices[0].message.content,
}
ausgabe = transkribieren_und_zusammenfassen("team_standup.mp3", language="de")
print("Transkript:\n", ausgabe["transkript"])
print("\nZusammenfassung:\n", ausgabe["zusammenfassung"])
Drop-in-Ersatz für OpenAI
Bestehender Code für die OpenAI Whisper API benötigt nur eine base_url-Änderung:
# Vorher (OpenAI)
client = OpenAI()
# Nachher (mittwald AI Hosting)
client = OpenAI(base_url="https://llm.aihosting.mittwald.de/v1")
Der gesamte übrige Code – Dateiverarbeitung, response_format, language, temperature – bleibt identisch.
Zeitstempel und Spracherkennung mit verbose_json
response_format="verbose_json" gibt segmentgenaue Zeitstempel, die erkannte Sprache und die Gesamtdauer zurück:
with open("aufnahme.mp3", "rb") as f:
result = client.audio.transcriptions.create(
model="whisper-large-v3-turbo",
file=f,
language="de",
response_format="verbose_json",
temperature=0,
)
print(result.text)
print(f"Sprache: {result.language}")
print(f"Dauer: {result.duration}s")
for seg in (result.segments or []):
print(f" [{seg.start:.1f}s–{seg.end:.1f}s] {seg.text}")