Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
118 commits
Select commit Hold shift + click to select a range
f3b2ed6
Add Whisper::Parakeet::Params
KitaitiMakoto Apr 20, 2026
30abb35
Add tests for Parakeet::Params
KitaitiMakoto Apr 20, 2026
703fe18
Remove unused variabel
KitaitiMakoto May 6, 2026
5555694
Add callbacks to Parakeet::Params
KitaitiMakoto May 6, 2026
f39b100
Group callback and user_data params
KitaitiMakoto May 6, 2026
f412e28
Undefine local macros
KitaitiMakoto May 6, 2026
b1dbf74
Define GetParakeetParams
KitaitiMakoto May 6, 2026
cd0e911
Remove unused variable
KitaitiMakoto May 6, 2026
d051c08
Use ITERATE_CALLBACK_PARAMS
KitaitiMakoto May 6, 2026
09eff4d
Use ITERATE_CALLBACK_PARAMS instead of ITERATE_USER_DATA_PARAMS
KitaitiMakoto May 6, 2026
1e7c734
Fix memsize
KitaitiMakoto May 6, 2026
17bd819
Remove unnecessary macros
KitaitiMakoto May 6, 2026
c589498
Simplify params registration
KitaitiMakoto May 6, 2026
105f7a8
Define Parakeet
KitaitiMakoto May 6, 2026
d051ab6
Add hook methods to Parakeet::Params
KitaitiMakoto May 6, 2026
a3515ac
Fix typo
KitaitiMakoto May 6, 2026
f55f3f3
Check callback container in GetParakeetParams
KitaitiMakoto May 6, 2026
3bae1e2
Reduce if
KitaitiMakoto May 8, 2026
8615ac8
Free parakeet_full_params
KitaitiMakoto May 8, 2026
fdaf031
Implement Parakeet::Context#initialize
KitaitiMakoto May 10, 2026
46a3a2c
Add TestParakeetContext
KitaitiMakoto May 10, 2026
2cfefa9
Add Parakeet::Segment
KitaitiMakoto May 10, 2026
6d2291d
Prevent double-free
KitaitiMakoto May 14, 2026
6bcc09b
Add Parakeet::Context#transcribe
KitaitiMakoto May 14, 2026
bb096e5
Add Parakeet::Context#each_segment
KitaitiMakoto May 14, 2026
63d3136
Define Parakeet::Segment attributes
KitaitiMakoto May 14, 2026
c2c12db
Define Parakeet::Segment#deconstruct_keys
KitaitiMakoto May 14, 2026
9941289
Add tests for Parakeet::Segment#deconstruct_keys
KitaitiMakoto May 14, 2026
ae88b19
Run Parakeet::Context#transcribe without GVL
KitaitiMakoto May 14, 2026
4f53fad
Make it to abort for Parakeet
KitaitiMakoto May 16, 2026
cc958f0
Add Parakeet.log_set
KitaitiMakoto May 16, 2026
997470c
Define Parakeet::Token
KitaitiMakoto May 18, 2026
10cf358
Define Parakeet::Segment#each_token
KitaitiMakoto May 18, 2026
94f327a
Implement some hooks of Parakeet::Params
KitaitiMakoto May 19, 2026
de505d2
Convert int to VALUE
KitaitiMakoto May 20, 2026
b3b9af6
Implement hooks for Parakeet
KitaitiMakoto May 20, 2026
fd550f7
Implement Parakeet::Context#full
KitaitiMakoto May 20, 2026
a5a6884
Add tests for Parakeet::Context#full
KitaitiMakoto May 20, 2026
13bee24
Add Parakeet to RBS
KitaitiMakoto May 20, 2026
cc143b6
Fix ruby_whisper_parakeet_params_free
KitaitiMakoto May 20, 2026
49fb119
Free ruby_whisper_parakeet_context
KitaitiMakoto May 20, 2026
451fe6b
Add tests for hooks
KitaitiMakoto May 20, 2026
1d5e7e2
Add Parakeet section to README
KitaitiMakoto May 20, 2026
ed58878
Add more attributes of Parakeet::Context
KitaitiMakoto May 20, 2026
fdd99ce
Add tests for Parakeet::Context's attributes
KitaitiMakoto May 20, 2026
9ed7a04
Update RBS
KitaitiMakoto May 20, 2026
93af6b2
Register parakeet-tdt-0.6b-v3
KitaitiMakoto May 22, 2026
cb669ef
Narrow scope of log constants
KitaitiMakoto May 22, 2026
49e6cf2
Extract activate and deactivate of log_queue
KitaitiMakoto May 22, 2026
1f713bc
Make start_log_callback_thread private
KitaitiMakoto May 22, 2026
d5e20de
Don't call start_log_callback_thread unncecessarilly
KitaitiMakoto May 22, 2026
620a78a
Early return from log_queue_enqueue when not active
KitaitiMakoto May 22, 2026
2864933
Gropu log_queue members
KitaitiMakoto May 22, 2026
ae4d63c
is_active -> is_open
KitaitiMakoto May 22, 2026
693fefd
Fix English
KitaitiMakoto May 22, 2026
b765ac4
Share parakeet full body function
KitaitiMakoto May 22, 2026
989cba6
ruby_whisper_parakeet_abort_callback_user_data -> ruby_whisper_abort_…
KitaitiMakoto May 22, 2026
6b47842
NULL check for callback containers
KitaitiMakoto May 22, 2026
c607352
Fix Parakeet.log_set
KitaitiMakoto May 22, 2026
4b29493
Omit Parakeet tests on CI
KitaitiMakoto May 26, 2026
5287ddd
Extract Whisper::LogSettable
KitaitiMakoto May 26, 2026
31d254c
Join log callback thread in a log queue function
KitaitiMakoto May 26, 2026
b6170aa
Revert Join log callback thread in a log queue function
KitaitiMakoto May 26, 2026
f792bab
Extract output methods to modules
KitaitiMakoto May 27, 2026
3569163
Move Parakeet init functions into init_parakeet()
KitaitiMakoto May 27, 2026
aaeff7f
Add output methods to Parakeet classes
KitaitiMakoto May 27, 2026
f76e8fd
Add Parakeet's output methods to RBS
KitaitiMakoto May 27, 2026
cbfe86f
Use Whisper::Output in RBS
KitaitiMakoto May 28, 2026
b536fe6
Add LogSettable to RBS
KitaitiMakoto May 28, 2026
4f4224d
Fix module Token -> class Token
KitaitiMakoto May 28, 2026
6cefb43
Add Parakeet::Model
KitaitiMakoto May 28, 2026
5937d8c
Add test for Parakeet::Model
KitaitiMakoto May 28, 2026
fc561e8
Add Parakeet::Model to RBS
KitaitiMakoto May 28, 2026
351e8c3
Move position of Parakeet::Model in RBS
KitaitiMakoto May 28, 2026
15148c7
Parakeet -> TestBase::Parakeet
KitaitiMakoto May 28, 2026
6778df2
Add Parakeet::Context#model in RBS
KitaitiMakoto May 28, 2026
3a8e427
Add Whisper::Output
KitaitiMakoto May 28, 2026
e379e85
Fix nil check
KitaitiMakoto May 28, 2026
17bf01c
Define ruby_whisper_parakeet_model_memsize
KitaitiMakoto May 28, 2026
4f7ab94
Fix order of declaration in ruby_whisper_parakeet_model_get_xxx
KitaitiMakoto May 28, 2026
07dabf2
Define Parakeet.system_info_str
KitaitiMakoto May 29, 2026
aadd368
Add test for Parakeet.system_info_str
KitaitiMakoto May 29, 2026
ff7fbfa
Add signature of Parakeet.system_info_str
KitaitiMakoto May 29, 2026
64ad435
Define Parakeet::VERSION
KitaitiMakoto May 29, 2026
b31e481
Add test for Parakeet::VERSION
KitaitiMakoto May 29, 2026
ada170a
Add signature of Parakeet::VERSION
KitaitiMakoto May 29, 2026
c6e854b
Add Parakeet::Context::Params
KitaitiMakoto May 29, 2026
9b0213f
Make Parakeet::Context.new accept Context::Params
KitaitiMakoto May 29, 2026
4468a62
Add test for Parakeet::Context.new with Context::Params
KitaitiMakoto May 29, 2026
9029d9c
Update RBS
KitaitiMakoto May 29, 2026
7172c88
Remove params from Parakeet::Params which are moved from whisper_para…
KitaitiMakoto Jun 8, 2026
cfd0dd1
Remove tests for removed params
KitaitiMakoto Jun 8, 2026
ca3a565
Make Parakeet tests follow original behavior changes
KitaitiMakoto Jun 9, 2026
5b2bdc8
Add Parakeet model shortcuts
KitaitiMakoto Jun 14, 2026
b655b3d
Alloc token data in factory instead of alloc func
KitaitiMakoto Jun 14, 2026
ee1e22a
Fix variable name
KitaitiMakoto May 28, 2026
eb2f810
Update RBS
KitaitiMakoto May 28, 2026
318f85a
Refactor log settable module
KitaitiMakoto May 31, 2026
ca2f6e7
Use log settable for Whisper
KitaitiMakoto May 31, 2026
d58055b
Address deadlock
KitaitiMakoto Jun 5, 2026
2926922
Make test follow change of log queue implementation
KitaitiMakoto Jun 5, 2026
4f784ee
Refactor to make abort callback use the same way to parakeet's way
KitaitiMakoto Jun 12, 2026
31909b8
Remove redundant structs
KitaitiMakoto Jun 12, 2026
c844b6e
Fix test name
KitaitiMakoto Jun 14, 2026
7bac5e4
Fix README
KitaitiMakoto Jun 14, 2026
6c1071f
Add missing parallel transcription
KitaitiMakoto Jun 14, 2026
b85067b
Fix test for parakeet info
KitaitiMakoto Jun 14, 2026
519d349
Remove removed params
KitaitiMakoto Jun 14, 2026
396a2e4
Wait for logs dequeued
KitaitiMakoto Jun 14, 2026
280f90f
Fix instance variable name
KitaitiMakoto Jun 14, 2026
3d2be35
Load etc feature
KitaitiMakoto Jun 14, 2026
1c0b1a2
Remove unnecessary comment
KitaitiMakoto Jun 14, 2026
da08bfc
Remove unnecessary thread safety check
KitaitiMakoto Jun 14, 2026
b3a8675
Remove outdated comment
KitaitiMakoto Jun 15, 2026
c476f90
Skip downloading model if cache exists
KitaitiMakoto Jun 16, 2026
7d05454
Change Hugging Face URI for Parakeet models
KitaitiMakoto Jun 16, 2026
e0c4daf
Bump required Ruby version to 3.3
KitaitiMakoto Jun 17, 2026
e4bcb08
Fix English
KitaitiMakoto Jun 17, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/bindings-ruby.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ jobs:
steps:
- uses: ruby/setup-ruby@afeafc3d1ab54a631816aba4c914a0081c12ff2f # v1.310.0
with:
ruby-version: '3.2'
ruby-version: '3.3'
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- run: rake test
31 changes: 31 additions & 0 deletions bindings/ruby/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,37 @@ whisper
.full(Whisper::Params.new, samples)
```

### Parakeet ###

whispercpp gem now supports NVIDIA's ASR model Parakeet.

If you want to use Parakeet instead of Whisper, the API should feel familiar.
In most cases, replace `Whisper::Context` and `Whisper::Params` with `Whisper::Parakeet::Context` and `Whisper::Parakeet::Params`, then use `#transcribe`, `#full`, `#each_segment`, and `#each_token` in the same way.

