Skip to main content
The Model Download Manager provides utilities for downloading, caching, and managing sherpa-onnx models from the official GitHub releases.

Overview

Models are downloaded from the official k2-fsa/sherpa-onnx releases and stored in the app’s document directory. The manager handles:
  • Listing available models from GitHub releases
  • Downloading and extracting model archives
  • Checksum verification
  • Download progress and cancellation
  • LRU (Least Recently Used) cache management
  • Metadata tracking (download date, last used, disk size)

Model Categories

enum ModelCategory {
  Tts = 'tts',
  Stt = 'stt',
  Vad = 'vad',
  Diarization = 'diarization',
  Enhancement = 'enhancement',
  Separation = 'separation',
}

Core Functions

listModelsByCategory()

List available models for a category (from cache).
function listModelsByCategory<T extends ModelMetaBase>(
  category: ModelCategory
): Promise<T[]>

refreshModelsByCategory()

Refresh the list of available models from GitHub.
function refreshModelsByCategory<T extends ModelMetaBase>(
  category: ModelCategory,
  options?: {
    forceRefresh?: boolean;
    cacheTtlMinutes?: number;
    maxRetries?: number;
    signal?: AbortSignal;
  }
): Promise<T[]>

downloadModelByCategory()

Download and extract a model.
function downloadModelByCategory<T extends ModelMetaBase>(
  category: ModelCategory,
  id: string,
  options?: {
    onProgress?: (progress: DownloadProgress) => void;
    overwrite?: boolean;
    signal?: AbortSignal;
    maxRetries?: number;
    onChecksumIssue?: (issue: ChecksumIssue) => Promise<boolean>;
  }
): Promise<DownloadResult>

getLocalModelPathByCategory()

Get the local path to a downloaded model.
function getLocalModelPathByCategory(
  category: ModelCategory,
  id: string
): Promise<string | null>

isModelDownloadedByCategory()

Check if a model is downloaded.
function isModelDownloadedByCategory(
  category: ModelCategory,
  id: string
): Promise<boolean>

deleteModelByCategory()

Delete a downloaded model.
function deleteModelByCategory(
  category: ModelCategory,
  id: string
): Promise<void>

listDownloadedModelsByCategory()

List all downloaded models for a category.
function listDownloadedModelsByCategory<T extends ModelMetaBase>(
  category: ModelCategory
): Promise<T[]>

Examples

List and Download TTS Models

import {
  ModelCategory,
  listModelsByCategory,
  refreshModelsByCategory,
  downloadModelByCategory,
  getLocalModelPathByCategory,
} from 'react-native-sherpa-onnx/download';
import type { TtsModelMeta } from 'react-native-sherpa-onnx/download';

// Refresh model list from GitHub
const models = await refreshModelsByCategory<TtsModelMeta>(
  ModelCategory.Tts
);

console.log('Available TTS models:', models.length);

// Filter for English VITS models
const englishVits = models.filter(
  (m) => m.type === 'vits' && m.languages.includes('en')
);

// Download a model
const modelId = 'vits-piper-en_US-lessac-medium';

const result = await downloadModelByCategory(
  ModelCategory.Tts,
  modelId,
  {
    onProgress: (progress) => {
      console.log(`Download: ${progress.percent.toFixed(1)}%`);
      if (progress.speed) {
        const mbps = (progress.speed / 1024 / 1024).toFixed(2);
        console.log(`Speed: ${mbps} MB/s`);
      }
    },
  }
);

console.log('Downloaded to:', result.localPath);

// Get path for use with TTS
const modelPath = await getLocalModelPathByCategory(
  ModelCategory.Tts,
  modelId
);

Download with Progress UI

import { useState } from 'react';
import { ModelCategory, downloadModelByCategory } from 'react-native-sherpa-onnx/download';

function ModelDownloadComponent() {
  const [progress, setProgress] = useState(0);
  const [phase, setPhase] = useState<'downloading' | 'extracting'>('downloading');
  const [isDownloading, setIsDownloading] = useState(false);

  const download = async (modelId: string) => {
    setIsDownloading(true);
    
    try {
      await downloadModelByCategory(
        ModelCategory.Tts,
        modelId,
        {
          onProgress: (p) => {
            setProgress(p.percent);
            setPhase(p.phase || 'downloading');
          },
        }
      );
      
      console.log('Download complete!');
    } catch (error) {
      console.error('Download failed:', error);
    } finally {
      setIsDownloading(false);
    }
  };

  return (
    <View>
      {isDownloading && (
        <View>
          <Text>{phase}: {progress.toFixed(1)}%</Text>
          <ProgressBar progress={progress / 100} />
        </View>
      )}
    </View>
  );
}

Download with Cancellation

import { ModelCategory, downloadModelByCategory } from 'react-native-sherpa-onnx/download';

const abortController = new AbortController();

const downloadPromise = downloadModelByCategory(
  ModelCategory.Stt,
  'sherpa-onnx-whisper-tiny-en',
  {
    signal: abortController.signal,
    onProgress: (progress) => {
      console.log(`Progress: ${progress.percent}%`);
    },
  }
);

// Cancel after 5 seconds
setTimeout(() => {
  abortController.abort();
  console.log('Download cancelled');
}, 5000);

try {
  await downloadPromise;
} catch (error) {
  if (error.name === 'AbortError') {
    console.log('Download was cancelled');
  }
}

LRU Cache Management

import {
  ModelCategory,
  listDownloadedModelsWithMetadata,
  cleanupLeastRecentlyUsed,
} from 'react-native-sherpa-onnx/download';

