AGTCloud API Docs
Hướng dẫnAPI ReferenceTích hợp và tài nguyênCập nhật và hỗ trợ
Tương tác thời gian thực

GPT-Live Giọng nói thời gian thực

Tương tác giọng nói song công toàn phần và xử lý sự kiện phiên qua GPT-Live WebSocket.

GPT-Live cung cấp tương tác giọng nói song công toàn phần qua WebSocket liên tục, cho phép gửi âm thanh đầu vào, nhận giọng nói và văn bản chuyển đổi, cập nhật cấu hình phiên và duy trì ngữ cảnh nhiều lượt trên cùng phiên. Mô hình hiện được ghi nhận là gpt-live-1; phạm vi khả dụng thực tế phụ thuộc vào tài khoản hiện tại và danh mục mô hình.

WSS
wss://api.agtcloud.cn/v1/live/sessions

Xác thực và kết nối

Ứng dụng phía máy chủ dùng Bearer API Key trong Header bắt tay WebSocket. Mô hình không nằm trong tham số truy vấn mà được cấu hình trong sự kiện session.start đầu tiên sau khi kết nối.

MụcGiá trị
Địa chỉ kết nốiwss://api.agtcloud.cn/v1/live/sessions
AuthorizationBearer your-api-key
Vị trí mô hìnhsession.start.session.model
Âm thanh đầu vàoKhối âm thanh PCM thô mã hóa Base64

Chỉ lưu API Key dài hạn trên máy chủ đáng tin cậy. Tài liệu này chỉ đề cập tuyến WebSocket này, không bao gồm WebRTC, SIP, sideband, fork phiên hoặc tải bản ghi âm.

Quy trình phiên

  1. Thiết lập kết nối WebSocket bằng Bearer API Key.
  2. Gửi session.start để cấu hình mô hình, chỉ dẫn, âm thanh và phương thức ủy quyền.
  3. Sau khi nhận session.started, bắt đầu gửi âm thanh hoặc lệnh ứng dụng.
  4. Liên tục xử lý sự kiện văn bản chuyển đổi đầu vào, văn bản đầu ra, âm thanh đầu ra và mức sử dụng.
  5. Dừng tạo âm thanh rồi gửi session.close.
  6. Tiếp tục nhận sự kiện và hoàn tất bằng mức sử dụng cuối cùng trong session.closed.

Kết thúc một lượt nói không có nghĩa là kết thúc phiên. Hội thoại nhiều lượt nên giữ cùng kết nối; chỉ gửi session.close khi nghiệp vụ sẵn sàng kết thúc toàn bộ phiên.

Tham số khởi động

TrườngKiểuMô tả
typestringKhung đầu tiên cố định là session.start
event_idstringMã định danh sự kiện máy khách tùy chọn để liên kết lỗi
session.modelstringBắt buộc, ID mô hình GPT-Live
session.instructionsstringChỉ dẫn tùy chọn cho trợ lý giọng nói
session.audio.formatobjectĐịnh dạng âm thanh, ví dụ audio/pcm, 24 kHz
session.audio.output.voicestringGiọng nói đầu ra, ví dụ marin; giá trị hợp lệ phụ thuộc vào mô hình
session.delegationobjectPhương thức ủy quyền, dùng client hoặc responses

Sau khi kết nối được khởi động, có thể dùng session.update để cập nhật chỉ dẫn và cấu hình phiên được phép thay đổi, rồi chờ session.updated xác nhận. Không gửi lại session.start trên cùng kết nối và không chuyển mô hình giọng nói cấp cao nhất qua sự kiện cập nhật.

Chuẩn bị âm thanh và ví dụ gọi

Ví dụ dùng PCM signed 16-bit little-endian, 24 kHz, đơn kênh, không có phần đầu tệp WAV. Mỗi 100 ms tương ứng 4800 byte; mã hóa từng khối âm thanh thành Base64 khi gửi.

# Chuẩn bị âm thanh đầu vào
ffmpeg -i input.wav -f s16le -acodec pcm_s16le -ac 1 -ar 24000 audio.pcm

