Fix await issue. But it doesn't work tho.

This commit is contained in:
msqr1
2024-02-08 20:19:38 -08:00
parent 5228c666a2
commit 18de98dd3b
12 changed files with 122 additions and 5988 deletions

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
# Build the js file into here # Build the js file into this directory or the outer for release mode
cd .. && cd .. &&
SRC=$(realpath src) && SRC=$(realpath src) &&
@@ -7,6 +7,7 @@ VOSK=$(realpath vosk) &&
OPENFST=$(realpath openfst) && OPENFST=$(realpath openfst) &&
LIBARCHIVE=$(realpath libarchive) && LIBARCHIVE=$(realpath libarchive) &&
CLAPACK_WASM=$(realpath clapack-wasm) && CLAPACK_WASM=$(realpath clapack-wasm) &&
RELEASE=0 &&
MAX_MEMORY=${MAX_MEMORY:-300mb} && MAX_MEMORY=${MAX_MEMORY:-300mb} &&
MAX_THREADS=${MAX_THREADS:-2} && MAX_THREADS=${MAX_THREADS:-2} &&
@@ -36,9 +37,14 @@ fi
export PATH=:$PATH:$EMSDK/upstream/bin && export PATH=:$PATH:$EMSDK/upstream/bin &&
cd $SRC && cd $SRC &&
# Small build if [ $RELEASE = 0 ]; then
em++ -O0 global.cc genericModel.cc model.cc spkModel.cc recognizer.cc bindings.cc -sWASMFS -sWASM_BIGINT -sSINGLE_FILE -sMODULARIZE -sTRUSTED_TYPES -sEMBIND_STD_STRING_IS_UTF8 -sPTHREAD_POOL_DELAY_LOAD -sTEXTDECODER=2 -sPTHREAD_POOL_SIZE_STRICT=2 -sINITIAL_MEMORY=$MAX_MEMORY -sPTHREAD_POOL_SIZE=$MAX_THREADS -sPOLYFILL=0 -sSUPPORT_LONGJMP=0 -sEXPORTED_FUNCTIONS=_malloc,_main -sEXPORT_NAME=loadBR -sMALLOC=emmalloc -sEXPORTED_RUNTIME_METHODS=UTF8ToString,stringToUTF8OnStack -sENVIRONMENT=web,worker -I. -I$LIBARCHIVE/include -I$VOSK/src -L$LIBARCHIVE/lib -larchive -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 -pthread -flto --pre-js pre.js -o ../devel/BrowserRecognizer.js && em++ -O0 global.cc genericModel.cc model.cc spkModel.cc recognizer.cc bindings.cc -sWASMFS -sWASM_BIGINT -sSINGLE_FILE -sMODULARIZE -sTRUSTED_TYPES -sASSERTIONS=2 -sEMBIND_STD_STRING_IS_UTF8 -sPTHREAD_POOL_DELAY_LOAD -sTEXTDECODER=2 -sPTHREAD_POOL_SIZE_STRICT=2 -sINITIAL_MEMORY=$MAX_MEMORY -sPTHREAD_POOL_SIZE=$MAX_THREADS -sPOLYFILL=0 -sSUPPORT_LONGJMP=0 -sEXPORTED_FUNCTIONS=_malloc -sEXPORT_NAME=loadBR -sMALLOC=emmalloc -sEXPORTED_RUNTIME_METHODS=UTF8ToString,stringToUTF8OnStack -sENVIRONMENT=web,worker -I. -I$LIBARCHIVE/include -I$VOSK/src -L$LIBARCHIVE/lib -larchive -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 -pthread -flto --no-entry --pre-js pre.js -o ../devel/BrowserRecognizer.js &&
cd ../devel && cd ../devel &&
rm -f BrowserRecognizer.worker.js && rm -f BrowserRecognizer.worker.js &&
sed -i "s/locateFile('BrowserRecognizer.worker.js')/pthreadUrl/g" BrowserRecognizer.js && sed -i "s/locateFile('BrowserRecognizer.worker.js')/pthreadUrl/g" BrowserRecognizer.js
sed -i 's/locateFile("BrowserRecognizer.worker.js")/pthreadUrl/g' BrowserRecognizer.js else
em++ -O3 global.cc genericModel.cc model.cc spkModel.cc recognizer.cc bindings.cc -sWASMFS -sWASM_BIGINT -sSINGLE_FILE -sMODULARIZE -sTRUSTED_TYPES -sEMBIND_STD_STRING_IS_UTF8 -sPTHREAD_POOL_DELAY_LOAD -sTEXTDECODER=2 -sPTHREAD_POOL_SIZE_STRICT=2 -sINITIAL_MEMORY=$MAX_MEMORY -sPTHREAD_POOL_SIZE=$MAX_THREADS -sPOLYFILL=0 -sSUPPORT_LONGJMP=0 -sEXPORTED_FUNCTIONS=_malloc -sEXPORT_NAME=loadBR -sMALLOC=emmalloc -sEXPORTED_RUNTIME_METHODS=UTF8ToString,stringToUTF8OnStack -sENVIRONMENT=web,worker -I. -I$LIBARCHIVE/include -I$VOSK/src -L$LIBARCHIVE/lib -larchive -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 -pthread -flto --no-entry --pre-js pre.js -o ../BrowserRecognizer.js &&
cd .. &&
rm -f BrowserRecognizer.worker.js &&
sed -i 's/locateFile("BrowserRecognizer.worker.js")/pthreadUrl/g' BrowserRecognizer.js
fi

