ข้ามไปยังเนื้อหาหลัก

บทเรียน Grok Voice Transcribe 2.0 API: สร้างตัวถอดความสายสนับสนุนแบบเรียลไทม์

เรียนรู้การสร้างตัวถอดความสายสนับสนุนแบบเรียลไทม์ด้วย Grok Voice Transcribe 2.0 API ใน Python แล้วเพิ่มการแยกผู้พูด Smart Turn และออดิโอโทรศัพท์ 8 kHz
อัปเดตแล้ว 5 ต.ค. 2569  · 12 นาที อ่าน

สำรวจด้วย AI

ChatGPTClaudePerplexity

Grok Voice Transcribe 2.0 ของ SpaceXAI เป็นโมเดลถอดเสียงเป็นข้อความ ในบทเรียน Grok Voice Transcribe 2.0 API นี้ จะส่งไฟล์บันทึกผ่าน REST และส่งเสียงสดผ่าน WebSocket API จะส่งคืนข้อความ เวลาเป็นคำ ไอดีผู้พูดแบบเลือกได้ และอีเวนต์ปิดเทิร์น โดยไม่ตอบกลับผู้โทร

สายสนับสนุนยากกว่าผู้บรรยายเดี่ยวที่เสียงใส มีช่องว่างสั้นๆ ชื่อที่ไม่คุ้น หลายผู้พูด และรายละเอียดการติดต่อที่อ่านผ่านสายนอก 8 kHz โปรเจกต์ตัวอย่างชื่อ Qivora Sync ทำให้บทเรียนมีเส้นเรื่องเดียว: ลูกค้ารายงานการซิงก์ไฟล์ล้มเหลว เจ้าหน้าที่เก็บรายละเอียดการติดต่อ และวิศวกรสายเอสคาเลชันเข้าร่วม ไคลเอนต์ Python เดียวกันนี้จัดการไฟล์บันทึกก่อน และเสียงสดภายหลังได้

หากต้องการแบบพูดคุยสองทางที่โมเดลตอบผู้โทรเอง ดู บทเรียน Grok Voice Think Fast 2.0ของเรา โค้ดสำหรับบทเรียนนี้อยู่ใน ที่เก็บ GitHubนี้

สรุปสั้นๆ

เวลาไม่พอ? นี่คือสิ่งที่สายตัวอย่างแสดงให้เห็น

  • POST /v1/stt ใช้กับออดิโอบันทึก และ wss://api.x.ai/v1/stt ใช้กับเสียงสด โดยมีชุดตัวควบคุมร่วมสำหรับการแยกผู้พูด คำสำคัญ ฟิลเลอร์ และการจัดการออดิโอ

  • คำสำคัญช่วยแก้ชื่อผลิตภัณฑ์ที่แต่งขึ้น แต่พจนานุกรมที่เอนเอียงแรงดึงเสียงสะท้อนแผ่วๆ ให้เข้าหาชื่อนั้นในเช็คเสียงสด

  • ป้ายผู้พูดคงที่บนเสียงสะอาด แต่ไม่น่าเชื่อถือบน 8 kHz

  • ตอนสลับเป็นภาษาอาหรับยังคงใช้ตัวอักษรอาหรับ และ format=true แก้รูปแบบหมายเลขโทรศัพท์ได้ แต่แก้อีเมลได้แค่ครึ่งเดียว

  • ในช่วงหยุดยาวกลางหมายเลข Smart Turn ทะลุทุกค่าธรณีที่ทดสอบ ดังนั้นการจูนธรณีอย่างเดียวไม่พอ

Grok Voice Transcribe 2.0 คืออะไร

Grok Voice Transcribe 2.0 (grok-voice-transcribe-2.0) คือโมเดลถอดเสียงเป็นข้อความของ SpaceXAI เส้นทาง REST ใช้ถอดเสียงไฟล์ที่เสร็จแล้ว ส่วนเส้นทาง WebSocket ใช้กับเสียงสด

ประกาศ Grok Voice Transcribe 2.0 ของ SpaceXAI เน้นสายโทรศัพท์ หลายผู้พูด ข้อมูลยืนยันตัวตน และเสียงหลายภาษา สำหรับการเปรียบเทียบเบนช์มาร์ก ดู ภาพรวม Grok Voice Transcribe 2.0 ของเรา

สร้างตัวถอดความสายสนับสนุนแบบเรียลไทม์

ฟิกซ์เจอร์ Qivora Sync ที่ควบคุมได้ยังคงเดิม ขณะปรับออดิโอและการตั้งค่า API สายนี้มีชื่อผลิตภัณฑ์ที่แต่งขึ้น ฟิลเลอร์ การสลับภาษา รายละเอียดการติดต่อที่พูดสะกด ช่วงหยุดระหว่างการคีย์ด้วยคำพูด และผู้พูดคนที่สาม

