1use std::path::{Path, PathBuf};
4
5use serde::{Deserialize, Serialize};
6
7use crate::{ZaiResult, client::ZaiClient};
8
9pub type FileResponse = crate::tool::FileParseResultResponse;
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
15#[serde(rename_all = "UPPERCASE")]
16pub enum FileParseSyncFileType {
17 WPS,
19 PDF,
21 DOCX,
23 DOC,
25 XLS,
27 XLSX,
29 PPT,
31 PPTX,
33 PNG,
35 JPG,
37 JPEG,
39 CSV,
41 TXT,
43 MD,
45 HTML,
47 BMP,
49 GIF,
51 WEBP,
53 HEIC,
55 EPS,
57 ICNS,
59 IM,
61 PCX,
63 PPM,
65 TIFF,
67 XBM,
69 HEIF,
71 JP2,
73}
74
75impl FileParseSyncFileType {
76 pub const fn as_str(self) -> &'static str {
78 match self {
79 Self::WPS => "WPS",
80 Self::PDF => "PDF",
81 Self::DOCX => "DOCX",
82 Self::DOC => "DOC",
83 Self::XLS => "XLS",
84 Self::XLSX => "XLSX",
85 Self::PPT => "PPT",
86 Self::PPTX => "PPTX",
87 Self::PNG => "PNG",
88 Self::JPG => "JPG",
89 Self::JPEG => "JPEG",
90 Self::CSV => "CSV",
91 Self::TXT => "TXT",
92 Self::MD => "MD",
93 Self::HTML => "HTML",
94 Self::BMP => "BMP",
95 Self::GIF => "GIF",
96 Self::WEBP => "WEBP",
97 Self::HEIC => "HEIC",
98 Self::EPS => "EPS",
99 Self::ICNS => "ICNS",
100 Self::IM => "IM",
101 Self::PCX => "PCX",
102 Self::PPM => "PPM",
103 Self::TIFF => "TIFF",
104 Self::XBM => "XBM",
105 Self::HEIF => "HEIF",
106 Self::JP2 => "JP2",
107 }
108 }
109}
110
111pub struct FileParseSyncRequest {
116 file_path: PathBuf,
117 file_type: Option<FileParseSyncFileType>,
118}
119
120impl std::fmt::Debug for FileParseSyncRequest {
121 fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
122 formatter
123 .debug_struct("FileParseSyncRequest")
124 .field("file_path", &"[REDACTED]")
125 .field("file_type", &self.file_type)
126 .finish()
127 }
128}
129
130impl FileParseSyncRequest {
131 pub fn new(file_path: impl Into<PathBuf>) -> Self {
133 Self {
134 file_path: file_path.into(),
135 file_type: None,
136 }
137 }
138
139 pub fn with_file_type(mut self, file_type: FileParseSyncFileType) -> Self {
141 self.file_type = Some(file_type);
142 self
143 }
144
145 pub fn file_path(&self) -> &Path {
147 &self.file_path
148 }
149
150 pub const fn tool_type(&self) -> &'static str {
152 "prime-sync"
153 }
154
155 pub const fn file_type(&self) -> Option<FileParseSyncFileType> {
157 self.file_type
158 }
159
160 pub async fn send_via(&self, client: &ZaiClient) -> ZaiResult<FileResponse> {
163 let file_part = crate::client::transport::multipart::FilePart::from_path(&self.file_path)?;
164 let route = crate::client::routes::FILES_PARSE_SYNC;
165 let url = client.endpoints().resolve_route(route, &[])?;
166 let mut factory = crate::client::transport::multipart::MultipartBodyFactory::new()
167 .field("tool_type", self.tool_type())?;
168 if let Some(file_type) = self.file_type {
169 factory = factory.field("file_type", file_type.as_str())?;
170 }
171 factory = factory.file_named("file", file_part)?;
172
173 client
174 .send_multipart::<FileResponse>(route.method(), url, &factory)
175 .await
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182
183 #[test]
184 fn file_type_values_match_the_frozen_enum() {
185 let values = [
186 FileParseSyncFileType::WPS,
187 FileParseSyncFileType::PDF,
188 FileParseSyncFileType::DOCX,
189 FileParseSyncFileType::DOC,
190 FileParseSyncFileType::XLS,
191 FileParseSyncFileType::XLSX,
192 FileParseSyncFileType::PPT,
193 FileParseSyncFileType::PPTX,
194 FileParseSyncFileType::PNG,
195 FileParseSyncFileType::JPG,
196 FileParseSyncFileType::JPEG,
197 FileParseSyncFileType::CSV,
198 FileParseSyncFileType::TXT,
199 FileParseSyncFileType::MD,
200 FileParseSyncFileType::HTML,
201 FileParseSyncFileType::BMP,
202 FileParseSyncFileType::GIF,
203 FileParseSyncFileType::WEBP,
204 FileParseSyncFileType::HEIC,
205 FileParseSyncFileType::EPS,
206 FileParseSyncFileType::ICNS,
207 FileParseSyncFileType::IM,
208 FileParseSyncFileType::PCX,
209 FileParseSyncFileType::PPM,
210 FileParseSyncFileType::TIFF,
211 FileParseSyncFileType::XBM,
212 FileParseSyncFileType::HEIF,
213 FileParseSyncFileType::JP2,
214 ];
215 let expected = [
216 "WPS", "PDF", "DOCX", "DOC", "XLS", "XLSX", "PPT", "PPTX", "PNG", "JPG", "JPEG", "CSV",
217 "TXT", "MD", "HTML", "BMP", "GIF", "WEBP", "HEIC", "EPS", "ICNS", "IM", "PCX", "PPM",
218 "TIFF", "XBM", "HEIF", "JP2",
219 ];
220 assert_eq!(values.map(FileParseSyncFileType::as_str), expected);
221 for value in values {
222 assert_eq!(
223 serde_json::to_value(value).unwrap(),
224 serde_json::Value::String(value.as_str().to_owned())
225 );
226 }
227 }
228
229 #[test]
230 fn response_required_fields_do_not_default() {
231 assert!(
232 serde_json::from_value::<FileResponse>(serde_json::json!({
233 "status": "succeeded",
234 "message": "ok"
235 }))
236 .is_err()
237 );
238 }
239}