Chuyển đến nội dung chính

OpenAI Realtime API: Hướng dẫn kèm ví dụ

Tìm hiểu cách xây dựng ứng dụng AI thời gian thực với Realtime API của OpenAI. Hướng dẫn này bao gồm WebSocket, thiết lập Node.js, nhắn tin văn bản/âm thanh, gọi hàm và triển khai bản demo trợ lý giọng nói bằng React.
Đã cập nhật 5 thg 10, 2026  · 15 phút đọc

Khám phá cùng AI

ChatGPTClaudePerplexity

OpenAI Realtime API vừa ra mắt cho phép chúng ta tích hợp các trải nghiệm đa phương thức nhanh, độ trễ thấp vào ứng dụng. Với API này, chúng ta có thể tạo tương tác nói-chuyện liền mạch giữa người dùng và mô hình ngôn ngữ lớn (LLM).

API này loại bỏ nhu cầu dùng nhiều mô hình để đạt trải nghiệm điều khiển bằng giọng nói vì cung cấp giải pháp trọn gói trong một API tích hợp. Không chỉ nhằm giảm độ trễ, nó còn giữ được sắc thái cảm xúc và nhịp điệu tự nhiên của hội thoại.

Trong bài viết này, chúng ta sẽ học cách dùng OpenAI Realtime API để xây dựng trợ lý AI điều khiển bằng giọng nói. Chúng ta sẽ tạo kết nối WebSocket duy trì bằng Node.js và cách tận dụng nó trong terminal để giao tiếp với API. Ngoài ra, tôi sẽ hướng dẫn bạn triển khai một ứng dụng React sử dụng các khả năng của API này.

Tạo API Key cho OpenAI Realtime API

Để sử dụng OpenAI Realtime API, trước tiên chúng ta cần tạo API key. Truy cập trang API key. Lưu ý bạn cần có tài khoản. Ở đầu trang, nhấn nút “Create new secret key”.

Tạo secret key mới cho OpenAI Realtim API

Một cửa sổ bật lên sẽ hiện ra. Bạn có thể dùng các tùy chọn mặc định và nhấn “Create secret key”.

Tùy chọn mặc định để tạo OpenAI API key

Khi key được tạo, bạn sẽ có thể sao chép nó. Hãy chắc chắn sao chép trước khi đóng cửa sổ, vì đây là lần duy nhất key được hiển thị.

Sao chép OpenAI API key

Nếu làm mất key, bạn luôn có thể xóa và tạo key mới.

Để lưu key, chúng tôi khuyến nghị tạo tệp .env và lưu key theo định dạng sau:

OPENAI_API_KEY=<paste_they_key_here>

Chúng ta sẽ dùng tệp này xuyên suốt bài để kết nối tới API.

Cân nhắc chi phí cho Realtime API

Trước khi tiếp tục, lưu ý Realtime API không miễn phí, và chúng ta cần nạp tiền vào tài khoản để sử dụng. Bạn có thể nạp tiền tại trang thanh toán trong hồ sơ của bạn.

Để bạn hình dung chi phí, dưới đây là tổng quan số tiền tôi đã chi khi thử nghiệm API trong quá trình viết bài này:

Chi phí sử dụng OpenAI Realtime API

Tôi đã chi khoảng năm đô la tất cả. Đây không phải số lớn, nhưng đắt hơn nhiều so với các API khác của OpenAI. Hãy lưu ý điều này khi bạn thực hành theo bài viết.

Phần lớn chi phí (cột đầu) là do tôi dùng ứng dụng console React mà ta sẽ khám phá ở cuối bài. Phần còn lại, khoảng nửa đô, là chi phí dùng API qua WebSocket. Vì vậy, bạn có thể theo dõi bài viết này với chi phí dưới một đô.

Để biết chi tiết về giá của API, xem mục “Realtime API” trên trang giá của họ.

Sử dụng Realtime API với WebSocket

Khác với các thành phần khác của OpenAI API, Realtime API sử dụng WebSocket. WebSocket là một giao thức thiết lập kênh liên lạc hai chiều giữa client và server. Trái với mô hình yêu cầu-phản hồi truyền thống của HTTP, WebSocket hỗ trợ tương tác liên tục, thời gian thực. Điều này khiến WebSocket đặc biệt phù hợp với các ứng dụng thời gian thực như trò chuyện thoại.

Bài viết này sẽ trình bày cách WebSocket hoạt động và gồm nhiều ví dụ tương tác với Realtime API. 