View File

@@ -1,8 +1,18 @@
#include "genericModel.h" #include "genericModel.h"
genericModel::genericModel(const std::string& storepath, const std::string &id, int index) : storepath(storepath), id(id), index(index) { genericModel::genericModel(const std::string& storepath, const std::string &id, int index) : storepath(storepath), id(id), index(index) {}
void genericModel::checkModel() {
thrd.addTask([this](){
if(OPFSTried && !OPFSOk) {
fireEv("_checkMdl", "OPFS isn't available", index);
return;
}
if(!OPFSTried){
OPFSTried = true;
OPFSOk = wasmfs_create_directory("/opfs", 0777, wasmfs_create_opfs_backend()) == 0;
}
if(!OPFSOk) { if(!OPFSOk) {
fireEv("_continue", "OPFS isn't initialized or unavailable", index); fireEv("_checkMdl", "OPFS initialization failed", index);
return; return;
} }
fs::current_path("/opfs", tank); fs::current_path("/opfs", tank);
@@ -18,17 +28,23 @@ genericModel::genericModel(const std::string& storepath, const std::string &id,
if(tank.value() != 0) { if(tank.value() != 0) {
fireEv("_continue", "Unable to cd storepath", index); fireEv("_continue", "Unable to cd storepath", index);
} }
} if(!checkModelFiles() && !fs::exists("id", tank)) {
bool genericModel::checkModel() { fireEv("_checkMdl", "fetch", index);
if(!checkModelFiles()) return false; return;
if(!fs::exists("id", tank)) return false; }
std::ifstream file {"id", std::ifstream::binary}; std::ifstream file {"id", std::ifstream::in};
if(!file.is_open()) return false; if(!file.is_open()) {
fireEv("_checkMdl", "Couldn't open id file", index);
return;
}
long long size {file.seekg(0, std::ios::end).tellg()}; long long size {file.seekg(0, std::ios::end).tellg()};
std::string oldid(size, ' '); std::string oldid(size, ' ');
file.seekg(0); file.seekg(0);
file.read(&oldid[0], size); file.read(&oldid[0], size);
return id.compare(oldid) == 0; if(id.compare(oldid) == 0) fireEv("_checkMdl", nullptr, index);
else fireEv("_checkMdl", "fetch", index);
file.close();
});
} }
void genericModel::afterFetch() { void genericModel::afterFetch() {
thrd.addTask([this](){ thrd.addTask([this](){
@@ -45,7 +61,7 @@ void genericModel::afterFetch() {
fireEv("_continue", "URL contains invalid model files", index); fireEv("_continue", "URL contains invalid model files", index);
return; return;
} }
std::ofstream idFile("id"); std::ofstream idFile{"id"};
if(!idFile.is_open()) { if(!idFile.is_open()) {
fs::current_path("/opfs", tank); fs::current_path("/opfs", tank);
fs::remove_all(storepath, tank); fs::remove_all(storepath, tank);
@@ -76,10 +92,7 @@ bool genericModel::extractModel() {
fd = open(path.c_str(), O_CREAT | O_WRONLY | O_TRUNC); fd = open(path.c_str(), O_CREAT | O_WRONLY | O_TRUNC);
archive_read_data_into_fd(src, fd); archive_read_data_into_fd(src, fd);
close(fd); close(fd);
if(archive_errno(src) != 0) { if(archive_errno(src) != 0) return false;
emscripten_console_log(archive_error_string(src));
return false;
}
} }
archive_read_free(src); archive_read_free(src);
return true; return true;

View File

@@ -19,8 +19,8 @@ struct genericModel {
int index{}; int index{};
static bool extractModel(); static bool extractModel();
virtual bool checkModelFiles() = 0; virtual bool checkModelFiles() = 0;
virtual void load(bool newThrd) = 0; virtual void load(bool newTask) = 0;
bool checkModel(); void checkModel();
void afterFetch(); void afterFetch();
genericModel(const std::string &storepath, const std::string &id, int index); genericModel(const std::string &storepath, const std::string &id, int index);
}; };

View File

@@ -3,8 +3,8 @@
pthread_t dstThrd{pthread_self()}; pthread_t dstThrd{pthread_self()};
std::error_code tank{}; std::error_code tank{};
bool OPFSOk{}; bool OPFSOk{};
bool OPFSTried{};
ProxyingQueue glbQ{}; ProxyingQueue glbQ{};
void fireEv(const char *type, const char *content, int index) { void fireEv(const char *type, const char *content, int index) {
auto proxy{[index, type, content](){ auto proxy{[index, type, content](){
EM_ASM({ EM_ASM({
@@ -17,20 +17,19 @@ void fireEv(const char *type, const char *content, int index) {
} }
glbQ.proxySync(dstThrd, proxy); glbQ.proxySync(dstThrd, proxy);
} }
void reusableThrd::addTask(std::function<void()>&& task) {
void reusableThrd::addTask(std::function<void()> task) {
static std::thread thrd{[this](){ static std::thread thrd{[this](){
pthread_detach(pthread_self());
while(!done.test()) { while(!done.test()) {
blocker.wait(done.test(std::memory_order_relaxed) || queue.empty(), std::memory_order_relaxed);
blocker.clear(std::memory_order_relaxed);
while(!queue.empty()) { while(!queue.empty()) {
queue.front()(); queue.front()();
queue.pop(); queue.pop();
} }
blocker.wait(done.test(std::memory_order_relaxed) || queue.empty(), std::memory_order_relaxed);
blocker.clear(std::memory_order_relaxed);
} }
}}; }};
thrd.detach(); queue.emplace(task);
queue.emplace(std::move(task));
blocker.test_and_set(std::memory_order_relaxed); blocker.test_and_set(std::memory_order_relaxed);
blocker.notify_one(); blocker.notify_one();
} }
@@ -38,10 +37,3 @@ reusableThrd::~reusableThrd() {
done.test_and_set(std::memory_order_relaxed); done.test_and_set(std::memory_order_relaxed);
done.notify_one(); done.notify_one();
} }
int main() {
std::thread t{[](){
OPFSOk = wasmfs_create_directory("/opfs", 0777, wasmfs_create_opfs_backend()) == 0;
}};
t.detach();
emscripten_exit_with_live_runtime();
}

View File

@@ -10,17 +10,16 @@
using namespace emscripten; using namespace emscripten;
extern bool OPFSOk; extern bool OPFSOk;
extern bool OPFSTried;
extern std::error_code tank; extern std::error_code tank;
extern pthread_t dstThrd; extern pthread_t dstThrd;
extern ProxyingQueue glbQ; extern ProxyingQueue glbQ;
void fireEv(const char *type, const char *content, int index); void fireEv(const char *type, const char *content, int index);
int main();
struct reusableThrd { struct reusableThrd {
std::queue<std::function<void()>> queue{}; std::queue<std::function<void()>> queue{};
std::atomic_flag blocker{}; std::atomic_flag blocker{};
std::atomic_flag done{}; std::atomic_flag done{};
void addTask(std::function<void()> task); void addTask(std::function<void()>&& task);
~reusableThrd(); ~reusableThrd();
}; };

View File

@@ -7,19 +7,19 @@ model::~model() {
void model::afterFetch() { void model::afterFetch() {
genericModel::afterFetch(); genericModel::afterFetch();
} }
bool model::checkModel() { void model::checkModel() {
return genericModel::checkModel(); genericModel::checkModel();
} }
void model::load(bool newThrd) { void model::load(bool newTask) {
auto main{[this](){ auto main{[this](){
mdl = vosk_model_new("."); mdl = vosk_model_new(".");
if(mdl == nullptr) { if(mdl == nullptr) {
fireEv("_continue", "Unable to load model for recognition", index); fireEv("_continue", "Unable to load model for recognition", index);
return; return;
} }
fireEv("_continue", ".", index); fireEv("_continue", nullptr, index);
}}; }};
if(!newThrd) { if(!newTask) {
main(); main();
return; return;
} }

View File

@@ -5,9 +5,9 @@ struct model : genericModel {
bool checkModelFiles(); bool checkModelFiles();
VoskModel* mdl{}; VoskModel* mdl{};
model(const std::string& storepath, const std::string& id, int index); model(const std::string& storepath, const std::string& id, int index);
bool checkModel(); void checkModel();
void afterFetch(); void afterFetch();
void load(bool newThrd); void load(bool newTask);
~model(); ~model();
}; };

View File

@@ -17,22 +17,18 @@ class genericModel extends EventTarget {
let mdl = new genericModel() let mdl = new genericModel()
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
mdl.addEventListener("_continue", (ev) => { mdl.addEventListener("_continue", (ev) => {
if(ev.detail === ".") { if(ev.detail === "0") {
return resolve(mdl) return resolve(mdl)
} }
mdl.delete() mdl.delete()
reject(ev.detail) reject(ev.detail)
}, {once : true}) }, {once : true})
if(normalMdl) { mdl.addEventListener("_checkMdl", (ev) => {
mdl.obj = new Module.model(storepath, id, objs.length-1) switch(ev.detail) {
} case "0":
else { mdl.load(true);
mdl.obj = new Module.spkModel(storepath, id, objs.length-1) break;
} case "fetch":
if(mdl.obj.checkModel()) {
mdl.obj.load(true)
return;
}
(async () => { (async () => {
let res = await fetch(url) let res = await fetch(url)
if(!res.ok) { if(!res.ok) {
@@ -48,10 +44,18 @@ class genericModel extends EventTarget {
await wStream.close() await wStream.close()
mdl.obj.afterFetch() mdl.obj.afterFetch()
})() })()
break;
default:
reject(ev.detail)
}
}, {once : true})
if(normalMdl) mdl.obj = new Module.model(storepath, id, objs.length-1)
else mdl.obj = new Module.spkModel(storepath, id, objs.length-1)
mdl.obj.checkModel()
}) })
} }
delete() { delete() {
this.obj.delete() if (this.obj) this.obj.delete()
} }
} }
Module.makeModel = async (url, storepath, id) => { Module.makeModel = async (url, storepath, id) => {
@@ -69,15 +73,14 @@ class Recognizer extends EventTarget {
let rec = new Recognizer() let rec = new Recognizer()
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
rec.addEventListener("_continue", (ev) => { rec.addEventListener("_continue", (ev) => {
if(ev.detail == ".") { if(ev.detail == "0") {
objs.push(rec) rec.ptr = Module._malloc(512)
return resolve(rec) return resolve(rec)
} }
rec.delete() rec.delete()
reject(ev.detail) reject(ev.detail)
}, {once : true}) }, {once : true})
rec.obj = new Module.recognizer(model, sampleRate, objs.length-1) rec.obj = new Module.recognizer(model, sampleRate, objs.length-1)
rec.ptr = Module._malloc(512)
}) })
} }
async getNode(ctx, channelIndex = 0) { async getNode(ctx, channelIndex = 0) {
@@ -96,10 +99,8 @@ class Recognizer extends EventTarget {
this.obj.acceptWaveForm() this.obj.acceptWaveForm()
} }
delete() { delete() {
this.obj.delete() if (this.obj) this.obj.delete()
if(typeof this.node !== "undefined") { if(this.node) this.node.postMessage("0")
this.node.port.postMessage(".")
}
} }
setWords(words) { setWords(words) {
this.obj.setWords(words) this.obj.setWords(words)
@@ -136,7 +137,7 @@ let processorUrl = URL.createObjectURL(new Blob(['(',
process(inputs, outputs, params) { process(inputs, outputs, params) {
if(this.done) return false; if(this.done) return false;
this.wasmMem.set(inputs[0].getChannelData(this.channelIndex)); this.wasmMem.set(inputs[0].getChannelData(this.channelIndex));
this.recognizerPort.postMessage(".") this.recognizerPort.postMessage("0")
outputs = inputs outputs = inputs
return true return true
} }

View File

@@ -1,17 +1,13 @@
#include "recognizer.h" #include "recognizer.h"
recognizer::recognizer(model* mdl, float sampleRate, int index) : index(index) { recognizer::recognizer(model* mdl, float sampleRate, int index) : index(index) {
if(!OPFSOk) {
fireEv("_continue", "OPFS isn't initialized or unavailable", index);
return;
}
auto main{[this, mdl, sampleRate](){ auto main{[this, mdl, sampleRate](){
rec = vosk_recognizer_new(mdl->mdl,sampleRate); rec = vosk_recognizer_new(mdl->mdl,sampleRate);
if(rec == nullptr) { if(rec == nullptr) {
fireEv("_continue", "Unable to initialize recognizer", this->index); fireEv("_continue", "Unable to initialize recognizer", this->index);
return; return;
} }
fireEv("_continue", "." ,this->index); fireEv("_continue", nullptr, this->index);
while(!done.test(std::memory_order_relaxed)) { while(!done.test(std::memory_order_relaxed)) {
controller.wait(!done.test(std::memory_order_relaxed), std::memory_order_relaxed); controller.wait(!done.test(std::memory_order_relaxed), std::memory_order_relaxed);
controller.clear(std::memory_order_relaxed); controller.clear(std::memory_order_relaxed);

View File

@@ -8,22 +8,22 @@ spkModel::spkModel(const std::string& storepath, const std::string& id, int inde
spkModel::~spkModel() { spkModel::~spkModel() {
vosk_spk_model_free(mdl); vosk_spk_model_free(mdl);
} }
bool spkModel::checkModel() { void spkModel::checkModel() {
return genericModel::checkModel(); genericModel::checkModel();
} }
void spkModel::afterFetch() { void spkModel::afterFetch() {
genericModel::afterFetch(); genericModel::afterFetch();
} }
void spkModel::load(bool newThrd) { void spkModel::load(bool newTask) {
auto main{[this](){ auto main{[this](){
mdl = vosk_spk_model_new("."); mdl = vosk_spk_model_new(".");
if(mdl == nullptr) { if(mdl == nullptr) {
fireEv("_continue", "Unable to load model for recognition", index); fireEv("_continue", "Unable to load model for recognition", index);
return; return;
} }
fireEv("_continue", ".", index); fireEv("_continue", nullptr, index);
}}; }};
if(!newThrd) { if(!newTask) {
main(); main();
return; return;
} }

View File

@@ -5,8 +5,8 @@ struct spkModel : genericModel {
bool checkModelFiles(); bool checkModelFiles();
VoskSpkModel* mdl{}; VoskSpkModel* mdl{};
spkModel(const std::string& storepath, const std::string& id, int index); spkModel(const std::string& storepath, const std::string& id, int index);
bool checkModel(); void checkModel();
void afterFetch(); void afterFetch();
void load(bool newThrd); void load(bool newTask);
~spkModel(); ~spkModel();
}; };