ai_edge_model_dl 0.1.0
ai_edge_model_dl: ^0.1.0 copied to clipboard
Efficient model downloader for AI Edge with resumable downloads, progress tracking, and validation.
AI Edge Model DL (Downloader) #
A Flutter plugin for downloading and managing AI models efficiently, with seamless integration for AI Edge packages. Simplifies model path management and provides resumable downloads, progress tracking, and automatic validation.
Features #
- 🤝 AI Edge Integration - Seamless path resolution for AI Edge packages - just pass the model path directly
- 📥 Resumable Downloads - Automatically resume interrupted downloads from where they left off
- 📊 Progress Tracking - Real-time download progress with speed and time estimates
- ✅ Checksum Validation - Automatic MD5/SHA256 validation to ensure model integrity
- 🔄 Parallel Downloads - Concurrent chunk downloading for faster speeds
- 💾 Smart Storage - Platform-specific directory management with customizable paths
- 🎯 File Management - List, check, and delete downloaded models
- ⚡ Optimized Performance - Configurable chunk size and connection settings
Installation #
flutter pub add ai_edge_model_dl
Or add it manually to your pubspec.yaml:
dependencies:
ai_edge_model_dl:
Getting Started #
Basic Usage #
import 'package:ai_edge_model_dl/ai_edge_model_dl.dart';
// Create a downloader instance
final downloader = ModelDownloader();
// Download a model
final result = await downloader.downloadModel(
Uri.parse('https://example.com/model.task'),
fileName: 'gemma.task',
expectedChecksum: 'abc123...', // Optional MD5 or SHA256
expectedFileSize: 1024000, // Optional size validation
onProgress: (progress) {
print('Progress: ${(progress.progress * 100).toStringAsFixed(1)}%');
print('Speed: ${progress.speed}');
print('Remaining: ${progress.remainingTime}');
},
);
print('Model downloaded to: ${result.filePath}');
print('Size: ${result.fileSize} bytes');
print('Checksum: ${result.checksum}');
Integration with AI Edge #
import 'package:ai_edge/ai_edge.dart';
import 'package:ai_edge_model_dl/ai_edge_model_dl.dart';
// Download and use model with AI Edge
final downloader = ModelDownloader();
// Download model
final result = await downloader.downloadModel(
Uri.parse('https://example.com/gemma.task'),
fileName: 'gemma.task',
);
// Use directly with AI Edge - path resolution is handled automatically
final aiEdge = AiEdge.instance;
await aiEdge.initialize(
modelPath: result.filePath, // Direct path usage - no manual path management needed
maxTokens: 512,
);
// Or check if model exists before initializing
final modelPath = await downloader.getModelPath('gemma.task');
if (await downloader.isModelDownloaded('gemma.task')) {
await aiEdge.initialize(
modelPath: modelPath,
maxTokens: 512,
);
}
Configuration #
// Create a downloader with custom configuration
final downloader = ModelDownloader(
config: const ModelDownloaderConfig(
// Custom base directory (default: platform-specific)
baseDirectory: '/custom/path',
// Subdirectory for models (default: 'models')
modelSubdirectory: 'ai_models',
// Download settings
chunkSize: 5 * 1024 * 1024, // 5MB chunks
maxConcurrentRequests: 4, // Parallel connections
maxRetries: 3, // Retry attempts
connectionTimeout: Duration(seconds: 30),
// Validation
checksumType: ChecksumType.sha256,
validationFailureAction: ValidationFailureAction.deleteAndError,
// Progress updates
progressInterval: Duration(milliseconds: 500),
// File conflict strategy
conflictStrategy: FileConflictStrategy.overwrite,
// Custom headers (e.g., for authentication)
headers: {'Authorization': 'Bearer token'},
),
);
Usage #
Download with Progress Tracking #
await downloader.downloadModel(
Uri.parse('https://huggingface.co/model.task'),
fileName: 'model.task',
onProgress: (progress) {
// Progress information
print('Downloaded: ${progress.downloadedSize} / ${progress.totalSize}');
print('Progress: ${(progress.progress * 100).toStringAsFixed(1)}%');
print('Speed: ${progress.speed}');
// Time estimates
print('Remaining time: ${progress.remainingTime}');
// Custom time formatting
final formatted = progress.formatRemainingTime('H hours M minutes');
print('Time left: $formatted');
},
);
Checksum Validation #
// MD5 validation (32 characters)
final result = await downloader.downloadModel(
modelUri,
expectedChecksum: 'd41d8cd98f00b204e9800998ecf8427e',
);
// SHA256 validation (64 characters)
final result = await downloader.downloadModel(
modelUri,
expectedChecksum: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
);
// File size validation
final result = await downloader.downloadModel(
modelUri,
expectedFileSize: 1024000, // Expected size in bytes
);
Cancel Downloads #
// Start a download
final downloadFuture = downloader.downloadModel(
modelUri,
onProgress: (progress) {
print('Progress: ${progress.progress}');
},
);
// Cancel if needed (uses CancelToken internally)
downloader.cancelDownload();
// Handle cancellation
try {
await downloadFuture;
} catch (e) {
print('Download cancelled or failed: $e');
}
Model Management #
// Get models directory path
final modelsDir = await downloader.getModelsDirectory();
print('Models stored in: $modelsDir');
// Get path for a specific model
final modelPath = await downloader.getModelPath('gemma.task');
print('Model path: $modelPath');
// Check if a model exists
final exists = await downloader.isModelDownloaded('gemma.task');
print('Model exists: $exists');
// List all downloaded models
final models = await downloader.getDownloadedModels();
for (final model in models) {
print('Found model: $model');
}
// Delete a model
await downloader.deleteModel('old_model.task');
Error Handling #
try {
final result = await downloader.downloadModel(
modelUri,
expectedChecksum: 'abc123...',
expectedFileSize: 1024000,
);
} on ModelDownloaderException catch (e) {
switch (e.code) {
case ModelDownloaderErrorCode.checksumMismatch:
print('Checksum validation failed: ${e.message}');
case ModelDownloaderErrorCode.fileSizeMismatch:
print('File size validation failed: ${e.message}');
case ModelDownloaderErrorCode.invalidChecksumFormat:
print('Invalid checksum format: ${e.message}');
}
} catch (e) {
// Handle other exceptions (network errors, etc.)
print('Download failed: $e');
}
Resume Interrupted Downloads #
Downloads are automatically resumed if interrupted. The downloader:
- Detects partial downloads (
.tmpfiles) - Verifies existing chunks
- Continues from the last successful position
- Validates the complete file after resuming
// If this download is interrupted...
await downloader.downloadModel(
modelUri,
fileName: 'large_model.task',
);
// ...calling it again will resume from where it stopped
await downloader.downloadModel(
modelUri,
fileName: 'large_model.task',
);
Platform Setup #
iOS #
No additional setup required. Models are stored in the app's Application Support directory.
Android #
No additional setup required. Models are stored in the app's external storage directory (if available) or Application Support directory.
Storage Locations #
By default, models are stored in:
- iOS:
<app_support>/models/(Application Support directory - not backed up to iCloud) - Android:
<external_storage>/models/or<app_support>/models/(External storage preferred for better space availability)
You can customize the storage location:
final downloader = ModelDownloader(
config: const ModelDownloaderConfig(
baseDirectory: '/custom/path',
modelSubdirectory: 'ai_models',
),
);
API Reference #
Main Classes #
ModelDownloader
The main class for downloading and managing models.
ModelDownloaderConfig
Configuration options:
baseDirectory: Custom base directory path (nullable)modelSubdirectory: Subdirectory name for models (default: 'models')headers: HTTP headers for requestschecksumType: Type of checksum validation (ChecksumType.md5,ChecksumType.sha256,ChecksumType.none)conflictStrategy: How to handle existing files (FileConflictStrategy.overwrite,FileConflictStrategy.rename,FileConflictStrategy.error)progressInterval: How often to emit progress updatesconnectionTimeout: HTTP connection timeoutmaxConcurrentRequests: Number of parallel connectionschunkSize: Size of each download chunk in bytesmaxRetries: Number of retry attemptstempFileExtension: Extension for temporary files during download (default: '.tmp')validationFailureAction: Action on validation failure (ValidationFailureAction.deleteAndError,ValidationFailureAction.keepAndError)
ModelDownloadProgress
Download progress information:
progress: Download percentage (0.0 to 1.0)downloadedBytes: Bytes downloaded so fartotalBytes: Total file sizebytesPerSecond: Current download speedestimatedTimeRemaining: Estimated time to completiondownloadedSize: Human-readable downloaded size (e.g., "1.5 MB")totalSize: Human-readable total sizespeed: Human-readable speed (e.g., "2.5 MB/s")remainingTime: Formatted remaining timeformatRemainingTime(pattern): Custom time formatting
ValidationFailureAction
Actions when validation fails:
deleteAndError: Delete the file and throw error (default)keepAndError: Keep the file and throw error
ModelDownloaderException
Exception class for model downloader errors:
code: Error code (ModelDownloaderErrorCode)message: Human-readable error messagedetails: Optional details map with error-specific information
ModelDownloaderErrorCode
Error codes for exception handling:
checksumMismatch: Checksum validation failedfileSizeMismatch: File size validation failedinvalidChecksumFormat: Invalid checksum format (wrong length)
Example App #
Check out the complete example in the repository for demonstrations of:
- Model downloading with progress UI
- Resume capability after app restart
- Download cancellation
- Error handling
- Model management (list, delete)
Troubleshooting #
Common Issues #
Download fails immediately:
- Check network connectivity
- Verify the URL is accessible
- Ensure proper headers are set if authentication is required
Checksum validation fails:
- Verify the expected checksum is correct
- Ensure the checksum type matches (MD5 vs SHA256)
- Check if the file is corrupted during download
Out of storage space:
- Check available device storage
- Clean up old models using
deleteModel() - Consider downloading to external storage on Android
Slow download speeds:
- Increase
chunkSizefor better throughput - Adjust
maxConcurrentRequestsbased on server capabilities - Check network connection quality
License #
This project is licensed under the BSD 3-Clause License - see the LICENSE file for details.