Some bug fixes and change in pattern

This commit is contained in:
msqr1
2024-01-17 08:11:36 -08:00
parent 0b49fd7eca
commit 97ba7ee1b8
10 changed files with 52 additions and 91 deletions

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@ kaldi
libarchive libarchive
vosk-api vosk-api
zstd zstd
test.cc

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
# Browser-recognizer # Browser-recognizer
- A from-microphone speech recognizer built on Vosk that can be run on the browser, inspired by [vosk-browser](https://github.com/ccoreilly/vosk-browser), but built from scratch and no code taken! - A from-microphone speech recognizer built on Vosk that can be run on the browser, inspired by [vosk-browser](https://github.com/ccoreilly/vosk-browser), but built from scratch and no code taken!
- Browser-recognizer can run on the main browser thread or worker. - Browser-recognizer can run both in the browser main thread and web workers.
## Interface ## Interface
- setLogLevel: set Kaldi's log level (default: -1) - setLogLevel: set Kaldi's log level (default: -1)
- -2: Error - -2: Error
@@ -11,11 +11,15 @@
- 3: Debug - 3: Debug
### Model and SpkModel ### Model and SpkModel
``` ```
new Model(url, storepath, id) model = new Model()
new SpkModel(url, storepath, id) spkModel = new SpkModel()
// Add events listeners
model.init(url, storepath, id)
spkModel.init(url, storepath, id)
``` ```
#### Functions #### Functions
- ***constructor*** : Construct a model from an URL, storage path, and an ID. - ***constructor***: Construct the EventTarget part to enable addEventListener
- ***init*** : Initialize the internal object with an URL, storage path, and an ID.
- If **storepath** contains valid model files and **id** is the same, there will not be a fetch from **url**. - If **storepath** contains valid model files and **id** is the same, there will not be a fetch from **url**.
- If **storepath** doesn't contain valid model files, or if it contains valid model files but **id** is different, there will be a fetch from **url**, and the model is stored with **id**. - If **storepath** doesn't contain valid model files, or if it contains valid model files but **id** is different, there will be a fetch from **url**, and the model is stored with **id**.
- ***delete***: Delete self and free resources - ***delete***: Delete self and free resources
@@ -24,10 +28,13 @@ new SpkModel(url, storepath, id)
- ***error***: An error occured, check the event's **details** property. - ***error***: An error occured, check the event's **details** property.
### Recognizer ### Recognizer
``` ```
new Recognizer(model) recognizer = new Recognizer()
// Add event listeners
recognizer.init(model)
``` ```
#### Functions #### Functions
- ***constructor***: Construct a recognizer from a model object. - ***constructor***: Construct the EventTarget part to enable addEventListener
- ***init***: Construct the real internal object from a model
- ***start***: Start recognizing - ***start***: Start recognizing
- ***stop***: Stop recognizing - ***stop***: Stop recognizing
- ***setWords***: Return words' information in a result event (default: false) - ***setWords***: Return words' information in a result event (default: false)
@@ -49,8 +56,7 @@ new Recognizer(model)
__genericObj__.objects.forEach(obj => obj.delete()) __genericObj__.objects.forEach(obj => obj.delete())
``` ```
at the end of your program to automatically do that. We have to do this because Emscripten doesn't call destructors. See [here](https://emscripten.org/docs/getting_started/FAQ.html#what-does-exiting-the-runtime-mean-why-don-t-atexit-s-run). at the end of your program to automatically do that. We have to do this because Emscripten doesn't call destructors. See [here](https://emscripten.org/docs/getting_started/FAQ.html#what-does-exiting-the-runtime-mean-why-don-t-atexit-s-run).
- After calling the constructor, event listener s can be added right away while things are still loading. Calling an interface function at this time though, will block until loading is finished. - To be safe, always handle the API through events by adding all event listener before calling init().
- To be safe, always handle the API through emitted events.
### Guarantees ### Guarantees
- If an error occurs (error event is fired), no changes was made, and no other dependent events will fire. For example, if an error occur while loading the model, the "ready" event won't fire in order to prevent executing code on a nonexistent model. - If an error occurs (error event is fired), no changes was made, and no other dependent events will fire. For example, if an error occur while loading the model, the "ready" event won't fire in order to prevent executing code on a nonexistent model.
### Limitations compared to vosk-browser: ### Limitations compared to vosk-browser:
@@ -69,5 +75,9 @@ new Recognizer(model)
## Usage ## Usage
``` ```
<!--Load this from a script tag--> <!--Load this from a script tag-->
<script src="BrowserRecognizer.js"></script>
<!-->
<script>
</script>
``` ```

View File

@@ -4,13 +4,13 @@
using namespace emscripten; using namespace emscripten;
EMSCRIPTEN_BINDINGS() { EMSCRIPTEN_BINDINGS() {
function("setLogLevel", &vosk_set_log_level, allow_raw_pointers()); function("setLogLevel", &vosk_set_log_level, allow_raw_pointers());
class_<model, base<genericModel>>("__model__") class_<model>("__model__")
.constructor<std::string, std::string, std::string, int>(allow_raw_pointers()); .constructor<std::string, std::string, std::string, int>(allow_raw_pointers());
class_<spkModel, base<genericModel>>("__spkModel__") class_<spkModel>("__spkModel__")
.constructor<std::string, std::string, std::string, const int>(allow_raw_pointers()); .constructor<std::string, std::string, std::string, const int>(allow_raw_pointers());
class_<recognizer, base<genericObj>>("__recognizer__") class_<recognizer>("__recognizer__")
.constructor<model*, int, int>(allow_raw_pointers()) .constructor<model*, int, int>(allow_raw_pointers())
.function("start", &recognizer::start, allow_raw_pointers()) .function("start", &recognizer::start, allow_raw_pointers())
.function("stop", &recognizer::stop, allow_raw_pointers()) .function("stop", &recognizer::stop, allow_raw_pointers())

View File

@@ -34,12 +34,15 @@ bool genericModel::loadModel() {
fireEv("error", "Unable to fetch model"); fireEv("error", "Unable to fetch model");
return false; return false;
} }
if(!extractModel(".")) { if(!extractModel()) {
fireEv("error", "Unable to extract model"); fireEv("error", "Unable to extract model");
return false;
} }
fs::remove("opfs/model.tzst"); fs::remove("opfs/model.tzst");
if(!checkModel()) { if(!checkModel()) {
fireEv("error", "Model URL contains invalid model files"); fireEv("error", "Model URL contains invalid model files");
fs::remove_all(".");
return false;
} }
std::ofstream idFile("id"); std::ofstream idFile("id");
if(!idFile.is_open()) { if(!idFile.is_open()) {

View File

@@ -4,6 +4,7 @@
#include <string> #include <string>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <thread>
#include <vosk_api.h> #include <vosk_api.h>
#include <archive.h> #include <archive.h>

View File

@@ -1,9 +1,9 @@
class Model extends EventTarget{ class Model extends EventTarget{
constructor(url, storepath, id) { constructor() {
super() super()
this.obj = (async () => { }
return new Module.__model__(url, storepath, id, __genericObj__.objects.length) init(url, storepath, id) {
})() this.obj = new Module.__model__(url, storepath, id, __genericObj__.objects.length);
__genericObj__.objects.push(this) __genericObj__.objects.push(this)
} }
delete() { delete() {

View File

@@ -1,57 +1,39 @@
class Recognizer extends EventTarget { class Recognizer extends EventTarget {
constructor(model) { constructor() {
super()
}
init(model) {
ctx = new (AudioContext || webkitAudioContext)() ctx = new (AudioContext || webkitAudioContext)()
this.obj = (async () => {
new Module.__recognizer__(model.obj,ctx.sampleRate,__genericObj__.objects.length) new Module.__recognizer__(model.obj,ctx.sampleRate,__genericObj__.objects.length)
})()
__genericObj__.objects.push(this)
ctx.close() ctx.close()
return this; __genericObj__.objects.push(this)
} }
start() { start() {
this.obj.then(() => {
this.obj.start() this.obj.start()
})
} }
stop() { stop() {
this.obj.then(() => {
this.obj.stop() this.obj.stop()
})
} }
delete() { delete() {
this.obj.then(() => {
this.obj.deinit() this.obj.deinit()
this.obj.delete() this.obj.delete()
})
} }
setWords(words) { setWords(words) {
this.obj.then(() => {
this.obj.setWords(words) this.obj.setWords(words)
})
} }
setPartialWords(partialWords) { setPartialWords(partialWords) {
this.obj.then(() => {
this.obj.setPartialWords(partialWords) this.obj.setPartialWords(partialWords)
})
} }
setGrm(grm) { setGrm(grm) {
this.obj.then(() => {
this.obj.setGrm(grm) this.obj.setGrm(grm)
})
} }
setSpkModel(model) { setSpkModel(model) {
this.obj.then(() => {
this.obj.setSpkModel(model.obj) this.obj.setSpkModel(model.obj)
})
} }
setNLSML(nlsml) { setNLSML(nlsml) {
this.obj.then(() => {
this.obj.setNLSML(nlsml) this.obj.setNLSML(nlsml)
})
} }
setMaxAlternatives(alts) { setMaxAlternatives(alts) {
this.obj.then(() => {
this.obj.setMaxAlternatives(alts) this.obj.setMaxAlternatives(alts)
})
} }
} }

View File

@@ -1,14 +1,12 @@
class SpkModel extends EventTarget{ class SpkModel extends EventTarget{
constructor(url, storepath, id) { constructor() {
super() super()
this.obj = (async () => { }
return new Module.__spkModel__(url, storepath, id, __genericObj__.objects.length) init(url, storepath, id) {
})() this.obj = new Module.__spkModel__(url, storepath, id, __genericObj__.objects.length)
__genericObj__.objects.push(this) __genericObj__.objects.push(this)
} }
delete() { delete() {
this.obj.then(() => {
this.obj.delete() this.obj.delete()
})
} }
} }

19
test.cc
View File

@@ -1,19 +0,0 @@
#include <emscripten.h>
#include <emscripten/console.h>
#include <emscripten/bind.h>
using namespace emscripten;
struct A {
void doit() {
char bro[] {"Bro"};
MAIN_THREAD_EM_ASM({
console.log(UTF8ToString($0));
},bro);
}
~A() {
emscripten_console_log("Destructor called");
}
};
EMSCRIPTEN_BINDINGS() {
class_<A>("A")
.smart_ptr_constructor<
}