zai_rs/tool/file_parser_create/
data.rs1use std::path::Path;
4
5use super::{request::*, response::*};
6use crate::{
7 ZaiResult,
8 client::{ZaiClient, error::codes},
9};
10
11pub struct FileParseRequest {
28 file_path: std::path::PathBuf,
30 tool_type: ToolType,
32 file_type: Option<FileType>,
34}
35
36impl FileParseRequest {
37 pub fn new(file_path: &Path, tool_type: ToolType) -> crate::ZaiResult<Self> {
39 let metadata = std::fs::symlink_metadata(file_path).map_err(|error| {
40 if error.kind() == std::io::ErrorKind::NotFound {
41 crate::client::error::ZaiError::FileError {
42 code: codes::SDK_FILE_NOT_FOUND,
43 message: format!("File does not exist: {}", file_path.display()),
44 }
45 } else {
46 error.into()
47 }
48 })?;
49 if metadata.file_type().is_symlink() || !metadata.is_file() {
50 return Err(crate::client::error::ZaiError::FileError {
51 code: codes::SDK_FILE_NOT_FOUND,
52 message: format!("Path is not a regular file: {}", file_path.display()),
53 });
54 }
55
56 Ok(Self {
57 file_path: file_path.to_path_buf(),
58 tool_type,
59 file_type: None,
60 })
61 }
62
63 pub fn with_file_type(mut self, file_type: FileType) -> crate::ZaiResult<Self> {
65 if !file_type.is_supported_by(&self.tool_type) {
66 return Err(crate::client::validation::invalid(format!(
67 "file type {file_type:?} is not supported by tool type {:?}",
68 self.tool_type
69 )));
70 }
71 self.file_type = Some(file_type);
72 Ok(self)
73 }
74
75 pub fn new_with_auto_type(file_path: &Path, tool_type: ToolType) -> crate::ZaiResult<Self> {
77 let file_type = FileType::from_path(file_path).ok_or_else(|| {
78 crate::client::error::ZaiError::FileError {
79 code: codes::SDK_FILE_TYPE_UNSUPPORTED,
80 message: format!(
81 "Could not determine file type from path: {}",
82 file_path.display()
83 ),
84 }
85 })?;
86
87 Self::new(file_path, tool_type)?.with_file_type(file_type)
88 }
89
90 pub fn file_path(&self) -> &Path {
92 &self.file_path
93 }
94
95 pub const fn tool_type(&self) -> ToolType {
97 self.tool_type
98 }
99
100 pub const fn file_type(&self) -> Option<FileType> {
102 self.file_type
103 }
104
105 pub async fn send_via(&self, client: &ZaiClient) -> ZaiResult<FileParserCreateResponse> {
107 let part = crate::client::transport::multipart::FilePart::from_path(&self.file_path)?;
108
109 let route = crate::client::routes::FILES_PARSE;
110 let url = client.endpoints().resolve_route(route, &[])?;
111 let mut factory = crate::client::transport::multipart::MultipartBodyFactory::new()
112 .field("tool_type", self.tool_type.as_str())?;
113 if let Some(file_type) = self.file_type {
114 factory = factory.field("file_type", file_type.extension().to_ascii_uppercase())?;
115 }
116 let factory = factory.file_named("file", part)?;
117 let create_response = client
118 .send_multipart::<FileParserCreateResponse>(route.method(), url, &factory)
119 .await
120 .map_err(|e| e.context("file parser create"))?;
121
122 if !create_response.is_success() {
123 return Err(crate::client::error::ZaiError::ApiError {
124 code: codes::SDK_EXTERNAL_TOOL,
125 message: create_response.message.as_deref().map_or_else(
126 || "file parser did not return a usable task id".to_owned(),
127 |message| {
128 format!(
129 "file parser task creation failed: {}",
130 crate::client::error::mask_sensitive_info(message)
131 )
132 },
133 ),
134 });
135 }
136
137 Ok(create_response)
138 }
139}