// List downloaded models with metadata
const models = await listDownloadedModelsWithMetadata(ModelCategory.Tts);

console.log('Downloaded models:');
for (const m of models) {
  const sizeMB = ((m.sizeOnDisk || 0) / 1024 / 1024).toFixed(1);
  console.log(`${m.model.id}: ${sizeMB} MB, last used: ${m.lastUsed}`);
}

// Clean up old models (keep 3 most recent, delete others)
const deletedIds = await cleanupLeastRecentlyUsed(
  ModelCategory.Tts,
  {
    keepCount: 3,
  }
);

console.log('Deleted models:', deletedIds);

// Or free up specific amount of space
const targetBytes = 500 * 1024 * 1024; // 500 MB
await cleanupLeastRecentlyUsed(
  ModelCategory.Tts,
  {
    targetBytes,
    keepCount: 1,
  }
);

List Downloaded Models

import {
  ModelCategory,
  listDownloadedModelsByCategory,
  isModelDownloadedByCategory,
} from 'react-native-sherpa-onnx/download';

// Get all downloaded TTS models
const downloaded = await listDownloadedModelsByCategory(ModelCategory.Tts);

console.log('Downloaded TTS models:', downloaded.map(m => m.id));

// Check if specific model is downloaded
const isDownloaded = await isModelDownloadedByCategory(
  ModelCategory.Tts,
  'vits-piper-en_US-lessac-medium'
);

if (isDownloaded) {
  console.log('Model ready to use');
}

Subscribe to Events

subscribeDownloadProgress()

Subscribe to download progress events for all downloads.
function subscribeDownloadProgress(
  listener: DownloadProgressListener
): () => void

subscribeModelsListUpdated()

Subscribe to model list updates.
function subscribeModelsListUpdated(
  listener: ModelsListUpdatedListener
): () => void

Example

import {
  subscribeDownloadProgress,
  subscribeModelsListUpdated,
} from 'react-native-sherpa-onnx/download';

// Subscribe to download progress
const unsubscribeProgress = subscribeDownloadProgress(
  (category, modelId, progress) => {
    console.log(`${category}/${modelId}: ${progress.percent}%`);
  }
);

// Subscribe to model list updates
const unsubscribeList = subscribeModelsListUpdated(
  (category, models) => {
    console.log(`${category} models updated:`, models.length);
  }
);

// Later: unsubscribe
unsubscribeProgress();
unsubscribeList();

Types

TtsModelMeta

interface TtsModelMeta {
  id: string;
  displayName: string;
  type: TTSModelType | 'unknown';
  languages: string[];
  quantization: 'fp16' | 'int8' | 'int8-quantized' | 'unknown';
  sizeTier: 'tiny' | 'small' | 'medium' | 'large' | 'unknown';
  downloadUrl: string;
  archiveExt: 'tar.bz2' | 'onnx';
  bytes: number;
  sha256?: string;
  category: ModelCategory.Tts;
}

DownloadProgress

interface DownloadProgress {
  bytesDownloaded: number;
  totalBytes: number;
  percent: number;
  phase?: 'downloading' | 'extracting';
  speed?: number;  // bytes per second
  eta?: number;    // estimated seconds remaining
}

DownloadResult

interface DownloadResult {
  modelId: string;
  localPath: string;
}

Validation

The download manager includes built-in validation:
  • Checksum verification: SHA-256 checksums from GitHub releases
  • File validation: Ensures required model files exist after extraction
  • Disk space check: Verifies sufficient space before download
import {
  validateChecksum,
  validateExtractedFiles,
  checkDiskSpace,
} from 'react-native-sherpa-onnx/download';

// Check disk space
const spaceCheck = await checkDiskSpace(500 * 1024 * 1024); // 500 MB
if (!spaceCheck.success) {
  console.error('Insufficient space:', spaceCheck.message);
}

// Validate checksum
const checksumResult = await validateChecksum(
  '/path/to/model.tar.bz2',
  'expected_sha256_hash'
);

if (!checksumResult.success) {
  console.error('Checksum failed:', checksumResult.message);
}

Utility Functions

extractTarBz2()

Extract a .tar.bz2 archive file (requires libarchive).
function extractTarBz2(
  sourcePath: string,
  targetPath: string,
  force?: boolean,
  onProgress?: (event: ExtractProgressEvent) => void
): Promise<void>
sourcePath
string
required
Absolute path to the .tar.bz2 file
targetPath
string
required
Absolute path to extract to
force
boolean
If true, overwrite existing files. Default: false
onProgress
(event: ExtractProgressEvent) => void
Progress callback with bytesExtracted and totalBytes
If libarchive is disabled in your build (see Disable Libarchive), this function will reject with an error.
Example:
import { extractTarBz2 } from 'react-native-sherpa-onnx/download';

await extractTarBz2(
  '/path/to/model.tar.bz2',
  '/path/to/models/',
  false,
  (event) => {
    console.log(`Extracted ${event.bytesExtracted} / ${event.totalBytes}`);
  }
);

cancelExtractTarBz2()

Cancel an ongoing extraction.
function cancelExtractTarBz2(): void

computeFileSha256()

Compute SHA256 checksum of a file.
function computeFileSha256(
  filePath: string
): Promise<string>
filePath
string
required
Absolute path to the file
Returns a promise resolving to the lowercase hex SHA256 hash. Example:
import { computeFileSha256 } from 'react-native-sherpa-onnx/download';

const hash = await computeFileSha256('/path/to/model.tar.bz2');
console.log('SHA256:', hash);

See Also

Build docs developers (and LLMs) love