Compare commits
2 Commits
12ddda5c0e
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| faabeebb9a | |||
| 37601b386b |
+4
-12
@@ -2,8 +2,7 @@ use anyhow::{anyhow, Context, Result};
|
|||||||
use rodio::{Decoder, OutputStream, Sink};
|
use rodio::{Decoder, OutputStream, Sink};
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::process::{Child, Command};
|
use std::process::{Child, Command};
|
||||||
use std::sync::Arc;
|
use std::sync::{Arc, Mutex};
|
||||||
use tokio::sync::Mutex;
|
|
||||||
|
|
||||||
pub struct TtsEngine {
|
pub struct TtsEngine {
|
||||||
process: Arc<Mutex<Option<Child>>>,
|
process: Arc<Mutex<Option<Child>>>,
|
||||||
@@ -17,7 +16,6 @@ impl TtsEngine {
|
|||||||
let server_url = format!("http://127.0.0.1:{}", port);
|
let server_url = format!("http://127.0.0.1:{}", port);
|
||||||
let client = reqwest::Client::new();
|
let client = reqwest::Client::new();
|
||||||
|
|
||||||
// Check if server is already running
|
|
||||||
let already_running = client
|
let already_running = client
|
||||||
.get(&format!("{}/", server_url))
|
.get(&format!("{}/", server_url))
|
||||||
.send()
|
.send()
|
||||||
@@ -82,7 +80,6 @@ impl TtsEngine {
|
|||||||
|
|
||||||
let wav_bytes = response.bytes().await?;
|
let wav_bytes = response.bytes().await?;
|
||||||
|
|
||||||
// Play audio in a blocking thread (rodio requires sync)
|
|
||||||
let bytes = wav_bytes.to_vec();
|
let bytes = wav_bytes.to_vec();
|
||||||
std::thread::spawn(move || {
|
std::thread::spawn(move || {
|
||||||
if let Ok((_stream, stream_handle)) = OutputStream::try_default() {
|
if let Ok((_stream, stream_handle)) = OutputStream::try_default() {
|
||||||
@@ -98,8 +95,8 @@ impl TtsEngine {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn stop(&self) {
|
pub fn stop(&self) {
|
||||||
if let Ok(mut guard) = self.process.lock().await {
|
if let Ok(mut guard) = self.process.lock() {
|
||||||
if let Some(ref mut child) = *guard {
|
if let Some(ref mut child) = *guard {
|
||||||
let _ = child.kill();
|
let _ = child.kill();
|
||||||
let _ = child.wait();
|
let _ = child.wait();
|
||||||
@@ -118,11 +115,6 @@ impl TtsEngine {
|
|||||||
|
|
||||||
impl Drop for TtsEngine {
|
impl Drop for TtsEngine {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
if let Ok(mut guard) = self.process.lock() {
|
self.stop();
|
||||||
if let Some(ref mut child) = *guard {
|
|
||||||
let _ = child.kill();
|
|
||||||
let _ = child.wait();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1115,7 +1115,43 @@ async fn handle_chat_clear(State(state): State<AppState>) -> Json<serde_json::Va
|
|||||||
Json(serde_json::json!({"success": true}))
|
Json(serde_json::json!({"success": true}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct TtsSpeakRequest {
|
||||||
|
text: String,
|
||||||
|
speaker: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_tts_speak(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
Json(req): Json<TtsSpeakRequest>,
|
||||||
|
) -> Json<serde_json::Value> {
|
||||||
|
let tts = match &state.tts {
|
||||||
|
Some(t) => t.clone(),
|
||||||
|
None => {
|
||||||
|
return Json(serde_json::json!({"success": false, "error": "TTS not available"}))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let speaker = req.speaker.unwrap_or_else(|| "rick".to_string());
|
||||||
|
match tts.speak(&req.text, &speaker).await {
|
||||||
|
Ok(()) => Json(serde_json::json!({"success": true})),
|
||||||
|
Err(e) => Json(serde_json::json!({"success": false, "error": e.to_string()})),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_tts_status(
|
||||||
|
State(state): State<AppState>,
|
||||||
|
) -> Json<serde_json::Value> {
|
||||||
|
let available = match &state.tts {
|
||||||
|
Some(t) => t.is_available().await,
|
||||||
|
None => false,
|
||||||
|
};
|
||||||
|
Json(serde_json::json!({"available": available}))
|
||||||
|
}
|
||||||
|
|
||||||
async fn handle_shutdown(State(state): State<AppState>) -> Json<serde_json::Value> {
|
async fn handle_shutdown(State(state): State<AppState>) -> Json<serde_json::Value> {
|
||||||
|
if let Some(tts) = &state.tts {
|
||||||
|
tts.stop();
|
||||||
|
}
|
||||||
state.shutdown.notify_one();
|
state.shutdown.notify_one();
|
||||||
Json(serde_json::json!({"success": true, "message": "Server shutting down..."}))
|
Json(serde_json::json!({"success": true, "message": "Server shutting down..."}))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"rustc_fingerprint":8393308305887522202,"outputs":{"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\USER-PC\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\npacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"cmpxchg16b\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_feature=\"sse3\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"pc\"\nwindows\n","stderr":""},"12004014463585500860":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\USER-PC\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\npacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"cmpxchg16b\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_feature=\"sse3\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"pc\"\nwindows\n","stderr":""},"4774525245087777997":{"success":true,"status":"","code":0,"stdout":"rustc 1.96.0 (ac68faa20 2026-05-25)\nbinary: rustc\ncommit-hash: ac68faa20c58cbccd01ee7208bf3b6e93a7d7f96\ncommit-date: 2026-05-25\nhost: x86_64-pc-windows-msvc\nrelease: 1.96.0\nLLVM version: 22.1.2\n","stderr":""}},"successes":{}}
|
{"rustc_fingerprint":2822674519504102369,"outputs":{"4774525245087777997":{"success":true,"status":"","code":0,"stdout":"rustc 1.96.0 (ac68faa20 2026-05-25)\nbinary: rustc\ncommit-hash: ac68faa20c58cbccd01ee7208bf3b6e93a7d7f96\ncommit-date: 2026-05-25\nhost: x86_64-pc-windows-msvc\nrelease: 1.96.0\nLLVM version: 22.1.2\n","stderr":""},"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\n___.lib\n___.dll\nC:\\Users\\USER-PC\\.rustup\\toolchains\\stable-x86_64-pc-windows-msvc\npacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"msvc\"\ntarget_family=\"windows\"\ntarget_feature=\"cmpxchg16b\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_feature=\"sse3\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"pc\"\nwindows\n","stderr":""}},"successes":{}}
|
||||||
Reference in New Issue
Block a user