Skip to main content

lc_schema/messages/
image.rs

1//! Image content type (multimodal vision support)
2
3use serde::{Deserialize, Serialize};
4
5/// Image content (URL or base64 data URI)
6///
7/// OpenAI Vision uses `image_url.url` (an https URL or a `data:image/...;base64,...` data URI);
8/// Ollama uses raw base64 bytes. This type uniformly stores the value in the `url` field,
9/// letting each provider convert it at serialization time.
10#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
11pub struct ImageContent {
12    /// Image URL or base64 data URI
13    pub url: String,
14}
15
16impl ImageContent {
17    /// Create from a URL
18    pub fn from_url(url: impl Into<String>) -> Self {
19        Self { url: url.into() }
20    }
21
22    /// Create from base64 data (auto-wrapped as a data URI)
23    pub fn from_base64(data: impl Into<String>) -> Self {
24        Self {
25            url: format!("data:image/png;base64,{}", data.into()),
26        }
27    }
28
29    /// Create from base64 data with the given MIME type
30    pub fn from_base64_with_mime(data: impl Into<String>, mime: &str) -> Self {
31        Self {
32            url: format!("data:{};base64,{}", mime, data.into()),
33        }
34    }
35
36    /// Whether this is a base64 data URI
37    pub fn is_base64(&self) -> bool {
38        self.url.starts_with("data:")
39    }
40
41    /// Extract the raw base64 data (when this is a data URI)
42    pub fn base64_data(&self) -> Option<&str> {
43        self.url
44            .split_once(',')
45            .filter(|(prefix, _)| prefix.contains("base64"))
46            .map(|(_, data)| data)
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    #[test]
55    fn test_from_url() {
56        let img = ImageContent::from_url("https://example.com/image.jpg");
57        assert_eq!(img.url, "https://example.com/image.jpg");
58        assert!(!img.is_base64());
59    }
60
61    #[test]
62    fn test_from_base64() {
63        let img = ImageContent::from_base64("abc123");
64        assert!(img.is_base64());
65        assert_eq!(img.base64_data(), Some("abc123"));
66    }
67
68    #[test]
69    fn test_from_base64_with_mime() {
70        let img = ImageContent::from_base64_with_mime("xyz", "image/jpeg");
71        assert!(img.url.starts_with("data:image/jpeg;base64,"));
72        assert_eq!(img.base64_data(), Some("xyz"));
73    }
74
75    #[test]
76    fn test_url_not_base64() {
77        let img = ImageContent::from_url("https://example.com/img.png");
78        assert_eq!(img.base64_data(), None);
79    }
80}