replicate_client/models/
file.rs

1//! File handling types for inputs and outputs.
2
3use bytes::Bytes;
4use serde::{Deserialize, Serialize};
5use std::path::{Path, PathBuf};
6
7/// Represents different ways to provide file input to a model.
8#[derive(Debug, Clone)]
9pub enum FileInput {
10    /// A URL to a publicly accessible file
11    Url(String),
12    /// A local file path
13    Path(PathBuf),
14    /// Raw bytes with optional filename and content type
15    Bytes {
16        data: Bytes,
17        filename: Option<String>,
18        content_type: Option<String>,
19    },
20}
21
22impl FileInput {
23    /// Create a file input from a URL
24    pub fn from_url(url: impl Into<String>) -> Self {
25        Self::Url(url.into())
26    }
27
28    /// Create a file input from a local path
29    pub fn from_path(path: impl AsRef<Path>) -> Self {
30        Self::Path(path.as_ref().to_path_buf())
31    }
32
33    /// Create a file input from raw bytes
34    pub fn from_bytes(data: impl Into<Bytes>) -> Self {
35        Self::Bytes {
36            data: data.into(),
37            filename: None,
38            content_type: None,
39        }
40    }
41
42    /// Create a file input from bytes with metadata
43    pub fn from_bytes_with_metadata(
44        data: impl Into<Bytes>,
45        filename: Option<String>,
46        content_type: Option<String>,
47    ) -> Self {
48        Self::Bytes {
49            data: data.into(),
50            filename,
51            content_type,
52        }
53    }
54
55    /// Check if this is a URL input
56    pub fn is_url(&self) -> bool {
57        matches!(self, Self::Url(_))
58    }
59
60    /// Check if this is a file path input
61    pub fn is_path(&self) -> bool {
62        matches!(self, Self::Path(_))
63    }
64
65    /// Check if this is a bytes input
66    pub fn is_bytes(&self) -> bool {
67        matches!(self, Self::Bytes { .. })
68    }
69
70    /// Get the URL if this is a URL input
71    pub fn as_url(&self) -> Option<&str> {
72        match self {
73            Self::Url(url) => Some(url),
74            _ => None,
75        }
76    }
77
78    /// Get the path if this is a path input
79    pub fn as_path(&self) -> Option<&Path> {
80        match self {
81            Self::Path(path) => Some(path),
82            _ => None,
83        }
84    }
85}
86
87impl From<String> for FileInput {
88    fn from(s: String) -> Self {
89        if s.starts_with("http://") || s.starts_with("https://") {
90            Self::Url(s)
91        } else {
92            Self::Path(PathBuf::from(s))
93        }
94    }
95}
96
97impl From<&str> for FileInput {
98    fn from(s: &str) -> Self {
99        Self::from(s.to_string())
100    }
101}
102
103impl From<PathBuf> for FileInput {
104    fn from(path: PathBuf) -> Self {
105        Self::Path(path)
106    }
107}
108
109impl From<&Path> for FileInput {
110    fn from(path: &Path) -> Self {
111        Self::Path(path.to_path_buf())
112    }
113}
114
115/// Represents a file output from a model.
116#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct FileOutput {
118    /// The URL to download the file
119    pub url: String,
120    /// Optional filename
121    pub filename: Option<String>,
122    /// Optional content type
123    pub content_type: Option<String>,
124    /// Optional file size in bytes
125    pub size: Option<u64>,
126}
127
128impl FileOutput {
129    /// Create a new file output
130    pub fn new(url: impl Into<String>) -> Self {
131        Self {
132            url: url.into(),
133            filename: None,
134            content_type: None,
135            size: None,
136        }
137    }
138
139    /// Set the filename
140    pub fn with_filename(mut self, filename: impl Into<String>) -> Self {
141        self.filename = Some(filename.into());
142        self
143    }
144
145    /// Set the content type
146    pub fn with_content_type(mut self, content_type: impl Into<String>) -> Self {
147        self.content_type = Some(content_type.into());
148        self
149    }
150
151    /// Set the file size
152    pub fn with_size(mut self, size: u64) -> Self {
153        self.size = Some(size);
154        self
155    }
156
157    /// Download the file as bytes
158    pub async fn download(&self) -> crate::Result<Bytes> {
159        let response = reqwest::get(&self.url).await?;
160        let bytes = response.bytes().await?;
161        Ok(bytes)
162    }
163
164    /// Save the file to a local path
165    pub async fn save_to_path(&self, path: impl AsRef<Path>) -> crate::Result<()> {
166        let bytes = self.download().await?;
167        tokio::fs::write(path, bytes).await?;
168        Ok(())
169    }
170}
171
172impl From<String> for FileOutput {
173    fn from(url: String) -> Self {
174        Self::new(url)
175    }
176}
177
178impl From<&str> for FileOutput {
179    fn from(url: &str) -> Self {
180        Self::new(url)
181    }
182}
183
184/// File encoding strategy for uploads.
185#[derive(Debug, Clone, Serialize, Deserialize)]
186#[serde(rename_all = "snake_case")]
187pub enum FileEncodingStrategy {
188    /// Upload files as base64-encoded data URLs
189    Base64DataUrl,
190    /// Upload files as multipart form data
191    Multipart,
192}
193
194impl Default for FileEncodingStrategy {
195    fn default() -> Self {
196        Self::Multipart
197    }
198}