IoTLabs

Nghiên cứu, Sáng tạo và Thử nghiệm

Series ESP-WebRTC: Tích Hợp OpenAI Realtime API — ESP32 Nói Chuyện Với GPT-4o

Đây là bài thú vị nhất trong series: kết nối ESP32-P4 trực tiếp với OpenAI Realtime API để tạo AI voice assistant chạy hoàn toàn trên phần cứng nhúng — nói chuyện với ESP32 như nói chuyện với ChatGPT, nhưng không cần điện thoại hay laptop.

OpenAI Realtime API Là Gì?

OpenAI Realtime API (2024) là API cho phép giao tiếp audio real-time với GPT-4o:

  • Input: audio stream (Opus 24kHz)
  • Output: audio stream (Opus 24kHz) + text transcript
  • Transport: WebRTC hoặc WebSocket
  • Latency: ~300–500ms (voice-to-voice)

Thay vì: mic → STT → text → GPT → text → TTS → speaker (latency 2–5 giây), Realtime API xử lý audio trực tiếp trong một bước.

esp-webrtc-solution có sẵn adapter cho OpenAI Realtime API trong components/esp_webrtc/signaling/openai/.

Yêu Cầu

  • ESP32-P4 hoặc ESP32-S3 Korvo-1 (cần mic chất lượng tốt)
  • OpenAI API key (có billing)
  • Microphone tốt: INMP441 hoặc dual mic của Korvo-1
  • Speaker: 8Ω 1W+

Chi phí API: OpenAI Realtime API tính tiền theo token audio. Khoảng $0.06/phút audio input + $0.24/phút audio output (tháng 7/2024). Ước tính ~10.000 VNĐ/phút conversation.

Cách OpenAI Realtime Hoạt Động Qua WebRTC

ESP32                          OpenAI Realtime API
  │                                    │
  ├── POST /v1/realtime/sessions ──────→ (lấy ephemeral token)
  │◄─────────────── { client_secret } ─┤
  │                                    │
  ├── WebRTC Offer (Opus audio) ───────→
  │◄─────────────── WebRTC Answer ─────┤
  │                                    │
  ├── Audio stream (Opus 24kHz) ───────→ GPT-4o processes
  │◄─── Audio response (Opus 24kHz) ───┤ + interruption support
  │                                    │
  └── (ongoing conversation) ──────────┘

Không cần STUN/TURN — OpenAI là server công khai, kết nối trực tiếp qua internet.

Lấy API Key Và Ephemeral Token

Trực tiếp gọi API từ ESP32 cần xử lý auth. OpenAI khuyến nghị tạo ephemeral token ngắn hạn từ server của bạn (để không expose API key trên device):

# Backend server (Python/Flask đơn giản)
import openai
from flask import Flask, jsonify

app = Flask(__name__)
client = openai.OpenAI(api_key="sk-...")

@app.route('/get-realtime-token')
def get_token():
    session = client.beta.realtime.sessions.create(
        model="gpt-4o-realtime-preview",
        voice="alloy",
        instructions="Bạn là trợ lý IoT. Trả lời ngắn gọn bằng tiếng Việt.",
        input_audio_transcription={"model": "whisper-1"},
    )
    return jsonify({"client_secret": session.client_secret.value})

if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

ESP32 gọi /get-realtime-token để lấy token ngắn hạn (1 phút), rồi dùng token đó kết nối WebRTC với OpenAI.

Cấu Hình ESP32

#include "esp_webrtc.h"
#include "esp_webrtc_openai.h"

// Lấy ephemeral token từ backend
static char s_token[512];
static void fetch_openai_token(void) {
    // HTTP GET đến backend server của bạn
    esp_http_client_config_t config = {
        .url = "http://192.168.1.100:5000/get-realtime-token",
    };
    esp_http_client_handle_t client = esp_http_client_init(&config);
    esp_http_client_perform(client);
    // Parse JSON response, lấy client_secret → s_token
    esp_http_client_cleanup(client);
}

