Chapter 14 · the loop closes — talk in, talk out
Synthesize a sentence → transcribe it back. If it returns intact, both halves work.
spoke: The quick brown fox jumps over the lazy dog.
transcript: The quick brown fox jumps over the lazy dog.
Keep a round-trip check — audio bugs are miserable by ear.
def speak(text, path):
r = client.audio.speech.create(
model="gpt-4o-mini-tts", voice="alloy", input=text)
open(path, "wb").write(r.content) # MP3
def transcribe(path):
return client.audio.transcriptions.create(
model="gpt-4o-mini-transcribe", file=open(path, "rb")).textGemini returns raw PCM — no header. Nothing plays it until you wrap it:
with wave.open(path, "wb") as w:
w.setnchannels(1); w.setsampwidth(2)
w.setframerate(24000); w.writeframes(pcm)
Silent audio? Suspect the header before the model.
Same result, different door.
Two return text; one returns audio the page plays.
Two one-call directions close the loop. The lesson is format, not API: wrap PCM before it plays. And most audio features are STT + a text step — everything you know still applies. Next: long context, and what a million tokens really costs.