1use serde::{Deserialize, Serialize};
8use serde_json::Value;
9
10use crate::openai::common::{ListObjectType, Rest};
11
12#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
13#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
14pub struct CreateFileRequest {
15 pub purpose: FilePurpose,
16 pub file: String,
17 #[serde(default, flatten)]
18 pub rest: Rest,
19}
20
21#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
22#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
23pub struct ListFilesRequest {
24 #[serde(skip_serializing_if = "Option::is_none")]
25 pub after: Option<String>,
26 #[serde(skip_serializing_if = "Option::is_none")]
27 pub limit: Option<u32>,
28 #[serde(skip_serializing_if = "Option::is_none")]
29 pub purpose: Option<FilePurpose>,
30 #[serde(default, flatten)]
31 pub rest: Rest,
32}
33
34#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
35#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
36pub struct RetrieveFileRequest {
37 pub file_id: String,
38 #[serde(default, flatten)]
39 pub rest: Rest,
40}
41
42#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
43#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
44pub struct RetrieveFileContentRequest {
45 pub file_id: String,
46 #[serde(default, flatten)]
47 pub rest: Rest,
48}
49
50#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
51#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
52pub struct DeleteFileRequest {
53 pub file_id: String,
54 #[serde(default, flatten)]
55 pub rest: Rest,
56}
57
58#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
59#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
60pub struct FileObject {
61 pub id: String,
62 pub object: String,
63 pub bytes: u64,
64 pub created_at: i64,
65 pub filename: String,
66 pub purpose: FilePurpose,
67 #[serde(skip_serializing_if = "Option::is_none")]
68 pub status: Option<String>,
69 #[serde(skip_serializing_if = "Option::is_none")]
72 pub status_details: Option<Value>,
73 #[serde(default, flatten)]
74 pub rest: Rest,
75}
76
77#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
78#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
79pub struct ListFilesResponse {
80 pub object: ListObjectType,
81 pub data: Vec<FileObject>,
82 #[serde(default)]
83 pub has_more: bool,
84 #[serde(default, flatten)]
85 pub rest: Rest,
86}
87
88#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, gproxy_protocol_macros::WireBuilder)]
89#[cfg_attr(not(feature = "exhaustive"), non_exhaustive)]
90pub struct DeleteFileResponse {
91 pub id: String,
92 pub object: String,
93 pub deleted: bool,
94 #[serde(default, flatten)]
95 pub rest: Rest,
96}
97
98pub type FileContent = Vec<u8>;
100
101macro_rules! extensible_string {
102 ($name:ident, $known:ident { $($variant:ident => $wire:literal),+ $(,)? }) => {
103 #[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
104 #[serde(untagged)]
105 pub enum $name {
106 Known($known),
107 Unknown(String),
108 }
109
110 #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
111 pub enum $known {
112 $(#[serde(rename = $wire)] $variant),+
113 }
114 };
115}
116
117extensible_string!(FilePurpose, KnownFilePurpose {
118 Assistants => "assistants",
119});
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124 use serde_json::json;
125
126 #[test]
127 fn file_models_round_trip_unknown_fields_and_variants() {
128 let value = json!({
129 "id":"file_1",
130 "object":"file.future",
131 "bytes":4,
132 "created_at":1,
133 "filename":"a.bin",
134 "purpose":"future-purpose",
135 "status":"future-status",
136 "future_file":{"x":1}
137 });
138 let file: FileObject = serde_json::from_value(value.clone()).unwrap();
139 assert_eq!(serde_json::to_value(file).unwrap(), value);
140
141 let list = json!({
142 "object":"list",
143 "data":[],
144 "has_more":false,
145 "future_list":true
146 });
147 let parsed: ListFilesResponse = serde_json::from_value(list.clone()).unwrap();
148 assert_eq!(serde_json::to_value(parsed).unwrap(), list);
149 }
150}