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

basic ruby bindings using fiddle ffi #1309

Open
wants to merge 1 commit 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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions ruby/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pkg
vosk-model-small-en-us-0.15
Gemfile.lock
1 change: 1 addition & 0 deletions ruby/.rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--require spec_helper
24 changes: 24 additions & 0 deletions ruby/.rubocop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
---
AllCops:
TargetRubyVersion: 2.6
NewCops: enable

require:
- rubocop-rspec
- rubocop-performance
- rubocop-rake
- rubocop-packaging

Style/StringLiterals:
Enabled: true
EnforcedStyle: double_quotes

Style/StringLiteralsInInterpolation:
Enabled: true
EnforcedStyle: double_quotes

Layout/LineLength:
Max: 80

Style/Documentation:
Enabled: false
12 changes: 12 additions & 0 deletions ruby/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

source "https://rubygems.org"
gemspec

gem "rake", "~> 13.0"
gem "rspec", "~> 3.12"
gem "rubocop", "~> 1.48"
gem "rubocop-packaging", "~> 0.5.2"
gem "rubocop-performance", "~> 1.16"
gem "rubocop-rake", "~> 0.6.0"
gem "rubocop-rspec", "~> 2.19"
55 changes: 55 additions & 0 deletions ruby/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
# Vosk

Ruby bindings to [vosk-api](https://github.com/alphacep/vosk-api) using [fiddle](https://github.com/ruby/fiddle).

## Installation

Add this line to your application's Gemfile:

```ruby
gem 'vosk'
```

Or, to install the gem using `git`:

```ruby
gem "vosk",
git: "https://github.com/alphacep/vosk-api",
glob: "ruby/vosk.gemspec"
```

And then execute:

```
bundle install
```

Or install it yourself as:
```
gem install vosk
```

## Usage

```
git clone https://github.com/alphacep/vosk-api
cd vosk-api/ruby
bundle
bundle exec ruby examples/transcribe.rb
```

See [examples/transcribe.rb](examples/transcribe.rb) for more info.

## Development

After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).

## Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/alphacep/vosk-api.

## License