```ruby
require "whisper"

# It's useful to assign Whisper::Parakeet to top-level Parakeet constant unless you use Parakeet gem.
Parakeet = Whisper::Parakeet

parakeet = Parakeet::Context.new("path/to/model")

params = Parakeet::Params.new(
no_context: true
)

parakeet
.transcribe("path/to/audio.wav", params)
.each_segment do |segment|
puts "[#{segment.start_time} --> #{segment.end_time}] #{segment.text}"
end
```

The main differences are:

* Namespace is `Whisper::Parakeet`.
* Parakeet also supports `on_new_token` / `new_token_callback` in addition to segment and progress callbacks.

Custom context params
---------------------

Expand Down
17 changes: 16 additions & 1 deletion bindings/ruby/Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,21 @@ else
end
end

TEST_PARAKEET_MODEL = "test/fixtures/for-tests-ggml-parakeet-tdt.bin"
TEST_PARAKEET_MODEL_SRC = File.expand_path(File.join(__dir__, "..", "..", "models", "for-tests-ggml-parakeet-tdt.bin"))
TEST_PARAKEET_MODEL_DIR = TEST_PARAKEET_MODEL.pathmap("%d")
directory TEST_PARAKEET_MODEL_DIR
if File.exist? TEST_PARAKEET_MODEL_SRC
file TEST_PARAKEET_MODEL => [TEST_PARAKEET_MODEL_SRC, TEST_PARAKEET_MODEL_DIR] do |t|
symlink t.source, t.name
end
else
require "open-uri"
file TEST_PARAKEET_MODEL => TEST_PARAKEET_MODEL_DIR do |t|
File.write t.name, URI("https://github.com/ggml-org/whisper.cpp/raw/refs/heads/master/models/for-tests-ggml-parakeet-tdt.bin").read
end
end