# Phát âm thanh đầu ra đã lưu
ffplay -f s16le -ar 24000 -ac 1 reply.pcm

Ví dụ Node.js cần ws; ví dụ Python chỉ kiểm tra khởi động và đóng phiên, không gửi âm thanh.

npm install ws
python -m pip install websocket-client
WSSVí dụ phiên GPT-Live
import fs from 'node:fs';
import WebSocket from 'ws';

const key = process.env.API_KEY;
const file = process.argv[2];
if (!key || !file) throw new Error('Cần API_KEY và đường dẫn tệp PCM');

const pcm = fs.readFileSync(file);
if (!pcm.length || pcm.length % 2) {
  throw new Error('PCM không được rỗng và phải căn theo mẫu 16 bit');
}

const ws = new WebSocket('wss://api.agtcloud.cn/v1/live/sessions', {
  headers: { Authorization: 'Bearer ' + key },
  handshakeTimeout: 10000,
});
const audioOut = fs.createWriteStream('reply.pcm');
let started = false;
let closing = false;
let finalized = false;
let sender;
let drain;
let offset = 0;
let inputFinishedAt = 0;
let lastOutputAt = 0;

function send(event) {
  ws.send(JSON.stringify(event));
}

function closeSession(reason) {
  if (closing) return;
  closing = true;
  clearInterval(sender);
  console.error('Yêu cầu kết thúc:', reason);
  if (started && ws.readyState === WebSocket.OPEN) {
    send({ type: 'session.close' });
    drain = setTimeout(() => ws.terminate(), 15000);
  } else {
    ws.terminate();
  }
}

const limit = setTimeout(() => closeSession('Giới hạn ví dụ 60 giây'), 60000);

ws.on('open', () => send({
  type: 'session.start',
  event_id: 'start_001',
  session: {
    model: 'gpt-live-1',
    instructions: 'Hãy trả lời ngắn gọn bằng tiếng Việt và chờ người dùng nói trước.',
    audio: {
      format: { type: 'audio/pcm', rate: 24000 },
      output: { voice: 'marin' },
    },
    delegation: { type: 'client' },
  },
}));

ws.on('message', (raw) => {
  let event;
  try {
    event = JSON.parse(raw.toString());
  } catch {
    closeSession('JSON không hợp lệ');
    return;
  }

  if (event.type !== 'session.output_audio.delta') {
    console.log(raw.toString());
  }
  if (event.type === 'session.started' && !started) {
    started = true;
    sender = setInterval(() => {
      if (closing || ws.readyState !== WebSocket.OPEN) return;
      if (offset >= pcm.length) {
        inputFinishedAt ||= Date.now();
        if (
          lastOutputAt &&
          Date.now() - Math.max(lastOutputAt, inputFinishedAt) >= 3000
        ) {
          closeSession('Đầu ra đã hoàn tất');
          return;
        }
        send({
          type: 'session.input_audio.append',
          audio: Buffer.alloc(4800).toString('base64'),
        });
        return;
      }
      const chunk = pcm.subarray(offset, offset + 4800);
      offset += chunk.length;
      send({
        type: 'session.input_audio.append',
        audio: chunk.toString('base64'),
      });
    }, 100);
  }
  if (event.type === 'session.output_audio.delta') {
    lastOutputAt = Date.now();
    audioOut.write(Buffer.from(event.delta, 'base64'));
  }
  if (event.type === 'session.output_transcript.delta') {
    lastOutputAt = Date.now();
  }
  if (event.type === 'session.closed') {
    finalized = true;
    ws.close(1000);
  }
  if (event.type === 'error') closeSession('Lỗi dịch vụ');
});

ws.on('error', (error) => {
  console.error(error.message);
  closeSession('Lỗi kết nối');
});

ws.on('close', (code, reason) => {
  clearTimeout(limit);
  clearTimeout(drain);
  clearInterval(sender);
  audioOut.end();
  console.error({ code, reason: reason.toString(), finalized });
  if (!finalized || code !== 1000) process.exitCode = 1;
});