Chúng ta sẽ dùng Node.js, nên cần đảm bảo nó đã được cài trên máy. Nếu chưa, bạn có thể tải và cài Node.js từ trang chính thức.

Khởi tạo script

Để thực hành theo, chúng tôi khuyến nghị tạo một thư mục với tệp .env đã tạo ở trên. Bên trong thư mục đó, chạy lệnh sau để khởi tạo script:

npm init -y && touch index.js

Sau khi lệnh này hoàn tất, các tệp sau sẽ có trong thư mục:

Cấu trúc thư mục ban đầu

Cài đặt phụ thuộc

Bắt đầu bằng cách cài hai gói:

  • ws: Gói WebSocket, là gói chính để tương tác với API.
  • dotenv: Gói tiện ích để tải API key từ tệp .env.

Cài đặt bằng lệnh:

npm install ws dotenv

Kết nối tới Realtime API

Để khởi tạo kết nối với Realtime API, ta tạo đối tượng WebSocket mới truyền vào URL API và header với thông tin cần thiết để kết nối:

// Import the web socket library
const WebSocket = require("ws");
// Load the .env file into memory so the code has access to the key
const dotenv = require("dotenv");
dotenv.config();
function main() {
  // Connect to the API
  const url = "wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview-2024-10-01";
  const ws = new WebSocket(url, {
      headers: {
          "Authorization": "Bearer " + process.env.OPENAI_API_KEY,
          "OpenAI-Beta": "realtime=v1",
      },
  });
}
main();

Thiết lập hành động khi kết nối được mở

Đoạn mã trên tạo kết nối web socket tới API nhưng chưa làm gì với nó.

WebSocket cho phép chúng ta thiết lập hành động để thực thi khi có sự kiện xảy ra. Ta có thể dùng sự kiện open để chỉ định đoạn mã cần chạy khi kết nối được thiết lập.

Cú pháp tổng quát để thêm bộ lắng nghe sự kiện như sau:

ws.on(<event>, <function>);

Thay <event> bằng chuỗi tên sự kiện và <function> bằng hàm sẽ được thực thi khi sự kiện xảy ra. 

Dưới đây là cách hiển thị văn bản khi kết nối sẵn sàng:

// Add inside the main() function of index.js after creating ws
async function handleOpen() {
  console.log("Connection is opened");
}
ws.on("open", handleOpen);

Để chạy mã này, dùng lệnh:

node index.js

Nếu API key được thiết lập đúng, bạn sẽ thấy thông báo “Connection is open” trong terminal. Script sẽ tiếp tục chạy vì kết nối vẫn mở, nên bạn phải dừng thủ công.

Thiết lập hành động khi nhận tin nhắn

Một sự kiện khác có thể xử lý khi dùng WebSocket là sự kiện message. Sự kiện này kích hoạt mỗi khi nhận tin nhắn từ server. Hãy thêm hàm hiển thị mỗi tin nhắn nhận được:

// Add inside the main() function of index.js
 async function handleMessage(messageStr) {
    const message = JSON.parse(messageStr);
    console.log(message);
}
ws.on("message", handleMessage);

Chạy script bây giờ cũng sẽ hiển thị sự kiện session.created mà API gửi khi phiên được khởi tạo.

Các sự kiện WebSocket khác

Ở trên, chúng ta đã học cách thêm listener cho sự kiện open và message. WebSocket hỗ trợ thêm hai sự kiện khác mà ta sẽ không dùng trong ví dụ.

Sự kiện close có thể dùng để thêm callback khi socket bị đóng:

async function handleClose() {
  console.log(“Socket closed”);
}
ws.on(“close”, handleClose);

Sự kiện error dùng để thêm callback khi có lỗi:

async function handleError(error) {
  console.log(“Error”, error);
}
ws.on(“error”, handleError);

Giao tiếp với Realtime API

Làm việc với WebSocket yêu cầu lập trình theo kiểu hướng sự kiện. Tin nhắn được gửi qua lại trên kênh liên lạc, và ta không thể kiểm soát khi nào các tin này sẽ được gửi hoặc nhận. 

Mã khởi tạo giao tiếp nên được thêm bên trong handleOpen(). O Nếu không, sẽ xảy ra lỗi vì mã đó có thể chạy trước khi kênh WebSocket được tạo.

Điều tương tự áp dụng cho mã xử lý tin nhắn. Toàn bộ logic nên đặt trong hàm handleMessage().

