Skip to content

OpenAI

contrib ยท v0.1.0

OpenAI behind the voice contracts: realtime transcription and text-to-speech. Install both, or one part with --only stt or --only tts. The API key stays on the server.

Install copit add @chanx-kit/openai
Import from openai
Requires kits audio-stream-in, audio-stream-out
Parts stt (transcriber.py), tts (synthesizer.py): all by default, or copit add @chanx-kit/openai --only <part>
Contract transcriber@1
UI kits transcriber
Contract synthesizer@1
UI kits player
Python packages chanx>=2.10.2,<3, websockets>=13, httpx>=0.27
Keywords audio, speech-to-text, text-to-speech, openai, provider
Source kits/openai

OpenAI: realtime transcription and text-to-speech, each behind its contract, so any transcriber or player UI works with it and switching provider is one class.

copit add @chanx-kit/openai                 # both parts
copit add @chanx-kit/openai --only stt      # speech-to-text only
copit add @chanx-kit/openai --only tts      # text-to-speech only
Part Module Contract Needs
stt transcriber.py transcriber@1 audio-stream-in
tts synthesizer.py synthesizer@1 audio-stream-out

Leaving a part out also leaves out the base kit only it needs. Import from the part's module (from .ws_kits.openai.transcriber import ...), since the other may not be there. Picking parts needs copit 0.9; older copit installs both.

Set OPENAI_API_KEY in the server's environment; the browser never sees it.

Speech to text

Live speech-to-text with OpenAI's realtime transcription behind the transcriber contract.

from .ws_kits.openai.transcriber import OpenAITranscriberTopic

class MicTopic(OpenAITranscriberTopic):
    model = "gpt-4o-transcribe"
    turn_detection = {"type": "server_vad"}   # turns end on silence

Set OPENAI_API_KEY on the server. OpenAI realtime takes PCM16 mono at 24 kHz, the kit's default format.

OpenAI transcriber@1
...input_audio_transcription.delta transcript_partial (the turn's text so far)
...input_audio_transcription.completed transcript_final, then utterance_end
input_audio_buffer.speech_started (with server_vad) speech_started
input_audio_buffer.commit on audio_end the turn is transcribed, then the stream closes

With turn_detection = None (the default) one audio_start to audio_end is one turn; with server_vad OpenAI splits turns on silence and reports speech starting, which the voice agent uses for barge-in.

model turn_detection = None server_vad
gpt-live-transcribe (default) yes refused by OpenAI
gpt-4o-transcribe, gpt-4o-mini-transcribe yes yes

For a voice agent, use gpt-4o-transcribe with server_vad.

Verified against the live service (2026-09-27): partials, finals and utterance ends with the default model; speech-started events and turns split at pauses with gpt-4o-transcribe and server_vad.

Text to speech

Text-to-speech with OpenAI behind the synthesizer contract.

from .ws_kits.openai.synthesizer import OpenAISynthesizerTopic

class ReplyVoiceTopic(OpenAISynthesizerTopic):
    model = "gpt-4o-mini-tts"
    default_voice = "alloy"
    instructions = "Friendly and brisk."

Set OPENAI_API_KEY on the server. Each utterance is one streamed request to /v1/audio/speech with response_format: "pcm", which is raw PCM16 mono at 24 kHz, the kit's default output, so audio reaches listeners as it arrives with nothing to decode. It uses httpx; set transport to test without a network.

Verified against the live service (2026-09-27): 4.5 s of speech for a two-sentence line, first audio after about 2 s, transcribed back by the OpenAI transcriber.