voice_echo/pipeline/
bridge.rs1use serde_json::json;
2
3pub struct BridgeClient {
7 url: String,
8 caller_name: String,
9 client: reqwest::Client,
10}
11
12impl BridgeClient {
13 pub fn new(bridge_url: &str, caller_name: String) -> Self {
14 Self {
15 url: format!("{}/chat", bridge_url.trim_end_matches('/')),
16 caller_name,
17 client: reqwest::Client::new(),
18 }
19 }
20
21 pub async fn send(
26 &self,
27 call_sid: &str,
28 transcript: &str,
29 context: Option<&str>,
30 ) -> Result<String, BridgeError> {
31 let mut metadata = json!({
32 "call_sid": call_sid,
33 });
34 if let Some(ctx) = context {
35 metadata["context"] = json!(ctx);
36 }
37
38 let body = json!({
39 "channel": "voice",
40 "sender": self.caller_name,
41 "message": transcript,
42 "metadata": metadata,
43 });
44
45 let resp = self
46 .client
47 .post(&self.url)
48 .json(&body)
49 .send()
50 .await
51 .map_err(|e| BridgeError::Request(e.to_string()))?;
52
53 if !resp.status().is_success() {
54 let status = resp.status();
55 let body = resp.text().await.unwrap_or_default();
56 return Err(BridgeError::Response(format!("HTTP {status}: {body}")));
57 }
58
59 let parsed: serde_json::Value = resp
60 .json()
61 .await
62 .map_err(|e| BridgeError::Parse(e.to_string()))?;
63
64 parsed
65 .get("response")
66 .and_then(|v| v.as_str())
67 .map(String::from)
68 .ok_or_else(|| BridgeError::Parse("Missing 'response' field".into()))
69 }
70}
71
72#[derive(Debug, thiserror::Error)]
73pub enum BridgeError {
74 #[error("Bridge request failed: {0}")]
75 Request(String),
76 #[error("Bridge returned error: {0}")]
77 Response(String),
78 #[error("Failed to parse bridge response: {0}")]
79 Parse(String),
80}