rs_voice_toolkit_stt/lib.rs
1//! # STT (Speech-to-Text) Module - 语音转文本模块
2//!
3//! 这个模块提供了基于 OpenAI Whisper 模型的高质量语音识别功能,
4//! 支持文件转录、实时流式处理、语音活动检测等多种功能。
5//!
6//! ## 主要功能
7//!
8//! ### 核心特性
9//! - **高精度识别**: 基于 Whisper 模型,支持多种语言
10//! - **文件转录**: 支持多种音频格式的批量转录
11//! - **实时流式处理**: 支持音频流的实时转录
12//! - **语音活动检测**: 智能检测语音片段,提高处理效率
13//! - **多模型支持**: 支持 tiny、base、small、medium、large 等不同规模的模型
14//! - **性能监控**: 提供详细的性能指标和基准测试
15//!
16//! ### 支持的音频格式
17//! - **WAV**: 原生支持,无需转换
18//! - **MP3**: 自动转换为兼容格式
19//! - **FLAC**: 自动转换为兼容格式
20//! - **M4A**: 自动转换为兼容格式
21//! - **OGG**: 自动转换为兼容格式
22//!
23//! ## 快速开始
24//!
25//! ### 基本文件转录
26//!
27//! ```rust
28//! use rs_voice_toolkit_stt::{transcribe_file, WhisperConfig, SttError};
29//!
30//! #[tokio::main]
31//! async fn main() -> Result<(), SttError> {
32//! let model_path = "models/ggml-base.bin";
33//! let audio_path = "audio/hello.wav";
34//!
35//! // 基本转录
36//! let result = transcribe_file(model_path, audio_path).await?;
37//! println!("转录结果: {}", result.text);
38//! println!("处理时间: {:?}", result.processing_time);
39//!
40//! Ok(())
41//! }
42//! ```
43//!
44//! ### 自定义配置转录
45//!
46//! ```rust
47//! use rs_voice_toolkit_stt::{transcribe_file_with_config, WhisperConfig, SttError};
48//!
49//! #[tokio::main]
50//! async fn main() -> Result<(), SttError> {
51//! let model_path = "models/ggml-base.bin";
52//! let audio_path = "audio/hello.wav";
53//!
54//! // 自定义配置
55//! let config = WhisperConfig::new(model_path)
56//! .with_language("zh") // 指定中文
57//! .with_temperature(0.2) // 降低温度
58//! .with_vad(true) // 启用语音活动检测
59//! .with_translate(false); // 禁用翻译
60//!
61//! let result = transcribe_file_with_config(model_path, audio_path, Some(config)).await?;
62//! println!("转录结果: {}", result.text);
63//!
64//! Ok(())
65//! }
66//! ```
67//!
68//! ### 流式转录
69//!
70//! ```rust
71//! use rs_voice_toolkit_stt::{StreamingTranscriber, StreamingConfig, SttError};
72//!
73//! #[tokio::main]
74//! async fn main() -> Result<(), SttError> {
75//! let model_path = "models/ggml-base.bin";
76//!
77//! // 创建流式转录器
78//! let mut transcriber = StreamingTranscriber::new(model_path).await?;
79//!
80//! // 配置参数
81//! transcriber.set_language("auto")?;
82//! transcriber.set_task("transcribe")?;
83//! transcriber.enable_vad(true)?;
84//!
85//! // 模拟音频流处理
86//! let audio_chunks: Vec<Vec<f32>> = vec/*[音频数据块]*/;
87//!
88//! for chunk in audio_chunks {
89//! let segments = transcriber.process_audio(&chunk).await?;
90//! for segment in segments {
91//! println!("[{}s-{}s] {}", segment.start_time, segment.end_time, segment.text);
92//! }
93//! }
94//!
95//! // 获取最终结果
96//! let final_result = transcriber.finalize().await?;
97//! println!("最终转录: {}", final_result.text);
98//!
99//! Ok(())
100//! }
101//! ```
102//!
103//! ## 模型选择指南
104//!
105//! | 模型 | 大小 | 速度 | 准确度 | 适用场景 |
106//! |------|------|------|--------|----------|
107//! | tiny | ~39MB | 极快 | 一般 | 快速测试、实时应用 |
108//! | base | ~74MB | 快 | 良好 | 日常应用、平衡性能 |
109//! | small | ~244MB | 中等 | 很好 | 高要求应用 |
110//! | medium | ~769MB | 较慢 | 优秀 | 专业应用 |
111//! | large | ~1550MB | 慢 | 最佳 | 最高精度要求 |
112//!
113//! ## 性能优化
114//!
115//! ### 模型加载优化
116//! - 首次加载模型后保持实例,避免重复加载
117//! - 对于长期运行的应用,预加载常用模型
118//! - 使用模型缓存减少启动时间
119//!
120//! ### 音频处理优化
121//! - 启用 VAD (语音活动检测) 跳过静音部分
122//! - 预转换音频为 Whisper 兼容格式
123//! - 批量处理多个文件减少初始化开销
124//!
125//! ### 系统资源优化
126//! - 启用 GPU 加速 (CUDA/Vulkan/Metal)
127//! - 调整线程数以优化 CPU 使用率
128//! - 监控内存使用,避免大文件处理时的内存溢出
129//!
130//! ## 错误处理
131//!
132//! 模块提供了详细的错误类型,帮助快速定位问题:
133//!
134//! ```rust
135//! use rs_voice_toolkit_stt::{SttError, transcribe_file};
136//!
137//! match transcribe_file("model.bin", "audio.wav").await {
138//! Ok(result) => println!("转录成功: {}", result.text),
139//! Err(SttError::ModelLoadError(e)) => println!("模型加载失败: {}", e),
140//! Err(SttError::AudioProcessingError(e)) => println!("音频处理失败: {}", e),
141//! Err(SttError::WhisperError(e)) => println!("Whisper 处理失败: {}", e),
142//! Err(SttError::IoError(e)) => println!("IO 错误: {}", e),
143//! Err(e) => println!("其他错误: {}", e),
144//! }
145//! ```
146//!
147//! ## 系统要求
148//!
149//! - **内存**:
150//! - tiny 模型: ~200MB
151//! - base 模型: ~400MB
152//! - small 模型: ~800MB
153//! - medium 模型: ~1.5GB
154//! - large 模型: ~3GB
155//!
156//! - **CPU**: 支持多线程处理,推荐 4 核以上
157//! - **GPU**: 可选,支持 CUDA/Vulkan/Metal 加速
158//! - **磁盘**: 模型文件存储空间
159//!
160//! ## 注意事项
161//!
162//! - 首次使用需要下载 Whisper 模型文件
163//! - 建议在使用前验证音频文件格式
164//! - 长音频文件建议使用流式处理
165//! - 实时应用建议使用 tiny 或 base 模型
166
167// 模块导出集中于下方;避免未使用导入
168
169// 导入错误处理模块
170pub mod error;
171pub use error::{SttError, SttResult};
172
173// 导入音频处理模块
174pub mod audio;
175pub use audio::{AudioConfig, AudioData, AudioFormat};
176
177// 导入Whisper转录模块
178pub mod whisper;
179pub use whisper::{
180 transcribe_file, transcribe_file_with_config, transcribe_file_with_language,
181 transcribe_file_with_transcriber, TranscriptionResult, TranscriptionSegment, WhisperConfig,
182 WhisperTranscriber,
183};
184
185// 导入VAD模块
186pub mod vad;
187pub use vad::SimpleVad;
188
189#[cfg(test)]
190mod integration_tests {
191 use super::*;
192
193 #[tokio::test]
194 async fn test_end_to_end_transcription_on_fixture() {
195 // 定位 fixtures 模型与音频
196 let crate_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
197 let root_dir = crate_dir.parent().expect("stt crate has parent");
198 let model = root_dir.join("fixtures/models/ggml-tiny.bin");
199 let audio = root_dir.join("fixtures/audio/jfk.wav");
200
201 if !model.exists() || !audio.exists() {
202 eprintln!(
203 "跳过: 缺少 fixtures 模型或音频 ({} , {})",
204 model.display(),
205 audio.display()
206 );
207 return;
208 }
209
210 let result = transcribe_file(&model, &audio)
211 .await
212 .expect("端到端转录应成功");
213
214 assert!(!result.text.trim().is_empty(), "应产生非空文本");
215 assert!(result.audio_duration > 0);
216 }
217
218 #[tokio::test]
219 async fn test_transcription_bank_audio() {
220 // 定位 fixtures 模型与新增的bank_audio.m4a音频文件
221 let crate_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
222 let root_dir = crate_dir.parent().expect("stt crate has parent");
223 // 测试多个模型
224 let models = [
225 "ggml-tiny.bin",
226 "ggml-small.bin",
227 "ggml-medium.bin"
228 ];
229 let audio = root_dir.join("fixtures/audio/bank_audio.m4a");
230
231 if !audio.exists() {
232 eprintln!("跳过: 缺少音频文件: {}", audio.display());
233 return;
234 }
235
236 for model_name in models {
237 let model = root_dir.join("fixtures/models/").join(model_name);
238
239 if !model.exists() {
240 println!("跳过: 缺少模型文件: {}", model.display());
241 continue;
242 }
243
244 println!("\n开始测试bank_audio.m4a文件的转录,使用模型: {}", model.display());
245
246 // 方法1: 使用默认配置
247 let default_result = transcribe_file(&model, &audio).await;
248 println!("默认配置结果: {}", default_result.as_ref().map(|r| &r.text).unwrap_or(&String::from("失败")));
249
250 // 方法2: 明确指定语言为中文
251 let with_lang_result = transcribe_file_with_language(&model, &audio, "zh").await;
252 println!("指定中文结果: {}", with_lang_result.as_ref().map(|r| &r.text).unwrap_or(&String::from("失败")));
253
254 // 方法3: 自定义配置 - 降低置信度要求,适合不太清晰的音频
255 let custom_config = WhisperConfig::new(&model)
256 .with_language("zh")
257 .with_temperature(0.2) // 增加温度可能提高识别率
258 .with_vad(false); // 禁用VAD可能有助于捕获所有语音
259
260 let custom_result = transcribe_file_with_config(&model, &audio, Some(custom_config)).await;
261 println!("自定义配置结果: {}", custom_result.as_ref().map(|r| &r.text).unwrap_or(&String::from("失败")));
262 }
263 }
264
265 #[tokio::test]
266 async fn test_different_models_on_bank_audio() {
267 // 测试不同模型在同一音频上的表现
268 let crate_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR"));
269 let root_dir = crate_dir.parent().expect("stt crate has parent");
270 let audio = root_dir.join("fixtures/audio/bank_audio.m4a");
271
272 if !audio.exists() {
273 eprintln!("跳过: 缺少音频文件: {}", audio.display());
274 return;
275 }
276
277 // 尝试的模型列表
278 let models_to_test = [
279 "ggml-tiny.bin",
280 "ggml-small.bin",
281 "ggml-medium.bin",
282 ];
283
284 for model_name in models_to_test {
285 let model = root_dir.join("fixtures/models/").join(model_name);
286
287 if !model.exists() {
288 println!("跳过: 缺少模型文件: {}", model.display());
289 continue;
290 }
291
292 println!("\n测试模型: {}", model_name);
293 match transcribe_file(&model, &audio).await {
294 Ok(result) => {
295 println!(" 转录结果: {}", result.text);
296 println!(" 音频时长: {}毫秒", result.audio_duration);
297 println!(" 处理时长: {}毫秒", result.processing_time);
298 println!(" 实时因子: {:.2}x", result.real_time_factor());
299 println!(" 检测到的语言: {:?}", result.language);
300 println!(" 分段数量: {}", result.segments.len());
301 },
302 Err(err) => {
303 println!(" 转录失败: {}", err);
304 }
305 }
306 }
307 }
308}
309
310// 导入流式转录模块
311#[cfg(feature = "streaming")]
312pub mod streaming;
313#[cfg(feature = "streaming")]
314pub use streaming::{
315 create_custom_streaming_transcriber, create_streaming_transcriber, StreamingConfig,
316 StreamingEvent, StreamingTranscriber,
317};