From ca728e3dfc9f74110172680734f3fcdd5a1e1be8 Mon Sep 17 00:00:00 2001 From: Del Wang Date: Thu, 8 May 2025 22:38:30 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20client-kws?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/client-rust/Cargo.lock | 6 +- packages/client-rust/Cargo.toml | 11 +-- packages/client-rust/src/bin/client-kws.rs | 68 +++++++++++++++++++ .../client-rust/src/services/monitor/kws.rs | 2 +- packages/client-rust/src/utils/mod.rs | 1 + packages/client-rust/src/utils/rand.rs | 10 +++ 6 files changed, 89 insertions(+), 9 deletions(-) create mode 100644 packages/client-rust/src/bin/client-kws.rs create mode 100644 packages/client-rust/src/utils/rand.rs diff --git a/packages/client-rust/Cargo.lock b/packages/client-rust/Cargo.lock index 28ab8f9..8306e78 100644 --- a/packages/client-rust/Cargo.lock +++ b/packages/client-rust/Cargo.lock @@ -308,6 +308,7 @@ name = "open-xiaoai" version = "1.0.0" dependencies = [ "futures", + "rand", "serde", "serde_json", "tokio", @@ -385,13 +386,12 @@ checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" [[package]] name = "rand" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +checksum = "9fbfd9d094a40bf3ae768db9361049ace4c0e04a4fd6b359518bd7b73a73dd97" dependencies = [ "rand_chacha", "rand_core", - "zerocopy", ] [[package]] diff --git a/packages/client-rust/Cargo.toml b/packages/client-rust/Cargo.toml index d866aa4..b61b831 100644 --- a/packages/client-rust/Cargo.toml +++ b/packages/client-rust/Cargo.toml @@ -4,11 +4,11 @@ version = "1.0.0" edition = "2021" [profile.release] -lto = true -opt-level = "s" -codegen-units = 1 -panic = "abort" -strip = true +lto = true +opt-level = "s" +codegen-units = 1 +panic = "abort" +strip = true debug = false [workspace.metadata.cross.target.armv7-unknown-linux-gnueabihf] @@ -21,3 +21,4 @@ tokio-tungstenite = "0.26.2" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" uuid = { version = "1.15.1", features = ["v4"] } +rand = "0.9.1" diff --git a/packages/client-rust/src/bin/client-kws.rs b/packages/client-rust/src/bin/client-kws.rs new file mode 100644 index 0000000..efcba17 --- /dev/null +++ b/packages/client-rust/src/bin/client-kws.rs @@ -0,0 +1,68 @@ +use std::path::Path; + +use open_xiaoai::{ + services::monitor::kws::{KwsMonitor, KwsMonitorEvent, KWS_FILE_PATH}, + utils::{rand::pick_one, shell::run_shell}, +}; + +static KWS_REPLY_FILE_PATH: &str = "/data/open-xiaoai/kws/reply.txt"; + +async fn on_started() { + let welcome = std::env::args() + .nth(1) + .unwrap_or("自定义唤醒词已开启".to_string()); + let _ = run_shell(&format!("/usr/sbin/tts_play.sh '{}'", welcome)).await; +} + +async fn on_keyword(_keyword: String) { + println!("🔥 唤醒词: {}", _keyword); + + let mut wakeup_sounds = vec![ + "file:///usr/share/sound-vendor/AiNiRobot/wakeup_ei_01.wav".to_string(), + "file:///usr/share/sound-vendor/AiNiRobot/wakeup_zai_01.wav".to_string(), + ]; + + if Path::new(KWS_REPLY_FILE_PATH).exists() { + // 播放自定义唤醒提示音 + let content = std::fs::read_to_string(KWS_REPLY_FILE_PATH).unwrap(); + let replies = content + .split("\n") + .filter(|line| !line.trim().is_empty()) + .collect::>(); + if replies.len() > 0 { + wakeup_sounds.clear(); + wakeup_sounds.extend(replies.iter().map(|s| s.to_string())); + } + } + + let reply = pick_one(&wakeup_sounds); + let script = if reply.contains("://") { + format!("miplayer -f '{}'", reply) + } else { + format!("/usr/sbin/tts_play.sh '{}'", reply) + }; + let _ = run_shell(&script).await; + + // 唤醒 + let _ = run_shell(r#"ubus call pnshelper event_notify '{"src":1,"event":0}'"#).await; +} + +#[tokio::main] +async fn main() { + if Path::new(KWS_FILE_PATH).exists() { + on_started().await; + } + + KwsMonitor::start(|event| async move { + match event { + KwsMonitorEvent::Started => on_started().await, + KwsMonitorEvent::Keyword(keyword) => on_keyword(keyword).await, + } + Ok(()) + }) + .await; + + loop { + tokio::time::sleep(std::time::Duration::from_secs(1)).await; + } +} diff --git a/packages/client-rust/src/services/monitor/kws.rs b/packages/client-rust/src/services/monitor/kws.rs index 4113df5..e7f3bba 100644 --- a/packages/client-rust/src/services/monitor/kws.rs +++ b/packages/client-rust/src/services/monitor/kws.rs @@ -16,7 +16,7 @@ pub enum KwsMonitorEvent { pub struct KwsMonitor; -static KWS_FILE_PATH: &str = "/tmp/open-xiaoai/kws.log"; +pub static KWS_FILE_PATH: &str = "/tmp/open-xiaoai/kws.log"; static LAST_TIMESTAMP: AtomicU64 = AtomicU64::new(0); diff --git a/packages/client-rust/src/utils/mod.rs b/packages/client-rust/src/utils/mod.rs index edf7a60..24ba16a 100644 --- a/packages/client-rust/src/utils/mod.rs +++ b/packages/client-rust/src/utils/mod.rs @@ -1,3 +1,4 @@ pub mod event; pub mod shell; pub mod task; +pub mod rand; \ No newline at end of file diff --git a/packages/client-rust/src/utils/rand.rs b/packages/client-rust/src/utils/rand.rs new file mode 100644 index 0000000..3081435 --- /dev/null +++ b/packages/client-rust/src/utils/rand.rs @@ -0,0 +1,10 @@ +use rand::seq::IndexedRandom; +use std::cell::RefCell; + +thread_local! { + static RNG: RefCell = RefCell::new(rand::rng()); +} + +pub fn pick_one(items: &[T]) -> &T { + RNG.with(|rng| items.choose(&mut *rng.borrow_mut()).unwrap()) +}