Skip to content
Draft
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
605 changes: 545 additions & 60 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ members = [
"crates/buzz-pair-relay",
"crates/buzz-relay-mesh",
"crates/buzz-dev-mcp",
"crates/buzz-voice",
"examples/countdown-bot",
]
exclude = ["desktop/src-tauri"]
exclude = ["desktop/src-tauri", "crates/sherpa-onnx-sys"]
resolver = "2"

[workspace.package]
Expand Down Expand Up @@ -170,3 +171,4 @@ strip = true
# allowlist for the auth token). Revert to crates.io once #449 lands upstream.
[patch.crates-io]
aws-creds = { git = "https://github.com/tlongwell-block/rust-s3", rev = "c9fce3620dd434c1f810101d672cf384268dbb0f" }
sherpa-onnx-sys = { path = "crates/sherpa-onnx-sys" }
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ RUN apt-get update \
# locations. The normal runtime strips it below; runtime-debug retains it.
ENV CARGO_PROFILE_RELEASE_DEBUG=line-tables-only
COPY --from=planner /build/recipe.json recipe.json
# The sherpa sys patch keeps its published 1.13.4 version so Cargo can replace
# the registry crate. It is excluded from the workspace recipe because
# cargo-chef masks workspace package versions to 0.0.1.
COPY --from=planner /build/crates/sherpa-onnx-sys crates/sherpa-onnx-sys
# Cook the full workspace recipe — relay deps include workspace siblings, so
# scoping to -p buzz-relay misses transitive deps and re-builds them later.
RUN cargo chef cook --release --recipe-path recipe.json
Expand Down
3 changes: 3 additions & 0 deletions Dockerfile.push-gateway
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ RUN apt-get update \
&& apt-get install -y --no-install-recommends build-essential pkg-config libssl-dev ca-certificates \
&& rm -rf /var/lib/apt/lists/*
COPY --from=planner /build/recipe.json recipe.json
# Keep the patched sherpa sys crate at its published version; cargo-chef masks
# workspace package versions, so the patch remains outside the workspace recipe.
COPY --from=planner /build/crates/sherpa-onnx-sys crates/sherpa-onnx-sys
RUN cargo chef cook --release --recipe-path recipe.json
COPY . .
RUN cargo build --release --locked -p buzz-push-gateway --bin buzz-push-gateway \
Expand Down
1 change: 1 addition & 0 deletions Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,7 @@ test-unit:
#!/usr/bin/env bash
if command -v cargo-nextest &>/dev/null; then
cargo nextest run -p buzz-core -p buzz-auth --lib
cargo nextest run -p buzz-voice --lib
# buzz-db migrator/lint tests: pure SQL-parsing unit tests (no infra).
# They guard the embedded-migrator invariant (exactly the consolidated
# 0001; cutover/backfill stays an operator script, not startup state)
Expand Down
23 changes: 23 additions & 0 deletions crates/buzz-voice/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
[package]
name = "buzz-voice"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
repository.workspace = true
description = "Reusable local voice primitives for Buzz"

[features]
default = ["static"]
static = ["sherpa-onnx/static"]
shared = ["sherpa-onnx/shared"]

[dependencies]
ort = { version = "=2.0.0-rc.12", default-features = false, features = ["api-24", "ndarray", "std"] }
ort-sys = { version = "=2.0.0-rc.12", features = ["disable-linking"] }
rand = { workspace = true }
sentencepiece-model = "0.1"
serde = { workspace = true }
serde_json = { workspace = true }
sherpa-onnx = { version = "1.12", default-features = false }
tokenizers = { version = "0.22", default-features = false, features = ["fancy-regex"] }
75 changes: 75 additions & 0 deletions crates/buzz-voice/examples/pocket_april_onset.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
//! Generate one raw, untrimmed April Pocket TTS onset-stress clip.
//!
//! Each sentence is a separate synthesis call, making every sentence start an
//! explicit model-generation boundary. Outputs are concatenated without fades,
//! trimming, normalization, or gain; only 250 ms of digital silence is inserted
//! between calls so boundaries are easy to identify while listening.
//!
//! Usage:
//! cargo run --release -p buzz-voice --example pocket_april_onset -- \
//! <model-dir> <output.wav>

use std::path::PathBuf;

use buzz_voice::pocket::{
load_text_to_speech, load_voice_style, DEFAULT_VOICE, SAMPLE_RATE, VOICE_FILE_EXT,
};

const PASSAGE: &[&str] = &[
"Yep.",
"Hello there.",
"What happened?",
"Try this now.",
"Please check again.",
"Start with the smallest change.",
"I'm listening.",
"I've got it.",
"Sounds good to me.",
];

fn main() -> Result<(), String> {
let mut args = std::env::args().skip(1);
let model_dir = PathBuf::from(args.next().ok_or("missing model directory argument")?);
let output = PathBuf::from(args.next().ok_or("missing output WAV argument")?);
if args.next().is_some() {
return Err("unexpected extra argument".to_string());
}

let engine = load_text_to_speech(
model_dir
.to_str()
.ok_or_else(|| format!("model path is not UTF-8: {}", model_dir.display()))?,
)?;
let voice_path = model_dir.join(format!("{DEFAULT_VOICE}.{VOICE_FILE_EXT}"));
let voice = load_voice_style(&voice_path)?;
let boundary_silence = vec![0.0_f32; SAMPLE_RATE as usize / 4];
let mut combined = Vec::new();

for (index, text) in PASSAGE.iter().enumerate() {
eprintln!("boundary {}: {text}", index + 1);
let samples = engine.synth_chunk(text, "en", &voice, 1)?;
eprintln!(
" raw samples: {} ({:.3} s)",
samples.len(),
samples.len() as f32 / SAMPLE_RATE as f32
);
combined.extend_from_slice(&samples);
if index + 1 != PASSAGE.len() {
combined.extend_from_slice(&boundary_silence);
}
}

let output_str = output
.to_str()
.ok_or_else(|| format!("output path is not UTF-8: {}", output.display()))?;
if !sherpa_onnx::write(output_str, &combined, SAMPLE_RATE as i32) {
return Err(format!("could not write {}", output.display()));
}
eprintln!(
"wrote {} raw samples ({:.3} s) to {}",
combined.len(),
combined.len() as f32 / SAMPLE_RATE as f32,
output.display()
);
Ok(())
}
3 changes: 3 additions & 0 deletions crates/buzz-voice/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//! Reusable local voice primitives for Buzz.

pub mod pocket;
Loading
Loading