Current section

Files

Jump to
codex_sdk lib codex voice.ex
Raw

lib/codex/voice.ex

defmodule Codex.Voice do
@moduledoc """
Voice pipeline for speech-to-speech AI interactions.
This module provides a non-realtime voice pipeline that orchestrates:
1. Speech-to-text (STT) - Transcribe audio input
2. Workflow processing - Generate text responses
3. Text-to-speech (TTS) - Synthesize audio output
## Quick Start
# Create a workflow
workflow = Codex.Voice.SimpleWorkflow.new(fn text ->
["You said: \#{text}"]
end)
# Create pipeline
pipeline = Codex.Voice.Pipeline.new(workflow: workflow)
# Run with audio input
audio = Codex.Voice.Input.AudioInput.new(audio_bytes)
{:ok, result} = Codex.Voice.Pipeline.run(pipeline, audio)
# Stream output events
result
|> Codex.Voice.Result.stream()
|> Enum.each(fn event ->
case event.type do
:voice_stream_event_audio -> play(event.data)
:voice_stream_event_lifecycle -> handle(event.event)
:voice_stream_event_error -> log(event.error)
end
end)
## Components
- `Codex.Voice.Pipeline` - Main pipeline orchestrator
- `Codex.Voice.Workflow` - Workflow behaviour
- `Codex.Voice.SimpleWorkflow` - Function-based workflow
- `Codex.Voice.AgentWorkflow` - Agent-based workflow
- `Codex.Voice.Input` - Audio input types
- `Codex.Voice.Result` - Streamed result
## Convenience Functions
This module provides convenience functions to create and run voice pipelines
without needing to import submodules directly:
# Run a complete pipeline in one call
{:ok, result} = Codex.Voice.run(audio,
workflow: my_workflow,
config: %Codex.Voice.Config{
tts_settings: %{voice: :nova}
}
)
# Create audio inputs
audio = Codex.Voice.audio_input(binary_data)
streamed = Codex.Voice.streamed_input()
"""
alias Codex.Voice.Config
alias Codex.Voice.Input.AudioInput
alias Codex.Voice.Input.StreamedAudioInput
alias Codex.Voice.Pipeline
alias Codex.Voice.Result
alias Codex.Voice.SimpleWorkflow
@doc """
Create and run a voice pipeline.
This is a convenience function that creates a pipeline and runs it in one
step. For more control, use `Codex.Voice.Pipeline` directly.
## Options
- `:workflow` - The workflow to use (required)
- `:stt_model` - STT model name or instance
- `:tts_model` - TTS model name or instance
- `:config` - Pipeline configuration
## Returns
- `{:ok, result}` - A `Result` struct that can be streamed for events
## Example
workflow = Codex.Voice.SimpleWorkflow.new(fn text ->
["You said: \#{text}"]
end)
{:ok, result} = Codex.Voice.run(audio,
workflow: workflow,
config: %Codex.Voice.Config{
tts_settings: %Codex.Voice.Config.TTSSettings{voice: :nova}
}
)
# Stream output events
for event <- Codex.Voice.Result.stream(result) do
IO.inspect(event)
end
"""
@spec run(AudioInput.t() | StreamedAudioInput.t(), keyword()) :: {:ok, Result.t()}
def run(audio, opts) do
pipeline = Pipeline.new(opts)
Pipeline.run(pipeline, audio)
end
@doc """
Create an audio input from binary data.
## Options
- `:frame_rate` - Sample rate in Hz (default: 24000)
- `:sample_width` - Bytes per sample (default: 2)
- `:channels` - Number of audio channels (default: 1)
## Example
audio = Codex.Voice.audio_input(File.read!("recording.pcm"))
"""
@spec audio_input(binary(), keyword()) :: AudioInput.t()
def audio_input(data, opts \\ []) do
AudioInput.new(data, opts)
end
@doc """
Create a streamed audio input.
Use this for multi-turn conversations where you want to push audio
chunks incrementally.
## Example
input = Codex.Voice.streamed_input()
# Push chunks from another process
spawn(fn ->
for chunk <- audio_source do
Codex.Voice.Input.StreamedAudioInput.add(input, chunk)
end
Codex.Voice.Input.StreamedAudioInput.close(input)
end)
# Run the pipeline
{:ok, result} = Codex.Voice.run(input, workflow: my_workflow)
"""
@spec streamed_input() :: StreamedAudioInput.t()
def streamed_input do
StreamedAudioInput.new()
end
@doc """
Create a simple workflow from a function.
The function should take a transcription string and return an enumerable
of response text chunks.
## Options
- `:greeting` - Optional greeting to send when the workflow starts
## Example
workflow = Codex.Voice.simple_workflow(fn text ->
["You said: \#{text}"]
end, greeting: "Hello! How can I help?")
"""
@spec simple_workflow((String.t() -> Enumerable.t()), keyword()) :: SimpleWorkflow.t()
def simple_workflow(handler, opts \\ []) do
SimpleWorkflow.new(handler, opts)
end
@doc """
Create a new pipeline configuration.
## Options
- `:workflow_name` - Name for tracing
- `:stt_settings` - STT configuration
- `:tts_settings` - TTS configuration
- `:model_provider` - Custom model provider module
- `:trace_include_sensitive_data` - Include sensitive data in traces
- `:trace_include_sensitive_audio_data` - Include audio data in traces
## Example
config = Codex.Voice.config(
workflow_name: "Customer Support",
tts_settings: Codex.Voice.Config.TTSSettings.new(voice: :nova)
)
"""
@spec config(keyword()) :: Config.t()
def config(opts \\ []) do
Config.new(opts)
end
end