> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.tramlabs.io/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.tramlabs.io/_mcp/server.

# Audio

> Cách gửi và nhận audio với các model của Trạm AI

Trạm AI hỗ trợ cả việc gửi file audio đến các model tương thích lẫn nhận response audio qua API. Hướng dẫn này trình bày cách làm việc với audio đầu vào và audio đầu ra.

## Audio đầu vào

Người dùng có thể gửi file audio đến các model tương thích để transcribe, phân tích và xử lý. Request audio đầu vào dùng API `/v1/chat/completions` với content type `input_audio`. File audio phải được mã hóa base64 và kèm theo phần khai báo định dạng.

**Lưu ý**: File audio phải được **mã hóa base64** - URL trực tiếp không được hỗ trợ cho nội dung audio.

Người dùng có thể tìm model hỗ trợ audio đầu vào bằng cách lọc theo modality audio đầu vào trên [trang Models](/tong-quan/models).

### Gửi file audio

Dưới đây là cách gửi một file audio để xử lý:

**`TypeScript`**

```typescript title="TypeScript" expandable lines
import OpenAI from 'openai';
import fs from "fs/promises";

const openai = new OpenAI({
  baseURL: 'https://api.tramlabs.io/v1',
  apiKey: '{{API_KEY_REF}}',
});

async function encodeAudioToBase64(audioPath: string): Promise<string> {
  const audioBuffer = await fs.readFile(audioPath);
  return audioBuffer.toString("base64");
}

// Read and encode the audio file
const audioPath = "path/to/your/audio.wav";
const base64Audio = await encodeAudioToBase64(audioPath);

const result = await openai.chat.completions.create({
  model: "{{MODEL}}",
  messages: [
    {
      role: "user",
      content: [
        {
          type: "text",
          text: "Please transcribe this audio file.",
        },
        {
          type: "input_audio",
          inputAudio: {
            data: base64Audio,
            format: "wav",
          },
        },
      ],
    },
  ],
  stream: false,
});

console.log(result);
```

**`Python expandable lines`**

```python Python expandable lines
import requests
import json
import base64

def encode_audio_to_base64(audio_path):
    with open(audio_path, "rb") as audio_file:
        return base64.b64encode(audio_file.read()).decode('utf-8')

url = "https://api.tramlabs.io/v1/chat/completions"
headers = {
    "Authorization": f"Bearer {API_KEY_REF}",
    "Content-Type": "application/json"
}

# Read and encode the audio file
audio_path = "path/to/your/audio.wav"
base64_audio = encode_audio_to_base64(audio_path)

messages = [
    {
        "role": "user",
        "content": [
            {
                "type": "text",
                "text": "Please transcribe this audio file."
            },
            {
                "type": "input_audio",
                "input_audio": {
                    "data": base64_audio,
                    "format": "wav"
                }
            }
        ]
    }
]

payload = {
    "model": "{{MODEL}}",
    "messages": messages
}

response = requests.post(url, headers=headers, json=payload)
print(response.json())
```

**`TypeScript (fetch)`**

```typescript title="TypeScript (fetch)" expandable lines
import fs from "fs/promises";

async function encodeAudioToBase64(audioPath: string): Promise<string> {
  const audioBuffer = await fs.readFile(audioPath);
  return audioBuffer.toString("base64");
}

// Read and encode the audio file
const audioPath = "path/to/your/audio.wav";
const base64Audio = await encodeAudioToBase64(audioPath);

const response = await fetch("https://api.tramlabs.io/v1/chat/completions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY_REF}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "{{MODEL}}",
    messages: [
      {
        role: "user",
        content: [
          {
            type: "text",
            text: "Please transcribe this audio file.",
          },
          {
            type: "input_audio",
            input_audio: {
              data: base64Audio,
              format: "wav",
            },
          },
        ],
      },
    ],
  }),
});

const data = await response.json();
console.log(data);
```

### Các định dạng audio đầu vào hỗ trợ

Các định dạng audio được hỗ trợ sẽ khác nhau tùy provider. Một số định dạng phổ biến gồm:

* `wav` - WAV audio
* `mp3` - MP3 audio
* `aiff` - AIFF audio
* `aac` - AAC audio
* `ogg` - OGG Vorbis audio
* `flac` - FLAC audio
* `m4a` - M4A audio
* `pcm16` - PCM16 audio
* `pcm24` - PCM24 audio

**Lưu ý:** Hãy kiểm tra tài liệu của model để biết chính xác model đó hỗ trợ những định dạng audio nào. Không phải model nào cũng hỗ trợ tất cả định dạng.

## Audio đầu ra