Trong các ví dụ tiếp theo, chúng ta sẽ dùng đoạn mã sau làm điểm khởi đầu. Phần lớn thay đổi là cập nhật handleOpen() và handleMessage().

// Import the web socket library
const WebSocket = require("ws");
// Load the .env file into memory so the code has access to the key
const dotenv = require("dotenv");
dotenv.config();
function main() {
  // Connect to the API
  const url = "wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview-2024-10-01";
  const ws = new WebSocket(url, {
      headers: {
          "Authorization": "Bearer " + process.env.OPENAI_API_KEY,
          "OpenAI-Beta": "realtime=v1",
      },
  });
  async function handleOpen() {
    console.log("Connection is opened");
  }
  ws.on("open", handleOpen);
  async function handleMessage(messageStr) {
    const message = JSON.parse(messageStr);
    console.log(message);
  }
  ws.on("message", handleMessage);  
}
main();

Dùng Realtime API để gửi và nhận văn bản

Giao tiếp với Realtime API diễn ra thông qua các sự kiện. Tài liệu real-time API của OpenAI liệt kê các sự kiện được hỗ trợ. Ta dùng sự kiện conversation.item.create để bắt đầu một hội thoại. Các sự kiện được biểu diễn dưới dạng đối tượng JSON với các trường được mô tả trong tài liệu.

Dưới đây là ví dụ về sự kiện conversation.item.create gửi lời nhắc “Hãy giải thích trong một câu web socket là gì”:

const createConversationEvent = {
  type: "conversation.item.create",
  item: {
    type: "message",
    role: "user",
    content: [
      {
        type: "input_text",
        text: "Explain in one sentence what a web socket is"
      }
    ]
  }
};

Sự kiện này cho API biết chúng ta muốn bắt đầu hội thoại dạng văn bản. Điều này được chỉ rõ trong trường content, dùng kiểu “input_text” và cung cấp lời nhắc văn bản.

Ta dùng phương thức ws.send() để gửi tin nhắn. Gói web socket mong đợi đối số là chuỗi nên cần chuyển sự kiện JSON sang chuỗi bằng JSON.stringify(). Kết hợp lại, đây là cách gửi sự kiện trên:

ws.send(JSON.stringify(createConversationEvent));

Điều này sẽ khởi tạo hội thoại, nhưng sẽ không tự động kích hoạt API gửi phản hồi. Để yêu cầu phản hồi, ta gửi sự kiện response.create. Ví dụ:

const createResponseEvent = {
  type: "response.create",
  response: {
      modalities: ["text"],
      instructions: "Please assist the user.",
  }
}
ws.send(JSON.stringify(createResponseEvent));

Sự kiện này dùng tham số phản hồi modalities để yêu cầu phản hồi dạng văn bản. Phần chỉ dẫn là quan trọng nhất, mô tả điều ta muốn mô hình thực hiện, ở đây là lời nhắc chung nhằm hỗ trợ người dùng.

Ta gửi hai sự kiện này trong hàm handleOpen() để hội thoại được bắt đầu ngay khi kết nối được thiết lập. Đây là triển khai đầy đủ của handleOpen() trong ví dụ này:

async function handleOpen() {

  // Define what happens when the connection is opened

  // Create and send an event to initiate a conversation

  const createConversationEvent = {

    type: "conversation.item.create",

    item: {

      type: "message",

      role: "user",

      content: [

        {

          type: "input_text",

          text: "Explain in one sentence what a web socket is"

        }

      ]

    }

  };

  // Create and send an event to initiate a response

  ws.send(JSON.stringify(createConversationEvent));

  const createResponseEvent = {

    type: "response.create",

    response: {

        modalities: ["text"],

        instructions: "Please assist the user.",

    }

  }

  ws.send(JSON.stringify(createResponseEvent));

}

Về các tin nhắn đến, có ba loại sự kiện đáng chú ý cho ví dụ này: response.text.delta, response.text.done và response.done:

  • Sự kiện response.text.delta chứa phản hồi được chia thành từng mảnh trong trường delta. Chúng quan trọng khi ta muốn trải nghiệm thời gian thực vì cho phép stream phản hồi từng phần ngay lập tức. 
  • Sự kiện response.text.done đánh dấu kết thúc phản hồi văn bản và chứa toàn bộ câu trả lời trong trường text.
  • Sự kiện response.done đánh dấu kết thúc phản hồi.

Chúng ta có thể chỉ định cách script phản hồi các sự kiện này bằng câu lệnh switch trong hàm handleMessage():

