Files
buzz/crates/buzz-voice/tests/pocket_import_audio.rs
cls 9dfa06ffee
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
feat: import Chinese-localized Buzz source snapshot
Signed-off-by: cls_宁波本机 <908705107@qq.com>
2026-08-13 18:34:25 +08:00

134 lines
4.8 KiB
Rust

use std::{
fs,
path::{Path, PathBuf},
};
use buzz_voice::{
imported::{write_pcm16_wav, PcmStats, PocketVoiceLibrary},
pocket::{load_text_to_speech, load_voice_style, DEFAULT_VOICE, SAMPLE_RATE, VOICE_FILE_EXT},
};
const PREVIEW_TEXT: &str = "This is an objective Pocket voice preview.";
fn required_path(name: &str) -> PathBuf {
std::env::var_os(name)
.map(PathBuf::from)
.unwrap_or_else(|| panic!("{name} must point to the required local test path"))
}
fn checked_in_voice() -> PathBuf {
Path::new(env!("CARGO_MANIFEST_DIR"))
.join("../../desktop/src-tauri/resources/pocket-voices/eve.wav")
}
fn evidence_dir() -> PathBuf {
std::env::var_os("BUZZ_VOICE_EVIDENCE_DIR")
.map(PathBuf::from)
.unwrap_or_else(|| {
Path::new(env!("CARGO_MANIFEST_DIR")).join("../../target/buzz-voice-evidence")
})
}
fn synthesize(model_dir: &Path, voice_path: &Path, text: &str) -> (Vec<f32>, PcmStats) {
let engine = load_text_to_speech(
model_dir
.to_str()
.expect("Pocket model path must be valid UTF-8"),
)
.expect("load Pocket model");
let style = load_voice_style(voice_path).expect("load selected voice");
let samples = engine
.synth_chunk(text, "en", &style, 1)
.expect("synthesize preview");
let stats = PcmStats::analyze(&samples, SAMPLE_RATE);
assert!(
stats.is_non_silent(),
"generated PCM must be non-silent: {stats:?}"
);
assert!(
stats.duration_seconds > 0.2,
"generated PCM is unexpectedly short: {stats:?}"
);
(samples, stats)
}
#[test]
#[ignore = "requires BUZZ_POCKET_MODEL_DIR and runs the installed Pocket ONNX model"]
fn objective_import_synthesis_delete_and_mary_fallback() {
let model_dir = required_path("BUZZ_POCKET_MODEL_DIR");
let temp = tempfile::tempdir().expect("temporary voice workspace");
let source = temp.path().join("Imported Eve.wav");
fs::copy(checked_in_voice(), &source).expect("copy checked-in voice fixture");
let library_root = temp.path().join("library");
let library = PocketVoiceLibrary::new(&library_root);
let imported = library.import_path(&source).expect("import valid WAV");
assert_eq!(
library.find(&imported.key).expect("read selection"),
Some(imported.clone())
);
drop(library);
let relaunched = PocketVoiceLibrary::new(&library_root);
let selected = relaunched
.find(&imported.key)
.expect("reload persisted selection")
.expect("selected imported voice survived relaunch");
let imported_path = relaunched
.resolve_file(&selected)
.expect("resolve persisted imported voice");
let (imported_pcm, imported_stats) = synthesize(&model_dir, &imported_path, PREVIEW_TEXT);
let evidence = evidence_dir();
fs::create_dir_all(&evidence).expect("create evidence directory");
let imported_wav = evidence.join("imported-preview.wav");
write_pcm16_wav(&imported_wav, &imported_pcm, SAMPLE_RATE)
.expect("write imported preview evidence");
relaunched
.delete(&imported.key)
.expect("delete imported voice");
assert_eq!(
relaunched.find(&imported.key).expect("reload after delete"),
None
);
let mary_path = model_dir.join(format!("{DEFAULT_VOICE}.{VOICE_FILE_EXT}"));
assert_eq!(
mary_path.file_name().and_then(|name| name.to_str()),
Some("reference_sample.wav"),
"fallback must remain the deterministic Mary reference"
);
let (mary_pcm, mary_stats) = synthesize(&model_dir, &mary_path, PREVIEW_TEXT);
let mary_wav = evidence.join("mary-fallback-preview.wav");
write_pcm16_wav(&mary_wav, &mary_pcm, SAMPLE_RATE)
.expect("write Mary fallback preview evidence");
println!(
"{}",
serde_json::json!({
"importedKey": imported.key,
"persistence": "reloaded",
"afterDelete": "pocket:mary",
"importedPreview": {
"path": imported_wav,
"samples": imported_stats.sample_count,
"sampleRate": imported_stats.sample_rate,
"durationSeconds": imported_stats.duration_seconds,
"peak": imported_stats.peak,
"rms": imported_stats.rms,
"nonSilentSamples": imported_stats.non_silent_samples,
},
"maryFallbackPreview": {
"path": mary_wav,
"samples": mary_stats.sample_count,
"sampleRate": mary_stats.sample_rate,
"durationSeconds": mary_stats.duration_seconds,
"peak": mary_stats.peak,
"rms": mary_stats.rms,
"nonSilentSamples": mary_stats.non_silent_samples,
}
})
);
}