Paxa Labs

ลดความหน่วง

สิ่งที่ API ทำระหว่างรับคำขอเสียงจนส่งเสียงแรก ขั้นตอนใดที่ไคลเอนต์ควบคุมได้ และแต่ละทางเลือกมีต้นทุนอะไร

ดูเป็น Markdown

ระหว่างรับคำขอเสียงจนส่งเสียงแรก API ตรวจคีย์ คิดเครดิตของคำขอ เตรียมข้อความ และสังเคราะห์ช่วงต้นของข้อความ

curl -N -s -o /dev/null -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-v2", "stream": true}' \
  -w "connect %{time_connect}s, tls %{time_appconnect}s, first byte %{time_starttransfer}s\n"

สิ่งที่ทำก่อนสังเคราะห์#

API แคชคีย์ที่ตรวจแล้วไว้ 5 นาที คำขอที่มาถึงหลังแคชหมดอายุจึงต้องค้นฐานข้อมูลเพิ่มหนึ่งครั้ง API ยังแคชยอดเครดิตของบัญชีไว้ 60 นาทีหลังคำขอที่คิดเครดิตแต่ละครั้ง เมื่อยอดเครดิตในแคชมีอย่างน้อย 4 เท่าของค่าบริการของคำขอ การสังเคราะห์จะเริ่มพร้อมกับการคิดเครดิต

การคิดเครดิตยังคงเสร็จก่อนที่ API จะส่งไบต์แรก และคำขอที่ยอดเครดิตไม่พอตอบ 402 insufficient_credits โดยไม่มีเสียง ในสี่กรณีต่อไปนี้ API คิดเครดิตให้เสร็จก่อนจึงเริ่มสังเคราะห์ เวลารอจึงเพิ่มขึ้นเท่ากับเวลาของการคิดเครดิต

  • ยอดเครดิตในแคชต่ำกว่า 4 เท่าของค่าบริการของคำขอ
  • บัญชีไม่มีคำขอที่คิดเครดิตในช่วง 60 นาทีที่ผ่านมา จึงไม่มียอดเครดิตในแคช
  • คีย์มีวงเงินเครดิต ให้ใช้คีย์ที่ไม่มีวงเงินกับคำขอที่เสียงแรกสำคัญ และตั้งวงเงินไว้กับคีย์สำหรับงานแบตช์
  • คำขอมี Idempotency-Key ให้ส่งคีย์กับคำขอที่จะส่งซ้ำเมื่อล้มเหลว และละคีย์ได้ในรอบสนทนาที่จะพูดใหม่โดยไม่ส่งซ้ำ

เตรียมแคชก่อนรอบสนทนาแรก#

GET /v1/me ทำให้ API แคชคีย์และเปิดการเชื่อมต่อ แต่คำขอนี้ไม่คิดเครดิต ยอดเครดิตจึงยังไม่ถูกแคช มีเพียงคำขอที่คิดเครดิตเท่านั้นที่ทำให้ยอดเครดิตถูกแคช หากต้องการให้แคชทั้งสองพร้อมก่อนคำตอบแรกของสาย ให้สังเคราะห์หนึ่งคำตอนเริ่มสาย คำขอแรกที่ข้ามขั้นตอนนี้ต้องรอการค้นคีย์ และรอการคิดเครดิตที่ต้องเสร็จก่อนเริ่มสังเคราะห์

แบ่งข้อความยาว#

การตอบกลับแบบสตรีมเริ่มจากช่วงต้นของข้อความระหว่างที่ส่วนที่เหลือยังสังเคราะห์อยู่ เสียงแรกจึงแทบไม่ขึ้นกับความยาว ยกเว้นขั้นตอนเตรียมข้อความ ซึ่งทำกับข้อความทั้งหมดก่อนเริ่มสังเคราะห์ และใช้เวลาเพิ่มตามสัดส่วนของความยาว เมื่อเสียงแรกสำคัญและข้อความยาว ให้ส่งย่อหน้าแรกเป็นคำขอแยก แล้วต่อคิวส่วนที่เหลือตามหลัง

อ่านสตรีมเร็วเท่าที่เครือข่ายส่งได้#

