Skip to content

第一次合成

这一页覆盖完整生命周期:创建 client、加载模型、合成、查看结果、清理。

创建 client

ts
import { createTts } from "@optimalai/react-native";
import { kokoroZhInt8 } from "./optimalai-models";

const tts = createTts({
  model: kokoroZhInt8,
  voiceId: "zf_001",
  numThreads: 4,
});

createTts 开销很小 —— 它只是保存选项,在 load() 之前不会发生任何原生调用。

选项必需含义
model@optimalai/model-tools 生成的对象。
voiceId该 client 的默认音色。
numThreadsONNX 的 intra-op 线程数,按设备调优。

加载模型

ts
await tts.load();

这是开销最大的一步。它会解析资产 ID 为真实文件 URI、校验文件大小、解析 token 表与 两份词典、打开 ONNX session,并校验音色布局。冷启动时会有可感知的耗时 —— 请在 真机上测量,不要用模拟器。

重复到达 ready 是无害的;client 已就绪时 load() 会立即返回。

合成

ts
const result = await tts.synthesizeToFile({
  text: "你好,Hello world.",
  voiceId: "af_maple",
  speed: 1.0,
});
字段必需含义
text中文、英文或混合文本,上限 2000 个 code point。
voiceId仅本次覆盖 client 默认音色,不重载模型。
outputPath输出路径,缺省时在缓存目录生成文件名。
speed语速,0.52.0,默认 1.0

返回结果

ts
result.fileUri; // "file:///.../optimalai-1726000000000.wav"
result.sampleRate; // 24000
result.channels; // 1
result.voiceId; // "af_maple"
result.durationMs; // 生成音频的时长
result.modelId; // "kokoro-82m-v1.1-zh-int8"
result.modelVersion; // "1.1-zh-int8"
result.elapsedMs; // 合成耗时,不含加载

注意 elapsedMs 不含模型加载,它只度量合成调用本身。因此调优 numThreads 时应该盯这个数。

播放 WAV

SDK 只写文件,到此为止。播放由你负责:

tsx
import { useAudioPlayer, setAudioModeAsync } from "expo-audio";
import { useEffect } from "react";

const player = useAudioPlayer(null);

// iOS 下不打开这个开关会静音。
useEffect(() => {
  void setAudioModeAsync({ playsInSilentMode: true });
}, []);

async function synthesizeAndPlay() {
  const result = await tts.synthesizeToFile({ text: "你好,Hello world." });
  player.replace(result.fileUri);
  player.play();
}

清理

ts
await tts.reset();

reset() 会关闭 ONNX session 并把 client 退回 unloaded。在页面卸载时调用它, 或者在丢弃 client 之前调用。遭遇致命错误后,必须 reset() 才能再次 load() —— 见错误处理

文件生命周期

SDK 不会下载、播放、缓存、上传或删除它产出的 WAV。每个生成的文件都会留在磁盘上, 直到删掉它。如果你的 App 会反复合成,请自行管理该目录。

复用路径

如果你传入的 outputPath 已存在,合成会以 OUTPUT_EXISTS 失败,而不是静默覆盖。 请先删除文件,或让 SDK 生成新名字。

一次跑完

ts
const tts = createTts({
  model: kokoroZhInt8,
  voiceId: "zf_001",
  numThreads: 4,
});

await tts.load();

const first = await tts.synthesizeToFile({ text: "第一句。" });
const second = await tts.synthesizeToFile({
  text: "Second line.",
  voiceId: "af_maple",
  speed: 1.15,
});

await tts.reset();

两次合成,一次模型加载,中间没有重载。