ไปป์ไลน์สายสนับสนุน Qivora Sync: ผู้พูดสามคนเข้าสู่ Grok Voice Transcribe 2.0 ออกมาเป็นทรานสคริปต์สดที่แยกผู้พูดแล้ว

สามผู้พูดรวมเป็นทรานสคริปต์สดเดียว ภาพโดยผู้เขียน

สร้างสายสามผู้พูด

ฟิกซ์เจอร์ที่ควบคุมได้ใช้เสียงสามแบบที่แตกต่างกันจาก Grok Text to Speech API แต่ละช่วงภาษาถูกสังเคราะห์แยกกันและรวมด้วย ffmpeg เพื่อให้จุดสลับคงที่ API ยังรับ language=auto; การแยกคำขอเป็นการเลือกเพื่อการทดลอง ไม่ใช่ข้อบังคับของ API

กำหนดทรานสคริปต์ที่คาดหวัง

ก่อนคำขอแรก ให้กำหนดข้อความที่คาดหวัง ผู้พูด การสะกดชื่อผลิตภัณฑ์ รายละเอียดลูกค้า ฟิลเลอร์ และช่วงหยุด จากนั้นทุกการตั้งค่าจะมีเป้าหมายเดียวกัน

ตั้งค่า Grok Voice Transcribe 2.0 ใน Python

ติดตั้งไลบรารีที่ต้องใช้ก่อนส่งออดิโอ

ข้อกำหนดเบื้องต้น

ต้องมี Python 3.10 ขึ้นไป คีย์ API ของ xAI และ ffmpeg สำหรับสร้างออดิโอ ไคลเอนต์ Python ใช้ requests, websockets และ python-dotenv

เอกสาร Speech to Text ระบุว่า 2.0 เป็นค่าเริ่มต้นเมื่อไม่ระบุ model และ grok-voice-transcribe-1.0 หมดอายุเมื่อ 2 ตุลาคม 2026 แนะนำให้ปักหมุด ID เวอร์ชันไว้

ติดตั้งไลบรารีและสร้างออดิโอ

โคลนที่เก็บ ใส่คีย์ลงใน .env และสร้างออดิโอตัวอย่าง:

git clone https://github.com/KhalidAbdelaty/grok-voice-transcribe-2.0.git
cd grok-voice-transcribe-2.0
pip install -r requirements.txt
cp .env.example .env    # then paste your key into .env
python project/scripts/make_fixtures.py

คำสั่งตั้งค่าสร้างบทสนทนาและไฟล์ออดิโอที่ใช้ภายหลัง หากมีไฟล์บันทึกของตนเอง ให้ข้ามคำสั่งนั้น

ไฟล์ .env ที่เขียนบน Windows อาจทิ้ง \r ไว้ต่อท้ายคีย์ และ requests จะปฏิเสธเฮดเดอร์ก่อนส่งถึง SpaceXAI ให้ลบอักขระนั้นออกก่อนใส่คีย์ลงในเฮดเดอร์ Authorization

ตั้งค่ามาตรฐานพื้นฐานสำหรับการถอดความแบบแบตช์

ฐานเปรียบเทียบคือโมเดลโดยไม่เปิดตัวเลือกใดๆ เพื่อให้ทุกการเปลี่ยนแปลงภายหลังมีสิ่งให้เทียบ คำขอแรกส่งไฟล์และรุ่นโมเดลที่ปักหมุด:

import os
import requests
from dotenv import load_dotenv

load_dotenv()
api_key = os.environ["XAI_API_KEY"].strip()

with open("support_call.wav", "rb") as audio_file:
    response = requests.post(
        "https://api.x.ai/v1/stt",
        headers={"Authorization": f"Bearer {api_key}"},
        data=[("model", "grok-voice-transcribe-2.0")],
        files={"file": ("support_call.wav", audio_file, "audio/wav")},
    )

response.raise_for_status()
result = response.json()

การตอบกลับมี text, languageที่ตรวจจับได้ duration และอาร์เรย์ words ที่มีเวลาเป็นคำ เอกสารอ้างอิง REST แสดง confidence รายคำ แต่ไม่ปรากฏในคำตอบแบบแบตช์ของฟิกซ์เจอร์นี้ แนะนำให้ถือว่าฟิลด์นี้เป็นตัวเลือก และตรวจสอบการตอบกลับของ API ทุกครั้งก่อนใช้งาน วางฟิลด์ตัวเลือกไว้ก่อน file; ฟิลด์ที่ตามหลังอาจถูกละเลย