async function handleMessage(messageStr) {
  const message = JSON.parse(messageStr);
  // Define what happens when a message is received
  switch(message.type) {
    case "response.text.delta":
      // We got a new text chunk, print it
      process.stdout.write(message.delta);
    break;
    case "response.text.done":
      // The text is complete, print a new line
      process.stdout.write("\n");
    break;
    case "response.done":
      // Response complete, close the socket
      ws.close();
    break;
  }
}

Trong ví dụ này, ta dùng sự kiện response.text.delta để in từng mảnh phản hồi ra console ngay khi nhận được. Khi phản hồi hoàn tất, sự kiện response.text.done được kích hoạt, và ta in xuống dòng để biểu thị đầu ra đã xong. Cuối cùng, ta đóng web socket khi nhận sự kiện response.done.

Để chạy ví dụ này, dán các hàm trên vào mẫu mã phía trên và chạy bằng lệnh:

node index.js

Điều này sẽ tạo phản hồi trong terminal cho lời nhắc "Explain in one sentence what a web socket is", tương tự như khi dùng ChatGPT. 

Mã đầy đủ cho ví dụ văn bản có tại đây.

Dùng Realtime API để gửi và nhận âm thanh

Ví dụ trước cho thấy cách xử lý dữ liệu văn bản. Tuy nhiên, điểm hấp dẫn của Realtime API là tạo trợ lý giọng nói phản hồi theo thời gian thực.

Xử lý âm thanh phức tạp hơn một chút so với văn bản. Chúng ta sẽ lướt qua một số chi tiết đặc thù của âm thanh vì có thể làm lệch trọng tâm bài viết.

Trước tiên, cài hai gói:

npm install node-record-lpcm16 speaker
  • node-record-lpcm16 ghi âm từ micro để ta có thể gửi lời nhắc giọng nói.
  • speaker dùng để phát lại phản hồi giọng nói của AI.

Chúng ta cũng cần cài SoX (Sound eXchange), công cụ dòng lệnh xử lý âm thanh mà thư viện node sẽ dùng để kết nối micro và ghi âm. Dùng brew install sox trên macOS hoặc sudo apt install sox trên Linux.

Sau khi cài đặt các gói, ta import và thêm hàm startRecording() để ghi lời nhắc âm thanh của người dùng. Chúng tôi không giải thích chi tiết hàm này vì sẽ đi quá xa chủ đề chính. 

Thêm đoạn mã sau vào tệp index.js sau khi tải môi trường:

// Add to index.js before the main() function
// Import the web socket library
const WebSocket = require("ws");
// Load the .env file into memory so the code has access to the key
const dotenv = require("dotenv");
dotenv.config();
const Speaker = require("speaker");
const record = require("node-record-lpcm16");
// Function to start recording audio
function startRecording() {
  return new Promise((resolve, reject) => {
    console.log("Speak to send a message to the assistant. Press Enter when done.");
    // Create a buffer to hold the audio data
    const audioData = [];
    // Start recording in PCM16 format
    const recordingStream = record.record({
      sampleRate: 16000, // 16kHz sample rate (standard for speech recognition)
      threshold: 0, // Start recording immediately
      verbose: false,
      recordProgram: "sox", // Specify the program
    });
    // Capture audio data
    recordingStream.stream().on("data", (chunk) => {
      audioData.push(chunk); // Store the audio chunks
    });
    // Handle errors in the recording stream
    recordingStream.stream().on("error", (err) => {
      console.error("Error in recording stream:", err);
      reject(err);
    });
    // Set up standard input to listen for the Enter key press
    process.stdin.resume(); // Start listening to stdin
    process.stdin.on("data", () => {
      console.log("Recording stopped.");
      recordingStream.stop(); // Correctly stop the recording stream
      process.stdin.pause(); // Stop listening to stdin
      // Convert audio data to a single Buffer
      const audioBuffer = Buffer.concat(audioData);
      // Convert the Buffer to Base64
      const base64Audio = audioBuffer.toString("base64");
      resolve(base64Audio); // Resolve the promise with Base64 audio
    });
  });
};

Hàm startRecording() ghi âm từ micro và chờ bạn nhấn “Enter”. 

Tiếp theo, cập nhật hàm main() bằng cách khởi tạo Speaker() để phát phản hồi của AI:

// Add to the main() function after ws is initialized
const speaker = new Speaker({
  channels: 1, // Mono or Stereo
  bitDepth: 16, // PCM16 (16-bit audio)
  sampleRate: 24000, // Common sample rate (44.1kHz)
});

