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    /// Audio URL or base64 data URI.
16    pub url: String,
17}
18
19impl AudioContent {
20    /// Creates from a URL.
21    pub fn from_url(url: impl Into<String>) -> Self {
22        Self { url: url.into() }
23    }
24
25    /// Creates from base64 data (auto-wraps as data URI).
26    pub fn from_base64(data: impl Into<String>) -> Self {
27        Self {
28            url: format!("data:audio/wav;base64,{}", data.into()),
29        }
30    }
31
32    /// Creates from base64 data with a specific MIME type.
33    pub fn from_base64_with_mime(data: impl Into<String>, mime: &str) -> Self {
34        Self {
35            url: format!("data:{};base64,{}", mime, data.into()),
36        }
37    }
38
39    /// Returns whether this is a base64 data URI.
40    pub fn is_base64(&self) -> bool {
41        self.url.starts_with("data:")
42    }
43
44    /// Extracts the base64 raw data (if this is a data URI).
45    pub fn base64_data(&self) -> Option<&str> {
46        self.url
47            .split_once(',')
48            .filter(|(prefix, _)| prefix.contains("base64"))
49            .map(|(_, data)| data)
50    }
51}
52
53#[cfg(test)]
54mod tests {
55    use super::*;
56
57    #[test]
58    fn test_from_url() {
59        let audio = AudioContent::from_url("https://example.com/audio.mp3");
60        assert_eq!(audio.url, "https://example.com/audio.mp3");
61        assert!(!audio.is_base64());
62    }
63
64    #[test]
65    fn test_from_base64() {
66        let audio = AudioContent::from_base64("abc123");
67        assert!(audio.is_base64());
68        assert_eq!(audio.base64_data(), Some("abc123"));
69    }
70
71    #[test]
72    fn test_from_base64_with_mime() {
73        let audio = AudioContent::from_base64_with_mime("xyz", "audio/mp3");
74        assert!(audio.url.starts_with("data:audio/mp3;base64,"));
75        assert_eq!(audio.base64_data(), Some("xyz"));
76    }
77
78    #[test]
79    fn test_url_not_base64() {
80        let audio = AudioContent::from_url("https://example.com/speech.wav");
81        assert_eq!(audio.base64_data(), None);
82    }
83}