Quickstart
This page walks the shortest path from an empty Expo app to a local WAV file. It assumes you already have private npm access; if not, start with Installation & prerequisites.
1. Install both packages
bash
npx expo install @optimalai/react-native@beta
npx @optimalai/model-tools@beta add kokoro-82m-v1.1-zh-int8The second command downloads the model kit, verifies every file against its recorded byte length and SHA-256, and generates optimalai-models.ts next to your app code. See Model preparation.
2. Register the plugin and the Metro asset types
In app.json:
json
{ "expo": { "plugins": ["@optimalai/react-native"] } }In metro.config.js:
js
const { getDefaultConfig } = require("expo/metro-config");
const { withOptimalAI } = require("@optimalai/react-native/metro");
module.exports = withOptimalAI(getDefaultConfig(__dirname));Then rebuild your Development Build. Expo Go cannot load this SDK — native ONNX Runtime code has to be compiled into the app. Details in Expo & Metro setup.
3. Synthesize
ts
import { createTts } from "@optimalai/react-native";
import { kokoroZhInt8 } from "./optimalai-models";
const tts = createTts({
model: kokoroZhInt8,
voiceId: "zf_001",
numThreads: 4,
});
await tts.load();
const result = await tts.synthesizeToFile({
text: "你好,Hello world.",
voiceId: "af_maple", // Optional: overrides the default voice for this WAV.
});
console.log(result.fileUri);result.fileUri is a file:// URI pointing at a 24 kHz, 16-bit, mono WAV in your app's cache directory.
4. Play it yourself
The SDK does not play audio. Hand the URI to whatever player you already use:
ts
import { useAudioPlayer } from "expo-audio";
const player = useAudioPlayer(null);
player.replace(result.fileUri);
player.play();5. Release the model when you are done
ts
await tts.reset();The shape of the whole thing
| Step | Call | Notes |
|---|---|---|
| Create | createTts({ model, voiceId, numThreads? }) | Cheap; does not touch the native model yet. |
| Load | await tts.load() | Cold start. Resolves the asset URIs and opens the ONNX session. |
| Synthesize | await tts.synthesizeToFile({ text, voiceId?, outputPath?, speed? }) | One at a time per client. |
| Inspect | tts.status() | unloaded / loading / ready / synthesizing / failed. |
| Release | await tts.reset() | Frees the session and returns to unloaded. |
Where to go next
- First synthesis — the full picture, including result fields and file lifecycle.
- Voices & speed — pick from 103 voices and tune prosody.
- Error handling — every error code and how to recover.
- Known limitations — read before you ship.