ฐานเปรียบเทียบลบฟิลเลอร์ คงข้อความอาหรับเป็นตัวอักษรอาหรับ และเว้นตัวเลขที่พูดออกจากกัน ทั้งยังสะกดชื่อผลิตภัณฑ์ที่แต่งขึ้นผิดอย่างสม่ำเสมอ

เพิ่มการแยกผู้พูด คำสำคัญ และการจัดรูปแบบข้อความ

ทรานสคริปต์สำหรับสนับสนุนต้องมีป้ายผู้พูด การสะกดชื่อผลิตภัณฑ์ให้ถูก และรายละเอียดลูกค้าที่ใช้การได้ แต่ละการตั้งค่าเป็นอีกหนึ่งฟิลด์แบบฟอร์ม:

data = [
    ("model", "grok-voice-transcribe-2.0"),
    ("diarize", "true"),         # a speaker id on every word
    ("keyterm", "Qivora Sync"),  # repeat the field for more terms
    ("language", "en"),          # required by format
    ("format", "true"),          # inverse text normalization
    ("filler_words", "false"),   # the default; true keeps "uh" and "um"
]

เพิ่มตัวเลือกทีละรายการกับออดิโอชุดเดิม เริ่มจากป้ายผู้พูด

จัดกลุ่มคำเป็นช่วงการพูดของผู้พูด

การแยกผู้พูด ให้คำมีไอดีผู้พูดแบบตัวเลข ไม่ใช่ชื่อ จัดกลุ่มคำที่ต่อเนื่องกันและมีไอดีเดียวกันเพื่อสร้างช่วงการพูด:

def group_turns(words):
    turns = []
    for word in words:
        if turns and turns[-1]["speaker"] == word.get("speaker"):
            turns[-1]["words"].append(word["text"])
            turns[-1]["end"] = word["end"]
        else:
            turns.append({"speaker": word.get("speaker"), "start": word["start"],
                          "end": word["end"], "words": [word["text"]]})
    for turn in turns:
        turn["text"] = " ".join(turn.pop("words"))
    return turns

บนเสียงสะอาด แต่ละช่วงที่ทราบคงไอดีผู้พูดสม่ำเสมอ การแมปชื่อด้วยลำดับการปรากฏครั้งแรกใช้ได้เฉพาะเมื่อทราบลำดับการพูดอยู่แล้ว ระบบจริงควรมีการแมปผู้พูดของตนเอง

ทรานสคริปต์ที่แยกผู้พูดของสาย Qivora Sync แสดงช่วงการพูดแยกสามผู้พูดพร้อมเวลา

เสียงสะอาดช่วยให้ป้ายผู้พูดสม่ำเสมอ ภาพโดยผู้เขียน

ใช้การเอนเอียงคำสำคัญกับชื่อผลิตภัณฑ์

การเอนเอียงคำสำคัญเป็นคำใบ้ระดับคำขอ ไม่ใช่การเทรน ส่งผ่าน keyterm=Qivora Sync (ได้สูงสุด 100 คำ สูงสุด 50 อักขระต่อคำ) โมเดลจะโน้มเอียงไปทางการสะกดนั้นเมื่อเสียงสนับสนุน

คำสำคัญช่วยแก้ข้อผิดพลาดชื่อผลิตภัณฑ์ของฐานเปรียบเทียบโดยไม่เปลี่ยนทรานสคริปต์ส่วนรอบข้าง

ในการตรวจสอบเสียงสดแยกต่างหาก พจนานุกรมที่เอนเอียงแรงดึงเสียงสะท้อนแผ่วๆ ให้เข้าใกล้คำสำคัญ ผลนั้นไม่ได้หมายความว่าคำสำคัญทำให้เกิดข้อความเท็จด้วยตัวมันเอง; แต่หมายความว่าเสียงกำกวมยังต้องตรวจเช็คเสียงสะท้อน

ถอดความการสลับภาษาอังกฤษ-อาหรับ

อย่างที่ฐานเปรียบเทียบแสดง ภาษาอาหรับของ Khalid ยังคงเป็นตัวอักษรอาหรับ ผลลัพธ์เหมือนกันทั้งกับการตรวจจับอัตโนมัติและกับ language=enเพราะ language เลือกกฎการจัดรูปแบบ ไม่ได้บังคับภาษาผลลัพธ์

จัดรูปแบบหมายเลขโทรศัพท์และอีเมลที่พูดสะกด

ฐานเปรียบเทียบเว้นตัวเลขที่พูดออกจากกัน Inverse Text Normalization (ITN) แปลงรูปแบบคำพูดให้เป็นรูปแบบตัวเขียน format=true เปิดใช้และต้องมี language มิฉะนั้นคำขอจะล้มเหลวด้วย 400

