diff --git a/README.md b/README.md index 706b86e..c01e93c 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,11 @@ npm install -S react-native-vosk Vosk uses prebuilt models to perform speech recognition offline. You have to download the model(s) that you need on [Vosk official website](https://alphacephei.com/vosk/models) Avoid using too heavy models, because the computation time required to load them into your app could lead to bad user experience. -Then, unzip the model in your app folder. If you just need to use the iOS version, put the model folder wherever you want, and import it as described below. If you need both iOS and Android to work, you can avoid to copy the model twice for both projects by importing the model from the Android assets folder in XCode. Just do as follow: +Then, unzip the model in your app folder. If you just need to use the iOS version, put the model folder wherever you want, and import it as described below. If you need both iOS and Android to work, you can avoid to copy the model twice for both projects by importing the model from the Android assets folder in XCode. + +**Experimental**: Loading a model dynamically into the app storage, aside from the main bundle is a new and experimental feature. Would love for you all to test, and let us know if it is a viable option. If you choose to download a model to your app’s storage (preferably internal), you can pass the model directory path when calling `vosk.loadModel(path)`. + +To download and load a model as part of an app's Main Bundle, just do as follows: ### Android @@ -82,6 +86,50 @@ Note that `start()` method will ask for audio record permission. [See complete example...](https://github.com/riderodd/react-native-vosk/blob/main/example/src/App.tsx) +## Experimental Loading via Path + +* Primarily intended for models that are not included in the app’s Main Bundle. + +### Preliminary Steps +* Use a file system package to download and store a model from remote location + * [react-native-file-access](https://www.npmjs.com/package/react-native-file-access) is one that we found to be stable, but this is a personal preference based on use + +```js +import Vosk from 'react-native-vosk'; + +// ... + +const vosk = new Vosk(); + +const path = "some/path/to/model/directory"; + +vosk + .loadModel(path) + .then(() => { + const options = { + grammar: ['left', 'right', '[unk]'], + }; + + vosk + .start(options) + .then(() => { + console.log('Recognizer successfuly started'); + }) + .catch((e) => { + console.log('Error: ' + e); + }); + + const resultEvent = vosk.onResult((res) => { + console.log('A onResult event has been caught: ' + res); + }); + + // Don't forget to call resultEvent.remove(); to delete the listener + }) + .catch((e) => { + console.error(e); + }); +``` + ### Methods | Method | Argument | Return | Description | diff --git a/android/src/main/java/com/vosk/VoskModule.kt b/android/src/main/java/com/vosk/VoskModule.kt index 6e2c644..1ebb979 100644 --- a/android/src/main/java/com/vosk/VoskModule.kt +++ b/android/src/main/java/com/vosk/VoskModule.kt @@ -107,14 +107,22 @@ class VoskModule(reactContext: ReactApplicationContext) : @ReactMethod fun loadModel(path: String, promise: Promise) { cleanModel() - StorageService.unpack(context, path, "models", - { model: Model? -> - this.model = model - promise.resolve("Model successfully loaded") + try { + this.model = Model(path) + promise.resolve("Model successfully loaded") + } catch (e: IOException) { + println("Model directory does not exist at path: " + path) + + // Load model from main app bundle + StorageService.unpack(context, path, "models", + { model: Model? -> + this.model = model + promise.resolve("Model successfully loaded") + } + ) { e: IOException -> + this.model = null + promise.reject(e) } - ) { e: IOException -> - this.model = null - promise.reject(e) } } diff --git a/ios/VoskModel.swift b/ios/VoskModel.swift index 19bfd23..6c2b832 100644 --- a/ios/VoskModel.swift +++ b/ios/VoskModel.swift @@ -20,10 +20,16 @@ public final class VoskModel { let appBundle = Bundle(for: Self.self) - // Load model from main app bundle - if let resourcePath = Bundle.main.resourcePath { - let modelPath = resourcePath + "/" + name - model = vosk_model_new(modelPath) + if let loadedModel = vosk_model_new(name) { + print("Model successfully loaded from path.") + model = loadedModel + } else { + print("Model directory does not exist at path: \(name)") + // Load model from main app bundle + if let resourcePath = Bundle.main.resourcePath { + let modelPath = resourcePath + "/" + name + model = vosk_model_new(modelPath) + } } // Get the URL to the spk model inside this pod