Membangun antarmuka suara: speech-to-text dengan Whisper, text-to-speech, dan voice agent real-time yang sedang tren di 2026. Kalian memahami arsitektur voice pipeline, latensi sebagai masalah utama, hingga pertimbangan telephony dan biayatype: text

Di episode 13 kalian mengenal multimodal; episode ini fokus pada satu modalitas yang menjadi tren terpanas 2025-2026: suara. Voice agents — asisten yang bisa diajak bicara secara natural dan real-time — tiba-tiba menjadi kategori produk tersendiri, dari layanan pelanggan otomatis sampai tutor bahasa.
Mengapa penting? Karena suara adalah antarmuka paling alami bagi manusia. Produk yang menawarkan percakapan suara (bukan hanya chat) membuka pengguna yang tidak nyaman mengetik: telepon, dapur, mobil. Dan di 2026, membangun voice agent tidak lagi butuh tim riset — cukup memahami pipeline yang tepat.
Voice agent tersusun dari tiga komponen yang dipasang berurutan:
Setiap tahap menambah latensi. Ini masalah terbesar voice agent: percakapan manusia yang natural menuntut respons di bawah ~1 detik — jika lebih, pengguna merasakan jeda yang canggung. Latensi adalah metrik nomor satu untuk produk suara.
Langkah pertama: ubah audio menjadi teks. Whisper adalah standar de facto — tersedia via API maupun open-weight:
from openai import OpenAI
client = OpenAI()
with open("pertanyaan.wav", "rb") as f:
r = client.audio.transcriptions.create(
model="whisper-1",
file=f,
language="id",
)
print(r.text)Untuk produksi dengan biaya rendah dan privasi, jalankan Whisper lokal (dalam Docker atau faster-whisper):
pip install faster-whisperfrom faster_whisper import WhisperModel
model = WhisperModel("small", device="cpu", compute_type="int8")
segments, info = model.transcribe("pertanyaan.wav", language="id")
print(" ".join(s.text for s in segments))Model small cukup untuk mayoritas kasus; ukuran model menentukan akurasi vs latensi — prinsip yang sama dengan pemilihan LLM di episode 2.
Langkah kedua: ubah jawaban menjadi suara. Ada dua pendekatan:
from pathlib import Path
r = client.audio.speech.create(
model="gpt-4o-mini-tts",
voice="alloy",
input="Halo, saya asisten suara kamu. Ada yang bisa dibantu?",
)
r.stream_to_file(Path("jawaban.mp3"))Note
Untuk bahasa Indonesia, uji dulu kualitas suara lokal vs API. Model TTS lokal (misal Kokoro) sudah mendukung bahasa Indonesia dengan kualitas mengejutkan baik di 2026 — dan gratis tanpa batas kuota.
Untuk percakapan natural, model bahasa harus menerima input teks hasil STT, lalu outputnya di-ubah ke suara. Alur sinkron paling sederhana:
from faster_whisper import WhisperModel
from openai import OpenAI
client = OpenAI()
stt = WhisperModel("small", device="cpu", compute_type="int8")
SISTEM = {"role": "system", "content": "Kamu asisten suara yang ramah. "
"Jawab singkat, maksimal 2 kalimat, cocok dibacakan."}
def dengar(path: str) -> str:
segments, _ = stt.transcribe(path, language="id")
return " ".join(s.text for s in segments)
def bicara(text: str) -> None:
r = client.audio.speech.create(model="gpt-4o-mini-tts", voice="alloy", input=text)
r.stream_to_file("jawaban.mp3")
def proses(teks: str, history: list[dict]) -> str:
history.append({"role": "user", "content": teks})
r = client.chat.completions.create(
model="gpt-4o-mini", messages=[SISTEM] + history, max_tokens=150)
reply = r.choices[0].message.content
history.append({"role": "assistant", "content": reply})
return reply
history: list[dict] = []
while True:
rekam("input.wav") # placeholder rekam mikrofon
teks = dengar("input.wav")
if "selesai" in teks.lower():
break
bicara(proses(teks, history))Perhatikan dua detail penting: system prompt memaksa jawaban singkat (cocok untuk dibacakan, bukan dibaca), dan riwayat memakai pola memory dari episode 12.
Tiga pertimbangan produksi:
max_tokens.Inti yang harus dibawa pulang:
faster-whisper lokal) untuk STT; API atau Kokoro/Piper untuk TTS.Di episode 15 selanjutnya kita turun ke fondasi data: data & preprocessing untuk AI — data cleaning, strategi chunking yang benar, data quality untuk RAG, dan pipeline data yang menjaga knowledge base tetap sehat. Sampai jumpa di episode 15!