Xong phần này, ta có thể triển khai handleOpen() và handleMessage() để xử lý âm thanh.

Trong handleOpen(), ta chỉ cần gọi startRecording() để ghi lời nhắc âm thanh của người dùng. Đồng thời cần cập nhật sự kiện đôi chút:

  1. Cập nhật nội dung của createConversationEvent dùng kiểu “input_audio” thay vì “input_text và thay trường text bằng           audio: base64AudioData.
  2. Thêm “audio” vào modality phản hồi trong createResponseEvent.

Đây là hàm handleOpen() đã cập nhật:

async function handleOpen() {
  // Define what happens when the connection is opened
  const base64AudioData = await startRecording();
  const createConversationEvent = {
    type: "conversation.item.create",
    item: {
      type: "message",
      role: "user",
      content: [
        {
          type: "input_audio",
          audio: base64AudioData,
        },
      ],
    },
  };
  ws.send(JSON.stringify(createConversationEvent));
  const createResponseEvent = {
    type: "response.create",
    response: {
      modalities: ["text", "audio"],
      instructions: "Please assist the user.",
    },
  };
  ws.send(JSON.stringify(createResponseEvent));
}

Để triển khai handleMessage(), ta chỉnh sự kiện “response.audio.delta” để cập nhật bộ đệm âm thanh và phát phần âm thanh mới:

case "response.audio.delta":
  // We got a new audio chunk
  const base64AudioChunk = message.delta;
  const audioBuffer = Buffer.from(base64AudioChunk, "base64");
  speaker.write(audioBuffer);
  break;

Ta bỏ sự kiện “response.text.done” khỏi câu lệnh switch và cập nhật sự kiện “response.done” để dừng loa:

case "response.audio.done":
  speaker.end();
  ws.close();
  break;

Triển khai cuối cùng của hàm handleMessage() trông như sau:

function handleMessage(messageStr) {
  const message = JSON.parse(messageStr);
  // Define what happens when a message is received
  switch (message.type) {
    case "response.audio.delta":
      // We got a new audio chunk
      const base64AudioChunk = message.delta;
      const audioBuffer = Buffer.from(base64AudioChunk, "base64");
      speaker.write(audioBuffer);
      break;
    case "response.audio.done":
      speaker.end();
      ws.close();
      break;
  }
}

Để chạy ví dụ này, áp dụng các chỉnh sửa vào mã mẫu và chạy bằng lệnh:

node index.js

Micro sẽ bắt đầu ghi âm. Bạn nói yêu cầu và nhấn “Enter” để gửi. Sau đó, phản hồi của AI sẽ phát qua loa (đảm bảo micro không tắt và loa có âm lượng).

Mã đầy đủ cho ví dụ âm thanh có tại đây.

Gọi hàm (Function calling)

Một tính năng hay của OpenAI API là khả năng thực hiện gọi hàm. Ta có thể thêm các hàm cho trợ lý và nếu phát hiện một trong các hàm đó hữu ích để đưa ra câu trả lời, AI sẽ gửi sự kiện yêu cầu gọi một hàm cụ thể.

Tài liệu OpenAI cung cấp sơ đồ sau giải thích vòng đời của một lần gọi hàm:

Vòng đời gọi hàm

Nguồn: OpenAI

Từ sơ đồ, ta thấy client phải cung cấp định nghĩa các hàm mà LLM có thể gọi. Việc thực thi hàm sẽ diễn ra phía client; AI sẽ gửi sự kiện yêu cầu gọi hàm và đối số. Sau đó, ta có trách nhiệm gửi lại kết quả.

Hãy trang bị cho trợ lý của chúng ta một hàm cộng hai số. Ta sẽ xây dựng ví dụ này bằng cách mở rộng ví dụ âm thanh ở trên.

Để chỉ rõ các hàm sẵn có, ta phải cung cấp cho LLM danh sách công cụ (tools). Mỗi tool là một đối tượng JSON mô tả thông tin về hàm. Đây là cách định nghĩa một tool cho hàm cộng:

const sumTool = {
  type: "function",
  name: "calculate_sum",
 description: "Use this function when asked to add numbers together, for example when asked 'What's 4 + 6'?.",
  parameters: {
      type: "object",
      properties: {
          "a": { "type": "number" },
          "b": { "type": "number" }
      },
      required: ["a", "b"]
  }
}

