use std::path::Path;
use super::{request::*, response::*};
use crate::{
ZaiResult,
client::{ZaiClient, error::codes},
};
pub struct FileParseRequest {
file_path: std::path::PathBuf,
tool_type: ToolType,
file_type: Option<FileType>,
}
impl FileParseRequest {
pub fn new(file_path: &Path, tool_type: ToolType) -> crate::ZaiResult<Self> {
let metadata = std::fs::symlink_metadata(file_path).map_err(|error| {
if error.kind() == std::io::ErrorKind::NotFound {
crate::client::error::ZaiError::FileError {
code: codes::SDK_FILE_NOT_FOUND,
message: format!("File does not exist: {}", file_path.display()),
}
} else {
error.into()
}
})?;
if metadata.file_type().is_symlink() || !metadata.is_file() {
return Err(crate::client::error::ZaiError::FileError {
code: codes::SDK_FILE_NOT_FOUND,
message: format!("Path is not a regular file: {}", file_path.display()),
});
}
Ok(Self {
file_path: file_path.to_path_buf(),
tool_type,
file_type: None,
})
}
pub fn with_file_type(mut self, file_type: FileType) -> crate::ZaiResult<Self> {
if !file_type.is_supported_by(&self.tool_type) {
return Err(crate::client::validation::invalid(format!(
"file type {file_type:?} is not supported by tool type {:?}",
self.tool_type
)));
}
self.file_type = Some(file_type);
Ok(self)
}
pub fn new_with_auto_type(file_path: &Path, tool_type: ToolType) -> crate::ZaiResult<Self> {
let file_type = FileType::from_path(file_path).ok_or_else(|| {
crate::client::error::ZaiError::FileError {
code: codes::SDK_FILE_TYPE_UNSUPPORTED,
message: format!(
"Could not determine file type from path: {}",
file_path.display()
),
}
})?;
Self::new(file_path, tool_type)?.with_file_type(file_type)
}
pub fn file_path(&self) -> &Path {
&self.file_path
}
pub const fn tool_type(&self) -> ToolType {
self.tool_type
}
pub const fn file_type(&self) -> Option<FileType> {
self.file_type
}
pub async fn send_via(&self, client: &ZaiClient) -> ZaiResult<FileParserCreateResponse> {
let part = crate::client::transport::multipart::FilePart::from_path(&self.file_path)?;
let route = crate::client::routes::FILES_PARSE;
let url = client.endpoints().resolve_route(route, &[])?;
let mut factory = crate::client::transport::multipart::MultipartBodyFactory::new()
.field("tool_type", self.tool_type.as_str())?;
if let Some(file_type) = self.file_type {
factory = factory.field("file_type", file_type.extension().to_ascii_uppercase())?;
}
let factory = factory.file_named("file", part)?;
let create_response = client
.send_multipart::<FileParserCreateResponse>(route.method(), url, &factory)
.await
.map_err(|e| e.context("file parser create"))?;
if !create_response.is_success() {
return Err(crate::client::error::ZaiError::ApiError {
code: codes::SDK_EXTERNAL_TOOL,
message: create_response.message.as_deref().map_or_else(
|| "file parser did not return a usable task id".to_owned(),
|message| {
format!(
"file parser task creation failed: {}",
crate::client::error::mask_sensitive_info(message)
)
},
),
});
}
Ok(create_response)
}
}