Model reference · open weights

kokoro-ru

Available as managed deployment Audio zaakirio · community Text→speech 1 variants 10k dl/mo

kokoro-ru is an open-weight audio or speech model from zaakirio. AxForge deploys and operates it for you on dedicated EU-owned hardware — with the licence handled where one is required.

Available as managed deployment — configured and operated for you on dedicated EU hardware, quoted per deployment.

What it is

Released byzaakirio
TypeAudio & music
TaskText→speech
Runs withkokoro
Released2026-07-29
Popularity10k downloads / month
LicenceOpen weights

About

What kokoro-ru is

Russian text-to-speech at 82M parameters, running 9.8x faster than realtime on a laptop CPU with no GPU. Three fixed voices from consented studio actors.

A Russian port of Kokoro-82M.

RTF        0.102      9.8x realtime, CPU only
params     81.81M
peak RAM   2.39 GB
Read the full model card

Voices

voice    gender   checkpoint
sveta    female   kokoro-ru-v2-base.pth
masha    female   kokoro-ru-v2-base.pth
dima     male     kokoro-ru-v2-dima.pth

Sveta — heard in the clip above — is the flagship voice. She and Masha share one checkpoint and differ only by voicepack, so the release is two model files, not three.

Usage

Works with the stock kokoro package, unmodified.

import torch, soundfile as sf
from kokoro import KModel
from huggingface_hub import hf_hub_download
from ru_g2p import RuG2P            # this repo

REPO  = "zaakirio/kokoro-ru"
g2p   = RuG2P()
model = KModel(repo_id=REPO,
               model=hf_hub_download(REPO, "kokoro-ru-v2-base.pth")).eval()
pack  = torch.load(hf_hub_download(REPO, "voices/sveta.pt"),
                   map_location="cpu", weights_only=False)

ipa, oov = g2p("Здравствуйте! Как ваши дела?")
assert not oov
with torch.no_grad():
    audio = model(ipa, pack[len(ipa) - 1], 1.0, return_output=True).audio

sf.write("out.wav", audio.cpu().numpy(), 24000)

Russian TTS lives or dies on lexical stress — за́мок is a castle, замо́к is a padlock. ru_g2p.py resolves stress, ё and homographs with RUAccent, applies Russian vowel reduction, then phonemizes. Feed it text, not IPA.

Evaluation

Whisper large-v3 round-trip against Piper, the incumbent free local Russian TTS, on identical sentences with identical ASR and normalisation. We average 2.50% WER against Piper's 4.38% and beat three of its four voices — but Piper's irina transcribes perfectly and we do not.

Two caveats worth stating: the set is 79 words, so these gaps are one or two words; and ASR accuracy measures intelligibility, not naturalness.

Frontend stress and orthoepy — homographs, ё restoration, the -ого/-его rule and its adverb exceptions, silent-consonant clusters: 15/16 correct.

Limitations

Timbre is darker than the source recordings, and varies by voice. Measured in the 6-10 kHz band against Piper irina at -25.4 dB:

dima    -23.6 dB    brighter than Piper
masha   -26.2 dB    level with Piper
sveta   -33.8 dB    noticeably darker, least training data (2.82 h)

Fricative artifact. ж/ш/х carry narrowband spectral ridges where real speech has flat noise, +7.8 dB against +1.2 dB. Around 31 dB below programme level, so audible only at high volume.

Homographs are 93.8%, not perfect. Known failure: "Это была настоящая мука" gives flour rather than torment. Pass explicit stress for critical text.

Prosody is deterministic. Like all Kokoro models the style vector is chosen by phoneme-string length, so identical text always produces identical audio.

Training

base        hexgrad/Kokoro-82M, kikiri-tts / StyleTTS2 recipe
corpus      29.28 h, 16 speakers, 53% female, 47% full-band
stage 1     5 epochs   val mel 0.230
stage 2     10 epochs  val mel 0.318
hardware    1x RTX A6000, ~$16 total