TEST_MEMORY_VIEW = "test/jfk_reader/jfk_reader.#{RbConfig::CONFIG['DLEXT']}"
file TEST_MEMORY_VIEW => "test/jfk_reader/jfk_reader.c" do |t|
chdir "test/jfk_reader" do
Expand All @@ -93,4 +108,4 @@ file TEST_MEMORY_VIEW => "test/jfk_reader/jfk_reader.c" do |t|
end
CLEAN.include TEST_MEMORY_VIEW

task test: [LIB_FILE, TEST_MEMORY_VIEW, TEST_FIXTURE_AUDIO]
task test: [LIB_FILE, TEST_MEMORY_VIEW, TEST_FIXTURE_AUDIO, TEST_PARAKEET_MODEL]
116 changes: 36 additions & 80 deletions bindings/ruby/ext/ruby_whisper.c
Original file line number Diff line number Diff line change
@@ -1,19 +1,29 @@
#include "ruby_whisper.h"

VALUE mWhisper;
VALUE mLogSettable;
VALUE mVAD;
VALUE mParakeet;
VALUE cContext;
VALUE cParams;
VALUE cVADContext;
VALUE cVADParams;
VALUE cVADSegments;
VALUE cVADSegment;
VALUE cParakeetContext;
VALUE cParakeetContextParams;
VALUE cParakeetParams;
VALUE cParakeetSegment;
VALUE cParakeetModel;
VALUE eError;

