/* * Copyright (c) 田梓萱[小草林] 2021-2024. * All Rights Reserved. * All codes are protected by China's regulations on the protection of computer software, and infringement must be investigated. * 版权所有 (c) 田梓萱[小草林] 2021-2024. * 所有代码均受中国《计算机软件保护条例》保护,侵权必究. */ import "dart:convert"; import "dart:ffi"; import "dart:io"; import "dart:isolate"; import "package:ffi/ffi.dart"; import "package:flutter/foundation.dart"; import "package:path_provider/path_provider.dart"; import "package:whisper_flutter_new/bean/_models.dart"; import "package:whisper_flutter_new/bean/whisper_dto.dart"; import "package:whisper_flutter_new/download_model.dart"; import "package:whisper_flutter_new/whisper_bindings_generated.dart"; export "package:whisper_flutter_new/bean/_models.dart"; export "package:whisper_flutter_new/download_model.dart" show WhisperModel; /// Entry point of whisper_flutter_plus class Whisper { /// [model] is required /// [modelDir] is path where downloaded model will be stored. /// Default to library directory const Whisper({required this.model, this.modelDir, this.downloadHost}); /// model used for transcription final WhisperModel model; /// override of model storage path final String? modelDir; // override of model download host final String? downloadHost; DynamicLibrary _openLib() { if (Platform.isAndroid) { return DynamicLibrary.open("libwhisper.so"); } else { return DynamicLibrary.process(); } } Future _getModelDir() async { if (modelDir != null) { return modelDir!; } final Directory libraryDirectory = Platform.isAndroid ? await getApplicationSupportDirectory() : await getLibraryDirectory(); return libraryDirectory.path; } Future _initModel() async { final String modelDir = await _getModelDir(); final File modelFile = File(model.getPath(modelDir)); final bool isModelExist = modelFile.existsSync(); if (isModelExist) { if (kDebugMode) { debugPrint("Use existing model ${model.modelName}"); } return; } else { await downloadModel( model: model, destinationPath: modelDir, downloadHost: downloadHost); } } Future> _request({ required WhisperRequestDto whisperRequest, }) async { if (model != WhisperModel.none) { await _initModel(); } return Isolate.run( () async { final Pointer data = whisperRequest.toRequestString().toNativeUtf8(); final Pointer res = WhisperFlutterBindings(_openLib()).request(data.cast()); final Map result = json.decode( res.cast().toDartString(), ) as Map; try { malloc.free(data); malloc.free(res); } catch (_) {} if (kDebugMode) { debugPrint("Result = $result"); } return result; }, ); } /// Transcribe audio file to text Future transcribe({ required TranscribeRequest transcribeRequest, }) async { final String modelDir = await _getModelDir(); final Map result = await _request( whisperRequest: TranscribeRequestDto.fromTranscribeRequest( transcribeRequest, model.getPath(modelDir), ), ); if (kDebugMode) { debugPrint("Transcribe request $result"); } if (result["text"] == null) { if (kDebugMode) { debugPrint('Transcribe Exception ${result['message']}'); } throw Exception(result["message"]); } return WhisperTranscribeResponse.fromJson(result); } /// Get whisper version Future getVersion() async { final Map result = await _request( whisperRequest: const VersionRequest(), ); final WhisperVersionResponse response = WhisperVersionResponse.fromJson( result, ); return response.message; } }