互动小说配音,支持中文、英语和泰语

为分支故事配上中文、英语或泰语语音,涵盖聊天小说、视觉小说和选择驱动的游戏。可以预先生成整棵剧情树,也可以在运行时沿读者选择的路线实时朗读。

可以试试的想法

出现选项

จะเดินเข้าไปถามเขาตรง ๆ หรือจะรอดูเงียบ ๆ อยู่ตรงนี้ก่อนดี

Nom Yenpaxa-tts-flash-v2在语音页面打开
读者选择的路线

เธอเลือกจะเดินเข้าไป และนั่นคือจุดที่ทุกอย่างเปลี่ยนไปตลอดกาล

Nom Yenpaxa-tts-flash-v2在语音页面打开
聊天形式的一句台词

ไม่ต้องมาทำเป็นห่วงตอนนี้หรอก ตอนที่ฉันต้องการเธอ เธออยู่ไหน

Nom Yenpaxa-tts-flash-v2在语音页面打开
读者错过的路线

ถ้าวันนั้นเธอเลือกอีกทาง เรื่องทั้งหมดนี้คงไม่มีวันเกิดขึ้นเลย

Nom Yenpaxa-tts-flash-v2在语音页面打开

每张卡片播放的都是 Nom Yen 按卡片脚本原文生成的真实音频。在语音页面打开后,可以让它说任何内容。

分支章节如何配音

分支故事是唯一一种在读者行动之前无法知道下一句的小说。Joylada 把泰语小说做成逐条点击阅读的聊天形式,基于 Ren'Py 等引擎的视觉小说则按说话人逐行写对白,在场景之间插入选项。两种形式都让工作室面对同一个选择。预先生成整棵树,每个分支都是现成的文件,在任何人打开应用之前就已就绪,无论有没有读者走到那里,费用都已付出。运行时朗读,则只为读者实际走过的路线付费,代价是阅读期间要一直保持一个连接。哪种更便宜,取决于普通读者会看到树的多大部分,下表用实际数字把两种方式都算了出来。

来源:Joylada(在新标签页中打开)Ren'Py(在新标签页中打开)

  1. 把树展开成片段

    每个节点变成一段带说话人和音色 ID 的语音片段。不超过 5,000 个字符的片段是一个请求,更长的片段在句子边界处拆分。

  2. 按场景选择预先生成或实时朗读

    每位读者都会看到的序章值得生成一次,冷门分支则值得按需朗读。这个选择按场景来定,上线后也能更改,无需改动脚本。

  3. 缓存读者已经听过的内容

    运行时朗读的台词就是普通 MP3。保存下来后,重玩的路线会命中缓存,同一路线第二次重读不再花钱。

预先生成整棵树,还是实时朗读路线

预先生成整棵树,还是实时朗读路线
交付方式字符积分费用
一位读者的路线,120 句10,800108$0.11
10,000 位读者,运行时朗读108,000,0001,080,000$1,080
整棵树配音一次,供今后所有读者使用约 $1.44

按每 1,000 字符 10 积分、每句 90 个字符计算。预先生成为全部读者一次付清,运行时朗读按每位读者付费。两者的平衡点大约在 13 位读者。

一章,四个结局

chapter-07.tree
scene_07a  ณิชา     nomyen       96 chars
scene_07a  ธาวิน    massaman     82 chars
  choice_1 -> scene_07b
  choice_2 -> scene_07c

scene_07b  ณิชา     nomyen       88 chars    [pre-rendered]
scene_07c  ณิชา     nomyen       94 chars    [pre-rendered]
scene_07c  คุณยาย   miangkham    90 chars    [pre-rendered]

# 4 个分支 x 约 400 句 = 上面这棵树
# 一位读者听到其中约 120 句

树是工作室做预算的单位,路线是读者听到的单位。两种方式都是每个说话人对应一个音色 ID。

从上线到稳定

上线

序章已生成

每位读者都会读到序章。它只配音一次,以文件形式提供。这一部分没有任何需要在运行时决定的事。

第 1 周

冷门分支实时朗读

几乎没人走到的深层路线不预先生成,真走到那里的读者会通过实时连接听到朗读。被跳过的台词收到取消指令后停止,队列中剩余的部分不收费。

第 3 个月

热门路线进入缓存

实时朗读过一次的台词就是一个普通 MP3。把读者实际走到的台词保存下来,树的大部分就变成了文件,从头到尾都不用专门决定去生成它。

第 12 个月

整棵树不再产生费用

读者走过的部分都已配音,重读就是命中缓存。只有在您写下一章时,才会开始新的支出。

一个打开的实时连接占用套餐的一个语音并发名额。运行时方案按同时在线的读者数确定规模,每天的台词数量不计入其中。

面向开发者

TypeScript 示例打开运行时会话使用的实时 socket,Python 快速入门像预生成批处理那样发送一个片段。选项请求展示了每个场景固定使用的音色、模型和格式。

完整 API 参考
// 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-v2",
    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
};

试听音色

50 个正式音色中的几个,均通过 API 使用公开的音色 ID 生成。全部音色可在文本转语音页面试听。

  • Hor Mok仅 v2在语音页面打开
  • Khanom Krokv1 + v2男声主音色
  • Nom Yenv1 + v2女声主音色
  • Foi Thongv1 + v2旁白

短句本身就是难题

分支小说由碎片写成,可能是一行聊天、一句回嘴或一个选项标签。泰语词与词之间不加空格,四个词的片段几乎没有上下文可供分词。Paxa TTS Flash v2 根据拼写判断声调,不查词典,孤立的短句因此依然听得明白。

常见问题

应该预先生成整棵树,还是运行时朗读?

预先生成一次约 $1.44,覆盖全部读者。运行时朗读每位读者约 $0.11。读者少于约 13 位时,运行时朗读更便宜,超过这个数则预先生成更便宜。

每个角色可以用不同的音色吗?

可以,最多可用音色库全部 50 个音色。每个说话人的音色 ID 写在脚本里,同一个 ID 每次运行都返回同一个声音。

读者点击跳过一句台词时会怎样?

在实时 socket 上发送一个 cancel 帧。这句台词停止,队列中剩余的部分被丢弃且不收费,同一个连接继续承载下一句。

一位读者会占用多少套餐容量?

一个打开的实时连接在保持打开期间占用一个语音并发名额。运行时方案按同时在线的读者数确定规模,每天的台词数量不计入其中。

音频可以放进游戏里发布吗?

用免费积分生成的内容仅供个人使用和评估。购买套餐或积分后,生成的内容归您所有,可用于任何用途,包括放进商业作品中发布,购买之前生成的内容也一并适用。

从免费积分开始

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