Skip to content
This repository was archived by the owner on Jul 30, 2025. It is now read-only.

Commit c338931

Browse files
committed
Add OpenVINO example (and rework example structure)
1 parent 0db2771 commit c338931

File tree

9 files changed

+150
-29
lines changed

9 files changed

+150
-29
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[workspace]
22
members = ["sys"]
3-
exclude = ["examples/full_usage"]
3+
exclude = ["examples/examples_common", "examples/full_usage", "examples/openvino_usage"]
44

55
[package]
66
name = "whisper-rs"
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "examples-common"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
hound = "3"
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
use hound::{SampleFormat, WavReader};
2+
use std::path::Path;
3+
4+
pub fn parse_wav_file(path: &Path) -> Vec<i16> {
5+
let reader = WavReader::open(path).expect("failed to read file");
6+
7+
if reader.spec().channels != 1 {
8+
panic!("expected mono audio file");
9+
}
10+
if reader.spec().sample_format != SampleFormat::Int {
11+
panic!("expected integer sample format");
12+
}
13+
if reader.spec().sample_rate != 16000 {
14+
panic!("expected 16KHz sample rate");
15+
}
16+
if reader.spec().bits_per_sample != 16 {
17+
panic!("expected 16 bits per sample");
18+
}
19+
20+
reader
21+
.into_samples::<i16>()
22+
.map(|x| x.expect("sample"))
23+
.collect::<Vec<_>>()
24+
}
-61.8 KB
Binary file not shown.

examples/full_usage/Cargo.toml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
[package]
22
name = "full_usage"
33
version = "0.1.0"
4-
edition = "2021"
5-
6-
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
4+
edition = "2024"
75

86
[dependencies]
9-
hound = "3"
107
whisper-rs = { path = "../.." }
8+
examples-common = { path = "../examples_common" }

examples/full_usage/src/main.rs

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,8 @@
11
#![allow(clippy::uninlined_format_args)]
22

3-
use hound::{SampleFormat, WavReader};
43
use std::path::Path;
54
use whisper_rs::{FullParams, SamplingStrategy, WhisperContext, WhisperContextParameters};
65