หมายเลขโทรศัพท์ถูกร้อยเป็นสตริงตัวเลขเดียว อีเมลถูกทำให้เป็นปกติแค่บางส่วน: เครื่องหมายวรรคตอนดีขึ้น แต่คำว่า "at" ที่พูด และโดเมนที่สะกดยังต้องเกลา

ผลที่ไม่สม่ำเสมอนั้นน่าหงุดหงิด ITN จัดรูปแบบข้อความ ไม่ได้ตรวจสอบความถูกต้องของข้อมูลการติดต่อ แนะนำให้ตรวจสอบทั้งสองฟิลด์ก่อนจัดเก็บ

ITN ยังสามารถเขียนวลีบอกระยะเวลาให้เป็นคำย่อเชิงปริมาณได้ด้วย ในคำตอบแบบแบตช์ที่จัดรูปแบบของฟิกซ์เจอร์นี้ เฉพาะ text ระดับบนสุดเท่านั้นที่ถูกทำให้เป็นปกติ; อาร์เรย์ words ยังคงรูปแบบคำพูด

เก็บหรือเอาคำฟิลเลอร์ออก

อย่างที่ฐานเปรียบเทียบแสดง ฟิลเลอร์ถูกลบออกจาก text และ words ตามค่าเริ่มต้น filler_words=true นำ "uh" และ "um" ของ Khalid กลับมาตามที่คาด ไว้ปิดสำหรับโน้ตสนับสนุน และเปิดสำหรับบันทึกคำต่อคำสำหรับ QA

เอาต์พุตแบบแบตช์รองรับผู้พูด พจนานุกรม การจัดรูปแบบ และการควบคุมคำฟิลเลอร์ ต่อไปให้ส่งออดิโอเดียวกันเป็นสตรีมสด

สตรีม Grok Voice Transcribe 2.0 ผ่าน WebSocket

เส้นทางสตรีมใช้พารามิเตอร์คิวรีแทนข้อความตั้งค่า รอ transcript.created ส่งออดิโอบิตนารีดิบ (ไม่ใช่ base64) และปิดด้วย {"type": "audio.done"} บทเรียน GPT Live Transcribe ของเราใช้รูปแบบเดียวกันกับโมเดลอื่น

เริ่มจากอีเวนต์ จากนั้นเชื่อมต่อไคลเอนต์

แบบแบตช์ใช้ format=true ตามเอกสารคู่กับ language=en เอกสารสตรีมระบุว่า language เปิด ITN แต่ในการทดสอบสด language=en เพียงอย่างเดียวไม่เปลี่ยนทรานสคริปต์ รายการคิวรีของ WebSocket ไม่มี format ดังนั้นบทเรียนนี้จึงถือว่า ITN บนสตรีมเป็นพฤติกรรมที่ต้องตรวจสอบ ไม่ใช่พึ่งพา

อ่านอีเวนต์ชั่วคราวและสุดท้าย

ทุกการอัปเดตทรานสคริปต์คืออีเวนต์ transcript.partial ที่มีบูลีนสองตัว ข้อความชั่วคราวอาจยังเปลี่ยนได้ เมื่อเป็นชิ้นสุดท้าย (is_final=true) จะล็อกข้อความราว 3 วินาทีในขณะที่เทิร์นยังเปิดอยู่ และเมื่อเป็นอุตเทอแรนซ์สุดท้าย (speech_final=true) จะปิดเทิร์น

โฟลว์อีเวนต์สตรีมตั้งแต่สร้างทรานสคริปต์ ผ่านช่วงชั่วคราว ชิ้นสุดท้าย อุตเทอแรนซ์สุดท้าย จนถึงสถานะเสร็จ

สถานะสตรีมพาเนื้อความไปสู่ความเป็นที่สุดท้าย ภาพโดยผู้เขียน

สตรีมออดิโอ PCM 16 kHz ใน Python

สำหรับสตรีม ให้แปลงต้นทางเป็นโมโน PCM 16 บิตที่ 16 kHz ก่อน ไคลเอนต์หลักส่งทีละชิ้นความยาว 100 มิลลิวินาทีในจังหวะเวลาเรียลไทม์ ขณะที่งานอีกตัวรับอีเวนต์ทรานสคริปต์:

import asyncio, json, os, wave
import websockets
from dotenv import load_dotenv 

load_dotenv()

url = ("wss://api.x.ai/v1/stt?model=grok-voice-transcribe-2.0"
       "&sample_rate=16000&encoding=pcm&interim_results=true&diarize=true")
headers = {"Authorization": f"Bearer {os.environ['XAI_API_KEY'].strip()}"}

