use open_xiaoai::services::connect::message::MessageManager; use open_xiaoai::services::connect::rpc::RPC; use open_xiaoai::services::audio::config::AudioConfig; use pyo3::prelude::*; use pyo3::types::PyBytes; use serde_json::json; use server::AppServer; pub mod macros; pub mod python; pub mod server; #[pyfunction] fn on_output_data(py: Python, data: Py) -> PyResult> { let bytes = data.as_bytes(py).to_vec(); pyo3_async_runtimes::tokio::future_into_py(py, async move { let _ = MessageManager::instance() .send_stream("play", bytes, None) .await; Ok(()) }) } #[pyfunction] fn start_server(py: Python) -> PyResult> { pyo3_async_runtimes::tokio::future_into_py(py, async { AppServer::run().await; Ok(()) }) } #[pyfunction] fn run_shell(py: Python, script: String, timeout_millis: f64) -> PyResult> { pyo3_async_runtimes::tokio::future_into_py(py, async move { let res = RPC::instance() .call_remote("run_shell", Some(json!(script)), Some(timeout_millis as u64)) .await; let result = match res { Err(e) => format!("run_shell error: {}", e), Ok(res) => match res.data { Some(data) => serde_json::to_string(&data).unwrap_or_default(), None => String::new(), }, }; Ok(result) }) } #[pyfunction] fn start_recording(py: Python, config_json: Option) -> PyResult> { pyo3_async_runtimes::tokio::future_into_py(py, async move { let config = config_json .and_then(|text| serde_json::from_str::(&text).ok()); let res = RPC::instance() .call_remote("start_recording", config.map(|c| json!(c)), None) .await; Ok(match res { Ok(_) => true, Err(_) => false, }) }) } #[pyfunction] fn stop_recording(py: Python) -> PyResult> { pyo3_async_runtimes::tokio::future_into_py(py, async move { let res = RPC::instance().call_remote("stop_recording", None, None).await; Ok(match res { Ok(_) => true, Err(_) => false, }) }) } #[pyfunction] fn start_play(py: Python, config_json: Option) -> PyResult> { pyo3_async_runtimes::tokio::future_into_py(py, async move { let config = config_json .and_then(|text| serde_json::from_str::(&text).ok()); let res = RPC::instance() .call_remote("start_play", config.map(|c| json!(c)), None) .await; Ok(match res { Ok(_) => true, Err(_) => false, }) }) } #[pyfunction] fn stop_play(py: Python) -> PyResult> { pyo3_async_runtimes::tokio::future_into_py(py, async move { let res = RPC::instance().call_remote("stop_play", None, None).await; Ok(match res { Ok(_) => true, Err(_) => false, }) }) } #[pymodule] fn open_xiaoai_server(_py: Python, m: Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(start_server, &m)?)?; m.add_function(wrap_pyfunction!(on_output_data, &m)?)?; m.add_function(wrap_pyfunction!(run_shell, &m)?)?; m.add_function(wrap_pyfunction!(start_recording, &m)?)?; m.add_function(wrap_pyfunction!(stop_recording, &m)?)?; m.add_function(wrap_pyfunction!(start_play, &m)?)?; m.add_function(wrap_pyfunction!(stop_play, &m)?)?; crate::python::init_module(&m)?; Ok(()) }