process.on('SIGINT', () => closeSession('Người dùng đã dừng'));

Tham khảo sự kiện

API này gửi âm thanh Base64 bằng session.input_audio.append, không dùng khung âm thanh nhị phân và endStream của Muse, cũng không dùng sự kiện input_audio_buffer.* của OpenAI Realtime.

Sự kiện phía ứng dụng khách · Phiên

session.start

Khởi động phiên GPT-Live và gửi cấu hình mô hình, chỉ dẫn, âm thanh và ủy quyền.

TrườngKiểuBắt buộcMô tảVí dụ
typechuỗiCóCố định là session.start.session.start
event_idchuỗiKhôngMã định danh sự kiện máy khách.start_001
session.modelchuỗiCóID mô hình GPT-Live.gpt-live-1
session.instructionschuỗiKhôngChỉ dẫn hội thoại cho trợ lý giọng nói.Hãy trả lời ngắn gọn bằng tiếng Trung.
session.audio.format.typechuỗiKhôngLoại định dạng âm thanh.audio/pcm
session.audio.format.ratesố nguyênKhôngTần số lấy mẫu âm thanh.24000
session.audio.output.voicechuỗiKhôngGiọng nói đầu ra.marin
session.delegation.typechuỗiCóPhương thức ủy quyền.client
Ví dụ JSON
{
  "type": "session.start",
  "event_id": "start_001",
  "session": {
    "model": "gpt-live-1",
    "instructions": "Hãy trả lời ngắn gọn bằng tiếng Trung.",
    "audio": {
      "format": {
        "type": "audio/pcm",
        "rate": 24000
      },
      "output": {
        "voice": "marin"
      }
    },
    "delegation": {
      "type": "client"
    }
  }
}

Mức sử dụng và tính phí

session.usage.updated trả về giá trị tích lũy của phiên hiện tại, không phải phần sử dụng tăng thêm của một lượt riêng lẻ. Máy khách không nên cộng các giá trị ở nhiều thời điểm; khi đóng bình thường, dùng session.closed.usage.seconds làm thời lượng phiên cuối cùng.

Chi phí có thể gồm thời lượng phiên giọng nói, mức sử dụng mô hình phía sau và gọi công cụ. Giá cụ thể và phạm vi mô hình khả dụng hiện tại dựa theo Danh mục mô hình.

Phương thức ủy quyền

  • client: ứng dụng tự xử lý tác vụ cần ủy quyền, phù hợp để xác minh phiên giọng nói cơ bản trước.
  • responses: máy chủ thực thi mô hình và công cụ Responses đã cấu hình. Mô hình mục tiêu, công cụ và quyền phải khả dụng trên trang hiện tại.

Khi dùng responses, chi phí mô hình và công cụ của tác vụ phía sau có thể phát sinh riêng. Không coi MODEL_ID trong ví dụ là mô hình cố định luôn khả dụng.

Xử lý lỗi

Hiện tượngKiểm tra và xử lý
Bắt tay trả về 401Kiểm tra Bearer API Key, quyền mô hình và địa chỉ trang hiện tại
Đường dẫn trả về 404Xác nhận đường dẫn kết nối cuối cùng là /v1/live/sessions, không ghép /v1 hai lần
Khung đầu tiên sai hoặc khởi động quá thời gianSau khi kết nối, gửi session.start trước và chỉ gửi âm thanh khi nhận session.started
Không có âm thanh hoặc âm thanh bị méoKiểm tra độ sâu bit PCM, thứ tự byte, tần số lấy mẫu, số kênh và phần đầu tệp WAV
Không nhận được session.closedLưu mức sử dụng tích lũy cuối cùng, sự kiện lỗi và lý do đóng; không tự phát lại toàn bộ âm thanh
Ủy quyền phía sau bị từ chốiKiểm tra mô hình Responses, công cụ, quyền và phạm vi hỗ trợ của trang hiện tại

Tài liệu tham khảo