← chapter

Audio: speech to text and back

Chapter 14 · the loop closes — talk in, talk out

The hour

The round trip

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.

Speak + transcribe (OpenAI)

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")).text

The #1 audio bug (Gemini TTS)

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

Two philosophies of STT

Same result, different door.

Put it to work — three apps

Two return text; one returns audio the page plays.

Takeaway

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.