Skip to main content

lc_schema/messages/
file.rs

1// lc-schema/src/messages/file.rs
2//! File content type (multimodal document/file support).
3//!
4//! Supports both URL-based and base64-encoded file content,
5//! with explicit MIME type support for diverse document formats.
6
7use serde::{Deserialize, Serialize};
8
9/// File content (URL or base64 data URI).
10///
11/// Used for document/file input in multimodal interactions,
12/// such as PDF processing or document analysis.
13#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
14pub struct FileContent {
15    /// URL or data URI for the file.
16    pub url: String,
17    /// MIME type of the file (e.g., "application/pdf", "text/csv").
18    pub mime_type: Option<String>,
19    /// Optional filename for reference.
20    pub name: Option<String>,
21}
22
23impl FileContent {
24    /// Creates from a URL.
25    pub fn from_url(url: impl Into<String>) -> Self {
26        Self {
27            url: url.into(),
28            mime_type: None,
29            name: None,
30        }
31    }
32
33    /// Creates from base64 data with an explicit MIME type.
34    pub fn from_base64(data: impl Into<String>, mime: &str) -> Self {
35        Self {
36            url: format!("data:{};base64,{}", mime, data.into()),
37            mime_type: Some(mime.to_string()),
38            name: None,
39        }
40    }
41
42    /// Creates from a URL with a known MIME type.
43    pub fn from_url_with_mime(url: impl Into<String>, mime: impl Into<String>) -> Self {
44        Self {
45            url: url.into(),
46            mime_type: Some(mime.into()),
47            name: None,
48        }
49    }
50
51    /// Sets the filename.
52    pub fn with_name(mut self, name: impl Into<String>) -> Self {
53        self.name = Some(name.into());
54        self
55    }
56
57    /// Returns whether this is a base64 data URI.
58    pub fn is_base64(&self) -> bool {
59        self.url.starts_with("data:")
60    }
61
62    /// Extracts the base64 raw data (if this is a data URI).
63    pub fn base64_data(&self) -> Option<&str> {
64        self.url
65            .split_once(',')
66            .filter(|(prefix, _)| prefix.contains("base64"))
67            .map(|(_, data)| data)
68    }
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn test_from_url() {
77        let file = FileContent::from_url("https://example.com/doc.pdf");
78        assert_eq!(file.url, "https://example.com/doc.pdf");
79        assert!(!file.is_base64());
80        assert!(file.mime_type.is_none());
81    }
82
83    #[test]
84    fn test_from_url_with_mime() {
85        let file = FileContent::from_url_with_mime("https://example.com/data.csv", "text/csv");
86        assert_eq!(file.mime_type, Some("text/csv".to_string()));
87    }
88
89    #[test]
90    fn test_from_base64() {
91        let file = FileContent::from_base64("abc123", "application/pdf");
92        assert!(file.is_base64());
93        assert_eq!(file.mime_type, Some("application/pdf".to_string()));
94        assert_eq!(file.base64_data(), Some("abc123"));
95    }
96
97    #[test]
98    fn test_with_name() {
99        let file = FileContent::from_url("https://example.com/doc.pdf").with_name("report.pdf");
100        assert_eq!(file.name, Some("report.pdf".to_string()));
101    }
102}