VALUE cSegment;
VALUE cToken;
VALUE cModel;

VALUE mOutputContext;
VALUE mOutputSegment;

ID id_to_s;
ID id_call;
ID id___method__;
Expand All @@ -27,9 +37,11 @@ ID id_pre_converted_models;
ID id_coreml_compiled_models;
ID id_cache;
ID id_n_processors;

static bool is_log_callback_finalized = false;
static bool is_ruby_log_callback_present = false;
ID id_extended;
ID id_start_log_callback_thread;
ID id_log_callback_thread;
ID id_alive_p;
ID id_join;

// High level API
extern VALUE ruby_whisper_segment_allocate(VALUE klass);
Expand All @@ -45,8 +57,13 @@ extern void init_ruby_whisper_vad_params(VALUE *mVAD);
extern void init_ruby_whisper_vad_context(VALUE *mVAD);
extern void init_ruby_whisper_vad_segment(VALUE *mVAD);
extern void init_ruby_whisper_vad_segments(VALUE *mVAD);
extern void init_ruby_whisper_parakeet(VALUE *mWhisper);
extern void register_callbacks(ruby_whisper_params *rwp, VALUE *context);

static ruby_whisper_log_queue whisper_log_queue;

LOG_SETTABLE_SETUP(whisper_log_queue, mWhisper, whisper_log_set)

