Skip to main content

adk_audio/tools/
speak.rs

1//! SpeakTool — synthesize text to speech via a configured TtsProvider.
2
3use std::sync::Arc;
4
5use async_trait::async_trait;
6use serde_json::Value;
7
8use crate::traits::{TtsProvider, TtsRequest};
9
10/// Tool that synthesizes text to speech audio.
11///
12/// Accepts JSON `{text, voice?, emotion?}` and returns `{duration_ms, sample_rate}`.
13pub struct SpeakTool {
14    tts: Arc<dyn TtsProvider>,
15    default_voice: String,
16}
17
18impl SpeakTool {
19    /// Create a new `SpeakTool` with the given TTS provider and default voice.
20    pub fn new(tts: Arc<dyn TtsProvider>, default_voice: impl Into<String>) -> Self {
21        Self { tts, default_voice: default_voice.into() }
22    }
23}
24
25#[async_trait]
26impl adk_core::Tool for SpeakTool {
27    fn name(&self) -> &str {
28        "speak"
29    }
30
31    fn description(&self) -> &str {
32        "Synthesize text to speech audio"
33    }
34
35    fn parameters_schema(&self) -> Option<Value> {
36        Some(serde_json::json!({
37            "type": "object",
38            "properties": {
39                "text": { "type": "string", "description": "Text to speak" },
40                "voice": { "type": "string", "description": "Voice ID (optional)" },
41                "emotion": { "type": "string", "enum": ["neutral","happy","sad","angry","whisper","excited","calm"] }
42            },
43            "required": ["text"]
44        }))
45    }
46
47    async fn execute(
48        &self,
49        _ctx: Arc<dyn adk_core::ToolContext>,
50        args: Value,
51    ) -> adk_core::Result<Value> {
52        let text = args["text"].as_str().unwrap_or_default();
53        let voice = args["voice"].as_str().unwrap_or(&self.default_voice).to_string();
54        let request = TtsRequest { text: text.into(), voice, ..Default::default() };
55        let frame = self
56            .tts
57            .synthesize(&request)
58            .await
59            .map_err(|e| adk_core::AdkError::tool(format!("speak: {e}")))?;
60        Ok(serde_json::json!({
61            "duration_ms": frame.duration_ms,
62            "sample_rate": frame.sample_rate
63        }))
64    }
65}