elevenlabs_sdk/services/
forced_alignment.rs1use super::voices::{append_file_part, append_text_field, uuid_v4_simple};
23use crate::{client::ElevenLabsClient, error::Result, types::ForcedAlignmentResponse};
24
25#[derive(Debug)]
29pub struct ForcedAlignmentService<'a> {
30 client: &'a ElevenLabsClient,
31}
32
33impl<'a> ForcedAlignmentService<'a> {
34 pub(crate) const fn new(client: &'a ElevenLabsClient) -> Self {
36 Self { client }
37 }
38
39 pub async fn create(
54 &self,
55 audio_data: &[u8],
56 file_name: &str,
57 text: &str,
58 ) -> Result<ForcedAlignmentResponse> {
59 let boundary = uuid_v4_simple();
60 let mut body = Vec::new();
61
62 append_file_part(
63 &mut body,
64 &boundary,
65 "file",
66 file_name,
67 "application/octet-stream",
68 audio_data,
69 );
70 append_text_field(&mut body, &boundary, "text", text);
71
72 body.extend_from_slice(format!("--{boundary}--\r\n").as_bytes());
74
75 let content_type = format!("multipart/form-data; boundary={boundary}");
76 self.client.post_multipart("/v1/forced-alignment", body, &content_type).await
77 }
78}
79
80#[cfg(test)]
85#[expect(clippy::unwrap_used, reason = "tests use unwrap")]
86mod tests {
87 use wiremock::{
88 Mock, MockServer, ResponseTemplate,
89 matchers::{header, method, path},
90 };
91
92 use crate::{ElevenLabsClient, config::ClientConfig};
93
94 #[tokio::test]
95 async fn create_returns_alignment() {
96 let mock_server = MockServer::start().await;
97
98 Mock::given(method("POST"))
99 .and(path("/v1/forced-alignment"))
100 .and(header("xi-api-key", "test-key"))
101 .respond_with(ResponseTemplate::new(200).set_body_json(serde_json::json!({
102 "characters": [
103 {"text": "H", "start": 0.0, "end": 0.1},
104 {"text": "e", "start": 0.1, "end": 0.2},
105 {"text": "l", "start": 0.2, "end": 0.3}
106 ],
107 "words": [
108 {"text": "Hel", "start": 0.0, "end": 0.3, "loss": 0.1}
109 ],
110 "loss": 0.5
111 })))
112 .mount(&mock_server)
113 .await;
114
115 let config = ClientConfig::builder("test-key").base_url(mock_server.uri()).build();
116 let client = ElevenLabsClient::new(config).unwrap();
117
118 let audio = b"fake-audio-data";
119 let result = client.forced_alignment().create(audio, "test.mp3", "Hello").await.unwrap();
120
121 assert_eq!(result.characters.len(), 3);
122 }
123}