async def stream_call(path):
    async with websockets.connect(url, additional_headers=headers) as ws:
        assert json.loads(await ws.recv())["type"] == "transcript.created"

        async def send():
            with wave.open(path, "rb") as wf:
                assert wf.getframerate() == 16000
                assert wf.getnchannels() == 1
                assert wf.getsampwidth() == 2
                while chunk := wf.readframes(1600):
                    await ws.send(chunk)
                    await asyncio.sleep(0.1)
            await ws.send(json.dumps({"type": "audio.done"}))

        async def receive():
            async for raw in ws:
                event = json.loads(raw)
                if event["type"] == "transcript.partial":
                    print(event["text"])
                elif event["type"] == "transcript.done":
                    break

        await asyncio.gather(send(), receive())

ข้อความชั่วคราวเพิ่มขึ้นราวทุกครึ่งวินาที นี่เป็นการวัดในเครื่อง ไม่ใช่ค่าหน่วงเวลาทางการ

เทอร์มินัลแสดงคำบรรยายชั่วคราวอัปเดตก่อนกลายเป็นบรรทัดทรานสคริปต์สุดท้าย

คำบรรยายชั่วคราวนิ่งกลายเป็นทรานสคริปต์สุดท้าย ภาพโดยผู้เขียน

ชิ้นสุดท้ายช่วยตรึงข้อความโดยไม่ปิดเทิร์น Smart Turn ควบคุมว่าเมื่อไร speech_final จะปิด

คงลำดับชิ้นส่วนทรานสคริปต์

การแสดงเฉพาะอีเวนต์ที่กำลังทำงานทำให้คำก่อนหน้าหายไปหลังชิ้นสุดท้ายของแต่ละชิ้น เพราะข้อความชั่วคราวถัดไปเริ่มใหม่จากเสียงที่เข้ามา

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

ข้อความสามารถเติบโตโดยไม่สูญเสียชิ้นก่อนหน้า เมื่อจัดการสถานะการแสดงผลแล้ว เส้นเขตเทิร์นคือปัญหาสตรีมที่เหลือ

ใช้ Smart Turn เพื่อตรวจจับจุดจบของเทิร์น

Smart Turn ประเมินทุกความเงียบและคาดการณ์ว่าผู้พูดพูดจบหรือยัง ใช้แก้กรณีหมายเลขของ Khalid อย่าง "ศูนย์ หนึ่ง ศูนย์, ห้า ห้า ห้า, [หยุด], หนึ่ง สอง สาม สี่" ที่ความเงียบอย่างเดียวบอกไม่ได้ว่าเป็นช่วงคิดหรือจบแล้ว

ทดสอบธรณีของ Smart Turn

ธรณีไม่ได้หมายถึงความมั่นใจในการถอดความ หรือ ธรณี VAD แต่คือความน่าจะเป็นว่าเทิร์นจบ ที่ความเงียบต้องผ่านก่อนที่ speech_final จะยิง; ต่ำกว่านั้น เทิร์นยังเปิดอยู่ ตั้งค่าด้วยพารามิเตอร์คิวรีสองตัว:

params += [
    ("smart_turn", "0.7"),           # end-of-turn probability needed to close
    ("smart_turn_timeout", "3000"),  # close anyway after 3 s of silence
]

เอกสารระบุว่า 0.5 สมดุล 0.7 ระมัดระวังสำหรับลำดับตัวเลข และ 0.9 ระมัดระวังมาก ในฟิกซ์เจอร์นี้ ช่วงหยุดที่สั้นกว่าหน้าต่าง endpointing ค่าเริ่มต้น ไม่ให้ผลตัดสิน Smart Turn ที่เป็นประโยชน์ นี่เป็นผลการสังเกต ไม่ใช่กฎเวลาในเอกสาร

ในการทดสอบสตรีม การหยุดส่งเฟรมเสียงไม่ทำให้ตัวจับเวลาความเงียบที่สังเกตเห็นเดินต่อ การส่งความเงียบดิจิทัลต่อไปทำให้ Smart Turn ปิดอุตเทอแรนซ์ได้

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

ไทม์ไลน์ของอุตเทอแรนซ์หมายเลขโทรศัพท์ แสดงคำพูด ช่วงหยุด และความมั่นใจปิดเทิร์นที่แต่ละค่าธรณี

ช่วงหยุดยาวอาจแบ่งการคีย์ตัวเลขด้วยคำพูด ภาพโดยผู้เขียน

ผู้โทรที่เป็นมนุษย์คาดเดายากกว่า ลำดับตัวเลขสั้นๆ อาจดูเสร็จแล้ว จากนั้นผู้โทรพูดต่อ

หาก Smart Turn ปิดระหว่างการคีย์ตัวเลขด้วยคำพูด ให้รอสั้นๆ และรวมส่วนต่อเนื่องก่อนตอบกลับ

