Skip to content

Commit

Permalink
Nodejs Addon blocking main thread. Implemented Napi::AsyncWorker (gge…
Browse files Browse the repository at this point in the history
…rganov#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
  • Loading branch information
LucasZNK authored and iThalay committed Sep 23, 2024
1 parent ccf2864 commit 672aef2
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 50 deletions.
81 changes: 47 additions & 34 deletions examples/addon.node/addon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,51 +292,64 @@ int run(whisper_params &params, std::vector<std::vector<std::string>> &result) {
return 0;
}

Napi::Object whisper(const Napi::CallbackInfo& info) {
Napi::Env env = info.Env();
if (info.Length() <= 0 || !info[0].IsObject()) {
Napi::TypeError::New(env, "object expected").ThrowAsJavaScriptException();
class Worker : public Napi::AsyncWorker {
public:
Worker(Napi::Function& callback, whisper_params params)
: Napi::AsyncWorker(callback), params(params) {}

void Execute() override {
run(params, result);
}

void OnOK() override {
Napi::HandleScope scope(Env());
Napi::Object res = Napi::Array::New(Env(), result.size());
for (uint64_t i = 0; i < result.size(); ++i) {
Napi::Object tmp = Napi::Array::New(Env(), 3);
for (uint64_t j = 0; j < 3; ++j) {
tmp[j] = Napi::String::New(Env(), result[i][j]);
}
res[i] = tmp;
}
whisper_params params;
std::vector<std::vector<std::string>> result;
Callback().Call({Env().Null(), res});
}

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>();
private:
whisper_params params;
std::vector<std::vector<std::string>> result;
};

params.language = language;
params.model = model;
params.fname_inp.emplace_back(input);

// run model
run(params, result);

fprintf(stderr, "RESULT:\n");
for (auto sentence:result) {
fprintf(stderr, "t0: %s, t1: %s, content: %s \n",
sentence[0].c_str(), sentence[1].c_str(), sentence[2].c_str());
}
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 res = Napi::Array::New(env, result.size());
for (uint64_t i = 0; i < result.size(); ++i) {
Napi::Object tmp = Napi::Array::New(env, 3);
for (uint64_t j = 0; j < 3; ++j) {
tmp[j] = Napi::String::New(env, result[i][j]);
}
res[i] = tmp;
}
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);

return res;
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) {
exports.Set(
Napi::String::New(env, "whisper"),
Napi::Function::New(env, whisper)
);
return exports;
exports.Set(
Napi::String::New(env, "whisper"),
Napi::Function::New(env, whisper)
);
return exports;
}

NODE_API_MODULE(whisper, Init);
41 changes: 25 additions & 16 deletions examples/addon.node/index.js
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
const path = require('path');
const { whisper } = require(path.join(__dirname, '../../build/Release/whisper-addon'));
const path = require("path");
const { whisper } = require(path.join(
__dirname,
"../../build/Release/whisper-addon"
));
const { promisify } = require("util");

const whisperAsync = promisify(whisper);

const whisperParams = {
language: 'en',
model: path.join(__dirname, '../../models/ggml-base.en.bin'),
fname_inp: '',
language: "en",
model: path.join(__dirname, "../../models/ggml-base.en.bin"),
fname_inp: "../../samples/jfk.wav",
};

const arguments = process.argv.slice(2);
const params = Object.fromEntries(
arguments.reduce((pre, item) => {
if (item.startsWith("--")) {
return [...pre, item.slice(2).split("=")];
}
return pre;
}, []),
arguments.reduce((pre, item) => {
if (item.startsWith("--")) {
return [...pre, item.slice(2).split("=")];
}
return pre;
}, [])
);

for (const key in params) {
if (whisperParams.hasOwnProperty(key)) {
whisperParams[key] = params[key];
}
if (whisperParams.hasOwnProperty(key)) {
whisperParams[key] = params[key];
}
}

console.log('whisperParams =', whisperParams);
console.log(whisper(whisperParams));
console.log("whisperParams =", whisperParams);

whisperAsync(whisperParams).then((result) => {
console.log(`Result from whisper: ${result}`);
});

0 comments on commit 672aef2

Please sign in to comment.