Skip to main content

lc_schema/messages/
audio.rs

1// lc-schema/src/messages/audio.rs
2//! Audio content type (multimodal audio support).
3//!
4//! Supports both URL-based and base64-encoded audio content,
5//! following the same pattern as `ImageContent`.
6
7use serde::{Deserialize, Serialize};
8
9/// Audio content (URL or base64 data URI).
10///
11/// Used for audio input/output in multimodal interactions,
12/// such as speech-to-text (Whisper) and text-to-speech (TTS).
13#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
14pub struct AudioContent {
15    pub url: String,
16}
17
18impl AudioContent {
19    /// Creates from a URL.
20    pub fn from_url(url: impl Into<String>) -> Self {
21        Self { url: url.into() }
22    }
23
24    /// Creates from base64 data (auto-wraps as data URI).
25    pub fn from_base64(data: impl Into<String>) -> Self {
26        Self {
27            url: format!("data:audio/wav;base64,{}", data.into()),
28        }
29    }
30
31    /// Creates from base64 data with a specific MIME type.
32    pub fn from_base64_with_mime(data: impl Into<String>, mime: &str) -> Self {
33        Self {
34            url: format!("data:{};base64,{}", mime, data.into()),
35        }
36    }
37
38    /// Returns whether this is a base64 data URI.
39    pub fn is_base64(&self) -> bool {
40        self.url.starts_with("data:")
41    }
42
43    /// Extracts the base64 raw data (if this is a data URI).
44    pub fn base64_data(&self) -> Option<&str> {
45        self.url
46            .split_once(',')
47            .filter(|(prefix, _)| prefix.contains("base64"))
48            .map(|(_, data)| data)
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use super::*;
55
56    #[test]
57    fn test_from_url() {
58        let audio = AudioContent::from_url("https://example.com/audio.mp3");
59        assert_eq!(audio.url, "https://example.com/audio.mp3");
60        assert!(!audio.is_base64());
61    }
62
63    #[test]
64    fn test_from_base64() {
65        let audio = AudioContent::from_base64("abc123");
66        assert!(audio.is_base64());
67        assert_eq!(audio.base64_data(), Some("abc123"));
68    }
69
70    #[test]
71    fn test_from_base64_with_mime() {
72        let audio = AudioContent::from_base64_with_mime("xyz", "audio/mp3");
73        assert!(audio.url.starts_with("data:audio/mp3;base64,"));
74        assert_eq!(audio.base64_data(), Some("xyz"));
75    }
76
77    #[test]
78    fn test_url_not_base64() {
79        let audio = AudioContent::from_url("https://example.com/speech.wav");
80        assert_eq!(audio.base64_data(), None);
81    }
82}