Audio Input and Output with Chat Completions
Audio-capable chat models can accept recorded audio inside a message and return generated audio in the same Chat Completions response. This fits turn-based applications that need a model to understand or answer with audio while keeping the OpenAI-compatible POST /v1/chat/completions request shape.
For standalone transcription, translation, or speech generation, use Speech and Audio. For interactive, bidirectional sessions, use the Realtime API.
AISIX preserves the OpenAI chat-audio request and response fields when the selected upstream uses a compatible OpenAI-shaped API. It does not translate these fields into another provider's native audio protocol.
Prerequisites
Before starting, prepare the following:
- A running AISIX gateway that can serve proxy requests.
- A caller API key that can access the model alias.
- A model alias backed by an audio-capable Chat Completions model. Its provider key must use the
openaiorazure-openaiadapter, and the upstream must implement the OpenAI chat-audio request and response shape. - A local WAV recording named
question.wavfor the audio-input example. curl,jq, Python 3, and thebase64,file, andtrcommand-line utilities for the examples.
If you have not configured the upstream yet, follow OpenAI, Azure OpenAI, or Bring Your Own Endpoint. Choose a currently supported upstream audio model and create an AISIX alias for it.
For a routing alias, every eligible target must use one of these adapters and support the same chat-audio fields. A fallback to a text-only or differently shaped provider can lose the audio content or fail upstream.
Export the gateway connection and request values:
# AISIX_PROXY has no trailing slash or endpoint path such as /v1.
# The local quickstarts use http://127.0.0.1:3000.
export AISIX_PROXY="YOUR_AISIX_GATEWAY_ORIGIN"
export AISIX_API_KEY="YOUR_CALLER_API_KEY"
export AISIX_MODEL="audio-chat-prod"
Generate an Audio Response
Request both text and audio output, then save the complete response:
curl -sS -X POST "${AISIX_PROXY}/v1/chat/completions" \
-H "Authorization: Bearer ${AISIX_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"model": "'"${AISIX_MODEL}"'",
"modalities": ["text", "audio"],
"audio": {
"voice": "alloy",
"format": "wav"
},
"messages": [
{
"role": "user",
"content": "Say: Your AISIX audio route is working."
}
]
}' > chat-audio-response.json
AISIX replaces the alias with the upstream model ID before dispatch. The upstream chooses which voices and output formats it accepts.
Inspect the returned audio metadata without printing the base64 payload:
jq '{
model,
audio: (.choices[0].message.audio | {
id,
transcript,
expires_at,
encoded_characters: (.data | length)
})
}' chat-audio-response.json
The response keeps model set to the AISIX alias. The audio object contains the provider's audio identifier, base64 data, transcript, and expiration timestamp when the upstream returns those fields.
Decode the generated WAV file with the Python standard library:
python3 - <<'PY'
import base64
import json
with open("chat-audio-response.json", encoding="utf-8") as response_file:
response = json.load(response_file)
audio = response["choices"][0]["message"]["audio"]
with open("aisix-chat-audio.wav", "wb") as audio_file:
audio_file.write(base64.b64decode(audio["data"]))
print(audio.get("transcript", ""))
PY
file aisix-chat-audio.wav
The final command should identify a WAV file. If you request another format, use a matching filename and media player.
Send Audio in a Message
Encode a local recording and place it in an input_audio content block. This example asks the model to answer with audio so you can use the same response handling as the previous request:
base64 < question.wav | tr -d '\n' | \
jq -Rs \
--arg model "$AISIX_MODEL" \
'{
model: $model,
modalities: ["text", "audio"],
audio: {
voice: "alloy",
format: "wav"
},
messages: [
{
role: "user",
content: [
{
type: "text",
text: "Answer the question in this recording."
},
{
type: "input_audio",
input_audio: {
data: .,
format: "wav"
}
}
]
}
]
}' > chat-audio-input.json
curl -sS -X POST "${AISIX_PROXY}/v1/chat/completions" \
-H "Authorization: Bearer ${AISIX_API_KEY}" \
-H "Content-Type: application/json" \
--data @chat-audio-input.json \
> chat-audio-response.json
AISIX forwards the typed content blocks unchanged through an OpenAI-compatible adapter. It does not decode the recording or convert it to another provider's audio-input shape.
Understand Current Behavior
Chat audio uses the ordinary Chat Completions authentication, model access, routing, retry, and request telemetry path. The audio-specific behavior has these boundaries:
- Use a non-streaming request. Omit
streamor set it tofalse. AISIX preservesmessage.audioon a complete response, but it does not currently return streameddelta.audiochunks. - Keep the provider protocol compatible. The
openaiandazure-openaiadapters preserve the audio request fields and the non-streamingmessage.audioobject. Other adapters can reduce typed message content to text and do not translate the audio fields into a provider-native voice API. - Apply guardrails to text separately from audio. Input guardrails can inspect the text content blocks, and output guardrails can inspect ordinary returned message text. They do not inspect the bytes in
input_audio, the generated audio data, or the transcript nested insidemessage.audio. - Treat Cloud audio cost as an upstream detail. AISIX records the normalized prompt and completion totals the upstream reports, but it does not retain separate audio-token counts. AISIX Cloud pricing therefore cannot apply distinct text-token and audio-token rates to the same Chat Completions request.
Because audio is base64-encoded inside JSON, request and response bodies are larger than the underlying binary files. Account for that expansion when setting client, proxy, or load-balancer body limits.
Troubleshoot Chat Audio
If the response succeeds but has no message.audio, check that the request includes the audio modality and an audio object, and that the upstream model supports audio output through Chat Completions. A text-only model can accept the HTTP request but reject or ignore unsupported audio fields upstream.
If AISIX returns an upstream decode or provider error, call the same upstream model directly with the provider's documented request shape. Confirm the model ID, voice, format, and audio-input encoding before changing gateway policy.
If the request works without streaming but produces no audio when stream is enabled, keep the request non-streaming. Use the Realtime API when the application needs incremental, bidirectional audio.
Next Steps
You have now sent and received audio inside an OpenAI-compatible chat request. Continue with Speech and Audio for standalone transcription or speech synthesis, or Realtime API for interactive voice sessions.