Synthesize short speech with native MOSS-TTS Nano on a CPU desktop
Use the official MOSS-TTS family’s CPU-oriented Nano member and its complete native ONNX audio codec. One fixed original English sentence is spoken using a reader-recorded own or authorized voice reference. All 16 audio codebooks are retained; the configured 512 global-row budget separates text, reference frames and generated audio frames. Output is 48 kHz stereo PCM WAV through a private educational endpoint. Fit, speed, voice similarity and speech quality remain unmeasured.
- Hardware
- Intel Core i5-12400 desktop, 4 inference threads, 32 GiB RAM
- Runtime
- Native MOSS-TTS Nano complete ONNX CPU speech pipeline native Nano source 8b7bcc9341b3b4ef3a3a58ba1338a7d85ff133eb; ONNX Runtime1.23.2 CPU; SentencePiece0.2.1; NumPy2.2.3; Python3.12 · CPU
- Model format
- ONNX external-data bundle · Publisher native ONNX float32 tensors; CPUExecutionProvider, all 16 audio codebooks retained · Publisher native ONNX float32 export; all 16 codebooks, no additional quantization
- Workload
- 512 token context · 1 concurrent
Based on source documentation; this setup has not been executed by OpenTools. Memory: unknown. No compatible measurement available.
Read the complete setup guide
Before you start
- Use an owned Intel Core i5-12400 Ubuntu 24.04 x86_64 desktop with 32 GiB RAM, 40 GiB free disk and four inference threads. These allocations are not measured fit or minima.
- Frozen MOSS-TTS is a family record dated February 2026. Its official parent README expressly recommends the later April 2026 Nano member for CPU use. This guide names that exact member; it does not silently replace flagship 8B, local-transformer, realtime, sound-effect or other family modes. Family guide total remains open.
- Review exact native code/model/codec Apache 2.0 terms and use only a reader-owned or authorized voice recording. Record 1–5seconds of clean natural speech, not a sine wave or a copied third-party example. Export uncompressed PCM16 WAV at 48 kHz mono or stereo. The native Nano request uses reference audio codes and target text without a separate reference-transcript field.
- No recording or voice is supplied or transmitted by the author. Place your recording as own-recording.wav in the dedicated workspace. On cloud, transfer it privately using existing SSH/scp yourself; never expose the speech service publicly. Treat recordings/generated voice as private data.
- Use Python 3.12 with source-qualified ONNX Runtime 1.23.2 CPU, NumPy 2.2.3 and SentencePiece 0.2.1. Direct official OrtCpuRuntime module is selected; upperCLI imports Torch/torchaudio and is not invoked. No dependency stripping or source patch is needed for this native low-level API. This is documented, unexecuted compatibility.
Exact model and requirements
- Artifact:
- OpenMOSS Team / MOSI.AI / MOSS-TTS Nano100M ONNX with complete Nano ONNX audio tokenizer · checkpoint OpenMOSS-Team/MOSS-TTS-Nano-100M-ONNX
- Publisher revision:
- f52645cb467506d8e18e746ddd59482685b74e58
- Artifact digest:
- The complete TTS+codec multi-file bundle has no single publisher aggregate digest. All 18 selected files have exact per-file publisher LFS SHA256 or Git blob SHA1 in the reader manifest.
- Download size:
- 0.71 GiB
- Memory requirement (unknown):
- Unknown — No measured full-process peak for native TTS/global-local state/codec/ONNX sessions at this budget.
- System RAM / disk:
- Unknown / Unknown
- Placement:
- single device. One CPU host; one reference, one fixed sentence and one serial request. All native ONNX sessions use CPUExecutionProvider; no CUDA, disk or GPU offload.
- KV cache:
- Native ONNX global/local past/present state is retained as exported. No separate cache-precision measurement or alternative cache quantization is claimed.
- Workload:
- 512 token context; Unknown; Not applicable; concurrency 1; batch 1; cache cold; repetitions Unknown.
- Tokenizer:
- Pinned Nano SentencePiece text tokenizer plus16-codebook audio rows, native prompt templates · f52645cb467506d8e18e746ddd59482685b74e58
- Sampling / reasoning:
- Source-supported greedy mode: do_sample=False, sample_mode=greedy, max_new_frames 125 and native audio repetition penalty 1.2. Target fixed English sentence is encoded raw like native encode_text, <=75 text tokens. Reference1–5sec 48 kHz stereo PCM16 is encoded with full native codec; <=64 reference audio frames admitted. Native template plus reference/text prefill and 125 reserved future global rows must fit 512. No RNG-quality claim or native text normalization feature is implied. Native global input is a sequence of 17-wide rows: one text/slot field plus16 audio codebooks. A reference or generated audio frame occupies one global row, not 16 positions. Codec downsample 3840 at 48 kHz is 12.5 frames/sec; 125 output frames cap 10 sec before end effects. Generated frames must be1–124, rejecting potentially truncated cap-length speech. Local decoder/codebook steps are distinct. The original PyTorch config 32768 is not claimed as a proven ONNX maximum; 512 is this author-selected checked budget.
- Runtime prerequisites:
- Ubuntu 24.04 x86_64; See prerequisites above.
Actual native Nano code LICENSE is Apache License 2.0; parent family README expressly licenses family models under Apache 2.0, and both exact official ONNX TTS/codec cards declare Apache 2.0. Retain applicable license/copyright/NOTICE and change/patent obligations. This does not grant rights to imitate any person: use your own or otherwise authorized recording. No built-in voice identity, dataset/media right or downstream suitability clearance is inferred. No credentials, terms acceptance or recording acquisition is performed by this guide author.
- MOSS-TTS-Nano-100M-ONNX/moss_tts_global_shared.data · 0.41 GiB · revision f52645cb467506d8e18e746ddd59482685b74e58
- MOSS-TTS-Nano-100M-ONNX/moss_tts_local_shared.data · 0.21 GiB · revision f52645cb467506d8e18e746ddd59482685b74e58
- MOSS-TTS-Nano-100M-ONNX/tokenizer.model · 0 GiB · revision f52645cb467506d8e18e746ddd59482685b74e58
- MOSS-Audio-Tokenizer-Nano-ONNX/moss_audio_tokenizer_decode_shared.data · 0.04 GiB · revision ceff0d0749bfb3fa2d61149794ec6feef0d1e1ae
- MOSS-Audio-Tokenizer-Nano-ONNX/moss_audio_tokenizer_encode.data · 0.04 GiB · revision ceff0d0749bfb3fa2d61149794ec6feef0d1e1ae
- 762,195,739 bytes sums official ONNX graph/external-data file sizes, not complete installed footprint or runtime RAM.
- 32 GiB RAM, 40 GiB disk and four threads are planning choices. Native session initialization, graph optimization, K/V state, codec and OS add unknown peak overhead. No publisher throughput or sibling fit is transferred.
One-time setup and hardware
- hardware
- Unknown — Existing desktop purchase price and incremental hardware cost depend on the reader; unknown.
- Existing desktop purchase price and incremental hardware cost depend on the reader; unknown. Tax: unknown.
- setup
- Unknown — Initial provisioning/build time and labor cost are unknown.
- Initial provisioning/build time and labor cost are unknown. Tax: unknown.
Recurring costs
- electricity
- Unknown — Actual wall power, electricity rate and powered hours are unknown; no TDP-to-wall-power conversion.
- Actual wall power, electricity rate and powered hours are unknown; no TDP-to-wall-power conversion. Tax: unknown.
- storage
- Unknown — Incremental cost of local disk capacity is unknown. The 40 GiB free-disk walkthrough allocation is an author choice, not a measured requirement.
- Incremental cost of local disk capacity is unknown. The 40 GiB free-disk walkthrough allocation is an author choice, not a measured requirement. Tax: unknown.
- egress
- Unknown — Data transfer price, allowances and traffic volume are unknown.
- Data transfer price, allowances and traffic volume are unknown. Tax: unknown.
- administration
- Unknown — Maintenance labor rate and hours are unknown.
- Maintenance labor rate and hours are unknown. Tax: unknown.
Install the runtime
1. Create the native CPU runtime environment
Install source-qualified CPU packages and check resolution. Read the official low-level runtime directly from its pinned checkout; do not install the broader web/PyTorch project just to run this self-contained NumPy/ORT module. The complete TTS and codec sessions remain unchanged.
Commandset -e sudo apt-get update sudo apt-get install -y python3.12 python3.12-venv git curl ca-certificates openssl mkdir -p "$HOME/moss-nano-speech/models" cd "$HOME/moss-nano-speech" python3.12 -m venv .venv .venv/bin/python -m pip install 'onnxruntime==1.23.2' 'numpy==2.2.3' 'sentencepiece==0.2.1' 'huggingface-hub==0.36.2' git clone https://github.com/OpenMOSS/MOSS-TTS-Nano.git native-moss-nano git -C native-moss-nano checkout --detach 8b7bcc9341b3b4ef3a3a58ba1338a7d85ff133eb sha256sum --check <<'SHA256' 99477efaff28c12c0c8e16a6b4aab4e880a70851693fa303d932415ba180cbd5 native-moss-nano/ort_cpu_runtime.py SHA256 .venv/bin/python -m pip check .venv/bin/python -m pip freeze > resolved-environment.txtExpected result: Pinned native module and packages resolve, source hash/pip check pass and resolution is saved. No native session, weights or inference has run.
Download the model
1. Write the full TTS and codec manifest
Select all 18 exact official TTS/codec files, including every external-data graph dependency and tokenizer. LFS SHA256 and regular Git blob SHA1 are distinguished; Git SHA1 is identity rather than modern adversarial integrity. No mutable default auto-download is used.
Commandset -e cd "$HOME/moss-nano-speech" cat > component-manifest.json <<'MANIFEST' { "files": [ { "repository": "OpenMOSS-Team/MOSS-TTS-Nano-100M-ONNX", "revision": "f52645cb467506d8e18e746ddd59482685b74e58", "directory": "MOSS-TTS-Nano-100M-ONNX", "file": "README.md", "bytes": 6095, "algorithm": "git-blob-sha1", "digest": "7b61e0071d117e56943eefc753b7b65208da02fe" }, { "repository": "OpenMOSS-Team/MOSS-TTS-Nano-100M-ONNX", "revision": "f52645cb467506d8e18e746ddd59482685b74e58", "directory": "MOSS-TTS-Nano-100M-ONNX", "file": "browser_poc_manifest.json", "bytes": 503354, "algorithm": "git-blob-sha1", "digest": "8a04b980c3b9ea2f56747650ea255efe421ada38" }, { "repository": "OpenMOSS-Team/MOSS-TTS-Nano-100M-ONNX", "revision": "f52645cb467506d8e18e746ddd59482685b74e58", "directory": "MOSS-TTS-Nano-100M-ONNX", "file": "moss_tts_decode_step.onnx", "bytes": 291483, "algorithm": "sha256", "digest": "698cbc2fc1c2feca16e5895614ed52bbb32ded10f236c076f477b2e69abf32d8" }, { "repository": "OpenMOSS-Team/MOSS-TTS-Nano-100M-ONNX", "revision": "f52645cb467506d8e18e746ddd59482685b74e58", "directory": "MOSS-TTS-Nano-100M-ONNX", "file": "moss_tts_global_shared.data", "bytes": 440813568, "algorithm": "sha256", "digest": "bce8312c3df6a44545302cae229b61054fe0672e0b252ba59cba47adeed831dc" }, { "repository": "OpenMOSS-Team/MOSS-TTS-Nano-100M-ONNX", "revision": "f52645cb467506d8e18e746ddd59482685b74e58", "directory": "MOSS-TTS-Nano-100M-ONNX", "file": "moss_tts_local_cached_step.onnx", "bytes": 53685, "algorithm": "sha256", "digest": "aa9035fefc1c138a951a8bcfc0374fb03a25f1ece67f7f7f53bce349b84a1dd5" }, { "repository": "OpenMOSS-Team/MOSS-TTS-Nano-100M-ONNX", "revision": "f52645cb467506d8e18e746ddd59482685b74e58", "directory": "MOSS-TTS-Nano-100M-ONNX", "file": "moss_tts_local_decoder.onnx", "bytes": 49231, "algorithm": "sha256", "digest": "51aa754301b38550a5f9adda0ad93bd3dc95819afb511e6dcabf4a90b345a454" }, { "repository": "OpenMOSS-Team/MOSS-TTS-Nano-100M-ONNX", "revision": "f52645cb467506d8e18e746ddd59482685b74e58", "directory": "MOSS-TTS-Nano-100M-ONNX", "file": "moss_tts_local_fixed_sampled_frame.onnx", "bytes": 471262, "algorithm": "sha256", "digest": "40cdb00efc171c450cf91468e01429caa41b0252222cd308e978f58fe354afa8" }, { "repository": "OpenMOSS-Team/MOSS-TTS-Nano-100M-ONNX", "revision": "f52645cb467506d8e18e746ddd59482685b74e58", "directory": "MOSS-TTS-Nano-100M-ONNX", "file": "moss_tts_local_shared.data", "bytes": 229678080, "algorithm": "sha256", "digest": "bae7782032c0fb12490ab42afe009f87ae6c75a0f0596fc7b5c08e4d5ee93916" }, { "repository": "OpenMOSS-Team/MOSS-TTS-Nano-100M-ONNX", "revision": "f52645cb467506d8e18e746ddd59482685b74e58", "directory": "MOSS-TTS-Nano-100M-ONNX", "file": "moss_tts_prefill.onnx", "bytes": 283305, "algorithm": "sha256", "digest": "d56126dcd0574c2f15d98fc6b35eda68d0386b5bd9c5e38e28548d6f2ea8f3db" }, { "repository": "OpenMOSS-Team/MOSS-TTS-Nano-100M-ONNX", "revision": "f52645cb467506d8e18e746ddd59482685b74e58", "directory": "MOSS-TTS-Nano-100M-ONNX", "file": "tokenizer.model", "bytes": 470897, "algorithm": "sha256", "digest": "c353ee1479b536bf414c1b247f5542b6607fb8ae91320e5af1781fee200fddff" }, { "repository": "OpenMOSS-Team/MOSS-TTS-Nano-100M-ONNX", "revision": "f52645cb467506d8e18e746ddd59482685b74e58", "directory": "MOSS-TTS-Nano-100M-ONNX", "file": "tts_browser_onnx_meta.json", "bytes": 4487, "algorithm": "git-blob-sha1", "digest": "883597607ce139b2c4871468396af2c088ed2fe0" }, { "repository": "OpenMOSS-Team/MOSS-Audio-Tokenizer-Nano-ONNX", "revision": "ceff0d0749bfb3fa2d61149794ec6feef0d1e1ae", "directory": "MOSS-Audio-Tokenizer-Nano-ONNX", "file": "README.md", "bytes": 4892, "algorithm": "git-blob-sha1", "digest": "46f3d445b16e8a283dd62fc9bdeec8aa35a59337" }, { "repository": "OpenMOSS-Team/MOSS-Audio-Tokenizer-Nano-ONNX", "revision": "ceff0d0749bfb3fa2d61149794ec6feef0d1e1ae", "directory": "MOSS-Audio-Tokenizer-Nano-ONNX", "file": "codec_browser_onnx_meta.json", "bytes": 17036, "algorithm": "git-blob-sha1", "digest": "886953a56489516b847b7c1c953bde063eb78faa" }, { "repository": "OpenMOSS-Team/MOSS-Audio-Tokenizer-Nano-ONNX", "revision": "ceff0d0749bfb3fa2d61149794ec6feef0d1e1ae", "directory": "MOSS-Audio-Tokenizer-Nano-ONNX", "file": "moss_audio_tokenizer_decode_full.onnx", "bytes": 681902, "algorithm": "sha256", "digest": "0fbbafe3fd4afa2a019af5c5ced204af6e2d1db044fa40f021525d2aee95b4ac" }, { "repository": "OpenMOSS-Team/MOSS-Audio-Tokenizer-Nano-ONNX", "revision": "ceff0d0749bfb3fa2d61149794ec6feef0d1e1ae", "directory": "MOSS-Audio-Tokenizer-Nano-ONNX", "file": "moss_audio_tokenizer_decode_shared.data", "bytes": 44198912, "algorithm": "sha256", "digest": "e69d52e0f4e84ca27850557ee54face46632d3a5a16c89bd246c7c408466dcad" }, { "repository": "OpenMOSS-Team/MOSS-Audio-Tokenizer-Nano-ONNX", "revision": "ceff0d0749bfb3fa2d61149794ec6feef0d1e1ae", "directory": "MOSS-Audio-Tokenizer-Nano-ONNX", "file": "moss_audio_tokenizer_decode_step.onnx", "bytes": 351400, "algorithm": "sha256", "digest": "9527c86a29e1837edec1f74db57d5eeaadb3a715af3382703566460afed25855" }, { "repository": "OpenMOSS-Team/MOSS-Audio-Tokenizer-Nano-ONNX", "revision": "ceff0d0749bfb3fa2d61149794ec6feef0d1e1ae", "directory": "MOSS-Audio-Tokenizer-Nano-ONNX", "file": "moss_audio_tokenizer_encode.data", "bytes": 44507136, "algorithm": "sha256", "digest": "aa751265b2bab2887eac224484546b194875aa7494b607115439b3dc6b228a2c" }, { "repository": "OpenMOSS-Team/MOSS-Audio-Tokenizer-Nano-ONNX", "revision": "ceff0d0749bfb3fa2d61149794ec6feef0d1e1ae", "directory": "MOSS-Audio-Tokenizer-Nano-ONNX", "file": "moss_audio_tokenizer_encode.onnx", "bytes": 815775, "algorithm": "sha256", "digest": "eadea4a645abdcf98714c7aead122ee2ce7da6e080f9f80b977cd1ca8e19473a" } ] } MANIFEST sha256sum --check <<'SHA256' 7b0f9b6a346d2f1d384c1a2fd8d9dc3215246392c720b7f64cace88540eef19f component-manifest.json SHA256Expected result: Exact full manifest verifies before reader weight retrieval.
2. Retrieve and verify every native component
Reader-only official downloads. Preserve the native sibling-directory layout referenced by the manifest. Reject any file size/hash mismatch before creating ONNX sessions; codec encode/full-decode/stream-decode and all native TTS graphs remain present even when a branch is unused.
Commandset -e cd "$HOME/moss-nano-speech" .venv/bin/python - <<'PYDOWNLOAD' import hashlib,json,pathlib,shutil from huggingface_hub import hf_hub_download for row in json.load(open('component-manifest.json'))['files']: src=hf_hub_download(row['repository'],row['file'],revision=row['revision']) dst=pathlib.Path('models')/row['directory']/row['file'];dst.parent.mkdir(parents=True,exist_ok=True);shutil.copyfile(src,dst) assert dst.stat().st_size==row['bytes'] h=hashlib.sha256() if row['algorithm']=='sha256' else hashlib.sha1() if row['algorithm']=='git-blob-sha1':h.update(('blob '+str(row['bytes'])+'\0').encode()) with dst.open('rb') as f: for b in iter(lambda:f.read(1024*1024),b''):h.update(b) assert h.hexdigest()==row['digest'],row['file'] print('All18 components verified, no native session loaded.') PYDOWNLOADExpected result: All 18 pinned files verify. Download cache duplication adds disk overhead;40 GiB is not a measured minimum.
Configure
1. Prepare your own authorized reference recording
Copy only your own/authorized clean 1–5sec 48 kHz PCM16 recording to own-recording.wav first. This step validates its format and duplicates mono channels like the native wrapper, with no resampling or fabricated voice. Listen to the original to confirm intelligibility/authorization; matching reference transcript is not a native Nano input. Existing original file remains intact.
Commandset -e cd "$HOME/moss-nano-speech" .venv/bin/python - <<'PYREFERENCE' import pathlib,wave p=pathlib.Path('own-recording.wav');assert p.stat().st_size<=1000000 with wave.open(str(p),'rb') as src: c=src.getnchannels();n=src.getnframes() assert c in (1,2) and src.getsampwidth()==2 and src.getframerate()==48000 and src.getcomptype()=='NONE' assert 48000<=n<=240000 b=src.readframes(n);assert len(b)==n*c*2 and any(b) if c==1:b=b''.join(b[i:i+2]*2 for i in range(0,len(b),2)) with wave.open('reference.wav','wb') as dst: dst.setnchannels(2);dst.setsampwidth(2);dst.setframerate(48000);dst.writeframes(b) PYREFERENCE chmod 600 own-recording.wav reference.wav sha256sum reference.wav > reference.sha256Expected result: Actual reader-owned reference.wav is 48 kHz stereo PCM16,1–5seconds. Hash is reader-generated, not a fabricated publisher recording digest.
2. Create a stable private service key
Create only when absent and keep it private. Existing key is preserved; empty/invalid key must be restored rather than silently rotated.
Commandset -e cd "$HOME/moss-nano-speech" umask 077 if [ ! -e .api-key ]; then openssl rand -hex 32 > .api-key; fi chmod 600 .api-key test -s .api-key || { echo "Restore empty key before continuing"; exit 1; }Expected result: Private64-character lowercase hexadecimal key preserved or created.
3. Create the native speech harness
Reader-authored harness invokes unchanged official OrtCpuRuntime with complete codec. It verifies components/reference/source, encodes full 16-codebook reference, checks text/native global rows and rejects empty or cap-length generated speech. No arbitrary upload, file, URL, text or voice request is accepted.
Commandset -e cd "$HOME/moss-nano-speech" cat > moss_speech.py <<'PYSERVER' """Reader-authored educational fixed-input MOSS-TTS Nano native ONNX harness; not publisher server.""" import hashlib import hmac import json import math import pathlib from http.server import BaseHTTPRequestHandler, HTTPServer ROOT = pathlib.Path(__file__).resolve().parent PORT = 8996 TEXT = 'Welcome to this private speech demonstration.' def validate_audio(result): import base64 import io import wave wav, rows, frames, reference_hash, clipped = result if type(rows) is not int or type(frames) is not int or not 0 < frames < 125 or not 0 < rows <= 387: raise ValueError('native_row_budget') if not isinstance(wav, bytes) or not 44 <= len(wav) <= 1920044: raise ValueError('wav_size') with wave.open(io.BytesIO(wav), 'rb') as audio: if (audio.getnchannels(),audio.getsampwidth(),audio.getframerate(),audio.getcomptype()) != (2,2,48000,'NONE'): raise ValueError('wav_format') samples = audio.getnframes() if not 0 < samples <= frames*3840: raise ValueError('wav_duration') if len(audio.readframes(samples)) != samples*4: raise ValueError('wav_truncated') if not isinstance(reference_hash,str) or len(reference_hash)!=64 or any(c not in '0123456789abcdef' for c in reference_hash): raise ValueError('reference_hash') if type(clipped) is not int or not 0 <= clipped <= samples*2: raise ValueError('clipping_count') return {'fixture':'reader-own-reference-v1','text':TEXT,'mime_type':'audio/wav', 'wav_base64':base64.b64encode(wav).decode('ascii'),'sample_rate':48000, 'channels':2,'sample_frames':samples,'generated_audio_frames':frames, 'audio_codebook_count':16,'prefill_global_rows':rows, 'configured_global_row_budget':512,'max_new_audio_frames':125, 'reference_sha256':reference_hash,'pcm_clipped_samples':clipped, 'generated_text_tokens':None} def make_encoder(): # Reader execution only. Fake boundary tests do not import NumPy/ORT/SentencePiece. import sys import io import wave import numpy as np import sentencepiece as spm manifest=json.loads((ROOT/'component-manifest.json').read_text()) for row in manifest['files']: file=ROOT/'models'/row['directory']/row['file'] if file.stat().st_size!=row['bytes']:raise RuntimeError('component_size') h=hashlib.sha256() if row['algorithm']=='sha256' else hashlib.sha1() if row['algorithm']=='git-blob-sha1':h.update(('blob '+str(row['bytes'])+'\0').encode()) with file.open('rb') as stream: for chunk in iter(lambda:stream.read(1024*1024),b''):h.update(chunk) if h.hexdigest()!=row['digest']:raise RuntimeError('component_hash') reference=ROOT/'reference.wav' if reference.stat().st_size>1000000:raise RuntimeError('reference_size') reference_hash=hashlib.sha256(reference.read_bytes()).hexdigest() if reference_hash!=(ROOT/'reference.sha256').read_text().split()[0]:raise RuntimeError('reference_changed') with wave.open(str(reference),'rb') as audio: if (audio.getnchannels(),audio.getsampwidth(),audio.getframerate(),audio.getcomptype())!=(2,2,48000,'NONE'): raise RuntimeError('reference_format') n=audio.getnframes() if not 48000<=n<=240000:raise RuntimeError('reference_duration') pcm=audio.readframes(n) if len(pcm)!=n*4:raise RuntimeError('reference_truncated') waveform=np.frombuffer(pcm,dtype='<i2').astype(np.float32).reshape(-1,2).T[None,:,:]/32768.0 if not np.any(waveform):raise RuntimeError('reference_silent') native=ROOT/'native-moss-nano' if hashlib.sha256((native/'ort_cpu_runtime.py').read_bytes()).hexdigest()!='99477efaff28c12c0c8e16a6b4aab4e880a70851693fa303d932415ba180cbd5': raise RuntimeError('native_source_hash') sys.path.insert(0,str(native)) from ort_cpu_runtime import OrtCpuRuntime runtime=OrtCpuRuntime(ROOT/'models',thread_count=4,max_new_frames=125, do_sample=False,sample_mode='greedy',execution_provider='cpu') if runtime.manifest['tts_config']['n_vq']!=16:raise RuntimeError('codebook_count') config=runtime.codec_meta['codec_config'] if (config['sample_rate'],config['channels'],config['downsample_rate'],config['num_quantizers'])!=(48000,2,3840,16): raise RuntimeError('codec_variant') outputs=runtime.sessions['codec_encode'].run(None,{'waveform':waveform, 'input_lengths':np.asarray([n],dtype=np.int32)}) named=dict(zip([o.name for o in runtime.sessions['codec_encode'].get_outputs()],outputs,strict=True)) codes=np.asarray(named['audio_codes']);length=int(np.asarray(named['audio_code_lengths']).reshape(-1)[0]) if not np.issubdtype(codes.dtype,np.integer) or not 0<length<=64 or codes.ndim!=3 or codes.shape[0]!=1 or codes.shape[1]<length or codes.shape[2]!=16: raise RuntimeError('reference_code_shape') prompt_codes=codes[0,:length,:].astype(np.int32).tolist() if any(not 0<=v<1024 for row in prompt_codes for v in row):raise RuntimeError('reference_code_range') tokenizer=spm.SentencePieceProcessor(model_file=str(ROOT/'models/MOSS-TTS-Nano-100M-ONNX/tokenizer.model')) text_ids=[int(x) for x in tokenizer.encode(TEXT,out_type=int)] if not 0<len(text_ids)<=75:raise RuntimeError('text_budget') request=runtime.build_voice_clone_request_rows(prompt_codes,text_ids) rows=len(request['inputIds']) if rows+125>512 or any(len(row)!=17 for row in request['inputIds']):raise RuntimeError('global_row_budget') def encode(): frames=runtime.generate_audio_frames(request) if not 0<len(frames)<125:raise RuntimeError('empty_or_capped_audio') if any(len(row)!=16 or any(type(v) is not int or not 0<=v<1024 for v in row) for row in frames): raise RuntimeError('generated_code_shape') channels,count=runtime.decode_full_audio(frames) if len(channels)!=2 or not 0<count<=len(frames)*3840:raise RuntimeError('decoded_audio_shape') data=np.stack(channels,axis=1) if data.shape!=(count,2) or not np.isfinite(data).all() or not np.any(data):raise RuntimeError('decoded_audio_finiteness') clipped=int(np.count_nonzero(np.abs(data)>1)) pcm_out=(np.clip(data,-1,1)*32767).round().astype('<i2').tobytes() buffer=io.BytesIO() with wave.open(buffer,'wb') as out: out.setnchannels(2);out.setsampwidth(2);out.setframerate(48000);out.writeframes(pcm_out) return buffer.getvalue(),rows,len(frames),reference_hash,clipped return encode PYSERVERExpected result: First complete loader/codec/native-row/PCM validation fragment written.
4. Complete and verify private speech transport
Append the bounded private loopback protocol. Syntax/hash checks do not load any native model.
Commandset -e cd "$HOME/moss-nano-speech" cat >> moss_speech.py <<'PYSERVER' def create_server(encoder, key, port=PORT): if not isinstance(key, str) or len(key) != 64 or any(c not in '0123456789abcdef' for c in key): raise ValueError('key_format') class Handler(BaseHTTPRequestHandler): def setup(self): super().setup() self.connection.settimeout(5) def log_message(self, *_): pass # Do not log Bearer keys or request bodies. def reply(self, status, obj): data = json.dumps(obj, allow_nan=False, separators=(',', ':')).encode() self.send_response(status) self.send_header('Content-Type', 'application/json') self.send_header('Content-Length', str(len(data))) self.send_header('Connection', 'close') self.end_headers() self.wfile.write(data) self.close_connection = True def authorized(self): values = self.headers.get_all('Authorization', []) return len(values) == 1 and hmac.compare_digest(values[0].encode(), ('Bearer ' + key).encode()) def do_GET(self): if not self.authorized(): return self.reply(401, {'error': 'unauthorized'}) if self.path != '/health': return self.reply(404, {'error': 'not_found'}) return self.reply(200, {'ready': True, 'configured_global_row_budget': 512, 'audio_codebook_count': 16, 'generated_text_tokens': None}) def do_POST(self): if not self.authorized(): return self.reply(401, {'error': 'unauthorized'}) if self.path != '/v1/fixed-speech': return self.reply(404, {'error': 'not_found'}) if self.headers.get('Transfer-Encoding') is not None: return self.reply(400, {'error': 'transfer_encoding_unsupported'}) lengths = self.headers.get_all('Content-Length', []) if len(lengths) != 1: return self.reply(411, {'error': 'content_length_required'}) raw = lengths[0] if not raw or len(raw) > 4 or any(c not in '0123456789' for c in raw): return self.reply(413, {'error': 'invalid_or_excessive_length'}) n = int(raw) if n < 1 or n > 256: return self.reply(413, {'error': 'body_limit'}) if self.headers.get_content_type() != 'application/json': return self.reply(415, {'error': 'json_required'}) try: body = self.rfile.read(n) except (TimeoutError, OSError): return self.reply(408, {'error': 'body_timeout'}) if len(body) != n: return self.reply(400, {'error': 'incomplete_body'}) try: def unique(pairs): obj = {} for k, v in pairs: if k in obj: raise ValueError('duplicate_key') obj[k] = v return obj request = json.loads(body.decode('utf-8'), object_pairs_hook=unique, parse_constant=lambda _: (_ for _ in ()).throw(ValueError('constant'))) except (ValueError, UnicodeError, RecursionError): return self.reply(400, {'error': 'invalid_json'}) if type(request) is not dict or request != {'fixture': 'reader-own-reference-v1'}: return self.reply(400, {'error': 'fixed_fixture_required'}) try: result = validate_audio(encoder()) except Exception: return self.reply(500, {'error': 'native_speech_or_wav_failure'}) return self.reply(200, result) return HTTPServer(('127.0.0.1', port), Handler) if __name__ == '__main__': secret = (ROOT / '.api-key').read_text().strip() if len(secret)!=64 or any(c not in '0123456789abcdef' for c in secret): raise ValueError('key_format') encoder = make_encoder() with create_server(encoder, secret) as server: server.serve_forever() PYSERVER .venv/bin/python -m py_compile moss_speech.py sha256sum --check <<'SHA256' af684e3b9446099087a52b34b47000c41e532b68c2132e520714b2de984f4c90 moss_speech.py SHA256Expected result: Exact complete wrapper bytes and syntax pass without native imports.
Start the model
1. Start the private native CPU speech experiment
All native sessions use CPUExecutionProvider with four intra-op threads and one inter-op thread. Reference codec encoding occurs at startup; each generation builds native global/local cache afresh. No warmup, browser/web app, optional text-normalization path or streaming optimization is claimed.
Commandset -e cd "$HOME/moss-nano-speech" .venv/bin/python moss_speech.pyExpected result: After actual reader-side verified native load/reference encoding, loopback 127.0.0.1:8996 serves. Stop on load/codec/budget errors; successful speech is not claimed by the author.
Connect to your endpoint
http://127.0.0.1:8996/v1/fixed-speech
Same trusted desktop loopback only.
Access: loopback. Private Bearer key for health and synthesis. Send a JSON object with fixture set to reader-own-reference-v1. Response contains base64 WAV, reference hash, global rows, audio frames, codebook count and clipping count. No arbitrary text/audio/uploads/URLs/files or transcript fields are accepted.
Verify the setup
1. Validate WAV structure and listen to the speech
From a second server terminal, request only the fixed original sentence. Check exact native metadata, cap rejection and valid stereo PCM WAV; then listen locally. Speech must say the displayed sentence intelligibly, not merely have valid bytes. Voice similarity, prosody, pronunciation, loudness and clipping need human inspection; no quality metric is fabricated. Missing key must return 401.
Commandset -e cd "$HOME/moss-nano-speech" MOSS_KEY="$(cat .api-key)" curl --fail http://127.0.0.1:8996/health -H "Authorization: Bearer $MOSS_KEY" curl --fail http://127.0.0.1:8996/v1/fixed-speech -H "Authorization: Bearer $MOSS_KEY" -H 'Content-Type: application/json' -d '{"fixture":"reader-own-reference-v1"}' -o speech.json curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:8996/health unset MOSS_KEY .venv/bin/python - <<'PYVERIFY' import base64,io,json,wave d=json.load(open('speech.json'));assert d['generated_text_tokens'] is None assert d['configured_global_row_budget']==512 and d['audio_codebook_count']==16 assert 0<d['generated_audio_frames']<125 and d['prefill_global_rows']+125<=512 b=base64.b64decode(d['wav_base64'],validate=True);assert len(b)<=1920044 with wave.open(io.BytesIO(b),'rb') as w: assert (w.getnchannels(),w.getsampwidth(),w.getframerate(),w.getcomptype())==(2,2,48000,'NONE') assert w.getnframes()==d['sample_frames'] and 0<w.getnframes()<=d['generated_audio_frames']*3840 assert len(w.readframes(w.getnframes()))==w.getnframes()*4 open('speech.wav','wb').write(b) print(d['text']);print('Listen to speech.wav; validate intelligibility, voice permission and clipping manually.') PYVERIFYExpected result: Authenticated response has valid bounded WAV/native metadata; missing key 401. Listen to speech.wav with your local player. Invalid/capped/silent/nonfinite outputs fail; valid structure is not intelligibility or voice-quality proof.
Performance evidence
No compatible measurement available. Documented support and estimated memory do not establish response speed.
Limits and troubleshooting
- Frozen family date is February 2026; Nano is an explicitly named April 2026 member recommended by the official parent for CPU use. Flagship 8B, 1.7B/4B local transformer, realtime, dialogue, sound effects, voice design, other backends/streaming and other family jobs remain open. This pair is not family-complete.
- 512 is this author-selected total native global-row budget: template/reference/text prefill plus 125 reserved future rows. Each audio row contains 16 codebook IDs plus a text/slot column. It is not 512 text tokens, a scalar-codec-ID count or a proven ONNX global maximum.
- Native codec 48 kHz stereo/downsample 3840 gives 12.5 audio frames/sec. 125 generated frames cap 10 sec; reaching the cap is rejected as potentially truncated. Decoded sample count/end effects are checked rather than equated blindly with frame count.
- Full native codec encode/full-decode/stream-decode sessions and all required TTS graphs/external data remain pinned. Using the low-level native NumPy/ORT API is not an incomplete text-only substitute. The broader CLI imports Torch/torchaudio and is not falsely represented as a no-Torch entrypoint.
- Original target text is fixed English. Reader must provide own/authorized clean speech; no provided identity or recording is copied. Native Nano uses reference codes and target text without a separate reference-transcript field. Robust normalization, long-text chunking and arbitrary scripts are outside this bounded raw-token path.
- Greedy mode is a source-supported choice differing from default fixed sampling. Native repetition penalty 1.2 remains. No measured naturalness, speaker similarity, sample-rate quality, realtime factor or benchmark transfer is claimed.
- Native decoded arrays must be finite/nonzero. PCM16 conversion clips values outside[-1,1] and reports clipped sample count; listening and loudness assessment remain necessary. No generated WAV, actual reference, listening result or successful native inference is supplied here.
- 32 GiB RAM, 40 GiB disk and four threads are selected allocations; full session/cache/codec load fit and performance remain unknown. Official file sizes are not runtime memory or a measured minimum.
- Reader-authored serial HTTPServer uses private key/loopback, bounded strict fixed JSON and WAV/output checks, but no inference deadline or public multiuser-production guarantee. Reference/voice files remain private reader data.
- Fake WAV tests validate protocol/security/output boundaries only, not native ONNX compatibility, codec correctness, speech content or voice consent. Native code/model/source pins remain unchanged.
- Native component/provider/session error
- Stop on hash, metadata, ONNX load or provider errors. Use exact 18-file layout/native module and CPUExecutionProvider; do not float to main, omit codec graphs or replace the full speech path with a text-only endpoint.
- Reference format, code shape or budget error
- Use your own/authorized 1–5sec 48 kHz PCM16 mono/stereo source and exact reference conversion/hash. Listen to clean natural speech first. Do not substitute synthetic tones or silently crop/reduce codebooks; shorter authorized recording may be needed to fit this chosen row bound.
- 401 or rejected request
- Use matching private 64-character key and exact fixed selector. Extra text, audio, URLs, files and transcript fields are rejected.
- Capped, silent, nonfinite or unintelligible speech
- Treat cap-length/empty/nonfinite as failure and inspect actual audio/reference. A valid WAV can be wrong or sound poor; record the defect. This guide promises no native quality or speed. Do not remove completion guards or use someone else’s voice to force a demo.
Stop the model
1. Stop the private speech service
Press Ctrl+C in the foreground terminal and unset client key. Confirm loopback speech endpoint no longer serves.
Commandunset MOSS_KEYExpected result: Native sessions and endpoint stop; reader reference/output files remain until removed.
Uninstall
1. Remove the dedicated private experiment
Preserve desired authorized outputs, source/license and audit records first. Confirm directory before deletion. Remove only these selected model caches if unused by other work; shared Ubuntu packages remain. Deleting files is not a promise of forensic erasure.
Commandrm -r -- "$HOME/moss-nano-speech" rm -r -- "$HOME/.cache/huggingface/hub/models--OpenMOSS-Team--MOSS-TTS-Nano-100M-ONNX" rm -r -- "$HOME/.cache/huggingface/hub/models--OpenMOSS-Team--MOSS-Audio-Tokenizer-Nano-ONNX"Expected result: The dedicated native checkout, virtual environment, model bundle, reference recording, outputs, private key and selected model caches are removed if present.
Sources and verification
Sources checked Oct 16, 2026. Verification source
- https://api.github.com/repos/OpenMOSS/MOSS-TTS/commits/mainpublisher · retrieved Oct 16, 2026
- https://api.github.com/repos/OpenMOSS/MOSS-TTS/git/trees/main?recursive=1publisher · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/OpenMOSS/MOSS-TTS/934d6826b084c46a0d033402174d5f8ac4ed2519/README.mdpublisher · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/OpenMOSS/MOSS-TTS/934d6826b084c46a0d033402174d5f8ac4ed2519/LICENSEpublisher · retrieved Oct 16, 2026
- https://api.github.com/repos/OpenMOSS/MOSS-TTS-Nano/commits/mainpublisher · retrieved Oct 16, 2026
- https://api.github.com/repos/OpenMOSS/MOSS-TTS-Nano/git/trees/main?recursive=1publisher · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/OpenMOSS/MOSS-TTS-Nano/8b7bcc9341b3b4ef3a3a58ba1338a7d85ff133eb/README.mdpublisher · retrieved Oct 16, 2026 · revision 8b7bcc9
- https://raw.githubusercontent.com/OpenMOSS/MOSS-TTS-Nano/8b7bcc9341b3b4ef3a3a58ba1338a7d85ff133eb/LICENSEpublisher · retrieved Oct 16, 2026 · revision 8b7bcc9
- https://raw.githubusercontent.com/OpenMOSS/MOSS-TTS-Nano/8b7bcc9341b3b4ef3a3a58ba1338a7d85ff133eb/pyproject.tomlpublisher · retrieved Oct 16, 2026 · revision 8b7bcc9
- https://raw.githubusercontent.com/OpenMOSS/MOSS-TTS-Nano/8b7bcc9341b3b4ef3a3a58ba1338a7d85ff133eb/infer_onnx.pypublisher · retrieved Oct 16, 2026 · revision 8b7bcc9
- https://raw.githubusercontent.com/OpenMOSS/MOSS-TTS-Nano/8b7bcc9341b3b4ef3a3a58ba1338a7d85ff133eb/onnx_tts_runtime.pypublisher · retrieved Oct 16, 2026 · revision 8b7bcc9
- https://raw.githubusercontent.com/OpenMOSS/MOSS-TTS-Nano/8b7bcc9341b3b4ef3a3a58ba1338a7d85ff133eb/ort_cpu_runtime.pypublisher · retrieved Oct 16, 2026 · revision 8b7bcc9
- https://raw.githubusercontent.com/OpenMOSS/MOSS-TTS-Nano/8b7bcc9341b3b4ef3a3a58ba1338a7d85ff133eb/moss_tts_nano/defaults.pypublisher · retrieved Oct 16, 2026 · revision 8b7bcc9
- https://raw.githubusercontent.com/OpenMOSS/MOSS-TTS-Nano/8b7bcc9341b3b4ef3a3a58ba1338a7d85ff133eb/requirements.txtpublisher · retrieved Oct 16, 2026 · revision 8b7bcc9
- https://raw.githubusercontent.com/OpenMOSS/MOSS-TTS-Nano/8b7bcc9341b3b4ef3a3a58ba1338a7d85ff133eb/moss_tts_nano_runtime.pypublisher · retrieved Oct 16, 2026 · revision 8b7bcc9
- https://raw.githubusercontent.com/OpenMOSS/MOSS-TTS-Nano/8b7bcc9341b3b4ef3a3a58ba1338a7d85ff133eb/text_normalization_pipeline.pypublisher · retrieved Oct 16, 2026 · revision 8b7bcc9
- https://huggingface.co/api/models/OpenMOSS-Team/MOSS-TTS-Nano-100M-ONNX?blobs=truepublisher · retrieved Oct 16, 2026
- https://huggingface.co/api/models/OpenMOSS-Team/MOSS-Audio-Tokenizer-Nano-ONNX?blobs=truepublisher · retrieved Oct 16, 2026
- https://huggingface.co/OpenMOSS-Team/MOSS-TTS-Nano-100M-ONNX/resolve/f52645cb467506d8e18e746ddd59482685b74e58/README.mdpublisher · retrieved Oct 16, 2026 · revision f52645c
- https://huggingface.co/OpenMOSS-Team/MOSS-TTS-Nano-100M-ONNX/resolve/f52645cb467506d8e18e746ddd59482685b74e58/browser_poc_manifest.jsonpublisher · retrieved Oct 16, 2026 · revision f52645c
- https://huggingface.co/OpenMOSS-Team/MOSS-TTS-Nano-100M-ONNX/resolve/f52645cb467506d8e18e746ddd59482685b74e58/tts_browser_onnx_meta.jsonpublisher · retrieved Oct 16, 2026 · revision f52645c
- https://huggingface.co/OpenMOSS-Team/MOSS-Audio-Tokenizer-Nano-ONNX/resolve/ceff0d0749bfb3fa2d61149794ec6feef0d1e1ae/README.mdpublisher · retrieved Oct 16, 2026 · revision ceff0d0
- https://huggingface.co/OpenMOSS-Team/MOSS-Audio-Tokenizer-Nano-ONNX/resolve/ceff0d0749bfb3fa2d61149794ec6feef0d1e1ae/codec_browser_onnx_meta.jsonpublisher · retrieved Oct 16, 2026 · revision ceff0d0
- https://huggingface.co/api/models/OpenMOSS-Team/MOSS-TTS-Nano?blobs=truepublisher · retrieved Oct 16, 2026
- https://huggingface.co/OpenMOSS-Team/MOSS-TTS-Nano/resolve/44502f80dbf9743528fa921cc544d662c685ebec/config.jsonpublisher · retrieved Oct 16, 2026
- https://pypi.org/pypi/onnxruntime/jsonruntime maintainer · retrieved Oct 16, 2026
- https://pypi.org/pypi/sentencepiece/0.2.1/jsonruntime maintainer · retrieved Oct 16, 2026
- https://pypi.org/pypi/onnxruntime/1.23.2/jsonruntime maintainer · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/microsoft/onnxruntime/v1.23.2/onnxruntime/python/onnxruntime_inference_collection.pyruntime maintainer · retrieved Oct 16, 2026
- https://pypi.org/pypi/huggingface-hub/0.36.2/jsonruntime maintainer · retrieved Oct 16, 2026
- https://pypi.org/pypi/numpy/2.2.3/jsonruntime maintainer · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/pytorch/vision/v0.21.0/torchvision/transforms/functional.pyruntime maintainer · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/pytorch/vision/v0.21.0/torchvision/transforms/transforms.pyruntime maintainer · retrieved Oct 16, 2026
- https://pypi.org/pypi/pillow/11.1.0/jsonruntime maintainer · retrieved Oct 16, 2026
- https://download.pytorch.org/whl/cpu/torch/runtime maintainer · retrieved Oct 16, 2026
- https://docs.python.org/3.11/library/http.server.htmlruntime maintainer · retrieved Oct 16, 2026
- https://docs.python.org/3.11/library/hmac.htmlruntime maintainer · retrieved Oct 16, 2026
- https://download.pytorch.org/whl/cpu/torchvision/runtime maintainer · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/pytorch/vision/v0.21.0/README.mdruntime maintainer · retrieved Oct 16, 2026
- https://pypi.org/pypi/torchvision/0.21.0/jsonruntime maintainer · retrieved Oct 16, 2026
- https://opentools.ai/llms/moss-ttsopentools · retrieved Oct 16, 2026 · revision moss-nano-reader-v1
- https://www.intel.com/content/www/us/en/products/sku/134586/intel-core-i512400-processor-18m-cache-up-to-4-40-ghz/specifications.htmlmanufacturer · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/ggml-org/llama.cpp/620d2225cc436ab0b001e3200e590e3b286ef9ab/ggml/src/ggml-cpu/CMakeLists.txtruntime maintainer · retrieved Oct 16, 2026 · revision 620d222
- https://docs.liquid.ai/lfm/inference/llama-cppruntime maintainer · retrieved Oct 16, 2026
- https://raw.githubusercontent.com/ggml-org/llama.cpp/620d2225cc436ab0b001e3200e590e3b286ef9ab/docs/build.mdruntime maintainer · retrieved Oct 16, 2026 · revision 620d222