mirror of
https://github.com/ggerganov/whisper.cpp.git
synced 2025-04-20 09:18:41 +02:00
examples : support progress_callback API for addon.node (#2941)
* feat: progress supported * fix: missing params * style: Format the code to improve readability Unified code indentation ensures consistent coding style, enhancing code readability and maintainability. * feat: support prompt api --------- Co-authored-by: linxiaodong <calm.lin@wukongsch.com>
This commit is contained in:
parent
f28bf5d186
commit
1279f0d0bc
@ -18,6 +18,7 @@ const whisperParamsMock = {
|
||||
translate: true,
|
||||
no_timestamps: false,
|
||||
audio_ctx: 0,
|
||||
max_len: 0,
|
||||
};
|
||||
|
||||
describe("Run whisper.node", () => {
|
||||
|
@ -128,7 +128,67 @@ void whisper_print_segment_callback(struct whisper_context * ctx, struct whisper
|
||||
|
||||
void cb_log_disable(enum ggml_log_level, const char *, void *) {}
|
||||
|
||||
int run(whisper_params ¶ms, std::vector<std::vector<std::string>> &result) {
|
||||
class ProgressWorker : public Napi::AsyncWorker {
|
||||
public:
|
||||
ProgressWorker(Napi::Function& callback, whisper_params params, Napi::Function progress_callback, Napi::Env env)
|
||||
: Napi::AsyncWorker(callback), params(params), env(env) {
|
||||
// Create thread-safe function
|
||||
if (!progress_callback.IsEmpty()) {
|
||||
tsfn = Napi::ThreadSafeFunction::New(
|
||||
env,
|
||||
progress_callback,
|
||||
"Progress Callback",
|
||||
0,
|
||||
1
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
~ProgressWorker() {
|
||||
if (tsfn) {
|
||||
// Make sure to release the thread-safe function on destruction
|
||||
tsfn.Release();
|
||||
}
|
||||
}
|
||||
|
||||
void Execute() override {
|
||||
// Use custom run function with progress callback support
|
||||
run_with_progress(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;
|
||||
}
|
||||
Callback().Call({Env().Null(), res});
|
||||
}
|
||||
|
||||
// Progress callback function - using thread-safe function
|
||||
void OnProgress(int progress) {
|
||||
if (tsfn) {
|
||||
// Use thread-safe function to call JavaScript callback
|
||||
auto callback = [progress](Napi::Env env, Napi::Function jsCallback) {
|
||||
jsCallback.Call({Napi::Number::New(env, progress)});
|
||||
};
|
||||
|
||||
tsfn.BlockingCall(callback);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
whisper_params params;
|
||||
std::vector<std::vector<std::string>> result;
|
||||
Napi::Env env;
|
||||
Napi::ThreadSafeFunction tsfn;
|
||||
|
||||
// Custom run function with progress callback support
|
||||
int run_with_progress(whisper_params ¶ms, std::vector<std::vector<std::string>> &result) {
|
||||
if (params.no_prints) {
|
||||
whisper_log_set(cb_log_disable, NULL);
|
||||
}
|
||||
@ -144,7 +204,6 @@ int run(whisper_params ¶ms, std::vector<std::vector<std::string>> &result) {
|
||||
}
|
||||
|
||||
// whisper init
|
||||
|
||||
struct whisper_context_params cparams = whisper_context_default_params();
|
||||
cparams.use_gpu = params.use_gpu;
|
||||
cparams.flash_attn = params.flash_attn;
|
||||
@ -155,8 +214,7 @@ int run(whisper_params ¶ms, std::vector<std::vector<std::string>> &result) {
|
||||
return 3;
|
||||
}
|
||||
|
||||
// if params.pcmf32 is provided, set params.fname_inp to "buffer"
|
||||
// this is simpler than further modifications in the code
|
||||
// If params.pcmf32 provides, set params.fname_inp as "buffer"
|
||||
if (!params.pcmf32.empty()) {
|
||||
fprintf(stderr, "info: using audio buffer as input\n");
|
||||
params.fname_inp.clear();
|
||||
@ -170,7 +228,7 @@ int run(whisper_params ¶ms, std::vector<std::vector<std::string>> &result) {
|
||||
std::vector<float> pcmf32; // mono-channel F32 PCM
|
||||
std::vector<std::vector<float>> pcmf32s; // stereo-channel F32 PCM
|
||||
|
||||
// read the input audio file if params.pcmf32 is not provided
|
||||
// If params.pcmf32 is empty, read input audio file
|
||||
if (params.pcmf32.empty()) {
|
||||
if (!::read_audio_data(fname_inp, pcmf32, pcmf32s, params.diarize)) {
|
||||
fprintf(stderr, "error: failed to read audio file '%s'\n", fname_inp.c_str());
|
||||
@ -180,14 +238,14 @@ int run(whisper_params ¶ms, std::vector<std::vector<std::string>> &result) {
|
||||
pcmf32 = params.pcmf32;
|
||||
}
|
||||
|
||||
// print system information
|
||||
// Print system info
|
||||
if (!params.no_prints) {
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "system_info: n_threads = %d / %d | %s\n",
|
||||
params.n_threads*params.n_processors, std::thread::hardware_concurrency(), whisper_print_system_info());
|
||||
}
|
||||
|
||||
// print some info about the processing
|
||||
// Print processing info
|
||||
if (!params.no_prints) {
|
||||
fprintf(stderr, "\n");
|
||||
if (!whisper_is_multilingual(ctx)) {
|
||||
@ -208,7 +266,7 @@ int run(whisper_params ¶ms, std::vector<std::vector<std::string>> &result) {
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
// run the inference
|
||||
// Run inference
|
||||
{
|
||||
whisper_full_params wparams = whisper_full_default_params(WHISPER_SAMPLING_GREEDY);
|
||||
|
||||
@ -241,17 +299,22 @@ int run(whisper_params ¶ms, std::vector<std::vector<std::string>> &result) {
|
||||
|
||||
whisper_print_user_data user_data = { ¶ms, &pcmf32s };
|
||||
|
||||
// this callback is called on each new segment
|
||||
// This callback is called for each new segment
|
||||
if (!wparams.print_realtime) {
|
||||
wparams.new_segment_callback = whisper_print_segment_callback;
|
||||
wparams.new_segment_callback_user_data = &user_data;
|
||||
}
|
||||
|
||||
// example for abort mechanism
|
||||
// in this example, we do not abort the processing, but we could if the flag is set to true
|
||||
// the callback is called before every encoder run - if it returns false, the processing is aborted
|
||||
// Set progress callback
|
||||
wparams.progress_callback = [](struct whisper_context * /*ctx*/, struct whisper_state * /*state*/, int progress, void * user_data) {
|
||||
ProgressWorker* worker = static_cast<ProgressWorker*>(user_data);
|
||||
worker->OnProgress(progress);
|
||||
};
|
||||
wparams.progress_callback_user_data = this;
|
||||
|
||||
// Abort mechanism example
|
||||
{
|
||||
static bool is_aborted = false; // NOTE: this should be atomic to avoid data race
|
||||
static bool is_aborted = false; // Note: this should be atomic to avoid data races
|
||||
|
||||
wparams.encoder_begin_callback = [](struct whisper_context * /*ctx*/, struct whisper_state * /*state*/, void * user_data) {
|
||||
bool is_aborted = *(bool*)user_data;
|
||||
@ -284,36 +347,8 @@ int run(whisper_params ¶ms, std::vector<std::vector<std::string>> &result) {
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
Callback().Call({Env().Null(), 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()) {
|
||||
@ -333,6 +368,23 @@ Napi::Value whisper(const Napi::CallbackInfo& info) {
|
||||
bool comma_in_time = whisper_params.Get("comma_in_time").As<Napi::Boolean>();
|
||||
int32_t max_len = whisper_params.Get("max_len").As<Napi::Number>();
|
||||
|
||||
// support prompt
|
||||
std::string prompt = "";
|
||||
if (whisper_params.Has("prompt") && whisper_params.Get("prompt").IsString()) {
|
||||
prompt = whisper_params.Get("prompt").As<Napi::String>();
|
||||
}
|
||||
|
||||
// Add support for print_progress
|
||||
bool print_progress = false;
|
||||
if (whisper_params.Has("print_progress")) {
|
||||
print_progress = whisper_params.Get("print_progress").As<Napi::Boolean>();
|
||||
}
|
||||
// Add support for progress_callback
|
||||
Napi::Function progress_callback;
|
||||
if (whisper_params.Has("progress_callback") && whisper_params.Get("progress_callback").IsFunction()) {
|
||||
progress_callback = whisper_params.Get("progress_callback").As<Napi::Function>();
|
||||
}
|
||||
|
||||
Napi::Value pcmf32Value = whisper_params.Get("pcmf32");
|
||||
std::vector<float> pcmf32_vec;
|
||||
if (pcmf32Value.IsTypedArray()) {
|
||||
@ -355,9 +407,12 @@ Napi::Value whisper(const Napi::CallbackInfo& info) {
|
||||
params.pcmf32 = pcmf32_vec;
|
||||
params.comma_in_time = comma_in_time;
|
||||
params.max_len = max_len;
|
||||
params.print_progress = print_progress;
|
||||
params.prompt = prompt;
|
||||
|
||||
Napi::Function callback = info[1].As<Napi::Function>();
|
||||
Worker* worker = new Worker(callback, params);
|
||||
// Create a new Worker class with progress callback support
|
||||
ProgressWorker* worker = new ProgressWorker(callback, params, progress_callback, env);
|
||||
worker->Queue();
|
||||
return env.Undefined();
|
||||
}
|
||||
|
@ -19,6 +19,9 @@ const whisperParams = {
|
||||
no_timestamps: false,
|
||||
audio_ctx: 0,
|
||||
max_len: 0,
|
||||
progress_callback: (progress) => {
|
||||
console.log(`progress: ${progress}%`);
|
||||
}
|
||||
};
|
||||
|
||||
const arguments = process.argv.slice(2);
|
||||
|
Loading…
Reference in New Issue
Block a user