转写结果
复述一次预订
spokenขอจองโต๊ะวันเสาร์ที่ สิบห้า สำหรับ สี่ ท่านค่ะ
writtenขอจองโต๊ะวันเสาร์ที่ 15 สำหรับ 4 ท่านค่ะ
来电者的一轮发言。书面写法把日期和人数写成阿拉伯数字,这正是预订电话要填写的格式。
逐个报出的快递单号
spokenพัสดุเลขที่ ที เอช หนึ่ง สอง สาม สี่ ห้า หก ส่งถึงไหนแล้วคะ
writtenพัสดุเลขที่ TH123456 ส่งถึงไหนแล้วคะ
在泰语句子里逐个字母报出的编号。最终结果以一个字符串返回,可以直接拿去查询。
复述的金额
spokenยอดที่ต้องชำระคือ หนึ่งพันสองร้อยห้าสิบ บาท ใช่ไหมคะ
writtenยอดที่ต้องชำระคือ 1,250 บาท ใช่ไหมคะ
来电者确认一个数字。就在来电者说出它的那一轮,数字落进了支付流程读取的字段。
本页每组转写对照都是编写的示意,用来说明格式选项会改变什么,发布前已对照实际输出复核。语音转文字页面提供模型对真实录音的实录转写,并注明采集日期。
实时产品如何使用这条连接
录音可以等,对话等不了。在实时产品里,下一步要靠转写稿来推进。语音智能体据此决定如何回复。主管通过它看出一通电话正在出问题。演讲者下方的字幕屏直接显示它。在这三种场景里,说出的话与文字之间的时间差就是产品本身。实时转写把文件这个中间环节拿掉了。麦克风或电话线路一产生音频,就通过 WebSocket 上传,说话人还在继续说,转写稿已经逐轮返回。让这一切可用的关键是轮次。连接会找出说话人停下的位置,发出一句完整的话,下游代码读到的是一整句泰语,结尾可以信赖。泰语让这个判断比看上去更难。泰文书写时词与词之间没有空格,表示一个意思说完的信号,往往是句末的语气词。
为一场对话打开一条连接
发送一个 start 帧,写明模型、编码和采样率,然后随着采集持续推送音频帧。API 密钥留在您的服务器上,浏览器通过它中转麦克风音频。
显示中间结果,按最终结果行事
如果界面上有内容要显示,就先绘制中间结果。下一步操作以每一轮的最终结果为准,其中带有轮次编号、文本,以及它在音频中的位置。
结束会话并读取总量
线路挂断时发送 end 帧。done 事件会报告接收的音频、轮次数,以及这条连接应付的积分,整条连接在请求日志里记为一行。
线路上的一次对话
client → {"type":"start","model":"paxa-stt-lite-realtime-v1-preview"}
server ← {"type":"started","connection":"7d9c2b7e"}
client → 音频帧,在线路接通期间持续发送
server ← {"type":"speech_started","turn":1}
server ← {"type":"speech_ended","turn":1}
server ← {"type":"transcript","turn":1,"is_final":true}
client → {"type":"end"}
server ← {"type":"done","turns":12}一条连接承载整场对话。每一轮的所有事件都沿同一条连接返回,与上行的音频交错进行。
服务端替您判断的事
16 或 48 kHz
输入音频
2 个事件
轮次边界
1 个最终结果
先中间结果,后最终结果
4 小时
单次会话上限
轮次检测在服务端运行。客户端负责发送音频、读取事件,同一套约定适用于浏览器中转、SIP 网关,以及按自身节奏播放的音频文件。
一轮发言,从中间结果到最终结果
transcript turn 2 interim สวัสดีค่ะ transcript turn 2 interim สวัสดีค่ะ อยากสอบถาม transcript turn 2 interim สวัสดีค่ะ อยากสอบถามเรื่องบิล speech_ended turn 2 charged seq 2 transcript turn 2 final สวัสดีค่ะ อยากสอบถามเรื่องบิลเดือนนี้ค่ะ
中间结果是进行中这一轮的草稿,会被下一条替换。轮次结束时切分出它的计费区间,最终结果在扣费之后到达。模型未能转写的轮次会以一条错误代替最终结果,这一轮的音频也不计入费用。
实时收听的费用
| 工作量 | 接收的音频 | 费用 |
|---|---|---|
| 一通电话,5 分钟 | 5 分钟 | $0.06 |
| 100 通电话 | 8.3 小时 | $6.25 |
| 1,000 通已接电话 | 约 $62.50 | |
接收的音频每分钟 12.5 积分,静音也计算在内,按每通已接电话 5 分钟计算。模型未能转写的轮次不收费,整个会话在日志里显示为一行。
面向开发者
TypeScript 和 Python 示例打开连接,按实际节奏上传音频,并从每一轮的最终结果中读取内容。第三个标签页是一轮发言产生的事件流。
完整 API 参考import { open } from "node:fs/promises"; // 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: relay the audio through your // server. const socket = new WebSocket("wss://api.paxalabs.com/v1/stt/live", { headers: { Authorization: `Bearer ${process.env.PAXA_API_KEY}` }, }); socket.onopen = async () => { socket.send(JSON.stringify({ type: "start", model: "paxa-stt-lite-realtime-v1-preview", audio: { encoding: "pcm_s16le", sample_rate: 16000 }, language: "th", })); // 16 kHz signed 16-bit mono is 32,000 bytes a second. A microphone // delivers frames at this pace on its own; a file has to be paced. const file = await open("caller.pcm"); const frame = new Uint8Array(640); // 20 ms for (;;) { const { bytesRead } = await file.read(frame, 0, frame.length); if (bytesRead === 0) break; socket.send(frame.subarray(0, bytesRead)); await new Promise((resolve) => setTimeout(resolve, 20)); } socket.send(JSON.stringify({ type: "end" })); }; socket.onmessage = (event) => { const message = JSON.parse(String(event.data)); switch (message.type) { case "speech_started": // The user is talking: stop the agent's audio, cancel its reply. break; case "transcript": if (message.is_final) console.log(`turn ${message.turn}: ${message.text}`); break; case "done": socket.close(); } };
import json import os import time from websockets.sync.client import connect # pip install websockets with connect( "wss://api.paxalabs.com/v1/stt/live", additional_headers={"Authorization": f"Bearer {os.environ['PAXA_API_KEY']}"}, ) as socket: socket.send(json.dumps({ "type": "start", "model": "paxa-stt-lite-realtime-v1-preview", "audio": {"encoding": "pcm_s16le", "sample_rate": 16000}, "language": "th", })) # 16 kHz signed 16-bit mono is 32,000 bytes a second; a file has to # be paced the way a microphone paces itself. with open("caller.pcm", "rb") as audio: while frame := audio.read(640): # 20 ms socket.send(frame) time.sleep(0.02) socket.send(json.dumps({"type": "end"})) for message in socket: event = json.loads(message) if event["type"] == "transcript" and event["is_final"]: print(event["turn"], event["text"]) elif event["type"] == "done": break
{"type":"started","connection":"7d9c2b7e-4a41-4c8e-9a35-1f26d8c04b7a","model":"paxa-stt-lite-realtime-v1-preview"} {"type":"speech_started","turn":1,"time":0.3} {"type":"speech_ended","turn":1,"time":12.252} {"type":"charged","seq":1,"seconds":12.252,"credits":2.56,"total_credits":2.56} {"type":"transcript","turn":1,"is_final":true,"text":"สวัสดีค่ะคุณสมชายยอดชำระของท่านจำนวน พันสองร้อยห้าสิบ บาทครบกำหนดวันที่ สิบห้า สิงหาคมนี้ชำระผ่านแอปได้ตลอด ยี่สิบสี่ ชั่วโมงค่ะ","start":0.3,"end":12.252} {"type":"done","total_seconds":12.252,"turns":1,"total_credits":2.56}
模型在实时场景里听什么
Paxa STT Lite Realtime 优先转写泰语,其他语言按原话转写,包括中途切换语言的句子。它直接从音频本身判断轮次边界,不需要客户端提供任何提示。在评测方法一并公开之前,它不公布任何准确率数字。
常见问题
实时会话如何计费?
按连接接收的音频计费,静音也计算在内,每分钟 12.5 积分。连接在每一轮处切分成区间,边进行边扣费,整条连接在请求日志里记为一行,并带有总额。
某一轮失败了会怎样?
这一轮的音频不计费,同时会有一个错误事件指明是哪一轮。连接保持打开,下一轮照常进行,累计总额也已经把它算进去了。
浏览器能直接打开这条连接吗?
API 密钥绝不能放在浏览器里,所以音频要经过您的服务器。页面把麦克风帧流式发送到您自己的中转服务,由中转服务持有密钥和连接。
我们已经有录音了,该用哪个接口?
用整段处理的接口。POST /v1/stt 接收最长 60 分钟的文件,一次性返回完整转写稿。它每分钟的价格也更低,因为不需要跟上说话人的节奏。
从免费积分开始
使用 Google、GitHub 或 Hugging Face 登录,即可用 100 一次性免费积分处理您自己的文本。