Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(examples)!: node addon support muti input files and callback function support provide progress #1913

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/addon.node/.gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.idea
node_modules
build
dist
24 changes: 0 additions & 24 deletions examples/addon.node/__test__/whisper.spec.js

This file was deleted.

38 changes: 38 additions & 0 deletions examples/addon.node/__test__/whisper.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import * as path from 'path'
import { describe, it, expect } from 'vitest'

const { whisper } = require(path.join(
__dirname,
"../../../build/Release/whisper-addon"
));

function whisperAsync(params: WhisperParams, callback?: (index: number) => any) {
return new Promise<Array<WhisperResultItem>>((resolve, reject) => {
whisper(params, (error: Error, result: {res: Array<WhisperResultItem>, index: number}) => {
if(error) {
return reject(error);
} else if(result.res){
return resolve(result.res);
}
callback?.(result.index)
})
})
}

const whisperParamsMock = {
language: "en",
model: path.join(__dirname, "../../../models/ggml-base.en.bin"),
fname_inp: [path.join(__dirname, "../../../samples/jfk.wav")],
use_gpu: true,
} satisfies WhisperParams;

describe("Run whisper.node", () => {
it("it should receive a non-empty value", async () => {
const result = await whisperAsync(whisperParamsMock, (index) => {
console.log({index})
})

expect(result.length).toBeGreaterThan(0);
}, 100000);
});

51 changes: 40 additions & 11 deletions examples/addon.node/addon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -257,31 +257,56 @@ int run(whisper_params &params, std::vector<std::vector<std::string>> &result) {
return 0;
}

class Worker : public Napi::AsyncWorker {
class Worker : public Napi::AsyncProgressWorker<size_t> {
public:
Worker(Napi::Function& callback, whisper_params params)
: Napi::AsyncWorker(callback), params(params) {}
: Napi::AsyncProgressWorker<size_t>(callback), params(params) {}

void Execute() override {
run(params, result);
void Execute(const ExecutionProgress& progress) override {
for (size_t i = 0; i < (int) params.fname_inp.size(); ++i) {

std::vector<std::vector<std::string>> current_result;
whisper_params single_file_params = params;
single_file_params.fname_inp.clear();
single_file_params.fname_inp.push_back(params.fname_inp[i]);

run(single_file_params, current_result);

results.push_back(current_result);

progress.Send(&i, 1);
}
}

void OnProgress(const size_t* data, size_t count) override {
Napi::HandleScope scope(Env());
Napi::Object _res = Napi::Object::New(Env());
_res.Set("res", Env().Null());
_res.Set("index", Napi::Number::New(Env(), *data));
Callback().Call({Env().Null(), _res});
}

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 res = Napi::Array::New(Env(), results.size());
for (uint64_t i = 0; i < results.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]);
for (uint64_t k = 0; k < 1; ++k) {
tmp[j] = Napi::String::New(Env(), results[i][k][j]);
}
}
res[i] = tmp;
}
Callback().Call({Env().Null(), res});
Napi::Object _res = Napi::Object::New(Env());
_res.Set("res", res);
_res.Set("index", Env().Null());
Callback().Call({Env().Null(), _res});
}

private:
whisper_params params;
std::vector<std::vector<std::string>> result;
std::vector<std::vector<std::vector<std::string>>> results;
};


Expand All @@ -296,12 +321,16 @@ Napi::Value whisper(const Napi::CallbackInfo& info) {
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>();
Napi::Array inputArray = whisper_params.Get("fname_inp").As<Napi::Array>();
std::vector<std::string> input;
for (uint32_t i = 0; i < inputArray.Length(); i++) {
input.push_back(inputArray.Get(i).As<Napi::String>());
}
bool use_gpu = whisper_params.Get("use_gpu").As<Napi::Boolean>();

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

Napi::Function callback = info[1].As<Napi::Function>();
Expand Down
37 changes: 0 additions & 37 deletions examples/addon.node/index.js

This file was deleted.

48 changes: 48 additions & 0 deletions examples/addon.node/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import * as path from 'path'

const { whisper } = require(path.join(
__dirname,
"../../build/Release/whisper-addon"
));

function whisperAsync(params: WhisperParams, callback?: (index: number) => any) {
return new Promise<Array<WhisperResultItem>>((resolve, reject) => {
whisper(params, (error: Error, result: {res: Array<WhisperResultItem>, index: number}) => {
if(error) {
return reject(error);
} else if(result.res){
return resolve(result.res);
}
callback?.(result.index)
})
})
}

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

const args = process.argv.slice(2);
const params = Object.fromEntries(
args.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];
}
}

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

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