Giải thích cấu trúc đối tượng:

  • Trường type chỉ ra rằng ta đang định nghĩa một hàm.
  • Trường name dùng để nhận diện hàm. LLM sẽ dùng tên này để cho biết hàm nào nó muốn gọi.
  • Trường description dùng để xác định khi nào LLM nên dùng hàm này.
  • Trường parameters dùng để chỉ định đối số của hàm. Ở đây là hai số a và b.

Bước tiếp theo là định nghĩa hàm trong mã. Ta sẽ dùng một từ điển với khóa calculate_sum để dễ gọi đúng hàm khi phản hồi sự kiện gọi hàm:

const functions = {
  calculate_sum: (args) => args.a + args.b,
}

API sẽ cung cấp đối số hàm dưới dạng từ điển có cấu trúc giống như trong parameters ở trên. Trong trường hợp cộng, ví dụ 3 và 5, từ điển sẽ là {“a”: 3, “b”: 5}.

Hai hằng sumTool và functions có thể thêm vào đầu tệp index.js, sau phần import và trước hàm main().

Tiếp theo, cập nhật sự kiện response.create để cho LLM biết sumTools sẵn có. Thực hiện bằng cách thêm trường tools và tool_choice vào response:

const createResponseEvent = {
  type: "response.create",
  response: {
    modalities: ["text", "audio"],
    instructions: "Please assist the user.",
    tools: [sumTool], // New
    tool_choice: "auto", // New
  },
};

Khi LLM quyết định muốn gọi hàm, nó sẽ phát ra sự kiện response.function_call_arguments.done. Ta cần phản hồi bằng cách:

  1. Lấy thông tin hàm và gọi hàm.
  2. Gửi kết quả của lần gọi hàm.
  3. Yêu cầu một phản hồi.

Ta xử lý bằng cách thêm case sau vào câu lệnh switch trong hàm hanldeMessage():

case "response.function_call_arguments.done":
  console.log(Using function ${message.name} with arguments ${message.arguments});
  // 1. Get the function information and call the function
  const function_name = message.name;
  const function_arguments = JSON.parse(message.arguments);
  const result = functions[function_name](function_arguments);
  // 2. Send the result of the function call
  const functionOutputEvent = {
    type: "conversation.item.create",
    item: {
      type: "function_call_output",
      role: "system",
      output: ${result},
    }
  };
  ws.send(JSON.stringify(functionOutputEvent));
  // 3. Request a response
  ws.send(JSON.stringify({type: "response.create"}));
  break;

Nếu bây giờ chạy script và yêu cầu kết quả phép cộng hai số, mô hình sẽ gọi hàm và cung cấp kết quả.

Hàm này tương đối đơn giản nhưng vì thực thi ở phía client, nó có thể là bất cứ thứ gì. Ở phần tiếp theo, ta sẽ thấy hai ví dụ về các hàm phức tạp hơn.

Mã đầy đủ của ví dụ này có tại đây.

Ứng dụng Demo dùng OpenAI Realtime API

Đội ngũ OpenAI cung cấp một ứng dụng React demo để trình diễn Realtime API. Ở đây, chúng ta sẽ học cách thiết lập và khám phá cách hoạt động của nó. Đây là điểm khởi đầu tuyệt vời để xây dựng ứng dụng phức tạp hơn.

Thiết lập ứng dụng

Không cần kiến thức React để chạy được. Tuy nhiên, bạn cần quen thuộc với React nếu muốn chỉnh sửa hoặc mở rộng.

Ứng dụng được lưu trữ tại kho này. Để thiết lập, bắt đầu bằng cách clone bằng lệnh Git sau:

git clone org-14957082@github.com:openai/openai-realtime-console.git

Ngoài ra, bạn cũng có thể tải thủ công từ giao diện GitHub.

Để cài ứng dụng, dùng lệnh NPM (node package manager) sau:

npm install

Sau khi cài xong, tạo tệp tên .env ở thư mục gốc dự án và dán nội dung sau:

OPENAI_API_KEY=<openai_api_key>
REACT_APP_LOCAL_RELAY_SERVER_URL=http://localhost:8081

Thay <openai_api_key> bằng OpenAI API key của bạn.

Ứng dụng giờ đã sẵn sàng chạy. Nó gồm hai phần:

  1. Frontend React là giao diện web của ứng dụng.
  2. Máy chủ chuyển tiếp (relay server) hoạt động như trung gian giữa frontend và OpenAI API. 

Tương tác giữa API, máy chủ relay và frontend