Trạm AI hỗ trợ nhận response audio từ các model có khả năng tạo audio đầu ra. Để yêu cầu audio đầu ra, chỉ cần thêm hai tham số `modalities` và `audio` vào request.

Người dùng có thể tìm các model hỗ trợ audio đầu ra bằng cách lọc theo modality audio đầu ra trên [trang Models](/tong-quan/models).

### Yêu cầu audio đầu ra

Để nhận audio đầu ra, hãy đặt `modalities` thành `["text", "audio"]` và cung cấp cấu hình `audio` với giọng nói cùng định dạng mong muốn:

**`Python expandable lines`**

```python Python expandable lines
import requests
import json
import base64

url = "https://api.tramlabs.io/v1/chat/completions"
headers = {
    "Authorization": f"Bearer {API_KEY_REF}",
    "Content-Type": "application/json"
}

payload = {
    "model": "{{MODEL}}",
    "messages": [
        {
            "role": "user",
            "content": "Say hello in a friendly tone."
        }
    ],
    "modalities": ["text", "audio"],
    "audio": {
        "voice": "alloy",
        "format": "wav"
    },
    "stream": True
}

# Audio output requires streaming — the response is delivered as SSE chunks
response = requests.post(url, headers=headers, json=payload, stream=True)

audio_data_chunks = []
transcript_chunks = []

for line in response.iter_lines():
    if not line:
        continue
    decoded = line.decode("utf-8")
    if not decoded.startswith("data: "):
        continue
    data = decoded[len("data: "):]
    if data.strip() == "[DONE]":
        break
    chunk = json.loads(data)
    delta = chunk["choices"][0].get("delta", {})
    audio = delta.get("audio", {})
    if audio.get("data"):
        audio_data_chunks.append(audio["data"])
    if audio.get("transcript"):
        transcript_chunks.append(audio["transcript"])

transcript = "".join(transcript_chunks)
print(f"Transcript: {transcript}")

# Combine and decode the base64 audio chunks, then save
full_audio_b64 = "".join(audio_data_chunks)
audio_bytes = base64.b64decode(full_audio_b64)
with open("output.wav", "wb") as f:
    f.write(audio_bytes)
```

**`TypeScript (fetch)`**

```typescript title="TypeScript (fetch)" expandable lines
const response = await fetch("https://api.tramlabs.io/v1/chat/completions", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${API_KEY_REF}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "{{MODEL}}",
    messages: [
      {
        role: "user",
        content: "Say hello in a friendly tone.",
      },
    ],
    modalities: ["text", "audio"],
    audio: {
      voice: "alloy",
      format: "wav",
    },
    stream: true,
  }),
});

// Audio output requires streaming — parse the SSE chunks
const reader = response.body!.getReader();
const decoder = new TextDecoder();

const audioDataChunks: string[] = [];
const transcriptChunks: string[] = [];
let buffer = "";

while (true) {
  const { done, value } = await reader.read();
  if (done) break;

  buffer += decoder.decode(value, { stream: true });
  const lines = buffer.split("\n");
  buffer = lines.pop()!; // keep incomplete line in buffer

  for (const line of lines) {
    if (!line.startsWith("data: ")) continue;
    const data = line.slice("data: ".length).trim();
    if (data === "[DONE]") break;

    const chunk = JSON.parse(data);
    const audio = chunk.choices?.[0]?.delta?.audio;
    if (audio?.data) audioDataChunks.push(audio.data);
    if (audio?.transcript) transcriptChunks.push(audio.transcript);
  }
}

const transcript = transcriptChunks.join("");
console.log(`Transcript: ${transcript}`);

// audioDataChunks joined together is the full base64-encoded audio
const fullAudioB64 = audioDataChunks.join("");
```

### Định dạng chunk khi streaming

Audio đầu ra yêu cầu phải bật streaming (`stream: true`). Dữ liệu audio và transcript đều được gửi về theo từng phần qua trường `delta.audio` trong mỗi chunk:

**`lines`**

```json lines
{
  "choices": [
    {
      "delta": {
        "audio": {
          "data": "<base64-encoded audio chunk>",
          "transcript": "Hello"
        }
      }
    }
  ]
}
```

### Các tùy chọn cấu hình audio

Tham số `audio` chấp nhận những tùy chọn sau:

| Tùy chọn | Mô tả                                                                                                                             |
| -------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `voice`  | Giọng nói dùng để tạo audio (ví dụ: `alloy`, `echo`, `fable`, `onyx`, `nova`, `shimmer`). Các giọng khả dụng khác nhau tùy model. |
| `format` | Định dạng audio cho đầu ra (ví dụ: `wav`, `mp3`, `flac`, `opus`, `pcm16`). Các định dạng khả dụng khác nhau tùy model.            |