ตั้งค่าเวลา timeout ของ Smart Turn

smart_turn_timeout ปิดเทิร์นหลังความเงียบคงที่ แม้ Smart Turn จะไม่แน่ใจ บนสตรีมสามผู้พูดที่เร็ว Smart Turn จัดกลุ่มหลายช่วงที่ทราบก่อนที่ timeout จะบังคับปิด

หากทราบจุดจบเทิร์นอยู่แล้ว ให้ส่ง {"type": "finalize"} ที่แต่ละขอบเขต; หากไม่ ให้ใช้ Smart Turn คู่กับ timeout

เมื่อควบคุมขอบเขตเทิร์นได้แล้ว ผู้โทรคนเดิมยังต้องผ่านสาย 8 kHz ให้ได้

ถอดความออดิโอโทรศัพท์ 8 kHz

ออดิโอคุณภาพโทรศัพท์ที่นี่คือ G.711 mu-law 8 kHz ทำจากสายเดียวกัน:

ffmpeg -i support_call.wav -ar 8000 -ac 1 -f mulaw support_call_8k.raw

ออดิโอโทรศัพท์แบบดิบไม่มีคอนเทนเนอร์ ดังนั้นให้ตั้ง audio_format=mulaw และ sample_rate=8000 ในฟอร์มแบบแบตช์ หรือ encoding=mulaw&sample_rate=8000 บนซ็อกเก็ต ตรวจสอบข้อความและป้ายผู้พูดแยกกัน

เปรียบเทียบเสียงสะอาดกับเสียงโทรศัพท์

ข้อค้นพบเรื่องคำสำคัญ การจัดรูปแบบ และการสลับภาษาก่อนหน้า เปลี่ยนแปลงเล็กน้อยที่ 8 kHz

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

เวอร์ชันที่ไม่นิ่งจะจำกัดย่านสัญญาณของสายไว้ที่ 300–3400 Hz เข้ารหัสเป็น mu-law 8 kHz และดรอปแพ็กเก็ต 20 มิลลิวินาทีแต่ละแพ็กเก็ตด้วยความน่าจะเป็น 0.03 ใช้ค่า seed แบบสุ่มคงที่ 7 เพื่อให้ช่องว่างเดิมซ้ำได้ทุกครั้ง

การสูญเสียแพ็กเก็ตนั้นไม่ได้เปลี่ยนทรานสคริปต์ภาษาอังกฤษมากในตัวอย่างนี้ และรายละเอียดการติดต่อที่พูดยังคงเรียงลำดับถูกต้อง ผลนี้ใช้ได้เฉพาะตัวอย่างนี้เท่านั้น

การจำลองโทรศัพท์ทำให้ย่านเสียงแคบลงและดรอปแพ็กเก็ต ภาพโดยผู้เขียน

ปรับ VAD สำหรับเสียงโทรศัพท์

การตรวจจับกิจกรรมเสียง (VAD) ตัดสินว่าออดิโอเป็นเสียงพูดหรือไม่ เอกสารแนะนำให้ลด vad_threshold สำหรับเสียงโทรศัพท์ที่เบา โดยเสี่ยงต่อการเกิดข้อความจากเสียงรบกวน

การลด vad_threshold ไม่เปลี่ยนแปลงอะไรบนเสียงโทรศัพท์ที่สะอาด เพราะไม่มีเสียงเบาให้กู้คืน ผลลัพธ์ว่างนี้สนับสนุนกฎหนึ่งข้อ: ลดธรณีเฉพาะเมื่อเสียงโทรศัพท์หายไป

ใช้การถอดความแบบหลายแชนเนลเพื่อแยกผู้พูด

ใช้ฟอร์มแบบแบตช์ใหม่โดยไม่ใส่ diarize:

data = [
    ("model", "grok-voice-transcribe-2.0"),
    ("multichannel", "true"),
]

API ตรวจจับจำนวนแชนเนลจาก WAV หรือคอนเทนเนอร์อื่น สำหรับออดิโอดิบหลายแชนเนล ให้เพิ่ม ("channels", "3"); อินพุต WebSocket แบบหลายแชนเนลต้องระบุจำนวนแชนเนลอย่างชัดเจนด้วย

ส่งฟอร์มพร้อมไฟล์หลายแชนเนลผ่านคำขอ REST ที่แสดงก่อนหน้า แล้วอ่าน result["channels"] แต่ละรายการมีดัชนี ข้อความทรานสคริปต์ และคำที่มีเวลา ในฟิกซ์เจอร์สามแชนเนลที่ควบคุมได้ แต่ละแชนเนลมีเฉพาะผู้พูดที่กำหนดไว้ สตรีมมิงใช้การแยกแบบเดียวกันและเพิ่ม channel_index ในอีเวนต์