void app_main(void) {
    wifi_init_sta(CONFIG_WIFI_SSID, CONFIG_WIFI_PASS);
    wifi_wait_connected();

    // Capture: chỉ cần audio (mic)
    esp_capture_handle_t cap;
    esp_capture_cfg_t cap_cfg = { /* ... */ };
    init_audio_capture(&cap);

    // AV Render: chỉ cần audio (speaker)
    av_render_handle_t render;
    init_audio_render(&render);

    // Lấy token
    fetch_openai_token();

    // Cấu hình WebRTC với OpenAI signaling
    esp_webrtc_cfg_t cfg = {
        .signaling = {
            .type         = ESP_WEBRTC_SIGNALING_OPENAI,
            .openai_token = s_token,
            .openai_model = "gpt-4o-realtime-preview",
        },
        // OpenAI Realtime API yêu cầu Opus 24kHz
        .audio_send_codec       = ESP_WEBRTC_AUDIO_CODEC_OPUS,
        .audio_send_sample_rate = 24000,
        .audio_recv_codec       = ESP_WEBRTC_AUDIO_CODEC_OPUS,
        .audio_recv_sample_rate = 24000,

        // Không cần video
        .video_send_enable = false,
        .video_recv_enable = false,
    };

    esp_webrtc_handle_t webrtc;
    esp_webrtc_init(&cfg, &webrtc);
    esp_webrtc_set_av_source(webrtc, cap);
    esp_webrtc_set_av_render(webrtc, render);
    esp_webrtc_start(webrtc);

    ESP_LOGI("openai", "Voice assistant ready — nói gì đi!");
}

📷 [Hình minh hoạ: Flow diagram: Mic → ESP32 → OpenAI GPT-4o → ESP32 → Speaker, với latency labels]

Wake Word (Tùy Chọn)

Để không tốn API khi im lặng, thêm wake word detection. ESP32-S3 Korvo-1 có WakeNet tích hợp:

#include "esp_wn_iface.h"
#include "esp_wn_models.h"

// Model wake word tiếng Anh: "Hey ESP" hoặc tự train tiếng Việt
static const esp_wn_iface_t *wn = esp_wn_handle_from_name("wn9_hilexin");

static void wake_word_task(void *arg) {
    while (1) {
        // Nhận audio từ mic (16kHz)
        int16_t *buf = get_audio_buffer();
        int result = wn->detect(wn_model, buf, FRAME_SIZE);

        if (result > 0) {
            ESP_LOGI("ww", "Wake word detected!");
            // Bắt đầu stream đến OpenAI
            esp_webrtc_start_audio_send(g_webrtc);
            vTaskDelay(pdMS_TO_TICKS(5000));  // Stream 5 giây
            esp_webrtc_stop_audio_send(g_webrtc);
        }
        vTaskDelay(pdMS_TO_TICKS(10));
    }
}

Ví Dụ Conversation

[Người dùng]: "Nhiệt độ phòng bây giờ là bao nhiêu?"
[GPT-4o via ESP32]: "Tôi chưa có sensor nhiệt độ kết nối. Bạn cần thêm module DHT11 hoặc DS18B20."
[Người dùng]: "OK, bật đèn phòng khách đi"
[GPT-4o via ESP32]: "Đã bật đèn phòng khách." [kèm MQTT command]

Tích hợp với home automation: GPT-4o có thể gọi function trong system prompt để điều khiển thiết bị IoT.

Function Calling Với IoT

OpenAI Realtime API hỗ trợ function calling — GPT-4o có thể gọi hàm ESP32 định nghĩa:

// Trong system prompt, định nghĩa tools
const char *system_prompt =
    "Bạn là trợ lý nhà thông minh. "
    "Tools: control_light(room, state), get_temperature(room), control_fan(speed)";

// Khi GPT-4o muốn gọi function, nó gửi JSON qua data channel
// ESP32 parse và thực thi
static void on_data_message(const char *msg, void *ctx) {
    cJSON *json = cJSON_Parse(msg);
    const char *func = cJSON_GetStringValue(cJSON_GetObjectItem(json, "function"));
    if (strcmp(func, "control_light") == 0) {
        // Bật/tắt đèn qua GPIO hoặc MQTT
    }
    cJSON_Delete(json);
}

Bài tiếp theo: Tích Hợp Amazon KVS — Stream Video ESP32 Lên AWS Cloud