เพื่อน AI และแชทบอทบทบาทสมมติภาษาไทย
ให้เพื่อน AI หรือตัวละครบทบาทสมมติภาษาไทยมีเสียงเป็นของตัวเอง เปิด WebSocket เดียวต่อหนึ่งบทสนทนา สั่งหยุดได้เมื่อถูกพูดแทรก และใช้รหัสเสียงคงที่ที่ทำให้ตัวละครเป็นเสียงเดิมเสมอ
ไอเดียให้ลองเล่น
ทุกการ์ดเล่นคลิปจริงที่สร้างจากสคริปต์นั้น ๆ ด้วยเสียงนมเย็น เปิดใน Playground เพื่อให้พูดข้อความของคุณเองได้
ทำให้เพื่อน AI พูดได้อย่างไร
เพื่อน AI คือบทสนทนาที่ไม่มีงานรออยู่ตอนจบ เรื่องนี้เปลี่ยนหน้าที่ของชั้นเสียงไปทั้งหมด บอทบริการพูดผลลัพธ์ที่เขียนสคริปต์ไว้ไม่กี่แบบ ส่วนเพื่อน AI พูดทุกอย่างที่โมเดลเขียนขึ้นมา ตลอดทั้งคืน ด้วยเสียงที่ผู้ใช้ตัดสินใจไปแล้วว่าเป็นของใครคนหนึ่ง ลองถามคนที่เลิกเปิดแอปว่าทำไม คำตอบมักไม่ได้อยู่ที่บทที่เขียน แต่อยู่ที่วันหนึ่งเสียงมันเพี้ยนไปนิดหนึ่ง หรือมันพูดต่อทั้งที่เรากำลังจะพูดอะไรบางอย่าง สองอย่างที่รับน้ำหนักตรงนี้ อย่างแรกคือเสียงที่ไม่เพี้ยนไปตามเวลา ซึ่งรหัสเสียงคงที่ในแคตตาล็อกให้มาอยู่แล้ว อย่างที่สองคือการพูดแทรก คนที่คุยกับเพื่อน AI ย่อมพูดแทรกขึ้นมา และเพื่อน AI ที่ยังอ่านย่อหน้าเดิมต่อทั้งที่ไม่มีใครฟังแล้ว จะหมดความเป็นคนทันที ประเทศไทยเป็นตลาดที่เริ่มจากแชท LINE มีผู้ใช้ประจำเดือน 56 ล้านคน คิดเป็นร้อยละ 78.2 ของประชากร เพื่อน AI ภาษาไทยจึงมักเป็นสินค้าแชทที่เรียนรู้ที่จะพูดได้
ที่มา:DataReportal (2026)(opens in a new tab)
- เปิดซ็อกเก็ตพร้อมกับที่บทสนทนาเริ่มWebSocket เดียวรับทั้งเซสชัน ส่งโมเดล เสียง และรูปแบบไฟล์ครั้งเดียวตอนเปิด หลังจากนั้นทุกตาคือเฟรมข้อความบนการเชื่อมต่อที่อุ่นอยู่แล้ว
- สั่งสังเคราะห์ทีละประโยคส่งประโยคทันทีที่โมเดลเขียนจบ เสียงจะเริ่มกลับมาตั้งแต่ส่วนที่เหลือยังเขียนไม่เสร็จ และตาที่ถูกพูดแทรกกลางคันก็เหลือให้จ่ายแค่ประโยคเดียว
- สั่งหยุดทันทีที่อีกฝ่ายเริ่มพูดเฟรม cancel หยุดรอบที่กำลังพูดและทิ้งส่วนที่ค้างในบัฟเฟอร์ เซสชันยังเปิดอยู่ และเฟรมข้อความถัดไปเริ่มตาใหม่ได้ทันที
หนึ่งซ็อกเก็ต หลายตา และการพูดแทรกหนึ่งครั้ง
-> {"type":"start","model":"paxa-tts-flash-v1","voice":"sanaechan"}
<- {"type":"started","connection":"c_8f21","voice":"sanaechan"}
-> {"type":"text","text":"คืนนี้เป็นยังไงบ้าง"}
<- {"type":"charged","seq":1,"chars":19,"credits":0.29}
<- [เฟรมเสียงไบนารี]
<- {"type":"flushed","seq":1}
-> {"type":"text","text":"เล่าให้ฟังหน่อยสิ เราอยากรู้จริง ๆ นะ"}
<- {"type":"charged","seq":2,"chars":37,"credits":0.55}
<- [เฟรมเสียงไบนารี]
# ผู้ใช้เริ่มพูดแทรก
-> {"type":"cancel"}
<- {"type":"cancelled","seq":2}
-> {"type":"text","text":"ได้ ๆ ฟังอยู่"}ตาที่ 2 ยังคงค่าบริการ 0.55 เครดิตตามใบเสร็จเดิม ซึ่งเป็นส่วนต่างจากยอดสะสมของการเชื่อมต่อ ไม่มีอะไรค้างอยู่ในคิวหลังจากนั้น และการเชื่อมต่อเดิมรับตาถัดไปต่อได้โดยไม่ต้องเชื่อมใหม่
ค่าเสียงของเพื่อน AI
| บทสนทนา | จำนวนคำตอบ | ตัวอักษร | ค่าใช้จ่าย |
|---|---|---|---|
| หนึ่งค่ำคืน | 20 | 2,400 | $0.04 |
| ผู้ใช้ประจำหนึ่งคน หนึ่งเดือน | 1,200 | 144,000 | $2.16 |
| ผู้ใช้ประจำ 1,000 คน หนึ่งเดือน | ประมาณ $2,160 | ||
คำนวณที่ 15 เครดิตต่อ 1,000 ตัวอักษร จากคำตอบยาว 120 ตัวอักษร วันละ 40 คำตอบ ค่าบริการคิดตามตัวอักษรที่พูดออกไปจริง
ชีวิตของตัวละครหนึ่งตัว
ไม่มีขั้นตอนไหนบนไทม์ไลน์นี้ที่ใช้พารามิเตอร์อารมณ์หรือสไตล์ เพราะโมเดลที่ให้บริการอยู่ยังไม่มี สิ่งที่ทำให้ตัวละครเปลี่ยนไปตามเวลาคือบทที่เขียนและเสียงที่เลือก
สำหรับนักพัฒนา
ตัวอย่าง TypeScript และ Python เปิดซ็อกเก็ตสด ส่งข้อความเข้าไปตามที่มี แล้วอ่านใบเสร็จกับเฟรมเสียงกลับมา ส่วนตัวอย่างออปชันแสดงฟิลด์เสียง โมเดล และรูปแบบไฟล์ที่ตัวละครหนึ่งตัวตั้งครั้งเดียวแล้วใช้ไปตลอด
// Runs on Bun as-is; on Node, `import WebSocket from "ws"` accepts
// the same constructor options. Browsers cannot send this header, and
// API keys never ship to browsers anyway.
const socket = new WebSocket("wss://api.paxalabs.com/v1/tts/live", {
headers: { Authorization: `Bearer ${process.env.PAXA_API_KEY}` },
});
socket.binaryType = "arraybuffer";
socket.onopen = () => {
socket.send(JSON.stringify({
type: "start",
model: "paxa-tts-flash-v1",
voice: "khanomkrok",
timestamps: "word",
}));
// Send text whenever it becomes available, token by token if you like.
socket.send(JSON.stringify({ type: "text", text: "สวัสดีครับ ยินดีต้อนรับสู่ Paxa Labs" }));
socket.send(JSON.stringify({ type: "flush" }));
socket.send(JSON.stringify({ type: "end" }));
};
socket.onmessage = (event) => {
if (typeof event.data === "string") {
const message = JSON.parse(event.data);
if (message.type === "done") socket.close();
return;
}
player.feed(new Uint8Array(event.data)); // binary frames are audio
};import json
import os
from websockets.sync.client import connect # pip install websockets
with connect(
"wss://api.paxalabs.com/v1/tts/live",
additional_headers={"Authorization": f"Bearer {os.environ['PAXA_API_KEY']}"},
) as socket:
socket.send(json.dumps({"type": "start", "model": "paxa-tts-flash-v1", "voice": "khanomkrok"}))
socket.send(json.dumps({"type": "text", "text": "สวัสดีครับ ยินดีต้อนรับสู่ Paxa Labs"}))
socket.send(json.dumps({"type": "flush"}))
socket.send(json.dumps({"type": "end"}))
with open("speech.mp3", "wb") as f:
for frame in socket:
if isinstance(frame, bytes):
f.write(frame) # binary frames are audio
continue
event = json.loads(frame)
if event["type"] == "done":
breakcurl -X POST https://api.paxalabs.com/v1/tts \
-H "Authorization: Bearer $PAXA_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"text": "สวัสดีครับ ยินดีต้อนรับสู่ Paxa Labs",
"voice": "khanomkrok",
"model": "paxa-tts-flash-v1",
"format": "mp3",
"stream": false
}' \
--output speech.mp3ฟังเสียงจริง
เสน่ห์จันทน์หญิง0:04
เสียงอบอุ่นชวนฟัง มีเสน่ห์แบบค่ำคืน
ค่ำคืนนี้ ปล่อยให้เสียงของฉัน อยู่เป็นเพื่อนคุณจนกว่าจะหลับนะคะ
ขนมครกชาย0:03
เสียงผู้ใหญ่ใจเย็น ไม่เร่งรีบ เสียงชายหลักของทั้งชุด เหมาะกับสารคดี เรื่องเล่าย้อนวัน และงานบรรยาย
สมัยผมยังหนุ่ม แถวนี้ยังเป็นทุ่งนา เดินไปตลาดทีหนึ่งก็ค่อนวันแล้วครับ
นมเย็นหญิง0:06
เสียงสดใสมีพลัง เสียงหญิงหลักของทั้งชุด เหมาะกับโปรโมต คลิปโซเชียล และเสียงพูดในผลิตภัณฑ์ทั่วไป
ยินดีต้อนรับสู่ Paxa Labs ค่ะ เสียงภาษาไทยที่สลับเป็น English ได้กลางประโยค อย่างเป็นธรรมชาติ
ตะโก้หญิง0:05
เสียงสาวเป็นกันเอง เหมาะกับหนังสือเสียง สรุปข่าว และคลิปอธิบาย
ยามเช้าในกรุงเทพฯ แสงแดดอ่อน ๆ ทาบลงบนถนนที่เริ่มคึกคัก
เสียงบางส่วนจากทั้งหมด 26 เสียง สร้างจาก API ด้วยรหัสเสียงที่เปิดให้ใช้งานจริง ฟังครบทุกเสียงได้ที่หน้า Text-to-Speech
ทำไมภาษาไทยเก็บเรื่องนี้ไว้คนละที่
ภาษาไทยระบุความสัมพันธ์ไว้ในตัวคำเลย คำสรรพนามที่ผู้พูดเลือกใช้เรียกตัวเองและเรียกอีกฝ่าย กับคำลงท้ายที่ปิดประโยค วางคนสองคนไว้ในตำแหน่งที่สัมพันธ์กัน ตั้งแต่ก่อนที่น้ำเสียงจะเข้ามาเกี่ยว Paxa TTS Flash อ่านทั้งหมดนี้จากตัวสะกด ความสนิทของตัวละครจึงเป็นสิ่งที่ prompt กำหนด และเสียงเป็นฝ่ายแสดงออกมา
คำถามที่พบบ่อย
- อีกหกเดือนตัวละครจะยังเสียงเดิมไหม
- ยังเหมือนเดิม เสียงคือรหัสคงที่ในแคตตาล็อก และรหัสเดิมให้เสียงเดิมทุกคำขอ ความเป็นเสียงของตัวละครไม่ได้ขึ้นกับไฟล์ตัวอย่างที่คุณต้องเก็บรักษาไว้เอง
- หยุดพูดตอนผู้ใช้พูดแทรกได้อย่างไร
- ส่งเฟรม cancel บนซ็อกเก็ตสด ประโยคที่กำลังพูดจะหยุด ส่วนที่ค้างในคิวถูกทิ้งโดยไม่คิดเงิน และการเชื่อมต่อเดิมรับตาถัดไปต่อได้เลย
- ทำให้เพื่อน AI เสียงดีใจหรือเสียใจได้ไหม
- ยังไม่มีพารามิเตอร์สำหรับเรื่องนี้ สิ่งที่กำหนดว่าประโยคไทยหนึ่งประโยคฟังแล้วรู้สึกอย่างไร คือคำสรรพนามและคำลงท้ายที่ใช้เขียนมันขึ้นมา ซึ่งเป็นการเลือกฝั่ง prompt และเสียงที่คุณเลือกให้อ่าน
- ให้ตัวละครบทบาทสมมติแต่ละตัวมีเสียงของตัวเองได้ไหม
- ได้ถึง 26 ตัว ตัวละครละหนึ่งเสียงในแคตตาล็อก เรายังไม่มีบริการโคลนเสียง ถ้ามีตัวละครมากกว่าจำนวนเสียงที่มี ก็ต้องใช้เสียงซ้ำกันข้ามตัวละคร
- เพื่อน AI ที่ถูกใช้งานหนักมีค่าใช้จ่ายเท่าไร
- ประมาณ $2.16 ต่อเดือน สำหรับผู้ใช้ที่ได้รับคำตอบเป็นเสียงวันละ 40 ครั้ง ค่าเสียงคิดตามจำนวนตัวอักษร เดือนที่คุยน้อยจึงจ่ายน้อยลง และเดือนที่เงียบสนิทก็ไม่มีค่าใช้จ่าย
เริ่มต้นด้วยเครดิตฟรี
เข้าสู่ระบบด้วย Google, GitHub หรือ Hugging Face แล้วใช้เครดิตฟรี 100 เครดิตกับข้อความของคุณเอง