The gem is available as open source under the terms of the [Apache-2.0](https://opensource.org/license/apache-2-0/) license.
14 changes: 14 additions & 0 deletions ruby/Rakefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# frozen_string_literal: true

require "bundler/gem_tasks"
require "rspec/core/rake_task"
require "rake/clean"
require "rubocop/rake_task"

CLEAN.include "pkg", "vosk-model-small-en-us-0.15"

RSpec::Core::RakeTask.new(:spec)

RuboCop::RakeTask.new(:lint)

task default: %i[build lint spec]
15 changes: 15 additions & 0 deletions ruby/bin/console
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#!/usr/bin/env ruby
# frozen_string_literal: true

require "bundler/setup"
require "vosk"

# You can add fixtures and/or initialization code here to make experimenting
# with your gem easier. You can also use a different console, if you like.

# (If you use this, don't forget to add pry to your Gemfile!)
# require "pry"
# Pry.start

require "irb"
IRB.start(__FILE__)
8 changes: 8 additions & 0 deletions ruby/bin/setup
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
set -vx

bundle install

# Do any other automated setup that you need to do here
32 changes: 32 additions & 0 deletions ruby/examples/transcribe.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true

require "vosk"
require "json"
require "net/http"

MODEL = "vosk-model-small-en-us-0.15"

unless File.directory?(MODEL)
puts "Downloading #{MODEL}..."
model_zip = Net::HTTP.get(URI("https://alphacephei.com/vosk/models/#{MODEL}.zip"))
File.binwrite("model.zip", model_zip)
system "unzip model.zip", exception: true
File.delete("model.zip")
puts "Done"
end

# Vosk::FFI.vosk_set_log_level(-1)

model = Vosk::FFI.vosk_model_new(MODEL)
recognizer = Vosk::FFI.vosk_recognizer_new(model, 16_000.0)

file = File.open("../python/example/test.wav", "r")
file.seek 44, IO::SEEK_SET

audio = file.read

Vosk::FFI.vosk_recognizer_accept_waveform(recognizer, audio, audio.size)

result = Vosk::FFI.vosk_recognizer_final_result(recognizer).to_s

puts JSON.parse(result)
10 changes: 6 additions & 4 deletions ruby/lib/vosk.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
class Vosk
def self.hi
puts "Hello world!"
end
# frozen_string_literal: true

module Vosk
end

require_relative "vosk/version"
require_relative "vosk/ffi"
38 changes: 38 additions & 0 deletions ruby/lib/vosk/ffi.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# frozen_string_literal: true

require "fiddle"
require "fiddle/import"
require "rbconfig"

module Vosk
module FFI
extend Fiddle::Importer

begin
lib = "libvosk.#{RbConfig::CONFIG["SOEXT"]}"
dlload(lib)
rescue Fiddle::DLError => e
abort <<~MSG
Could not find `#{lib}`.

Install Vosk-api, then try again.

Error: #{e&.cause&.message || e&.message || e.inspect}
MSG
end

# rubocop:disable Layout/LineLength

extern "VoskModel *vosk_model_new(const char *model_path);"
extern "VoskRecognizer *vosk_recognizer_new(VoskModel *model, float sample_rate);"
extern "int vosk_recognizer_accept_waveform(VoskRecognizer *recognizer, const char *data, int length);"
extern "const char *vosk_recognizer_result(VoskRecognizer *recognizer);"
extern "const char *vosk_recognizer_final_result(VoskRecognizer *recognizer);"
extern "void vosk_recognizer_reset(VoskRecognizer *recognizer);"
extern "void vosk_recognizer_free(VoskRecognizer *recognizer);"
extern "void vosk_model_free(VoskModel *model);"
extern "void vosk_set_log_level(int log_level);"

# rubocop:enable Layout/LineLength
end
end
5 changes: 5 additions & 0 deletions ruby/lib/vosk/version.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# frozen_string_literal: true

module Vosk
VERSION = "0.3.45"
end
11 changes: 11 additions & 0 deletions ruby/spec/spec_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

RSpec.configure do |config|
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
config.disable_monkey_patching!
config.warnings = true
config.order = :random
Kernel.srand config.seed
end
21 changes: 21 additions & 0 deletions ruby/spec/vosk/ffi_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

require "vosk/ffi"

RSpec.describe Vosk::FFI do
%w[
vosk_model_new
vosk_recognizer_new
vosk_recognizer_accept_waveform
vosk_recognizer_result
vosk_recognizer_final_result
vosk_recognizer_reset
vosk_recognizer_free
vosk_model_free
vosk_set_log_level
].each do |method|
it ".#{method}" do
expect(described_class).to respond_to(method)
end
end
end
9 changes: 9 additions & 0 deletions ruby/spec/vosk_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# frozen_string_literal: true

require "vosk"

RSpec.describe Vosk do
it "has a version number" do
expect(Vosk::VERSION).to eq("0.3.45")
end
end
19 changes: 13 additions & 6 deletions ruby/vosk.gemspec
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
# frozen_string_literal: true

require_relative "lib/vosk/version"

Gem::Specification.new do |s|
s.name = "vosk"
s.version = "0.3.45"
s.version = Vosk::VERSION
s.summary = "Offline speech recognition API"
s.description = "Vosk is an offline open source speech recognition toolkit. It enables speech recognition for 20+ languages and dialects - English, Indian English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish, Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi, Filipino, Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech, Polish. More to come."
s.description = "Vosk is an offline open source speech recognition toolkit. It enables speech recognition for 20+ languages and dialects - English, Indian English, German, French, Spanish, Portuguese, Chinese, Russian, Turkish, Vietnamese, Italian, Dutch, Catalan, Arabic, Greek, Farsi, Filipino, Ukrainian, Kazakh, Swedish, Japanese, Esperanto, Hindi, Czech, Polish. More to come." # rubocop:disable Layout/LineLength
s.authors = ["Alpha Cephei Inc"]
s.email = "[email protected]"
s.files = ["lib/vosk.rb"]
s.homepage =
"https://rubygems.org/gems/vosk"
s.license = "Apache 2.0"
s.files = Dir.glob("lib/**/*.rb")
s.homepage = "https://rubygems.org/gems/vosk"
s.license = "Apache 2.0"
s.required_ruby_version = ">= 2.6.0"
s.metadata["homepage_uri"] = "https://github.com/alphacep/vosk-api"
s.metadata["source_code_uri"] = "https://github.com/alphacep/vosk-api"
s.metadata["rubygems_mfa_required"] = "true"
end