Draft 2 (failed)
This commit is contained in:
19
.gitignore
vendored
19
.gitignore
vendored
@@ -1,10 +1,11 @@
|
|||||||
.vscode
|
|
||||||
test.sh
|
|
||||||
index.html
|
|
||||||
model.tzst
|
|
||||||
clapack-wasm
|
|
||||||
kaldi
|
|
||||||
libarchive
|
|
||||||
vosk-api
|
|
||||||
zstd
|
zstd
|
||||||
test.cc
|
vosk-api
|
||||||
|
kaldi
|
||||||
|
test
|
||||||
|
test.sh
|
||||||
|
libarchive
|
||||||
|
.vscode
|
||||||
|
clapack-wasm
|
||||||
|
node_modules
|
||||||
|
package.json
|
||||||
|
package-lock.json
|
||||||
File diff suppressed because one or more lines are too long
@@ -12,34 +12,6 @@
|
|||||||
|
|
||||||
var Module = {};
|
var Module = {};
|
||||||
|
|
||||||
// Node.js support
|
|
||||||
var ENVIRONMENT_IS_NODE = typeof process == 'object' && typeof process.versions == 'object' && typeof process.versions.node == 'string';
|
|
||||||
if (ENVIRONMENT_IS_NODE) {
|
|
||||||
// Create as web-worker-like an environment as we can.
|
|
||||||
|
|
||||||
var nodeWorkerThreads = require('worker_threads');
|
|
||||||
|
|
||||||
var parentPort = nodeWorkerThreads.parentPort;
|
|
||||||
|
|
||||||
parentPort.on('message', (data) => onmessage({ data: data }));
|
|
||||||
|
|
||||||
var fs = require('fs');
|
|
||||||
var vm = require('vm');
|
|
||||||
|
|
||||||
Object.assign(global, {
|
|
||||||
self: global,
|
|
||||||
require,
|
|
||||||
Module,
|
|
||||||
location: {
|
|
||||||
href: __filename
|
|
||||||
},
|
|
||||||
Worker: nodeWorkerThreads.Worker,
|
|
||||||
importScripts: (f) => vm.runInThisContext(fs.readFileSync(f, 'utf8'), {filename: f}),
|
|
||||||
postMessage: (msg) => parentPort.postMessage(msg),
|
|
||||||
performance: global.performance || { now: Date.now },
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Thread-local guard variable for one-time init of the JS state
|
// Thread-local guard variable for one-time init of the JS state
|
||||||
var initializedJS = false;
|
var initializedJS = false;
|
||||||
|
|
||||||
@@ -49,11 +21,6 @@ function assert(condition, text) {
|
|||||||
|
|
||||||
function threadPrintErr() {
|
function threadPrintErr() {
|
||||||
var text = Array.prototype.slice.call(arguments).join(' ');
|
var text = Array.prototype.slice.call(arguments).join(' ');
|
||||||
// See https://github.com/emscripten-core/emscripten/issues/14804
|
|
||||||
if (ENVIRONMENT_IS_NODE) {
|
|
||||||
fs.writeSync(2, text + '\n');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
console.error(text);
|
console.error(text);
|
||||||
}
|
}
|
||||||
function threadAlert() {
|
function threadAlert() {
|
||||||
@@ -97,6 +64,7 @@ function handleMessage(e) {
|
|||||||
|
|
||||||
// And add a callback for when the runtime is initialized.
|
// And add a callback for when the runtime is initialized.
|
||||||
self.startWorker = (instance) => {
|
self.startWorker = (instance) => {
|
||||||
|
Module = instance;
|
||||||
// Notify the main thread that this thread has loaded.
|
// Notify the main thread that this thread has loaded.
|
||||||
postMessage({ 'cmd': 'loaded' });
|
postMessage({ 'cmd': 'loaded' });
|
||||||
// Process any messages that were queued before the thread was ready.
|
// Process any messages that were queued before the thread was ready.
|
||||||
@@ -133,6 +101,7 @@ function handleMessage(e) {
|
|||||||
importScripts(objectUrl);
|
importScripts(objectUrl);
|
||||||
URL.revokeObjectURL(objectUrl);
|
URL.revokeObjectURL(objectUrl);
|
||||||
}
|
}
|
||||||
|
loadBR(Module);
|
||||||
} else if (e.data.cmd === 'run') {
|
} else if (e.data.cmd === 'run') {
|
||||||
// Pass the thread address to wasm to store it for fast access.
|
// Pass the thread address to wasm to store it for fast access.
|
||||||
Module['__emscripten_thread_init'](e.data.pthread_ptr, /*is_main=*/0, /*is_runtime=*/0, /*can_block=*/1);
|
Module['__emscripten_thread_init'](e.data.pthread_ptr, /*is_main=*/0, /*is_runtime=*/0, /*can_block=*/1);
|
||||||
|
|||||||
13
README.md
13
README.md
@@ -25,7 +25,7 @@ spkModel.init(url, storepath, id)
|
|||||||
- ***delete***: Delete self and free resources
|
- ***delete***: Delete self and free resources
|
||||||
#### Events
|
#### Events
|
||||||
- ***ready***: The model is ready to be put into a recognizer via the constructor, or setSpkModel() for SpkModel.
|
- ***ready***: The model is ready to be put into a recognizer via the constructor, or setSpkModel() for SpkModel.
|
||||||
- ***error***: An error occured, check the event's **details** property.
|
- ***error***: An error occured, check the event's "details" property.
|
||||||
### Recognizer
|
### Recognizer
|
||||||
```
|
```
|
||||||
recognizer = new Recognizer()
|
recognizer = new Recognizer()
|
||||||
@@ -43,11 +43,11 @@ recognizer.init(model)
|
|||||||
- ***setMaxAlternatives***: Set the max number of alternatives for result event (default: false)
|
- ***setMaxAlternatives***: Set the max number of alternatives for result event (default: false)
|
||||||
- ***setGrm***: Add grammar to the recognizer (default: none)
|
- ***setGrm***: Add grammar to the recognizer (default: none)
|
||||||
- ***setSpkModel***: Set the speaker model of the recognizer (default: none)
|
- ***setSpkModel***: Set the speaker model of the recognizer (default: none)
|
||||||
- ***delete***: Delete self and free resources
|
- ***delete***: Call stop, delete self and free all resource
|
||||||
#### Events
|
#### Events
|
||||||
- ***partialResult***: There is a partial recognition result, check the event's **details** property
|
- ***partialResult***: There is a partial recognition result, check the event's "details" property
|
||||||
- ***result***: There is a full recognition result, check the event's **details** property
|
- ***result***: There is a full recognition result, check the event's "details" property
|
||||||
- ***error***: An error occured, check the event's **details** property.
|
- ***error***: An error occured, check the event's "details" property.
|
||||||
## Other key points
|
## Other key points
|
||||||
### IMPORTANT
|
### IMPORTANT
|
||||||
- You MUST call delete() on objects at the end of its usage. Or put:
|
- You MUST call delete() on objects at the end of its usage. Or put:
|
||||||
@@ -56,7 +56,8 @@ recognizer.init(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).
|
||||||
- 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 events by adding all event listener before calling init() on objects.
|
||||||
|
- Always call init on the regular Model object before calling init on the recognizer. SpkModel can be init and set later.
|
||||||
### 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:
|
||||||
|
|||||||
13
index.html
Normal file
13
index.html
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<script src="BrowserRecognizer.js" defer></script>
|
||||||
|
<script type="module" src="src/genericObj.js" defer></script>
|
||||||
|
<script src="src/model.js" defer></script>
|
||||||
|
<script src="src/spkModel.js" defer></script>
|
||||||
|
<script src="src/recognizer.js" defer></script>
|
||||||
|
</head>
|
||||||
|
<script>
|
||||||
|
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
@@ -8,6 +8,8 @@
|
|||||||
# Total build time is around 45 minutes, mostly from building Kaldi
|
# Total build time is around 45 minutes, mostly from building Kaldi
|
||||||
|
|
||||||
sudo apt install shtool libtool autogen autotools-dev pkg-config make &&
|
sudo apt install shtool libtool autogen autotools-dev pkg-config make &&
|
||||||
|
wget -qO- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bash &&
|
||||||
|
nvm install 20.11.0 &&
|
||||||
|
|
||||||
SRC=$(realpath src) &&
|
SRC=$(realpath src) &&
|
||||||
KALDI=$(realpath kaldi) &&
|
KALDI=$(realpath kaldi) &&
|
||||||
@@ -52,7 +54,7 @@ echo "PACKAGE_VERSION = 1.8.0" >> $OPENFST/Makefile &&
|
|||||||
|
|
||||||
cd $KALDI/src &&
|
cd $KALDI/src &&
|
||||||
git apply $SRC/kaldi.patch &&
|
git apply $SRC/kaldi.patch &&
|
||||||
CXXFLAGS="-O3 -msse3 -mssse3 -msse4.1 -msse4.2 -mavx -msimd128 -UHAVE_EXECINFO_H -pthread -flto" LDFLAGS="-O3 -sERROR_ON_UNDEFINED_SYMBOLS=0 -lembind -pthread -flto" emconfigure ./configure --use-cuda=no --with-cudadecoder=no --static --static-math=yes --static-fst=yes --double-precision=yes --debug-level=0 --clapack-root=$CLAPACK_WASM --host=WASM &&
|
CXXFLAGS="-O3 -msimd128 -UHAVE_EXECINFO_H -pthread -flto" LDFLAGS="-O3 -sERROR_ON_UNDEFINED_SYMBOLS=0 -lembind -pthread -flto" emconfigure ./configure --use-cuda=no --with-cudadecoder=no --static --static-math=yes --static-fst=yes --debug-level=0 --clapack-root=$CLAPACK_WASM --host=WASM &&
|
||||||
emmake make online2 lm rnnlm &&
|
emmake make online2 lm rnnlm &&
|
||||||
|
|
||||||
cd $VOSK/src &&
|
cd $VOSK/src &&
|
||||||
@@ -61,4 +63,4 @@ em++ -pthread -O3 -flto -I. -I$KALDI/src -I$OPENFST/include $VOSK_FILES -c &&
|
|||||||
emar -rcs vosk.a ${VOSK_FILES//.cc/.o} &&
|
emar -rcs vosk.a ${VOSK_FILES//.cc/.o} &&
|
||||||
|
|
||||||
cd $SRC
|
cd $SRC
|
||||||
em++ -O3 genericObj.cc genericModel.cc model.cc spkModel.cc recognizer.cc bindings.cc -sWASMFS -sWASM_BIGINT -sSUPPORT_BIG_ENDIAN -sSINGLE_FILE -sINITIAL_MEMORY=300mb -sASYNCIFY -sPTHREAD_POOL_SIZE=2 -pthread --no-entry -flto --post-js genericObj.js --post-js model.js --post-js spkModel.js --post-js recognizer.js -I. -I$LIBARCHIVE/include -I$VOSK/src -L$LIBARCHIVE/lib -larchive -L$ZSTD/lib -lzstd -L$KALDI/src -l:online2/kaldi-online2.a -l:decoder/kaldi-decoder.a -l:ivector/kaldi-ivector.a -l:gmm/kaldi-gmm.a -l:tree/kaldi-tree.a -l:feat/kaldi-feat.a -l:cudamatrix/kaldi-cudamatrix.a -l:lat/kaldi-lat.a -l:lm/kaldi-lm.a -l:rnnlm/kaldi-rnnlm.a -l:hmm/kaldi-hmm.a -l:nnet3/kaldi-nnet3.a -l:transform/kaldi-transform.a -l:matrix/kaldi-matrix.a -l:fstext/kaldi-fstext.a -l:util/kaldi-util.a -l:base/kaldi-base.a -L$OPENFST/lib -l:libfst.a -l:libfstngram.a -L$CLAPACK_WASM -l:CBLAS/lib/cblas.a -l:CLAPACK-3.2.1/lapack.a -l:CLAPACK-3.2.1/libcblaswr.a -l:f2c_BLAS-3.8.0/blas.a -l:libf2c/libf2c.a -L$VOSK/src -l:vosk.a -lopfs.js -lembind -lopenal -o BrowserRecognizer.js
|
em++ -O3 genericObj.cc genericModel.cc model.cc spkModel.cc recognizer.cc bindings.cc -sWASMFS -sWASM_BIGINT -sSUPPORT_BIG_ENDIAN -sSINGLE_FILE -sMODULARIZE -sASYNCIFY -sEXPORT_NAME=loadBR -sENVIRONMENT=web,worker -sINITIAL_MEMORY=300mb -sPTHREAD_POOL_SIZE=2 -pthread -flto -I. -I$LIBARCHIVE/include -I$VOSK/src -L$LIBARCHIVE/lib -larchive -L$ZSTD/lib -lzstd -L$KALDI/src -l:online2/kaldi-online2.a -l:decoder/kaldi-decoder.a -l:ivector/kaldi-ivector.a -l:gmm/kaldi-gmm.a -l:tree/kaldi-tree.a -l:feat/kaldi-feat.a -l:cudamatrix/kaldi-cudamatrix.a -l:lat/kaldi-lat.a -l:lm/kaldi-lm.a -l:rnnlm/kaldi-rnnlm.a -l:hmm/kaldi-hmm.a -l:nnet3/kaldi-nnet3.a -l:transform/kaldi-transform.a -l:matrix/kaldi-matrix.a -l:fstext/kaldi-fstext.a -l:util/kaldi-util.a -l:base/kaldi-base.a -L$OPENFST/lib -l:libfst.a -l:libfstngram.a -L$CLAPACK_WASM -l:CBLAS/lib/cblas.a -l:CLAPACK-3.2.1/lapack.a -l:CLAPACK-3.2.1/libcblaswr.a -l:f2c_BLAS-3.8.0/blas.a -l:libf2c/libf2c.a -L$VOSK/src -l:vosk.a -lopfs.js -lembind -lopenal -o ../BrowserRecognizer.js
|
||||||
|
|||||||
@@ -2,6 +2,13 @@
|
|||||||
#include "model.h"
|
#include "model.h"
|
||||||
#include "recognizer.h"
|
#include "recognizer.h"
|
||||||
using namespace emscripten;
|
using namespace emscripten;
|
||||||
|
int main() {
|
||||||
|
//vosk_set_log_level(-1);
|
||||||
|
std::thread t{[](){
|
||||||
|
wasmfs_create_directory("/opfs",0777,wasmfs_create_opfs_backend());
|
||||||
|
}};
|
||||||
|
t.detach();
|
||||||
|
}
|
||||||
EMSCRIPTEN_BINDINGS() {
|
EMSCRIPTEN_BINDINGS() {
|
||||||
function("setLogLevel", &vosk_set_log_level, allow_raw_pointers());
|
function("setLogLevel", &vosk_set_log_level, allow_raw_pointers());
|
||||||
class_<model>("__model__")
|
class_<model>("__model__")
|
||||||
@@ -14,7 +21,6 @@ EMSCRIPTEN_BINDINGS() {
|
|||||||
.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())
|
||||||
.function("deinit", &recognizer::deinit, allow_raw_pointers())
|
|
||||||
.function("setWords", &recognizer::setWords, allow_raw_pointers())
|
.function("setWords", &recognizer::setWords, allow_raw_pointers())
|
||||||
.function("setPartialWords", &recognizer::setPartialWords, allow_raw_pointers())
|
.function("setPartialWords", &recognizer::setPartialWords, allow_raw_pointers())
|
||||||
.function("setGrm", &recognizer::setGrm, allow_raw_pointers())
|
.function("setGrm", &recognizer::setGrm, allow_raw_pointers())
|
||||||
|
|||||||
16
src/clapack-wasm.patch
Normal file
16
src/clapack-wasm.patch
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
diff --git a/libf2c/main.c b/libf2c/main.c
|
||||||
|
index d95fdc9..ac82f68 100644
|
||||||
|
--- a/libf2c/main.c
|
||||||
|
+++ b/libf2c/main.c
|
||||||
|
@@ -105,9 +105,9 @@ char **xargv;
|
||||||
|
|
||||||
|
int
|
||||||
|
#ifdef KR_headers
|
||||||
|
-main(argc, argv) int argc; char **argv;
|
||||||
|
+m(argc, argv) int argc; char **argv;
|
||||||
|
#else
|
||||||
|
-main(int argc, char **argv)
|
||||||
|
+m(int argc, char **argv)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
xargc = argc;
|
||||||
@@ -1,21 +1,9 @@
|
|||||||
#include "genericModel.h"
|
#include "genericModel.h"
|
||||||
|
|
||||||
bool genericModel::first = true;
|
|
||||||
genericModel::genericModel(const std::string &url, const std::string& storepath, const std::string &id, int index) : url(url), id(id), genericObj(index) {
|
genericModel::genericModel(const std::string &url, const std::string& storepath, const std::string &id, int index) : url(url), id(id), genericObj(index) {
|
||||||
|
fs::current_path("/opfs");
|
||||||
|
fs::create_directories(storepath);
|
||||||
fs::current_path(storepath);
|
fs::current_path(storepath);
|
||||||
if(first) {
|
|
||||||
vosk_set_log_level(0);
|
|
||||||
int res{};
|
|
||||||
std::thread t{[&res](){
|
|
||||||
res = wasmfs_create_directory("opfs",0777,wasmfs_create_opfs_backend());
|
|
||||||
}};
|
|
||||||
t.join();
|
|
||||||
if(res == 1){
|
|
||||||
fireEv("error", "Unable to create OPFS directory");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
first = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
bool genericModel::checkId(const std::string& id) {
|
bool genericModel::checkId(const std::string& id) {
|
||||||
std::ifstream file {"id", std::ifstream::binary};
|
std::ifstream file {"id", std::ifstream::binary};
|
||||||
@@ -28,42 +16,46 @@ bool genericModel::checkId(const std::string& id) {
|
|||||||
file.read(&oldid[0], size);
|
file.read(&oldid[0], size);
|
||||||
return id.compare(oldid) == 0 ? true : false;
|
return id.compare(oldid) == 0 ? true : false;
|
||||||
}
|
}
|
||||||
bool genericModel::loadModel() {
|
bool genericModel::loadModel(const std::string& storepath) {
|
||||||
if(!checkModel() || !checkId(id)) {
|
if(!checkModel() || !checkId(id)) {
|
||||||
if(emscripten_wget(url.c_str(),"opfs/model.tzst") == 1) {
|
char filename[] {"/opfs/XXXXXX.tzst"};
|
||||||
|
close(mkostemps(filename, 5, O_PATH));
|
||||||
|
if(emscripten_wget(url.c_str(),filename) == 1) {
|
||||||
fireEv("error", "Unable to fetch model");
|
fireEv("error", "Unable to fetch model");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(!extractModel()) {
|
if(!extractModel(filename)) {
|
||||||
fireEv("error", "Unable to extract model");
|
fireEv("error", "Unable to extract model");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
fs::remove("opfs/model.tzst");
|
fs::remove(filename);
|
||||||
if(!checkModel()) {
|
if(!checkModel()) {
|
||||||
fireEv("error", "Model URL contains invalid model files");
|
fireEv("error", "Model URL contains invalid model files");
|
||||||
fs::remove_all(".");
|
fs::current_path("/opfs");
|
||||||
|
fs::remove_all(storepath);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
std::ofstream idFile("id");
|
std::ofstream idFile("id");
|
||||||
if(!idFile.is_open()) {
|
if(!idFile.is_open()) {
|
||||||
fireEv("error", "Unable to write new id");
|
fireEv("error", "Unable to write new id");
|
||||||
fs::remove_all(".");
|
fs::remove_all(storepath);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
idFile << id;
|
idFile << id;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool genericModel::extractModel() {
|
bool genericModel::extractModel(char* name) {
|
||||||
std::string path{};
|
std::string path{};
|
||||||
archive* src {archive_read_new()};
|
archive* src {archive_read_new()};
|
||||||
archive_entry* entry {};
|
archive_entry* entry {};
|
||||||
archive_read_support_filter_all(src);
|
archive_read_support_filter_all(src);
|
||||||
archive_read_support_format_all(src);
|
archive_read_support_format_all(src);
|
||||||
archive_read_open_filename(src, "opfs/model.tzst",10240);
|
archive_read_open_filename(src, name,10240);
|
||||||
if(archive_errno(src) != 0) return false;
|
if(archive_errno(src) != 0) return false;
|
||||||
while (archive_read_next_header(src, &entry) == ARCHIVE_OK) {
|
while (archive_read_next_header(src, &entry) == ARCHIVE_OK) {
|
||||||
path = archive_entry_pathname(entry);
|
path = archive_entry_pathname(entry);
|
||||||
|
// Strip first component
|
||||||
archive_entry_set_pathname(entry, path.substr(path.find("/")).c_str());
|
archive_entry_set_pathname(entry, path.substr(path.find("/")).c_str());
|
||||||
if(archive_errno(src) != 0) return false;
|
if(archive_errno(src) != 0) return false;
|
||||||
archive_read_extract(src, entry, ARCHIVE_EXTRACT_UNLINK);
|
archive_read_extract(src, entry, ARCHIVE_EXTRACT_UNLINK);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
#include <vosk_api.h>
|
#include <vosk_api.h>
|
||||||
#include <archive.h>
|
#include <archive.h>
|
||||||
#include <archive_entry.h>
|
#include <archive_entry.h>
|
||||||
@@ -15,12 +16,11 @@
|
|||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
struct genericModel : genericObj {
|
struct genericModel : genericObj {
|
||||||
static bool first;
|
|
||||||
const std::string url{};
|
const std::string url{};
|
||||||
const std::string id{};
|
const std::string id{};
|
||||||
static bool extractModel();
|
static bool extractModel(char *name);
|
||||||
static bool checkId(const std::string& id);
|
static bool checkId(const std::string& id);
|
||||||
virtual bool checkModel() = 0;
|
virtual bool checkModel() = 0;
|
||||||
bool loadModel();
|
bool loadModel(const std::string& storepath);
|
||||||
genericModel(const std::string &url, const std::string &storepath, const std::string &id, int index);
|
genericModel(const std::string &url, const std::string &storepath, const std::string &id, int index);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,13 +1,11 @@
|
|||||||
#include "genericObj.h"
|
#include "genericObj.h"
|
||||||
|
|
||||||
void genericObj::fireEv(const char *type, const char *content) {
|
void genericObj::fireEv(const char *type, const char *content) {
|
||||||
if(content == nullptr) {
|
|
||||||
EM_ASM({
|
EM_ASM({
|
||||||
|
if($0 === 0) {
|
||||||
__genericObj__.objects[$0].dispatchEvent(new Event(UTF8ToString($1)));
|
__genericObj__.objects[$0].dispatchEvent(new Event(UTF8ToString($1)));
|
||||||
},this->index, type);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
EM_ASM({
|
__genericObj__.objects[$0].dispatchEvent(new CustomEvent(UTF8ToString($1), {"details" : UTF8ToString($2)}));
|
||||||
__genericObj__.objects[$0].dispatchEvent(new CustomEvent(UTF8ToString($0), {"details" : UTF8ToString($1)}));
|
|
||||||
},this->index, type, content);
|
},this->index, type, content);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1,2 @@
|
|||||||
class __genericObj__ {static objects = []}
|
class __genericObj__ {static objects = []}
|
||||||
|
|
||||||
|
|||||||
@@ -25,18 +25,7 @@ index 4573e24f1..4af4e73ea 100644
|
|||||||
|
|
||||||
MultiThreadable::~MultiThreadable() {
|
MultiThreadable::~MultiThreadable() {
|
||||||
// default implementation does nothing
|
// default implementation does nothing
|
||||||
diff --git a/src/base/kaldi-types.h b/src/base/kaldi-types.h
|
|
||||||
index 7ebf4f853..2f5979e42 100644
|
|
||||||
--- a/src/base/kaldi-types.h
|
|
||||||
+++ b/src/base/kaldi-types.h
|
|
||||||
@@ -20,6 +20,7 @@
|
|
||||||
|
|
||||||
#ifndef KALDI_BASE_KALDI_TYPES_H_
|
|
||||||
#define KALDI_BASE_KALDI_TYPES_H_ 1
|
|
||||||
+#define KALDI_DOUBLEPRECISION 1
|
|
||||||
|
|
||||||
namespace kaldi {
|
|
||||||
// TYPEDEFS ..................................................................
|
|
||||||
diff --git a/src/ivector/ivector-extractor.cc b/src/ivector/ivector-extractor.cc
|
diff --git a/src/ivector/ivector-extractor.cc b/src/ivector/ivector-extractor.cc
|
||||||
index c3a122281..71d37256d 100644
|
index c3a122281..71d37256d 100644
|
||||||
--- a/src/ivector/ivector-extractor.cc
|
--- a/src/ivector/ivector-extractor.cc
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#include "model.h"
|
#include "model.h"
|
||||||
|
|
||||||
model::model(const std::string &url, const std::string& storepath, const std::string& id, int index) : genericModel(url, id, storepath, index) {
|
model::model(const std::string &url, const std::string& storepath, const std::string& id, int index) : genericModel(url, id, storepath, index) {
|
||||||
if(!loadModel()) return;
|
if(!loadModel(storepath)) return;
|
||||||
mdl = vosk_model_new(".");
|
mdl = vosk_model_new(".");
|
||||||
if(mdl == nullptr) {
|
if(mdl == nullptr) {
|
||||||
fireEv("error", "Unable to initialize model");
|
fireEv("error", "Unable to initialize model");
|
||||||
@@ -9,7 +9,9 @@ model::model(const std::string &url, const std::string& storepath, const std::st
|
|||||||
}
|
}
|
||||||
fireEv("ready");
|
fireEv("ready");
|
||||||
};
|
};
|
||||||
|
model::~model() {
|
||||||
|
vosk_model_free(mdl);
|
||||||
|
}
|
||||||
bool model::checkModel() {
|
bool model::checkModel() {
|
||||||
return fs::exists("am/final.mdl") &&
|
return fs::exists("am/final.mdl") &&
|
||||||
fs::exists("conf/mfcc.conf") &&
|
fs::exists("conf/mfcc.conf") &&
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ struct model : genericModel {
|
|||||||
bool checkModel();
|
bool checkModel();
|
||||||
VoskModel* mdl{};
|
VoskModel* mdl{};
|
||||||
model(const std::string &url, const std::string& storepath, const std::string& id, int index);
|
model(const std::string &url, const std::string& storepath, const std::string& id, int index);
|
||||||
|
~model();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,12 +3,10 @@ class Model extends EventTarget{
|
|||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
init(url, storepath, id) {
|
init(url, storepath, id) {
|
||||||
this.obj = new Module.__model__(url, storepath, id, __genericObj__.objects.length);
|
this.obj = new BrowserRecognizer.__model__(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()
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,11 +7,6 @@ void recognizer::stop() {
|
|||||||
controller.clear(std::memory_order_relaxed);
|
controller.clear(std::memory_order_relaxed);
|
||||||
controller.notify_all();
|
controller.notify_all();
|
||||||
}
|
}
|
||||||
void recognizer::deinit() {
|
|
||||||
done.test_and_set(std::memory_order_relaxed);
|
|
||||||
done.notify_all();
|
|
||||||
stop();
|
|
||||||
}
|
|
||||||
recognizer::recognizer(model* mdl, int sampleRate, int index) : genericObj(index) {
|
recognizer::recognizer(model* mdl, int sampleRate, int index) : genericObj(index) {
|
||||||
mic = alcCaptureOpenDevice("Emscripten OpenAL capture",sampleRate, AL_FORMAT_MONO16, 22480);
|
mic = alcCaptureOpenDevice("Emscripten OpenAL capture",sampleRate, AL_FORMAT_MONO16, 22480);
|
||||||
if(alcGetError(mic) != 0) {
|
if(alcGetError(mic) != 0) {
|
||||||
@@ -25,32 +20,15 @@ recognizer::recognizer(model* mdl, int sampleRate, int index) : genericObj(index
|
|||||||
}
|
}
|
||||||
main();
|
main();
|
||||||
}
|
}
|
||||||
void recognizer::main() {
|
recognizer::~recognizer() {
|
||||||
char buffer[22480];
|
done.test_and_set(std::memory_order_relaxed);
|
||||||
int sample{};
|
done.notify_all();
|
||||||
fireEv("ready");
|
stop();
|
||||||
while(!done.test()) {
|
|
||||||
controller.wait(done.test(std::memory_order_relaxed), std::memory_order_relaxed);
|
|
||||||
alcCaptureStart(mic);
|
|
||||||
while(controller.test()) {
|
|
||||||
alcGetIntegerv(mic, ALC_CAPTURE_SAMPLES, sizeof(int), &sample);
|
|
||||||
alcCaptureSamples(mic, buffer, sample);
|
|
||||||
switch(vosk_recognizer_accept_waveform(rec, buffer, 22480)) {
|
|
||||||
case 0:
|
|
||||||
fireEv("result", vosk_recognizer_result(rec));
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
fireEv("partialResult", vosk_recognizer_partial_result(rec));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fireEv("error", "Recognition result error");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
alcCaptureStop(mic);
|
|
||||||
}
|
|
||||||
vosk_recognizer_free(rec);
|
vosk_recognizer_free(rec);
|
||||||
alcCaptureCloseDevice(mic);
|
alcCaptureCloseDevice(mic);
|
||||||
}
|
}
|
||||||
|
void recognizer::acceptWaveForm() {
|
||||||
|
}
|
||||||
void recognizer::setGrm(const std::string& grm) {
|
void recognizer::setGrm(const std::string& grm) {
|
||||||
vosk_recognizer_set_grm(rec, grm.c_str());
|
vosk_recognizer_set_grm(rec, grm.c_str());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,13 +19,11 @@ namespace fs = std::filesystem;
|
|||||||
struct recognizer : genericObj {
|
struct recognizer : genericObj {
|
||||||
VoskRecognizer* rec{};
|
VoskRecognizer* rec{};
|
||||||
ALCdevice* mic{};
|
ALCdevice* mic{};
|
||||||
std::atomic_flag done {false};
|
void acceptWaveForm();
|
||||||
std::atomic_flag controller{false};
|
|
||||||
void main();
|
|
||||||
recognizer(model* model, int sampleRate, int index);
|
recognizer(model* model, int sampleRate, int index);
|
||||||
|
~recognizer();
|
||||||
void start();
|
void start();
|
||||||
void stop();
|
void stop();
|
||||||
void deinit();
|
|
||||||
void setSpkModel(spkModel* model);
|
void setSpkModel(spkModel* model);
|
||||||
void setGrm(const std::string& grm);
|
void setGrm(const std::string& grm);
|
||||||
void setWords(bool words);
|
void setWords(bool words);
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ class Recognizer extends EventTarget {
|
|||||||
}
|
}
|
||||||
init(model) {
|
init(model) {
|
||||||
ctx = new (AudioContext || webkitAudioContext)()
|
ctx = new (AudioContext || webkitAudioContext)()
|
||||||
new Module.__recognizer__(model.obj,ctx.sampleRate,__genericObj__.objects.length)
|
new BrowserRecognizer.__recognizer__(model.obj,ctx.sampleRate,__genericObj__.objects.length)
|
||||||
ctx.close()
|
ctx.close()
|
||||||
__genericObj__.objects.push(this)
|
__genericObj__.objects.push(this)
|
||||||
}
|
}
|
||||||
@@ -15,7 +15,6 @@ class Recognizer extends EventTarget {
|
|||||||
this.obj.stop()
|
this.obj.stop()
|
||||||
}
|
}
|
||||||
delete() {
|
delete() {
|
||||||
this.obj.deinit()
|
|
||||||
this.obj.delete()
|
this.obj.delete()
|
||||||
}
|
}
|
||||||
setWords(words) {
|
setWords(words) {
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
#include "spkModel.h"
|
#include "spkModel.h"
|
||||||
spkModel::spkModel(const std::string &url, const std::string& storepath, const std::string& id, int index) : genericModel(url, storepath, id, index) {
|
spkModel::spkModel(const std::string &url, const std::string& storepath, const std::string& id, int index) : genericModel(url, storepath, id, index) {
|
||||||
if(!loadModel()) return;
|
if(!loadModel(storepath)) return;
|
||||||
mdl = vosk_spk_model_new(".");
|
mdl = vosk_spk_model_new(".");
|
||||||
if(mdl == nullptr) {
|
if(mdl == nullptr) {
|
||||||
fireEv("error", "Unable to initialize speaker model");
|
fireEv("error", "Unable to initialize speaker model");
|
||||||
}
|
}
|
||||||
fireEv("ready");
|
fireEv("ready");
|
||||||
};
|
};
|
||||||
|
spkModel::~spkModel() {
|
||||||
|
vosk_spk_model_free(mdl);
|
||||||
|
}
|
||||||
bool spkModel::checkModel() {
|
bool spkModel::checkModel() {
|
||||||
return fs::exists("mfcc.conf") &&
|
return fs::exists("mfcc.conf") &&
|
||||||
fs::exists("final.ext.raw") &&
|
fs::exists("final.ext.raw") &&
|
||||||
|
|||||||
@@ -3,8 +3,9 @@
|
|||||||
|
|
||||||
struct spkModel : genericModel {
|
struct spkModel : genericModel {
|
||||||
bool checkModel();
|
bool checkModel();
|
||||||
spkModel(const std::string &url, const std::string& storepath, const std::string& id, const int index);
|
|
||||||
VoskSpkModel* mdl{};
|
VoskSpkModel* mdl{};
|
||||||
|
spkModel(const std::string &url, const std::string& storepath, const std::string& id, const int index);
|
||||||
|
~spkModel();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ class SpkModel extends EventTarget{
|
|||||||
super()
|
super()
|
||||||
}
|
}
|
||||||
init(url, storepath, id) {
|
init(url, storepath, id) {
|
||||||
this.obj = new Module.__spkModel__(url, storepath, id, __genericObj__.objects.length)
|
this.obj = new BrowserRecognizer.__spkModel__(url, storepath, id, __genericObj__.objects.length)
|
||||||
__genericObj__.objects.push(this)
|
__genericObj__.objects.push(this)
|
||||||
}
|
}
|
||||||
delete() {
|
delete() {
|
||||||
|
|||||||
Reference in New Issue
Block a user