Mục đích chính của việc triển khai relay server giữa frontend và OpenAI API là lưu trữ API key một cách an toàn. Không thể tương tác với API nếu thiếu key này.

Tuy nhiên, nếu lưu key ở frontend, bất kỳ người dùng nào cũng có thể truy cập. Vì vậy, giải pháp là thiết lập máy chủ lưu trữ an toàn key và hỗ trợ trao đổi dữ liệu giữa API và frontend. Trong kịch bản cụ thể này, mối lo ngại về bảo mật là tối thiểu vì ứng dụng chỉ chạy cục bộ. 

Để chạy ứng dụng, cần khởi động cả relay server và frontend. Để khởi chạy relay server, dùng lệnh:

npm run relay

Để khởi chạy frontend React, dùng lệnh:

npm start

Sau khi tải xong, một thẻ sẽ mở trên trình duyệt với ứng dụng đang chạy.

Giao diện realtime console

Sử dụng ứng dụng

Trước khi bắt đầu, hãy đảm bảo máy tính không tắt tiếng và cấp quyền truy cập micro cho ứng dụng.

Chúng ta bắt đầu bằng cách nhấn nút “connect”. Điều này sẽ gửi tin nhắn “Hello” tới Realtime API, và bạn sẽ nhận lời chào.

Kết nối tới API

Khi kết nối được thiết lập, một nút mới sẽ hiện ở giữa cho phép chúng ta nói chuyện với trợ lý AI. 

Ghi âm tin nhắn thoại

Để sử dụng, nhấn và giữ nút để nói. Tin nhắn sẽ được gửi khi thả nút.

Ứng dụng cũng có chế độ VAD (phát hiện hoạt động giọng nói) trong đó bạn không cần nhấn nút. Ở chế độ này, ứng dụng sẽ liên tục lắng nghe, cho phép hội thoại chủ động với trợ lý. Để dùng, chỉ cần nhấn nút “vad” và bắt đầu nói.

Chuyển sang chế độ phát hiện hoạt động giọng nói

Các hàm (Functions)

Như ta đã biết, Realtime API cung cấp tính năng cho phép AI thực hiện các hàm cụ thể. Bản demo này trình diễn hai hàm: một hàm hỏi dự báo thời tiết tại vị trí nhất định và một hàm thêm mục ghi nhớ để cá nhân hóa trợ lý. 

Hãy trải nghiệm bằng cách hỏi như “Thời tiết ngày mai ở New York thế nào?” và nêu sở thích như “Màu yêu thích của tôi là xanh dương.” Trợ lý sẽ trả lời bằng giọng nói, đồng thời thông tin cũng hiển thị ở bên phải ứng dụng.

Hiển thị hàm vị trí và bộ nhớ

Đôi khi tôi yêu cầu báo thời tiết, và phản hồi cho biết không thể truy cập lúc đó. Tuy nhiên, thông tin vẫn luôn hiển thị ở bên phải. Vì là ứng dụng demo, nó không nhằm mục đích là sản phẩm hoàn chỉnh mà chỉ để trình diễn khả năng của API.

Tìm hiểu client

Phần này cần hiểu biết ở mức khái quát về React vì chúng ta sẽ đề cập một số chi tiết triển khai của ứng dụng.

Chúng ta sẽ xem tệp ConsolePage.tsx. Đây là nơi phần lớn logic ứng dụng được định nghĩa. Ứng dụng demo không dùng WebSocket thô như ví dụ app dòng lệnh Node.js của chúng ta. Họ xây dựng một client thời gian thực để hỗ trợ tương tác với API. Đây là thứ được import ở đầu tệp:

import { RealtimeClient } from '@openai/realtime-api-beta';

Tích hợp với API được định nghĩa trong lời gọi useEffect() này. Mã trong useEffect() được chạy khi trang console được render lần đầu. Tương tự script Node.js của chúng ta, nó mô tả cách phản hồi các sự kiện từ API. Khác biệt chính là sử dụng lớp bọc RealtimeClient.

Định nghĩa tools

Hàm RealtimeClient.addTool() được dùng để định nghĩa tool. Nó nhận hai tham số:

  • Đối tượng JSON định nghĩa tool.
  • Hàm sẽ được thực thi.

Cách tiếp cận này đơn giản hóa tích hợp tool vì client đã sẵn sàng xử lý sự kiện và tự động gọi hàm. Tool bộ nhớ được định nghĩa tại đây, còn tool thời tiết được định nghĩa tại đây.

