> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/XDcobra/react-native-sherpa-onnx/llms.txt
> Use this file to discover all available pages before exploring further.

# Model Download Manager

> Download and manage sherpa-onnx models at runtime

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](https://github.com/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

```typescript theme={null}
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).

```typescript theme={null}
function listModelsByCategory<T extends ModelMetaBase>(
  category: ModelCategory
): Promise<T[]>
```

### refreshModelsByCategory()

Refresh the list of available models from GitHub.

```typescript theme={null}
function refreshModelsByCategory<T extends ModelMetaBase>(
  category: ModelCategory,
  options?: {
    forceRefresh?: boolean;
    cacheTtlMinutes?: number;
    maxRetries?: number;
    signal?: AbortSignal;
  }
): Promise<T[]>
```

### downloadModelByCategory()

Download and extract a model.

```typescript theme={null}
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.

```typescript theme={null}
function getLocalModelPathByCategory(
  category: ModelCategory,
  id: string
): Promise<string | null>
```

### isModelDownloadedByCategory()

Check if a model is downloaded.

```typescript theme={null}
function isModelDownloadedByCategory(
  category: ModelCategory,
  id: string
): Promise<boolean>
```

### deleteModelByCategory()

Delete a downloaded model.

```typescript theme={null}
function deleteModelByCategory(
  category: ModelCategory,
  id: string
): Promise<void>
```

### listDownloadedModelsByCategory()

List all downloaded models for a category.

```typescript theme={null}
function listDownloadedModelsByCategory<T extends ModelMetaBase>(
  category: ModelCategory
): Promise<T[]>
```

## Examples

### List and Download TTS Models

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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

```typescript theme={null}
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.

```typescript theme={null}
function subscribeDownloadProgress(
  listener: DownloadProgressListener
): () => void
```

### subscribeModelsListUpdated()

Subscribe to model list updates.

```typescript theme={null}
function subscribeModelsListUpdated(
  listener: ModelsListUpdatedListener
): () => void
```

### Example

```typescript theme={null}
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

```typescript theme={null}
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

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

### DownloadResult

```typescript theme={null}
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

```typescript theme={null}
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).

```typescript theme={null}
function extractTarBz2(
  sourcePath: string,
  targetPath: string,
  force?: boolean,
  onProgress?: (event: ExtractProgressEvent) => void
): Promise<void>
```

<ParamField path="sourcePath" type="string" required>
  Absolute path to the `.tar.bz2` file
</ParamField>

<ParamField path="targetPath" type="string" required>
  Absolute path to extract to
</ParamField>

<ParamField path="force" type="boolean">
  If `true`, overwrite existing files. Default: `false`
</ParamField>

<ParamField path="onProgress" type="(event: ExtractProgressEvent) => void">
  Progress callback with `bytesExtracted` and `totalBytes`
</ParamField>

<Note>
  If libarchive is disabled in your build (see [Disable Libarchive](/configuration/disable-libarchive)), this function will reject with an error.
</Note>

**Example:**

```typescript theme={null}
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.

```typescript theme={null}
function cancelExtractTarBz2(): void
```

### computeFileSha256()

Compute SHA256 checksum of a file.

```typescript theme={null}
function computeFileSha256(
  filePath: string
): Promise<string>
```

<ParamField path="filePath" type="string" required>
  Absolute path to the file
</ParamField>

Returns a promise resolving to the lowercase hex SHA256 hash.

**Example:**

```typescript theme={null}
import { computeFileSha256 } from 'react-native-sherpa-onnx/download';

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

## See Also

* [STT API](/api/stt/create-stt) - Using downloaded models with STT
* [TTS API](/api/tts/create-tts) - Using downloaded models with TTS
* [Model Path Utilities](/api/model-path) - Working with model paths
