泰语实时转写

在泰语还在说的时候就完成转写。一条 WebSocket 连接传输音频,找出每一轮发言在哪里结束,并为语音智能体和实时字幕返回完整的转写结果。

转写结果

复述一次预订

spokenขอจองโต๊ะวันเสาร์ที่ สิบห้า สำหรับ สี่ ท่านค่ะ

writtenขอจองโต๊ะวันเสาร์ที่ 15 สำหรับ 4 ท่านค่ะ

来电者的一轮发言。书面写法把日期和人数写成阿拉伯数字,这正是预订电话要填写的格式。

逐个报出的快递单号

spokenพัสดุเลขที่ ที เอช หนึ่ง สอง สาม สี่ ห้า หก ส่งถึงไหนแล้วคะ

writtenพัสดุเลขที่ TH123456 ส่งถึงไหนแล้วคะ

在泰语句子里逐个字母报出的编号。最终结果以一个字符串返回,可以直接拿去查询。

复述的金额

spokenยอดที่ต้องชำระคือ หนึ่งพันสองร้อยห้าสิบ บาท ใช่ไหมคะ

writtenยอดที่ต้องชำระคือ 1,250 บาท ใช่ไหมคะ

来电者确认一个数字。就在来电者说出它的那一轮,数字落进了支付流程读取的字段。

本页每组转写对照都是编写的示意,用来说明格式选项会改变什么,发布前已对照实际输出复核。语音转文字页面提供模型对真实录音的实录转写,并注明采集日期。

实时产品如何使用这条连接

录音可以等,对话等不了。在实时产品里,下一步要靠转写稿来推进。语音智能体据此决定如何回复。主管通过它看出一通电话正在出问题。演讲者下方的字幕屏直接显示它。在这三种场景里,说出的话与文字之间的时间差就是产品本身。实时转写把文件这个中间环节拿掉了。麦克风或电话线路一产生音频,就通过 WebSocket 上传,说话人还在继续说,转写稿已经逐轮返回。让这一切可用的关键是轮次。连接会找出说话人停下的位置,发出一句完整的话,下游代码读到的是一整句泰语,结尾可以信赖。泰语让这个判断比看上去更难。泰文书写时词与词之间没有空格,表示一个意思说完的信号,往往是句末的语气词。

  1. 为一场对话打开一条连接

    发送一个 start 帧,写明模型、编码和采样率,然后随着采集持续推送音频帧。API 密钥留在您的服务器上,浏览器通过它中转麦克风音频。

  2. 显示中间结果,按最终结果行事

    如果界面上有内容要显示,就先绘制中间结果。下一步操作以每一轮的最终结果为准,其中带有轮次编号、文本,以及它在音频中的位置。

  3. 结束会话并读取总量

    线路挂断时发送 end 帧。done 事件会报告接收的音频、轮次数,以及这条连接应付的积分,整条连接在请求日志里记为一行。

线路上的一次对话

session
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

输入音频

start 帧声明编码和采样率。16 位有符号 PCM 可使用其中任一采样率,电话线路的 mulaw 为 8 kHz。之后由二进制帧传输音频。

2 个事件

轮次边界

服务端会告知说话人在哪里开始、在哪里停下。下游不必盯着静音,也不必猜测一句泰语在哪里结束。

1 个最终结果

先中间结果,后最终结果

轮次进行中会陆续返回中间结果,字幕靠它保持滚动。轮次结束时返回最终结果,后续操作应以它为准。

4 小时

单次会话上限

一条连接最多接收这么长的音频,之后会像收到 end 帧一样结束会话。更长的内容请开第二条连接,它的轮次会从头编号。

轮次检测在服务端运行。客户端负责发送音频、读取事件,同一套约定适用于浏览器中转、SIP 网关,以及按自身节奏播放的音频文件。

一轮发言,从中间结果到最终结果

turn 2
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();
  }
};

模型在实时场景里听什么

Paxa STT Lite Realtime 优先转写泰语,其他语言按原话转写,包括中途切换语言的句子。它直接从音频本身判断轮次边界,不需要客户端提供任何提示。在评测方法一并公开之前,它不公布任何准确率数字。

常见问题

实时会话如何计费?

按连接接收的音频计费,静音也计算在内,每分钟 12.5 积分。连接在每一轮处切分成区间,边进行边扣费,整条连接在请求日志里记为一行,并带有总额。

某一轮失败了会怎样?

这一轮的音频不计费,同时会有一个错误事件指明是哪一轮。连接保持打开,下一轮照常进行,累计总额也已经把它算进去了。

浏览器能直接打开这条连接吗?

API 密钥绝不能放在浏览器里,所以音频要经过您的服务器。页面把麦克风帧流式发送到您自己的中转服务,由中转服务持有密钥和连接。

我们已经有录音了,该用哪个接口?

用整段处理的接口。POST /v1/stt 接收最长 60 分钟的文件,一次性返回完整转写稿。它每分钟的价格也更低,因为不需要跟上说话人的节奏。

从免费积分开始

使用 Google、GitHub 或 Hugging Face 登录,即可用 100 一次性免费积分处理您自己的文本。