Nodejs Addon blocking main thread. Implemented Napi::AsyncWorker (#642)

* fixed blocking code on node addon

* modify the example to run async

* format

* added logic to see the whisper output

* added logic to see the whisper output

* removed extra function for more clean example
This commit is contained in:
Lucas Zanek 2023-03-22 17:19:22 -03:00 committed by GitHub
parent 1d749919e3
commit 21165580a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 73 additions and 51 deletions

View File

@ -292,51 +292,64 @@ int run(whisper_params &params, std::vector<std::vector<std::string>> &result) {
return 0; return 0;
} }
Napi::Object whisper(const Napi::CallbackInfo& info) { class Worker : public Napi::AsyncWorker {
Napi::Env env = info.Env(); public:
if (info.Length() <= 0 || !info[0].IsObject()) { Worker(Napi::Function& callback, whisper_params params)
Napi::TypeError::New(env, "object expected").ThrowAsJavaScriptException(); : Napi::AsyncWorker(callback), params(params) {}
}
whisper_params params;
std::vector<std::vector<std::string>> result;
Napi::Object whisper_params = info[0].As<Napi::Object>(); void Execute() override {
std::string language = whisper_params.Get("language").As<Napi::String>();
std::string model = whisper_params.Get("model").As<Napi::String>();
std::string input = whisper_params.Get("fname_inp").As<Napi::String>();
params.language = language;
params.model = model;
params.fname_inp.emplace_back(input);
// run model
run(params, result); run(params, result);
}
fprintf(stderr, "RESULT:\n"); void OnOK() override {
for (auto sentence:result) { Napi::HandleScope scope(Env());
fprintf(stderr, "t0: %s, t1: %s, content: %s \n", Napi::Object res = Napi::Array::New(Env(), result.size());
sentence[0].c_str(), sentence[1].c_str(), sentence[2].c_str());
}
Napi::Object res = Napi::Array::New(env, result.size());
for (uint64_t i = 0; i < result.size(); ++i) { for (uint64_t i = 0; i < result.size(); ++i) {
Napi::Object tmp = Napi::Array::New(env, 3); Napi::Object tmp = Napi::Array::New(Env(), 3);
for (uint64_t j = 0; j < 3; ++j) { for (uint64_t j = 0; j < 3; ++j) {
tmp[j] = Napi::String::New(env, result[i][j]); tmp[j] = Napi::String::New(Env(), result[i][j]);
} }
res[i] = tmp; res[i] = tmp;
} }
Callback().Call({Env().Null(), res});
}
return res; private:
whisper_params params;
std::vector<std::vector<std::string>> result;
};
Napi::Value whisper(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() <= 0 || !info[0].IsObject()) {
Napi::TypeError::New(env, "object expected").ThrowAsJavaScriptException();
}
whisper_params params;
Napi::Object whisper_params = info[0].As<Napi::Object>();
std::string language = whisper_params.Get("language").As<Napi::String>();
std::string model = whisper_params.Get("model").As<Napi::String>();
std::string input = whisper_params.Get("fname_inp").As<Napi::String>();
params.language = language;
params.model = model;
params.fname_inp.emplace_back(input);
Napi::Function callback = info[1].As<Napi::Function>();
Worker* worker = new Worker(callback, params);
worker->Queue();
return env.Undefined();
} }
Napi::Object Init(Napi::Env env, Napi::Object exports) { Napi::Object Init(Napi::Env env, Napi::Object exports) {
exports.Set( exports.Set(
Napi::String::New(env, "whisper"), Napi::String::New(env, "whisper"),
Napi::Function::New(env, whisper) Napi::Function::New(env, whisper)
); );
return exports; return exports;
} }
NODE_API_MODULE(whisper, Init); NODE_API_MODULE(whisper, Init);

View File

@ -1,27 +1,36 @@
const path = require('path'); const path = require("path");
const { whisper } = require(path.join(__dirname, '../../build/Release/whisper-addon')); const { whisper } = require(path.join(
__dirname,
"../../build/Release/whisper-addon"
));
const { promisify } = require("util");
const whisperAsync = promisify(whisper);
const whisperParams = { const whisperParams = {
language: 'en', language: "en",
model: path.join(__dirname, '../../models/ggml-base.en.bin'), model: path.join(__dirname, "../../models/ggml-base.en.bin"),
fname_inp: '', fname_inp: "../../samples/jfk.wav",
}; };
const arguments = process.argv.slice(2); const arguments = process.argv.slice(2);
const params = Object.fromEntries( const params = Object.fromEntries(
arguments.reduce((pre, item) => { arguments.reduce((pre, item) => {
if (item.startsWith("--")) { if (item.startsWith("--")) {
return [...pre, item.slice(2).split("=")]; return [...pre, item.slice(2).split("=")];
} }
return pre; return pre;
}, []), }, [])
); );
for (const key in params) { for (const key in params) {
if (whisperParams.hasOwnProperty(key)) { if (whisperParams.hasOwnProperty(key)) {
whisperParams[key] = params[key]; whisperParams[key] = params[key];
} }
} }
console.log('whisperParams =', whisperParams); console.log("whisperParams =", whisperParams);
console.log(whisper(whisperParams));
whisperAsync(whisperParams).then((result) => {
console.log(`Result from whisper: ${result}`);
});