/*
* call-seq:
* lang_max_id -> Integer
Expand Down Expand Up @@ -102,79 +119,6 @@ static VALUE ruby_whisper_s_system_info_str(VALUE self) {
return rb_str_new2(whisper_print_system_info());
}

static VALUE ruby_whisper_s_finalize_log_callback(VALUE self, VALUE id) {
is_log_callback_finalized = true;
return Qnil;
}

typedef struct {
int level;
const char * buffer;
} call_log_callbacks_args;

static void*
call_log_callbacks(void *v_args) {
VALUE log_callback = rb_iv_get(mWhisper, "log_callback");
if (NIL_P(log_callback)) {
return NULL;
}

call_log_callbacks_args *args = (call_log_callbacks_args *)v_args;
VALUE user_data = rb_iv_get(mWhisper, "user_data");
rb_funcall(log_callback, id_call, 3, INT2NUM(args->level), rb_str_new2(args->buffer), user_data);

return NULL;
}

static void
ruby_whisper_log_callback(enum ggml_log_level level, const char * buffer, void * user_data) {
if (is_log_callback_finalized) {
return;
}
if (!is_ruby_log_callback_present) {
return;
}

call_log_callbacks_args args = {
level,
buffer,
};
if (ruby_thread_has_gvl_p()) {
call_log_callbacks((void *)&args);
} else {
rb_thread_call_with_gvl(call_log_callbacks, (void *)&args);
}
}

/*
* call-seq:
* log_set ->(level, buffer, user_data) { ... }, user_data -> nil
*/
static VALUE ruby_whisper_s_log_set(VALUE self, VALUE log_callback, VALUE user_data) {
VALUE old_callback = rb_iv_get(self, "log_callback");
if (!NIL_P(old_callback)) {
rb_undefine_finalizer(old_callback);
}

rb_iv_set(self, "log_callback", log_callback);
rb_iv_set(self, "user_data", user_data);

if (!NIL_P(log_callback)) {
VALUE finalize_log_callback = rb_funcall(mWhisper, rb_intern("method"), 1, rb_str_new2("finalize_log_callback"));
rb_define_finalizer(log_callback, finalize_log_callback);
}

if (NIL_P(log_callback)) {
whisper_log_set(NULL, NULL);
is_ruby_log_callback_present = false;
} else {
whisper_log_set(ruby_whisper_log_callback, NULL);
is_ruby_log_callback_present = true;
}

return Qnil;
}

void Init_whisper() {
id_to_s = rb_intern("to_s");
id_call = rb_intern("call");
Expand All @@ -189,9 +133,19 @@ void Init_whisper() {
id_coreml_compiled_models = rb_intern("coreml_compiled_models");
id_cache = rb_intern("cache");
id_n_processors = rb_intern("n_processors");
id_extended = rb_intern("extended");
id_start_log_callback_thread = rb_intern("start_log_callback_thread");
id_log_callback_thread = rb_intern("@log_callback_thread");
id_alive_p = rb_intern("alive?");
id_join = rb_intern("join");

mWhisper = rb_define_module("Whisper");
rb_require("whisper/log_settable");
mLogSettable = rb_path2class("Whisper::LogSettable");
mVAD = rb_define_module_under(mWhisper, "VAD");
rb_require("whisper/output");
mOutputContext = rb_path2class("Whisper::Output::Context");
mOutputSegment = rb_path2class("Whisper::Output::Segment");

rb_define_const(mWhisper, "VERSION", rb_str_new2(whisper_version()));
rb_define_const(mWhisper, "LOG_LEVEL_NONE", INT2NUM(GGML_LOG_LEVEL_NONE));
Expand Down Expand Up @@ -222,8 +176,8 @@ void Init_whisper() {
rb_define_singleton_method(mWhisper, "lang_str", ruby_whisper_s_lang_str, 1);
rb_define_singleton_method(mWhisper, "lang_str_full", ruby_whisper_s_lang_str_full, 1);
rb_define_singleton_method(mWhisper, "system_info_str", ruby_whisper_s_system_info_str, 0);
rb_define_singleton_method(mWhisper, "log_set", ruby_whisper_s_log_set, 2);
rb_define_private_method(rb_singleton_class(mWhisper), "finalize_log_callback", ruby_whisper_s_finalize_log_callback, 1);

LOG_SETTABLE_INIT(whisper_log_queue, mWhisper)

cContext = init_ruby_whisper_context(&mWhisper);
init_ruby_whisper_context_params(&cContext);
Expand All @@ -236,8 +190,10 @@ void Init_whisper() {
init_ruby_whisper_vad_segment(&mVAD);
init_ruby_whisper_vad_segments(&mVAD);
init_ruby_whisper_vad_context(&mVAD);
init_ruby_whisper_parakeet(&mWhisper);

rb_require("whisper/context");
rb_require("whisper/segment");
rb_require("whisper/model/uri");

rb_include_module(cContext, mOutputContext);
rb_include_module(cSegment, mOutputSegment);
}
Loading
Loading