คำขอแบบสตรีมถือช่องคำขอพร้อมกันไว้จนการตอบกลับจบ และการสังเคราะห์เร็วกว่าการเล่นเสียงหลายเท่า ไคลเอนต์ที่อ่านด้วยความเร็วของการเล่นจึงถือช่องไว้นานเท่าความยาวของเสียง ให้อ่านเนื้อหาเร็วเท่าที่เครือข่ายส่งได้แล้วบัฟเฟอร์ไว้ฝั่งคุณ ช่องจะว่างสำหรับคำขอถัดไป

เลือกระหว่าง HTTP กับการเชื่อมต่อสด#

การเชื่อมต่อสดยืนยันตัวตนครั้งเดียวแล้วส่งเฉพาะเฟรม text แต่การคิดเครดิตของการสังเคราะห์แต่ละครั้งต้องเสร็จก่อนการสังเคราะห์ครั้งนั้นจะเริ่ม สำหรับประโยคที่ครบแล้วหนึ่งประโยค คำขอ HTTP แบบสตรีมบนการเชื่อมต่อที่เปิดอยู่ทำงานฝั่งเซิร์ฟเวอร์น้อยกว่า การเชื่อมต่อสดเร็วกว่าเมื่อข้อความทยอยมาจากโมเดลภาษา และเมื่อทางเลือกอีกทางคือการเปิดการเชื่อมต่อใหม่ทุกรอบสนทนา ให้เปิดตั้งแต่เริ่มบทสนทนา เมื่อผู้ใช้พูดแทรกให้ส่ง cancel แล้วคงการเชื่อมต่อไว้ เพราะการเชื่อมต่อที่ปิดไปต้องอัปเกรดใหม่ทั้งหมด

รูปแบบเสียงและไทม์สแตมป์#

wav และ pcm ไม่ผ่านตัวเข้ารหัส mp3 เพิ่มการเข้ารหัสช่วงสั้น และ opus เพิ่มการเข้ารหัสที่นานที่สุด ทุกแบบใช้เวลาน้อยเมื่อเทียบกับการสังเคราะห์ การตอบกลับ wav แบบสตรีมคือ PCM 16 บิต little-endian โมโนที่ 24 kHz ต่อจากเฮดเดอร์ 44 ไบต์ ซึ่งฟิลด์ขนาดทั้งสองเป็น 0xFFFFFFFF ส่วน pcm ส่งแซมเปิลชุดเดียวกันโดยไม่มีเฮดเดอร์ ไปป์ไลน์ที่รับ PCM ดิบส่งแซมเปิลต่อได้ทันที ไม่ต้องมีตัวถอดรหัสและไม่ต้องตัดอะไรทิ้ง

timestamps ไม่ทำให้เสียงแรกช้าลง แต่เปลี่ยนการตอบกลับแบบสตรีมเป็นอีเวนต์ NDJSON ที่บรรจุเสียงเป็น base64 ซึ่งใหญ่ขึ้นราวหนึ่งในสามและส่งโดยไม่บีบอัด ส่วนการตอบกลับแบบไฟล์เต็มที่มีไทม์สแตมป์จะถูกบีบอัดด้วย gzip เมื่อไคลเอนต์รับ gzip ซึ่งลดส่วนที่เพิ่มขึ้นนั้นได้เกือบทั้งหมด

การรับส่งข้อมูล#

โฮสต์ของ API รองรับ HTTP/2 และ HTTP/3 การเชื่อมต่อ HTTP/2 หนึ่งเส้นรับส่งคำขอพร้อมกันได้ถึงจำนวนคำขอพร้อมกันของแพ็กเกจ จึงไม่ต้องมี connection pool การทิ้งการตอบกลับก่อนอ่านจบจะปิดการเชื่อมต่อ HTTP/1.1 ส่วนบน HTTP/2 จะรีเซ็ตเฉพาะสตรีมของคำขอนั้น การตอบกลับ preflight มี access-control-max-age 24 ชั่วโมง

การส่งซ้ำ#

API ไม่เข้าคิวคำขอ คำขอที่เกินโควตารายนาทีหรือเกินจำนวนคำขอพร้อมกันตอบ 429 ทันที และคำขอที่ถูกปฏิเสธยังนับรวมในโควตา ไคลเอนต์ที่ส่งซ้ำต่อเนื่องขณะได้ 429 จึงยืดเวลาที่ตัวเองถูกจำกัด เมื่อได้ rate_limited ให้รอตาม retry-after เมื่อได้ concurrency_limited ให้รอจนคำขอของคุณเองจบหนึ่งคำขอ