แนะนำให้ใช้ขาแยกเมื่อระบบโทรศัพท์มีให้ แตกต่างจากการแยกผู้พูดในส่วนเสียงโทรศัพท์ การแยกที่ทราบแน่ชัดไม่ต้องอนุมานผู้พูด

สร้างตัวถอดความสายสนับสนุนด้วย Python แบบครบชุด

ไคลเอนต์แบบครบชุดเผยชุดการตั้งค่าเดียว จากนั้นสร้างฟอร์ม REST หรือ URL WebSocket แยกกัน การตั้งค่าร่วมครอบคลุมการแยกผู้พูด คำสำคัญ คำฟิลเลอร์ การเข้ารหัสออดิโอ และการจัดการเทิร์น; การจัดรูปแบบเป็นไปตามกฎเฉพาะทรานสปอร์ตที่กล่าวไป

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

สำรวจเดโมเอเจนต์เสียงแบบเต็ม

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

Transcribe คงบทบาทเดิมในเดโมนั้น: สร้างข้อความ โมเดลภาษาช่วยเขียนคำตอบ และ Grok TTS พูดคำตอบออกมา

สายสนทนาสดสลับเส้นทางออดิโอกลางบทสนทนา วิดีโอโดยผู้เขียน

ข้อจำกัดของ Grok Voice Transcribe 2.0

ทรานสคริปต์สำหรับสนับสนุนอาจมีชื่อ เบอร์โทรศัพท์ และอีเมล เอกสาร คำถามที่พบบ่อยด้านความปลอดภัย ของ SpaceXAI ระบุว่าเก็บข้อมูล API แบบเข้ารหัสเมื่อพักเป็นเวลา 30 วันเพื่อการตรวจสอบการใช้งานในทางที่ผิด และยังระบุว่าไม่ใช้ข้อมูลเพื่อเทรนโดยไม่ได้รับอนุญาต ทีมที่เข้าเกณฑ์สามารถเปิด Zero Data Retention ได้ในระดับทีม

เก็บคีย์ API ไว้บนเซิร์ฟเวอร์ของตน เอกสาร Speech-to-Text ระบุให้พร็อกซี WebSocket ผ่านแบ็กเอนด์ของคุณ

สายที่ควบคุมได้หนึ่งสายไม่สามารถแทนสำเนียง ห้อง หรือสายโทรศัพท์ทั้งหมดได้ ตรวจสอบการตั้งค่ากับออดิโอจากสภาพแวดล้อมเป้าหมายก่อนใช้งานจริง

ข้อผิดพลาดทั่วไปและการแก้ไขปัญหา

ส่วนใหญ่ล้มเหลวจากการจัดรูปแบบออดิโอหรือการจัดการซ็อกเก็ต:

  • InvalidHeader ... return character(s) in header value คือ \r ของ Windows ที่ติดกับคีย์

  • รหัส 400 อาจหมายถึงขาด file หรือ url รูปแบบไม่รองรับ ออดิโอดิบที่ไม่มี sample_rate หรือ format=true ที่ไม่มี language

  • ในการทดสอบสตรีม การหยุดส่งเฟรมเสียงไม่ทำให้ตัวจับเวลาความเงียบที่สังเกตเห็นเดินต่อ; การส่งความเงียบดิจิทัลต่อไปช่วยให้ปิดเทิร์นได้

  • cannot call recv while another coroutine is already running recv หมายถึงมีคอร์รุตีนสองตัวอ่านซ็อกเก็ตเดียว ให้การเชื่อมต่อแต่ละรายการมีรีดเดอร์เดียว

  • ในการตั้งค่า Windows นี้ การประมวลผลออดิโอขาเข้าตัดพยางค์เงียบ ปิดมันหรือตั้งเป็นโหมดจับเสียงแบบ exclusive จะแก้ได้

หากไม่เข้าข่ายข้างต้น ให้เปรียบเทียบอีเวนต์ดิบกับออดิโอต้นทางเพื่อแยกสาเหตุ

ราคา Grok Voice Transcribe 2.0

หน้า ราคา ของ SpaceXAI ระบุค่าถอดความที่ $0.10 ต่อชั่วโมงผ่าน REST และ $0.20 ต่อชั่วโมงสำหรับสตรีม ประกาศระบุว่ารวมการแยกผู้พูด การประทับเวลา และคำสำคัญแล้ว คำนวณค่าใช้จ่ายจากระยะเวลาออดิโอ ไม่ใช่จำนวนคำขอ