7-
fn parse_wav_file(path: &Path) -> Vec<i16> {
8-
let reader = WavReader::open(path).expect("failed to read file");
9-
10-
if reader.spec().channels != 1 {
11-
panic!("expected mono audio file");
12-
}
13-
if reader.spec().sample_format != SampleFormat::Int {
14-
panic!("expected integer sample format");
15-
}
16-
if reader.spec().sample_rate != 16000 {
17-
panic!("expected 16KHz sample rate");
18-
}
19-
if reader.spec().bits_per_sample != 16 {
20-
panic!("expected 16 bits per sample");
21-
}
22-
23-
reader
24-
.into_samples::<i16>()
25-
.map(|x| x.expect("sample"))
26-
.collect::<Vec<_>>()
27-
}
28-
296
fn main() {
307
let arg1 = std::env::args()
318
.nth(1)
@@ -42,7 +19,7 @@ fn main() {
4219
panic!("whisper file doesn't exist")
4320
}
4421

45-
let original_samples = parse_wav_file(audio_path);
22+
let original_samples = examples_common::parse_wav_file(audio_path);
4623
let mut samples = vec![0.0f32; original_samples.len()];
4724
whisper_rs::convert_integer_to_float_audio(&original_samples, &mut samples)
4825
.expect("failed to convert samples");

examples/openvino_usage/Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[package]
2+
name = "openvino_usage"
3+
version = "0.1.0"
4+
edition = "2024"
5+
6+
[dependencies]
7+
whisper-rs = { path = "../..", features = ["openvino"] }
8+
examples-common = { path = "../examples_common" }

examples/openvino_usage/README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# OpenVINO Usage Example
2+
3+
Run `cargo build --release` in this directory,
4+
then `./target/release/openvino_usage ../examples_common/2830-3890-0043.wav /path/to/ggml-model.bin`
5+
6+
There should be an OpenVINO file associated with the model next to it,
7+
otherwise you will get an error at runtime.
8+
9+
## Getting your paws on OpenVINO data
10+
11+
Unfortunately there's no downloads of OpenVINO state. The only way to get it is generating it.
12+
13+
Example for most Linux distros (run this from the current directory):
14+
15+
```bash
16+
cd ../..
17+
18+
# We need to pull in whisper.cpp.
19+
# This should've already been done when you cloned the repo, but let's be sure.
20+
git submodule update --init --recursive
21+
22+
cd sys/whisper.cpp/models/
23+
24+
# Generate a new venv and install the required things.
25+
# This might take a bit, grab a drink.
26+
# (yes this installs CUDA even if you don't have a Nvidia GPU, enjoy your 6GB venv setup)
27+
python3.12 -m venv venv
28+
source venv/bin/activate
29+
python3 -m pip install -U pip
30+
python3 -m pip install -r requirements-openvino.txt
31+
32+
# This is the key line. Change base as necessary to the name of the model you want.
33+
python3 convert-whisper-to-openvino.py --model base
34+
```
35+
36+
Do note a line that states
37+
`assert x.shape[1:] == self.positional_embedding.shape, "incorrect audio shape"`
38+
is not fatal.
39+
The output file will still be generated normally.
40+
41+
See upstream's README for more info: https://github.com/ggerganov/whisper.cpp/#openvino-support
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
#![allow(clippy::uninlined_format_args)]
2+
3+
use std::path::Path;
4+
use whisper_rs::{FullParams, SamplingStrategy, WhisperContext, WhisperContextParameters};
5+
6+
fn main() {
7+
let arg1 = std::env::args()
8+
.nth(1)
9+
.expect("first argument should be path to WAV file");
10+
let audio_path = Path::new(&arg1);
11+
if !audio_path.exists() {
12+
panic!("audio file doesn't exist");
13+
}
14+
let arg2 = std::env::args()
15+
.nth(2)
16+
.expect("second argument should be path to Whisper model");
17+
let whisper_path = Path::new(&arg2);
18+
if !whisper_path.exists() {
19+
panic!("whisper file doesn't exist")
20+
}
21+
22+
let original_samples = examples_common::parse_wav_file(audio_path);
23+
let mut samples = vec![0.0f32; original_samples.len()];
24+
whisper_rs::convert_integer_to_float_audio(&original_samples, &mut samples)
25+
.expect("failed to convert samples");
26+
27+
let ctx = WhisperContext::new_with_params(
28+
&whisper_path.to_string_lossy(),
29+
WhisperContextParameters::default(),
30+
)
31+
.expect("failed to open model");
32+
let mut state = ctx.create_state().expect("failed to create a model state");
33+
34+
// Enable OpenVINO now
35+
// We're expecting the OpenVINO file sitting right next to the model
36+
state
37+
.init_openvino_encoder(None, "GPU", None)
38+
.expect("failed to enable openvino");
39+
40+
let mut params = FullParams::new(SamplingStrategy::default());
41+
params.set_initial_prompt("experience");
42+
params.set_progress_callback_safe(|progress| println!("Progress callback: {}%", progress));
43+
44+
let st = std::time::Instant::now();
45+
state
46+
.full(params, &samples)
47+
.expect("failed to convert samples");
48+
let et = std::time::Instant::now();
49+
50+
let num_segments = state
51+
.full_n_segments()
52+
.expect("failed to get number of segments");
53+
for i in 0..num_segments {
54+
let segment = state
55+
.full_get_segment_text(i)
56+
.expect("failed to get segment");
57+
let start_timestamp = state
58+
.full_get_segment_t0(i)
59+
.expect("failed to get start timestamp");
60+
let end_timestamp = state
61+
.full_get_segment_t1(i)
62+
.expect("failed to get end timestamp");
63+
println!("[{} - {}]: {}", start_timestamp, end_timestamp, segment);
64+
}
65+
println!("took {}ms", (et - st).as_millis());
66+
}

0 commit comments

Comments
 (0)