openai_compat/types/
files.rs1use serde::{Deserialize, Serialize};
4
5use crate::pagination::HasId;
6
7#[derive(Debug, Clone, Serialize, Deserialize)]
9#[non_exhaustive]
10pub struct FileObject {
11 pub id: String,
12 #[serde(default)]
13 pub bytes: Option<u64>,
14 #[serde(default)]
15 pub created_at: Option<i64>,
16 #[serde(default)]
17 pub expires_at: Option<i64>,
18 #[serde(default)]
19 pub filename: Option<String>,
20 #[serde(default)]
21 pub object: String,
22 #[serde(default)]
23 pub purpose: Option<String>,
24 #[serde(default)]
25 pub status: Option<String>,
26 #[serde(default)]
27 pub status_details: Option<String>,
28}
29
30impl HasId for FileObject {
31 fn id(&self) -> Option<&str> {
32 Some(&self.id)
33 }
34}
35
36#[derive(Debug, Clone)]
38pub struct FileUpload {
39 pub filename: String,
40 pub bytes: Vec<u8>,
41 pub content_type: Option<String>,
42}
43
44impl FileUpload {
45 pub fn new(filename: impl Into<String>, bytes: Vec<u8>) -> Self {
46 Self {
47 filename: filename.into(),
48 bytes,
49 content_type: None,
50 }
51 }
52
53 pub async fn from_path(path: impl AsRef<std::path::Path>) -> std::io::Result<Self> {
57 let path = path.as_ref();
58 let filename = path
59 .file_name()
60 .map(|n| n.to_string_lossy().into_owned())
61 .unwrap_or_else(|| "file".to_string());
62 let bytes = tokio::fs::read(path).await?;
63 let mut upload = Self::new(filename, bytes);
64 upload.content_type = path
65 .extension()
66 .and_then(|e| e.to_str())
67 .and_then(mime_for_extension)
68 .map(str::to_owned);
69 Ok(upload)
70 }
71}
72
73fn mime_for_extension(ext: &str) -> Option<&'static str> {
75 Some(match ext.to_ascii_lowercase().as_str() {
76 "mp3" | "mpga" => "audio/mpeg",
77 "wav" => "audio/wav",
78 "m4a" | "mp4" => "audio/mp4",
79 "flac" => "audio/flac",
80 "ogg" | "oga" => "audio/ogg",
81 "webm" => "audio/webm",
82 "json" => "application/json",
83 "jsonl" => "application/jsonl",
84 "txt" => "text/plain",
85 "csv" => "text/csv",
86 "pdf" => "application/pdf",
87 "png" => "image/png",
88 "jpg" | "jpeg" => "image/jpeg",
89 "gif" => "image/gif",
90 "webp" => "image/webp",
91 _ => return None,
92 })
93}