Voices come from the Dialogs corpus (studio, consented actors, OpenRAIL). Russian LibriSpeech contributed phonetic coverage to the base model but supplies no shipped voice. Weights are OpenRAIL, code is Apache-2.0.

Acknowledgements

hexgrad (Kokoro-82M), semidark (kikiri-tts), Den4ikAI (RUAccent), the OpenSLR Russian LibriSpeech contributors, and the Dialogs actors and authors.

ONNX / Node.js

ONNX exports of the same checkpoints, same layout as onnx-community/Kokoro-82M-v1.0-ONNX, so transformers.js / kokoro-js / onnxruntime can load this repo directly.

onnx/model.onnx                 fp32 base (sveta, masha), 326 MB
onnx/model_quantized.onnx       q8 base  (transformers.js dtype: "q8"), 138 MB
onnx/model_fp16.onnx            fp16 base (WebGPU only), 164 MB
onnx/model_dima.onnx            fp32 dima (male)
onnx/model_dima_quantized.onnx  q8 dima
onnx/model_dima_fp16.onnx       fp16 dima
voices/{sveta,masha,dima}.bin   style packs, raw float32 [510, 256]

The model is language-blind (phoneme ids in, audio out), so the export is the same one used for the English Kokoro v1.0; the Russian G2P lives outside the model. Validation: ONNX vs PyTorch identical durations and 0.87–0.90 waveform correlation (ceiling ~0.84 between two PyTorch runs — the decoder injects noise); q8 vs fp32 identical durations and 0.58 dB mel-L1.

Python (onnxruntime)

import numpy as np, onnxruntime as ort
from ru_g2p import RuG2P            # this repo

g2p = RuG2P()
ipa, oov = g2p("Здравствуйте! Как ваши дела?")
vocab = {c: i for c, i in __import__("json").load(open("config.json"))["vocab"].items()}
ids = [vocab[c] for c in ipa if c in vocab]

sess = ort.InferenceSession("onnx/model.onnx")     # or model_quantized.onnx
style = np.fromfile("voices/sveta.bin", dtype=np.float32).reshape(510, 256)
audio = sess.run(None, dict(
    input_ids=np.array([[0, *ids, 0]], np.int64),
    style=style[len(ipa) - 1][None],
    speed=np.ones(1, np.float32),
))[0]

Node.js

Fully local — onnxruntime-node for inference and the espeak-ng npm package (WASM, ru voice) for G2P:

import ort from "onnxruntime-node";
import ESpeakNg from "espeak-ng";
import fs from "node:fs";

const espeak = await ESpeakNg({ arguments: ["--phonout", "ipa.txt", "--ipa=3", "-q", "-v", "ru", text] });
const ipa = espeak.FS.readFile("ipa.txt", { encoding: "utf8" });
// map ipa chars to ids via config.json vocab, pad [0, ...ids, 0],
// style = voices/.bin row (len(ipa) - 1) * 256, then:
const { waveform } = await session.run({
  input_ids: new ort.Tensor("int64", BigInt64Array.from([0n,

From the published model card. Full card on the HuggingFace links in the sidebar.

How it works

How audio & music work

Audio or textinputAudio modelrecognise / synthesiseText or audiooutputSpeech-to-text turns audio into text; text-to-speech and music models turn text into audio.

Using it via the API

Call it like any OpenAI endpoint

Once AxForge deploys kokoro-ru for you, it answers on the OpenAI-compatible API — the same base URL and keys as every other model. (kokoro-ru below is illustrative; you get the exact model name on deployment.)

$ curl -sS https://api.axforge.ai/v1/audio/transcriptions \
  -H "Authorization: Bearer $AXFORGE_API_KEY" \
  -F model="kokoro-ru" -F file=@audio.mp3

Create an account — your API key is available in the console. 3M free tokens every 30 days with every new account.

© 2026 AxForge · EU-hosted AI infrastructure Pricing Docs Trust Privacy Terms