Ví dụ, để thêm tool cộng đã định nghĩa trước đó, ta có thể làm như sau:

client.addTool(
  {
    name: "calculate_sum",
    description: "Use this function when asked to add numbers together, for example when asked 'What's 4 + 6'?.",
    parameters: {
        type: "object",
        properties: {
            "a": { "type": "number" },
            "b": { "type": "number" }
        },
        required: ["a", "b"]
    }
  },
  (a: number, b: number): number => a + b
);

Lưu ý ứng dụng dùng TypeScript, vì vậy cần chỉ định kiểu trong định nghĩa hàm.

Lắng nghe sự kiện

Để lắng nghe sự kiện, dùng hàm RealtimeClient.on(). Nó nhận hai tham số: 

  1. Tên sự kiện.
  2. Hàm callback sẽ được thực thi.

Cách này tương tự hàm WebSocket.on() đã dùng trước đó, chỉ khác là triển khai tập sự kiện khác. Trang GitHub của họ cung cấp danh sách sự kiện được hỗ trợ.

Trong ví dụ này, các sự kiện sau được dùng:

  • Sự kiện realtime.event tại đây dùng để ghi log tất cả sự kiện.
  • Sự kiện error tại đây chỉ đơn giản là log lỗi ra console để debug.
  • Sự kiện conversation.interrupted tại đây dùng để hủy yêu cầu khi cuộc hội thoại bị gián đoạn.
  • Cuối cùng, sự kiện conversation.updated tại đây dùng để nối thêm âm thanh vào luồng khi các mảnh mới từ API gửi về.

    Kết luận

    Trong hướng dẫn này, chúng ta đã khám phá OpenAI Realtime API và cách nó sử dụng WebSocket cho giao tiếp thời gian thực. Chúng ta đã thiết lập môi trường Node.js để tương tác với API, gửi và nhận tin nhắn văn bản và âm thanh, cũng như triển khai gọi hàm để tăng cường chức năng.

    Chúng ta cũng đã khám phá ứng dụng React demo của OpenAI, minh họa cách triển khai một ứng dụng trợ lý giọng nói cơ bản.

    Để tìm hiểu thêm về các công cụ phát triển OpenAI mới nhất, tôi gợi ý các hướng dẫn sau:


François Aubry's photo
Author
François Aubry
LinkedIn
Kỹ sư full-stack & nhà sáng lập tại CheapGPT. Giảng dạy luôn là niềm đam mê của tôi. Từ những ngày còn là sinh viên, tôi đã háo hức tìm kiếm cơ hội kèm cặp và hỗ trợ các bạn học khác. Niềm đam mê đó đã thôi thúc tôi theo học tiến sĩ, nơi tôi cũng đảm nhiệm vai trò trợ giảng để hỗ trợ con đường học thuật của mình. Trong những năm ấy, tôi tìm thấy sự mãn nguyện lớn lao trong môi trường lớp học truyền thống, xây dựng kết nối và thúc đẩy việc học tập. Tuy nhiên, với sự ra đời của các nền tảng học trực tuyến, tôi nhận ra tiềm năng thay đổi của giáo dục số. Thực tế, tôi đã trực tiếp tham gia phát triển một nền tảng như vậy tại trường đại học của chúng tôi. Tôi tận tâm kết hợp các nguyên tắc giảng dạy truyền thống với những phương pháp số đổi mới. Đam mê của tôi là tạo ra các khóa học không chỉ hấp dẫn và giàu thông tin mà còn dễ tiếp cận với người học trong thời đại số này.
Chủ đề
Trí tuệ Nhân tạo
OpenAI
Mô hình Ngôn ngữ Lớn

Học phát triển ứng dụng AI!

Khóa học

Phát triển ứng dụng LLM với LangChain

3 giờ
52K
Khám phá cách xây dựng các ứng dụng tích hợp AI bằng cách sử dụng LLM, prompt, chain và agent trong LangChain.
Xem chi tiếtRight Arrow
Bắt Đầu Khóa Học
Xem thêmRight Arrow
Liên quan

blog

Claude Opus 4.6: Tính năng, Điểm chuẩn, Bài kiểm tra thực hành và hơn thế nữa

Mô hình mới nhất của Anthropic dẫn đầu ở mã hóa tác tử và lập luận phức tạp. Thêm vào đó, nó có cửa sổ ngữ cảnh 1M.
Matt Crabtree's photo

Matt Crabtree

10 phút

Xem ThêmXem Thêm