downloadModel function
Future<String>
downloadModel({
- required WhisperModel model,
- required String destinationPath,
- String? downloadHost,
- dynamic onDownloadProgress()?,
Download model to destinationPath
Throws ModelException if download fails.
Implementation
Future<String> downloadModel({
required WhisperModel model,
required String destinationPath,
String? downloadHost,
Function(int received, int total)? onDownloadProgress,
}) async {
if (kDebugMode) {
debugPrint('Download model ${model.modelName}');
}
final httpClient = HttpClient();
RandomAccessFile? raf;
File? tempFile;
try {
Uri modelUri;
if (downloadHost == null || downloadHost.isEmpty) {
/// Huggingface url to download model
modelUri = Uri.parse(
'https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-${model.modelName}.bin',
);
} else {
modelUri = Uri.parse(
'$downloadHost/ggml-${model.modelName}.bin',
);
}
await Directory(destinationPath).create(recursive: true);
final request = await httpClient.getUrl(modelUri);
final response = await request.close();
// Check for HTTP errors
if (response.statusCode != 200) {
throw ModelException.downloadFailed(
model.modelName,
'HTTP ${response.statusCode} ($modelUri)',
);
}
final contentLength = response.contentLength;
if (kDebugMode) {
debugPrint('Content length: $contentLength bytes');
}
final targetPath = '$destinationPath/ggml-${model.modelName}.bin';
final tempPath = '$targetPath.part';
tempFile = File(tempPath);
raf = tempFile.openSync(mode: FileMode.write);
int receivedBytes = 0;
await for (var chunk in response) {
raf.writeFromSync(chunk);
receivedBytes += chunk.length;
// Call progress callback if provided
if (onDownloadProgress != null && contentLength > 0) {
onDownloadProgress(receivedBytes, contentLength);
}
}
await raf.close();
raf = null;
// Validate downloaded file
if (!tempFile.existsSync() || tempFile.lengthSync() == 0) {
throw ModelException.downloadFailed(
model.modelName,
'Downloaded file is empty or missing ($modelUri -> $targetPath)',
);
}
// Atomic-ish replace: rename temp into final.
final targetFile = File(targetPath);
if (targetFile.existsSync()) {
try {
targetFile.deleteSync();
} catch (_) {}
}
tempFile.renameSync(targetPath);
tempFile = null;
if (kDebugMode) {
debugPrint('Download Done . Path = $targetPath');
}
return targetPath;
} on ModelException {
rethrow;
} on SocketException catch (e) {
throw ModelException.downloadFailed(
model.modelName,
'Network error: ${e.message}',
);
} on HttpException catch (e) {
throw ModelException.downloadFailed(
model.modelName,
'HTTP error: ${e.message}',
);
} catch (e) {
throw ModelException.downloadFailed(
model.modelName,
'$e',
);
} finally {
try {
await raf?.close();
} catch (_) {}
try {
httpClient.close(force: true);
} catch (_) {}
if (tempFile != null && tempFile.existsSync()) {
try {
tempFile.deleteSync();
} catch (_) {}
}
}
}