แต่ละสตรีมที่เปิดคิดตามระยะเวลาออดิโอของตนเอง ผู้ฟังคนที่สองเพิ่มต้นทุนสตรีม และจะเพิ่มนาที STT เป็นสองเท่าเฉพาะเมื่อทั้งสองสตรีมรับระยะเวลาเต็มเท่ากัน

ข้อคิดท้ายบท

ไม่แนะนำให้ประเมินตัวถอดความสายเฉพาะบนเสียงสะอาด ส่วนเสียงโทรศัพท์แสดงเหตุผลให้เห็นแล้ว

API ส่งคืนข้อมูลการถอดความ ฝั่งไคลเอนต์ยังต้องรับผิดชอบสถานะบทสนทนาและการตรวจสอบความถูกต้อง อีกทั้งควรรักษา ID โมเดลแบบมีเวอร์ชันไว้ ตั้งค่าที่เหลือให้เป็นจุดเริ่ม แล้วตรวจสอบกับออดิโอเป้าหมาย

ส่วนขยายถัดไปคืออินพุตโทรศัพท์ SIP คำศัพท์เฉพาะต่อสาย และการส่งออกไป CRM หากต้องการเอเจนต์แทนตัวถอดความ บทเรียน Grok Voice Agent API ของเราครอบเส้นทางนั้น

FAQs

Grok Voice Transcribe 2.0 รองรับการถอดความแบบเรียลไทม์หรือไม่

รองรับผ่าน WebSocket และไม่จำกัดเฉพาะ PCM ดิบ ไคลเอนต์ที่มีแบนด์วิดท์จำกัดสามารถสตรีมด้วย encoding=opus ประมาณ 4 KB/s เทียบกับ 48 KB/s สำหรับ PCM 24 kHz โดยแต่ละเฟรมต้องบรรจุแพ็กเก็ต Opus หนึ่งแพ็กเก็ต Opus รองรับเฉพาะโมโน จึงไม่รองรับการสตรีมหลายแชนเนล

Grok Voice Transcribe 2.0 รองรับการแยกผู้พูดหรือไม่

ตั้งค่า diarize=true บนปลายทางใดก็ได้ ในการตอบกลับสตรีมมิงแบบแยกผู้พูดของฟิกซ์เจอร์นี้ คำยังมีฟิลด์ที่ไม่อยู่ในเอกสารชื่อ speaker_confidence ด้วย ไม่แนะนำให้นำไปสร้างลอจิกแอปพลิเคชัน ให้มองไอดีผู้พูดเป็นป้ายเฉพาะคำขอหรือเซสชัน ไม่ใช่การรู้จำตัวตนถาวร

Grok Voice Transcribe 2.0 ถอดความหลายภาษาในไฟล์เดียวกันได้หรือไม่

การตรวจจับอัตโนมัติสามารถคงการสลับภาษากลางไฟล์ได้โดยไม่ต้องใบ้ พารามิเตอร์ language ควบคุมการจัดรูปแบบสำหรับ 25 ภาษาที่ระบุ รวมถึงอาหรับ (ar) ดังนั้นควรทดสอบโค้ดที่เกี่ยวข้องกับออดิโอของคุณเองก่อนพึ่งพาผลลัพธ์ที่จัดรูปแบบ

ความแตกต่างระหว่าง Smart Turn กับ VAD คืออะไร

VAD ถามว่าออดิโอเป็นเสียงพูดหรือไม่; Smart Turn ถามว่าเสียงพูดจบหรือยัง vad_threshold ค่าเริ่มต้นคือ 0.5 ในแบบแบตช์ และ 0.08 บนสตรีม endpointing ค่าเริ่มต้น 400 มิลลิวินาที และกำหนดความเงียบที่ต้องมีจึงจะปิดอุตเทอแรนซ์ได้

สามารถถอดความจาก URL แทนการอัปโหลดไฟล์ได้หรือไม่

ใช้ฟิลด์ url ของปลายทางแบบแบตช์แทน file SpaceXAI จะดาวน์โหลดไฟล์บันทึกฝั่งเซิร์ฟเวอร์ และหากดาวน์โหลดล้มเหลวจะส่งกลับ 502

หัวข้อ
ปัญญาประดิษฐ์
AI Agents

เรียนรู้ AI กับ DataCamp!

แทร็ก

วิศวกร AI ระดับ Associate สำหรับนักพัฒนา

26 ชม.
เรียนรู้วิธีผสาน AI เข้ากับแอปพลิเคชันซอฟต์แวร์โดยใช้ API และไลบรารีโอเพนซอร์ส เริ่มต้นเส้นทางสู่การเป็น AI Engineer ของคุณวันนี้!
ดูรายละเอียดRight Arrow
เริ่มคอร์ส
ดูเพิ่มเติมRight Arrow