Spaces:
Sleeping
Sleeping
ruby : Add no_speech_thold (#2641)
Browse files* Remove Whisper::Model.[]
* Fix Whisper::Model::URI#request
* Make Whisper::Context#initialize accept pre-converted model name
* Use downloading pre-converted model feature for testing
* Update README
* Remove unnecessary task
* Move whisper/model.rb -> whisper/model/uri.rb
* Update document comment of Whisper::Context#initialize
* Don't show download progress when not tty
* Pass String to raise
* Use cache model file if download fails
* Add test for auto download
* Specify required Ruby version
* Fix a typo
* Remove unnecessary flags
* Initialize Whisper::Params#diarize explicitely
* Remove redundant code from README for simplicity
* Add Whisper::Params#no_speech_thold attribute
* Add test for Whisper::Params#no_speech_thold
- bindings/ruby/README.md +13 -14
- bindings/ruby/Rakefile +4 -10
- bindings/ruby/ext/extconf.rb +0 -5
- bindings/ruby/ext/ruby_whisper.cpp +33 -4
- bindings/ruby/lib/whisper.rb +1 -1
- bindings/ruby/lib/whisper/{model.rb → model/uri.rb} +10 -12
- bindings/ruby/tests/helper.rb +0 -1
- bindings/ruby/tests/test_callback.rb +4 -7
- bindings/ruby/tests/test_model.rb +11 -4
- bindings/ruby/tests/test_params.rb +6 -0
- bindings/ruby/tests/test_segment.rb +1 -1
- bindings/ruby/tests/test_whisper.rb +5 -5
- bindings/ruby/whispercpp.gemspec +1 -1
bindings/ruby/README.md
CHANGED
|
@@ -22,7 +22,7 @@ Usage
|
|
| 22 |
```ruby
|
| 23 |
require "whisper"
|
| 24 |
|
| 25 |
-
whisper = Whisper::Context.new(
|
| 26 |
|
| 27 |
params = Whisper::Params.new
|
| 28 |
params.language = "en"
|
|
@@ -44,17 +44,23 @@ end
|
|
| 44 |
Some models are prepared up-front:
|
| 45 |
|
| 46 |
```ruby
|
| 47 |
-
base_en = Whisper::Model["base.en"]
|
| 48 |
whisper = Whisper::Context.new(base_en)
|
| 49 |
```
|
| 50 |
|
| 51 |
At first time you use a model, it is downloaded automatically. After that, downloaded cached file is used. To clear cache, call `#clear_cache`:
|
| 52 |
|
| 53 |
```ruby
|
| 54 |
-
Whisper::Model["base"].clear_cache
|
| 55 |
```
|
| 56 |
|
| 57 |
-
You can
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
```ruby
|
| 60 |
puts Whisper::Model.preconverted_model_names
|
|
@@ -124,13 +130,6 @@ end
|
|
| 124 |
You can also add hook to params called on new segment:
|
| 125 |
|
| 126 |
```ruby
|
| 127 |
-
def format_time(time_ms)
|
| 128 |
-
sec, decimal_part = time_ms.divmod(1000)
|
| 129 |
-
min, sec = sec.divmod(60)
|
| 130 |
-
hour, min = min.divmod(60)
|
| 131 |
-
"%02d:%02d:%02d.%03d" % [hour, min, sec, decimal_part]
|
| 132 |
-
end
|
| 133 |
-
|
| 134 |
# Add hook before calling #transcribe
|
| 135 |
params.on_new_segment do |segment|
|
| 136 |
line = "[%{st} --> %{ed}] %{text}" % {
|
|
@@ -151,7 +150,7 @@ whisper.transcribe("path/to/audio.wav", params)
|
|
| 151 |
You can see model information:
|
| 152 |
|
| 153 |
```ruby
|
| 154 |
-
whisper = Whisper::Context.new(
|
| 155 |
model = whisper.model
|
| 156 |
|
| 157 |
model.n_vocab # => 51864
|
|
@@ -200,7 +199,7 @@ Using this feature, you are also able to suppress log:
|
|
| 200 |
Whisper.log_set ->(level, buffer, user_data) {
|
| 201 |
# do nothing
|
| 202 |
}, nil
|
| 203 |
-
Whisper::Context.new(
|
| 204 |
```
|
| 205 |
|
| 206 |
### Low-level API to transcribe ###
|
|
@@ -214,7 +213,7 @@ require "wavefile"
|
|
| 214 |
reader = WaveFile::Reader.new("path/to/audio.wav", WaveFile::Format.new(:mono, :float, 16000))
|
| 215 |
samples = reader.enum_for(:each_buffer).map(&:samples).flatten
|
| 216 |
|
| 217 |
-
whisper = Whisper::Context.new(
|
| 218 |
whisper.full(Whisper::Params.new, samples)
|
| 219 |
whisper.each_segment do |segment|
|
| 220 |
puts segment.text
|
|
|
|
| 22 |
```ruby
|
| 23 |
require "whisper"
|
| 24 |
|
| 25 |
+
whisper = Whisper::Context.new("base")
|
| 26 |
|
| 27 |
params = Whisper::Params.new
|
| 28 |
params.language = "en"
|
|
|
|
| 44 |
Some models are prepared up-front:
|
| 45 |
|
| 46 |
```ruby
|
| 47 |
+
base_en = Whisper::Model.pre_converted_models["base.en"]
|
| 48 |
whisper = Whisper::Context.new(base_en)
|
| 49 |
```
|
| 50 |
|
| 51 |
At first time you use a model, it is downloaded automatically. After that, downloaded cached file is used. To clear cache, call `#clear_cache`:
|
| 52 |
|
| 53 |
```ruby
|
| 54 |
+
Whisper::Model.pre_converted_models["base"].clear_cache
|
| 55 |
```
|
| 56 |
|
| 57 |
+
You also can use shorthand for pre-converted models:
|
| 58 |
+
|
| 59 |
+
```ruby
|
| 60 |
+
whisper = Whisper::Context.new("base.en")
|
| 61 |
+
```
|
| 62 |
+
|
| 63 |
+
You can see the list of prepared model names by `Whisper::Model.preconverted_models.keys`:
|
| 64 |
|
| 65 |
```ruby
|
| 66 |
puts Whisper::Model.preconverted_model_names
|
|
|
|
| 130 |
You can also add hook to params called on new segment:
|
| 131 |
|
| 132 |
```ruby
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 133 |
# Add hook before calling #transcribe
|
| 134 |
params.on_new_segment do |segment|
|
| 135 |
line = "[%{st} --> %{ed}] %{text}" % {
|
|
|
|
| 150 |
You can see model information:
|
| 151 |
|
| 152 |
```ruby
|
| 153 |
+
whisper = Whisper::Context.new("base")
|
| 154 |
model = whisper.model
|
| 155 |
|
| 156 |
model.n_vocab # => 51864
|
|
|
|
| 199 |
Whisper.log_set ->(level, buffer, user_data) {
|
| 200 |
# do nothing
|
| 201 |
}, nil
|
| 202 |
+
Whisper::Context.new("base")
|
| 203 |
```
|
| 204 |
|
| 205 |
### Low-level API to transcribe ###
|
|
|
|
| 213 |
reader = WaveFile::Reader.new("path/to/audio.wav", WaveFile::Format.new(:mono, :float, 16000))
|
| 214 |
samples = reader.enum_for(:each_buffer).map(&:samples).flatten
|
| 215 |
|
| 216 |
+
whisper = Whisper::Context.new("base")
|
| 217 |
whisper.full(Whisper::Params.new, samples)
|
| 218 |
whisper.each_segment do |segment|
|
| 219 |
puts segment.text
|
bindings/ruby/Rakefile
CHANGED
|
@@ -25,7 +25,6 @@ task build: ["ext/Makefile", "ext/ruby_whisper.h", "ext/ruby_whisper.cpp", "whis
|
|
| 25 |
directory "pkg"
|
| 26 |
CLOBBER.include "pkg"
|
| 27 |
|
| 28 |
-
TEST_MODEL = "../../models/ggml-base.en.bin"
|
| 29 |
LIB_NAME = "whisper".ext(RbConfig::CONFIG["DLEXT"])
|
| 30 |
SO_FILE = File.join("ext", LIB_NAME)
|
| 31 |
LIB_FILE = File.join("lib", LIB_NAME)
|
|
@@ -41,23 +40,17 @@ file SO_FILE => "ext/Makefile" do |t|
|
|
| 41 |
sh "make"
|
| 42 |
end
|
| 43 |
end
|
| 44 |
-
CLEAN.include
|
| 45 |
|
| 46 |
directory "lib"
|
| 47 |
file LIB_FILE => [SO_FILE, "lib"] do |t|
|
| 48 |
copy t.source, t.name
|
| 49 |
end
|
|
|
|
| 50 |
|
| 51 |
Rake::TestTask.new do |t|
|
| 52 |
t.test_files = FileList["tests/test_*.rb"]
|
| 53 |
end
|
| 54 |
-
task test: [TEST_MODEL, LIB_FILE]
|
| 55 |
-
|
| 56 |
-
file TEST_MODEL do
|
| 57 |
-
Dir.chdir "../.." do
|
| 58 |
-
sh "./models/download-ggml-model.sh base.en"
|
| 59 |
-
end
|
| 60 |
-
end
|
| 61 |
|
| 62 |
TEST_MEMORY_VIEW = "tests/jfk_reader/jfk_reader.#{RbConfig::CONFIG['DLEXT']}"
|
| 63 |
file TEST_MEMORY_VIEW => "tests/jfk_reader/jfk_reader.c" do |t|
|
|
@@ -67,4 +60,5 @@ file TEST_MEMORY_VIEW => "tests/jfk_reader/jfk_reader.c" do |t|
|
|
| 67 |
end
|
| 68 |
end
|
| 69 |
CLEAN.include "tests/jfk_reader/jfk_reader.{o,#{RbConfig::CONFIG['DLEXT']}}"
|
| 70 |
-
|
|
|
|
|
|
| 25 |
directory "pkg"
|
| 26 |
CLOBBER.include "pkg"
|
| 27 |
|
|
|
|
| 28 |
LIB_NAME = "whisper".ext(RbConfig::CONFIG["DLEXT"])
|
| 29 |
SO_FILE = File.join("ext", LIB_NAME)
|
| 30 |
LIB_FILE = File.join("lib", LIB_NAME)
|
|
|
|
| 40 |
sh "make"
|
| 41 |
end
|
| 42 |
end
|
| 43 |
+
CLEAN.include SO_FILE
|
| 44 |
|
| 45 |
directory "lib"
|
| 46 |
file LIB_FILE => [SO_FILE, "lib"] do |t|
|
| 47 |
copy t.source, t.name
|
| 48 |
end
|
| 49 |
+
CLEAN.include LIB_FILE
|
| 50 |
|
| 51 |
Rake::TestTask.new do |t|
|
| 52 |
t.test_files = FileList["tests/test_*.rb"]
|
| 53 |
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
TEST_MEMORY_VIEW = "tests/jfk_reader/jfk_reader.#{RbConfig::CONFIG['DLEXT']}"
|
| 56 |
file TEST_MEMORY_VIEW => "tests/jfk_reader/jfk_reader.c" do |t|
|
|
|
|
| 60 |
end
|
| 61 |
end
|
| 62 |
CLEAN.include "tests/jfk_reader/jfk_reader.{o,#{RbConfig::CONFIG['DLEXT']}}"
|
| 63 |
+
|
| 64 |
+
task test: [LIB_FILE, TEST_MEMORY_VIEW]
|
bindings/ruby/ext/extconf.rb
CHANGED
|
@@ -111,11 +111,6 @@ unless ENV['RISCV']
|
|
| 111 |
$MK_CFLAGS << ' -march=native -mtune=native'
|
| 112 |
$HOST_CXXFLAGS << ' -march=native -mtune=native'
|
| 113 |
end
|
| 114 |
-
|
| 115 |
-
if $UNAME_M.match? /aarch64.*/
|
| 116 |
-
$MK_CFLAGS << ' -mcpu=native'
|
| 117 |
-
$MK_CXXFLAGS << ' -mcpu=native'
|
| 118 |
-
end
|
| 119 |
else
|
| 120 |
$MK_CFLAGS << ' -march=rv64gcv -mabi=lp64d'
|
| 121 |
$MK_CXXFLAGS << ' -march=rv64gcv -mabi=lp64d'
|
|
|
|
| 111 |
$MK_CFLAGS << ' -march=native -mtune=native'
|
| 112 |
$HOST_CXXFLAGS << ' -march=native -mtune=native'
|
| 113 |
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
else
|
| 115 |
$MK_CFLAGS << ' -march=rv64gcv -mabi=lp64d'
|
| 116 |
$MK_CXXFLAGS << ' -march=rv64gcv -mabi=lp64d'
|
bindings/ruby/ext/ruby_whisper.cpp
CHANGED
|
@@ -38,6 +38,9 @@ VALUE cContext;
|
|
| 38 |
VALUE cParams;
|
| 39 |
VALUE eError;
|
| 40 |
|
|
|
|
|
|
|
|
|
|
| 41 |
static ID id_to_s;
|
| 42 |
static ID id_call;
|
| 43 |
static ID id___method__;
|
|
@@ -46,6 +49,7 @@ static ID id_length;
|
|
| 46 |
static ID id_next;
|
| 47 |
static ID id_new;
|
| 48 |
static ID id_to_path;
|
|
|
|
| 49 |
|
| 50 |
static bool is_log_callback_finalized = false;
|
| 51 |
|
|
@@ -187,6 +191,7 @@ static VALUE ruby_whisper_params_allocate(VALUE klass) {
|
|
| 187 |
ruby_whisper_params *rwp;
|
| 188 |
rwp = ALLOC(ruby_whisper_params);
|
| 189 |
rwp->params = whisper_full_default_params(WHISPER_SAMPLING_GREEDY);
|
|
|
|
| 190 |
rwp->new_segment_callback_container = rb_whisper_callback_container_allocate();
|
| 191 |
rwp->progress_callback_container = rb_whisper_callback_container_allocate();
|
| 192 |
rwp->abort_callback_container = rb_whisper_callback_container_allocate();
|
|
@@ -195,7 +200,7 @@ static VALUE ruby_whisper_params_allocate(VALUE klass) {
|
|
| 195 |
|
| 196 |
/*
|
| 197 |
* call-seq:
|
| 198 |
-
* new(
|
| 199 |
* new("path/to/model.bin") -> Whisper::Context
|
| 200 |
* new(Whisper::Model::URI.new("https://example.net/uri/of/model.bin")) -> Whisper::Context
|
| 201 |
*/
|
|
@@ -207,6 +212,11 @@ static VALUE ruby_whisper_initialize(int argc, VALUE *argv, VALUE self) {
|
|
| 207 |
rb_scan_args(argc, argv, "01", &whisper_model_file_path);
|
| 208 |
Data_Get_Struct(self, ruby_whisper, rw);
|
| 209 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 210 |
if (rb_respond_to(whisper_model_file_path, id_to_path)) {
|
| 211 |
whisper_model_file_path = rb_funcall(whisper_model_file_path, id_to_path, 0);
|
| 212 |
}
|
|
@@ -1251,6 +1261,25 @@ static VALUE ruby_whisper_params_set_logprob_thold(VALUE self, VALUE value) {
|
|
| 1251 |
rwp->params.logprob_thold = RFLOAT_VALUE(value);
|
| 1252 |
return value;
|
| 1253 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1254 |
/*
|
| 1255 |
* Sets new segment callback, called for every newly generated text segment.
|
| 1256 |
*
|
|
@@ -1347,9 +1376,6 @@ typedef struct {
|
|
| 1347 |
VALUE context;
|
| 1348 |
} ruby_whisper_model;
|
| 1349 |
|
| 1350 |
-
VALUE cSegment;
|
| 1351 |
-
VALUE cModel;
|
| 1352 |
-
|
| 1353 |
static void rb_whisper_segment_mark(ruby_whisper_segment *rws) {
|
| 1354 |
rb_gc_mark(rws->context);
|
| 1355 |
}
|
|
@@ -1740,6 +1766,7 @@ void Init_whisper() {
|
|
| 1740 |
id_next = rb_intern("next");
|
| 1741 |
id_new = rb_intern("new");
|
| 1742 |
id_to_path = rb_intern("to_path");
|
|
|
|
| 1743 |
|
| 1744 |
mWhisper = rb_define_module("Whisper");
|
| 1745 |
cContext = rb_define_class_under(mWhisper, "Context", rb_cObject);
|
|
@@ -1835,6 +1862,8 @@ void Init_whisper() {
|
|
| 1835 |
rb_define_method(cParams, "entropy_thold=", ruby_whisper_params_set_entropy_thold, 1);
|
| 1836 |
rb_define_method(cParams, "logprob_thold", ruby_whisper_params_get_logprob_thold, 0);
|
| 1837 |
rb_define_method(cParams, "logprob_thold=", ruby_whisper_params_set_logprob_thold, 1);
|
|
|
|
|
|
|
| 1838 |
|
| 1839 |
rb_define_method(cParams, "new_segment_callback=", ruby_whisper_params_set_new_segment_callback, 1);
|
| 1840 |
rb_define_method(cParams, "new_segment_callback_user_data=", ruby_whisper_params_set_new_segment_callback_user_data, 1);
|
|
|
|
| 38 |
VALUE cParams;
|
| 39 |
VALUE eError;
|
| 40 |
|
| 41 |
+
VALUE cSegment;
|
| 42 |
+
VALUE cModel;
|
| 43 |
+
|
| 44 |
static ID id_to_s;
|
| 45 |
static ID id_call;
|
| 46 |
static ID id___method__;
|
|
|
|
| 49 |
static ID id_next;
|
| 50 |
static ID id_new;
|
| 51 |
static ID id_to_path;
|
| 52 |
+
static ID id_pre_converted_models;
|
| 53 |
|
| 54 |
static bool is_log_callback_finalized = false;
|
| 55 |
|
|
|
|
| 191 |
ruby_whisper_params *rwp;
|
| 192 |
rwp = ALLOC(ruby_whisper_params);
|
| 193 |
rwp->params = whisper_full_default_params(WHISPER_SAMPLING_GREEDY);
|
| 194 |
+
rwp->diarize = false;
|
| 195 |
rwp->new_segment_callback_container = rb_whisper_callback_container_allocate();
|
| 196 |
rwp->progress_callback_container = rb_whisper_callback_container_allocate();
|
| 197 |
rwp->abort_callback_container = rb_whisper_callback_container_allocate();
|
|
|
|
| 200 |
|
| 201 |
/*
|
| 202 |
* call-seq:
|
| 203 |
+
* new("base.en") -> Whisper::Context
|
| 204 |
* new("path/to/model.bin") -> Whisper::Context
|
| 205 |
* new(Whisper::Model::URI.new("https://example.net/uri/of/model.bin")) -> Whisper::Context
|
| 206 |
*/
|
|
|
|
| 212 |
rb_scan_args(argc, argv, "01", &whisper_model_file_path);
|
| 213 |
Data_Get_Struct(self, ruby_whisper, rw);
|
| 214 |
|
| 215 |
+
VALUE pre_converted_models = rb_funcall(cModel, id_pre_converted_models, 0);
|
| 216 |
+
VALUE pre_converted_model = rb_hash_aref(pre_converted_models, whisper_model_file_path);
|
| 217 |
+
if (!NIL_P(pre_converted_model)) {
|
| 218 |
+
whisper_model_file_path = pre_converted_model;
|
| 219 |
+
}
|
| 220 |
if (rb_respond_to(whisper_model_file_path, id_to_path)) {
|
| 221 |
whisper_model_file_path = rb_funcall(whisper_model_file_path, id_to_path, 0);
|
| 222 |
}
|
|
|
|
| 1261 |
rwp->params.logprob_thold = RFLOAT_VALUE(value);
|
| 1262 |
return value;
|
| 1263 |
}
|
| 1264 |
+
/*
|
| 1265 |
+
* call-seq:
|
| 1266 |
+
* no_speech_thold -> Float
|
| 1267 |
+
*/
|
| 1268 |
+
static VALUE ruby_whisper_params_get_no_speech_thold(VALUE self) {
|
| 1269 |
+
ruby_whisper_params *rwp;
|
| 1270 |
+
Data_Get_Struct(self, ruby_whisper_params, rwp);
|
| 1271 |
+
return DBL2NUM(rwp->params.no_speech_thold);
|
| 1272 |
+
}
|
| 1273 |
+
/*
|
| 1274 |
+
* call-seq:
|
| 1275 |
+
* no_speech_thold = threshold -> threshold
|
| 1276 |
+
*/
|
| 1277 |
+
static VALUE ruby_whisper_params_set_no_speech_thold(VALUE self, VALUE value) {
|
| 1278 |
+
ruby_whisper_params *rwp;
|
| 1279 |
+
Data_Get_Struct(self, ruby_whisper_params, rwp);
|
| 1280 |
+
rwp->params.no_speech_thold = RFLOAT_VALUE(value);
|
| 1281 |
+
return value;
|
| 1282 |
+
}
|
| 1283 |
/*
|
| 1284 |
* Sets new segment callback, called for every newly generated text segment.
|
| 1285 |
*
|
|
|
|
| 1376 |
VALUE context;
|
| 1377 |
} ruby_whisper_model;
|
| 1378 |
|
|
|
|
|
|
|
|
|
|
| 1379 |
static void rb_whisper_segment_mark(ruby_whisper_segment *rws) {
|
| 1380 |
rb_gc_mark(rws->context);
|
| 1381 |
}
|
|
|
|
| 1766 |
id_next = rb_intern("next");
|
| 1767 |
id_new = rb_intern("new");
|
| 1768 |
id_to_path = rb_intern("to_path");
|
| 1769 |
+
id_pre_converted_models = rb_intern("pre_converted_models");
|
| 1770 |
|
| 1771 |
mWhisper = rb_define_module("Whisper");
|
| 1772 |
cContext = rb_define_class_under(mWhisper, "Context", rb_cObject);
|
|
|
|
| 1862 |
rb_define_method(cParams, "entropy_thold=", ruby_whisper_params_set_entropy_thold, 1);
|
| 1863 |
rb_define_method(cParams, "logprob_thold", ruby_whisper_params_get_logprob_thold, 0);
|
| 1864 |
rb_define_method(cParams, "logprob_thold=", ruby_whisper_params_set_logprob_thold, 1);
|
| 1865 |
+
rb_define_method(cParams, "no_speech_thold", ruby_whisper_params_get_no_speech_thold, 0);
|
| 1866 |
+
rb_define_method(cParams, "no_speech_thold=", ruby_whisper_params_set_no_speech_thold, 1);
|
| 1867 |
|
| 1868 |
rb_define_method(cParams, "new_segment_callback=", ruby_whisper_params_set_new_segment_callback, 1);
|
| 1869 |
rb_define_method(cParams, "new_segment_callback_user_data=", ruby_whisper_params_set_new_segment_callback_user_data, 1);
|
bindings/ruby/lib/whisper.rb
CHANGED
|
@@ -1,2 +1,2 @@
|
|
| 1 |
require "whisper.so"
|
| 2 |
-
require "whisper/model"
|
|
|
|
| 1 |
require "whisper.so"
|
| 2 |
+
require "whisper/model/uri"
|
bindings/ruby/lib/whisper/{model.rb → model/uri.rb}
RENAMED
|
@@ -1,6 +1,7 @@
|
|
| 1 |
require "whisper.so"
|
| 2 |
require "uri"
|
| 3 |
require "net/http"
|
|
|
|
| 4 |
require "pathname"
|
| 5 |
require "io/console/size"
|
| 6 |
|
|
@@ -56,9 +57,11 @@ class Whisper::Model
|
|
| 56 |
when Net::HTTPOK
|
| 57 |
download response
|
| 58 |
when Net::HTTPRedirection
|
| 59 |
-
request URI(response["location"])
|
| 60 |
else
|
| 61 |
-
|
|
|
|
|
|
|
| 62 |
end
|
| 63 |
end
|
| 64 |
end
|
|
@@ -81,6 +84,7 @@ class Whisper::Model
|
|
| 81 |
end
|
| 82 |
|
| 83 |
def show_progress(current, size)
|
|
|
|
| 84 |
return unless size
|
| 85 |
|
| 86 |
unless @prev
|
|
@@ -111,7 +115,7 @@ class Whisper::Model
|
|
| 111 |
end
|
| 112 |
end
|
| 113 |
|
| 114 |
-
@
|
| 115 |
%w[
|
| 116 |
tiny
|
| 117 |
tiny.en
|
|
@@ -137,23 +141,17 @@ class Whisper::Model
|
|
| 137 |
large-v1
|
| 138 |
large-v2
|
| 139 |
large-v2-q5_0
|
| 140 |
-
large-v2-
|
| 141 |
large-v3
|
| 142 |
large-v3-q5_0
|
| 143 |
large-v3-turbo
|
| 144 |
large-v3-turbo-q5_0
|
| 145 |
large-v3-turbo-q8_0
|
| 146 |
].each do |name|
|
| 147 |
-
@
|
| 148 |
end
|
| 149 |
|
| 150 |
class << self
|
| 151 |
-
|
| 152 |
-
@names[name]
|
| 153 |
-
end
|
| 154 |
-
|
| 155 |
-
def preconverted_model_names
|
| 156 |
-
@names.keys
|
| 157 |
-
end
|
| 158 |
end
|
| 159 |
end
|
|
|
|
| 1 |
require "whisper.so"
|
| 2 |
require "uri"
|
| 3 |
require "net/http"
|
| 4 |
+
require "time"
|
| 5 |
require "pathname"
|
| 6 |
require "io/console/size"
|
| 7 |
|
|
|
|
| 57 |
when Net::HTTPOK
|
| 58 |
download response
|
| 59 |
when Net::HTTPRedirection
|
| 60 |
+
request URI(response["location"]), headers
|
| 61 |
else
|
| 62 |
+
return if headers.key?("if-modified-since") # Use cache file
|
| 63 |
+
|
| 64 |
+
raise "#{response.code} #{response.message}\n#{response.body}"
|
| 65 |
end
|
| 66 |
end
|
| 67 |
end
|
|
|
|
| 84 |
end
|
| 85 |
|
| 86 |
def show_progress(current, size)
|
| 87 |
+
return unless $stderr.tty?
|
| 88 |
return unless size
|
| 89 |
|
| 90 |
unless @prev
|
|
|
|
| 115 |
end
|
| 116 |
end
|
| 117 |
|
| 118 |
+
@pre_converted_models = {}
|
| 119 |
%w[
|
| 120 |
tiny
|
| 121 |
tiny.en
|
|
|
|
| 141 |
large-v1
|
| 142 |
large-v2
|
| 143 |
large-v2-q5_0
|
| 144 |
+
large-v2-q8_0
|
| 145 |
large-v3
|
| 146 |
large-v3-q5_0
|
| 147 |
large-v3-turbo
|
| 148 |
large-v3-turbo-q5_0
|
| 149 |
large-v3-turbo-q8_0
|
| 150 |
].each do |name|
|
| 151 |
+
@pre_converted_models[name] = URI.new("https://huggingface.co/ggerganov/whisper.cpp/resolve/main/ggml-#{name}.bin")
|
| 152 |
end
|
| 153 |
|
| 154 |
class << self
|
| 155 |
+
attr_reader :pre_converted_models
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 156 |
end
|
| 157 |
end
|
bindings/ruby/tests/helper.rb
CHANGED
|
@@ -3,6 +3,5 @@ require "whisper"
|
|
| 3 |
require_relative "jfk_reader/jfk_reader"
|
| 4 |
|
| 5 |
class TestBase < Test::Unit::TestCase
|
| 6 |
-
MODEL = File.join(__dir__, "..", "..", "..", "models", "ggml-base.en.bin")
|
| 7 |
AUDIO = File.join(__dir__, "..", "..", "..", "samples", "jfk.wav")
|
| 8 |
end
|
|
|
|
| 3 |
require_relative "jfk_reader/jfk_reader"
|
| 4 |
|
| 5 |
class TestBase < Test::Unit::TestCase
|
|
|
|
| 6 |
AUDIO = File.join(__dir__, "..", "..", "..", "samples", "jfk.wav")
|
| 7 |
end
|
bindings/ruby/tests/test_callback.rb
CHANGED
|
@@ -1,14 +1,11 @@
|
|
| 1 |
-
|
| 2 |
-
require "whisper"
|
| 3 |
-
|
| 4 |
-
class TestCallback < Test::Unit::TestCase
|
| 5 |
-
TOPDIR = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
| 6 |
|
|
|
|
| 7 |
def setup
|
| 8 |
GC.start
|
| 9 |
@params = Whisper::Params.new
|
| 10 |
-
@whisper = Whisper::Context.new(
|
| 11 |
-
@audio = File.join(
|
| 12 |
end
|
| 13 |
|
| 14 |
def test_new_segment_callback
|
|
|
|
| 1 |
+
require_relative "helper"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
|
| 3 |
+
class TestCallback < TestBase
|
| 4 |
def setup
|
| 5 |
GC.start
|
| 6 |
@params = Whisper::Params.new
|
| 7 |
+
@whisper = Whisper::Context.new("base.en")
|
| 8 |
+
@audio = File.join(AUDIO)
|
| 9 |
end
|
| 10 |
|
| 11 |
def test_new_segment_callback
|
bindings/ruby/tests/test_model.rb
CHANGED
|
@@ -3,12 +3,12 @@ require "pathname"
|
|
| 3 |
|
| 4 |
class TestModel < TestBase
|
| 5 |
def test_model
|
| 6 |
-
whisper = Whisper::Context.new(
|
| 7 |
assert_instance_of Whisper::Model, whisper.model
|
| 8 |
end
|
| 9 |
|
| 10 |
def test_attributes
|
| 11 |
-
whisper = Whisper::Context.new(
|
| 12 |
model = whisper.model
|
| 13 |
|
| 14 |
assert_equal 51864, model.n_vocab
|
|
@@ -26,7 +26,7 @@ class TestModel < TestBase
|
|
| 26 |
end
|
| 27 |
|
| 28 |
def test_gc
|
| 29 |
-
model = Whisper::Context.new(
|
| 30 |
GC.start
|
| 31 |
|
| 32 |
assert_equal 51864, model.n_vocab
|
|
@@ -44,7 +44,7 @@ class TestModel < TestBase
|
|
| 44 |
end
|
| 45 |
|
| 46 |
def test_pathname
|
| 47 |
-
path = Pathname(
|
| 48 |
whisper = Whisper::Context.new(path)
|
| 49 |
model = whisper.model
|
| 50 |
|
|
@@ -61,4 +61,11 @@ class TestModel < TestBase
|
|
| 61 |
assert_equal 1, model.ftype
|
| 62 |
assert_equal "base", model.type
|
| 63 |
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 64 |
end
|
|
|
|
| 3 |
|
| 4 |
class TestModel < TestBase
|
| 5 |
def test_model
|
| 6 |
+
whisper = Whisper::Context.new("base.en")
|
| 7 |
assert_instance_of Whisper::Model, whisper.model
|
| 8 |
end
|
| 9 |
|
| 10 |
def test_attributes
|
| 11 |
+
whisper = Whisper::Context.new("base.en")
|
| 12 |
model = whisper.model
|
| 13 |
|
| 14 |
assert_equal 51864, model.n_vocab
|
|
|
|
| 26 |
end
|
| 27 |
|
| 28 |
def test_gc
|
| 29 |
+
model = Whisper::Context.new("base.en").model
|
| 30 |
GC.start
|
| 31 |
|
| 32 |
assert_equal 51864, model.n_vocab
|
|
|
|
| 44 |
end
|
| 45 |
|
| 46 |
def test_pathname
|
| 47 |
+
path = Pathname(Whisper::Model.pre_converted_models["base.en"].to_path)
|
| 48 |
whisper = Whisper::Context.new(path)
|
| 49 |
model = whisper.model
|
| 50 |
|
|
|
|
| 61 |
assert_equal 1, model.ftype
|
| 62 |
assert_equal "base", model.type
|
| 63 |
end
|
| 64 |
+
|
| 65 |
+
def test_auto_download
|
| 66 |
+
path = Whisper::Model.pre_converted_models["base.en"].to_path
|
| 67 |
+
|
| 68 |
+
assert_path_exist path
|
| 69 |
+
assert_equal 147964211, File.size(path)
|
| 70 |
+
end
|
| 71 |
end
|
bindings/ruby/tests/test_params.rb
CHANGED
|
@@ -151,4 +151,10 @@ class TestParams < TestBase
|
|
| 151 |
@params.logprob_thold = -0.5
|
| 152 |
assert_in_delta -0.5, @params.logprob_thold
|
| 153 |
end
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 154 |
end
|
|
|
|
| 151 |
@params.logprob_thold = -0.5
|
| 152 |
assert_in_delta -0.5, @params.logprob_thold
|
| 153 |
end
|
| 154 |
+
|
| 155 |
+
def test_no_speech_thold
|
| 156 |
+
assert_in_delta 0.6, @params.no_speech_thold
|
| 157 |
+
@params.no_speech_thold = 0.2
|
| 158 |
+
assert_in_delta 0.2, @params.no_speech_thold
|
| 159 |
+
end
|
| 160 |
end
|
bindings/ruby/tests/test_segment.rb
CHANGED
|
@@ -5,7 +5,7 @@ class TestSegment < TestBase
|
|
| 5 |
attr_reader :whisper
|
| 6 |
|
| 7 |
def startup
|
| 8 |
-
@whisper = Whisper::Context.new(
|
| 9 |
params = Whisper::Params.new
|
| 10 |
params.print_timestamps = false
|
| 11 |
@whisper.transcribe(TestBase::AUDIO, params)
|
|
|
|
| 5 |
attr_reader :whisper
|
| 6 |
|
| 7 |
def startup
|
| 8 |
+
@whisper = Whisper::Context.new("base.en")
|
| 9 |
params = Whisper::Params.new
|
| 10 |
params.print_timestamps = false
|
| 11 |
@whisper.transcribe(TestBase::AUDIO, params)
|
bindings/ruby/tests/test_whisper.rb
CHANGED
|
@@ -11,7 +11,7 @@ class TestWhisper < TestBase
|
|
| 11 |
end
|
| 12 |
|
| 13 |
def test_whisper
|
| 14 |
-
@whisper = Whisper::Context.new(
|
| 15 |
params = Whisper::Params.new
|
| 16 |
params.print_timestamps = false
|
| 17 |
|
|
@@ -25,7 +25,7 @@ class TestWhisper < TestBase
|
|
| 25 |
attr_reader :whisper
|
| 26 |
|
| 27 |
def startup
|
| 28 |
-
@whisper = Whisper::Context.new(
|
| 29 |
params = Whisper::Params.new
|
| 30 |
params.print_timestamps = false
|
| 31 |
@whisper.transcribe(TestBase::AUDIO, params)
|
|
@@ -104,7 +104,7 @@ class TestWhisper < TestBase
|
|
| 104 |
logs << [level, buffer, udata]
|
| 105 |
}
|
| 106 |
Whisper.log_set log_callback, user_data
|
| 107 |
-
Whisper::Context.new(
|
| 108 |
|
| 109 |
assert logs.length > 30
|
| 110 |
logs.each do |log|
|
|
@@ -120,7 +120,7 @@ class TestWhisper < TestBase
|
|
| 120 |
}, nil
|
| 121 |
dev = StringIO.new("")
|
| 122 |
$stderr = dev
|
| 123 |
-
Whisper::Context.new(
|
| 124 |
assert_empty dev.string
|
| 125 |
ensure
|
| 126 |
$stderr = stderr
|
|
@@ -129,7 +129,7 @@ class TestWhisper < TestBase
|
|
| 129 |
sub_test_case "full" do
|
| 130 |
def setup
|
| 131 |
super
|
| 132 |
-
@whisper = Whisper::Context.new(
|
| 133 |
@samples = File.read(AUDIO, nil, 78).unpack("s<*").collect {|i| i.to_f / 2**15}
|
| 134 |
end
|
| 135 |
|
|
|
|
| 11 |
end
|
| 12 |
|
| 13 |
def test_whisper
|
| 14 |
+
@whisper = Whisper::Context.new("base.en")
|
| 15 |
params = Whisper::Params.new
|
| 16 |
params.print_timestamps = false
|
| 17 |
|
|
|
|
| 25 |
attr_reader :whisper
|
| 26 |
|
| 27 |
def startup
|
| 28 |
+
@whisper = Whisper::Context.new("base.en")
|
| 29 |
params = Whisper::Params.new
|
| 30 |
params.print_timestamps = false
|
| 31 |
@whisper.transcribe(TestBase::AUDIO, params)
|
|
|
|
| 104 |
logs << [level, buffer, udata]
|
| 105 |
}
|
| 106 |
Whisper.log_set log_callback, user_data
|
| 107 |
+
Whisper::Context.new("base.en")
|
| 108 |
|
| 109 |
assert logs.length > 30
|
| 110 |
logs.each do |log|
|
|
|
|
| 120 |
}, nil
|
| 121 |
dev = StringIO.new("")
|
| 122 |
$stderr = dev
|
| 123 |
+
Whisper::Context.new("base.en")
|
| 124 |
assert_empty dev.string
|
| 125 |
ensure
|
| 126 |
$stderr = stderr
|
|
|
|
| 129 |
sub_test_case "full" do
|
| 130 |
def setup
|
| 131 |
super
|
| 132 |
+
@whisper = Whisper::Context.new("base.en")
|
| 133 |
@samples = File.read(AUDIO, nil, 78).unpack("s<*").collect {|i| i.to_f / 2**15}
|
| 134 |
end
|
| 135 |
|
bindings/ruby/whispercpp.gemspec
CHANGED
|
@@ -23,7 +23,7 @@ Gem::Specification.new do |s|
|
|
| 23 |
s.test_files = s.files.select {|file| file.start_with? "tests/"}
|
| 24 |
|
| 25 |
s.extensions << 'ext/extconf.rb'
|
| 26 |
-
|
| 27 |
|
| 28 |
#### Documentation and testing.
|
| 29 |
s.homepage = 'https://github.com/ggerganov/whisper.cpp'
|
|
|
|
| 23 |
s.test_files = s.files.select {|file| file.start_with? "tests/"}
|
| 24 |
|
| 25 |
s.extensions << 'ext/extconf.rb'
|
| 26 |
+
s.required_ruby_version = '>= 3.1.0'
|
| 27 |
|
| 28 |
#### Documentation and testing.
|
| 29 |
s.homepage = 'https://github.com/ggerganov/whisper.cpp'
|