use reqwest::RequestBuilder;
use super::OpenAiClient;
use async_trait::async_trait;
use crate::{ByUrlRequest, DeleteResponse, DownloadRequest, FormRequest, GetRequest};
use std::io;
use std::io::{Error, ErrorKind};
use std::path::PathBuf;
use reqwest::multipart::{Form, Part};
use serde::{Serialize, Deserialize};
use with_id::WithRefId;
use crate::conversions::AsyncTryFrom;
use crate::file_to_part;
use derive_more::*;
use crate::fine_tunes::FineTuneFileInfo;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FileListResponse {
pub data: Vec<FileInfo>,
pub object: String,
}
#[async_trait]
impl GetRequest for FileListResponse {
const ENDPOINT: &'static str = "/files";
}
#[derive(Serialize, Deserialize, Debug, Clone, WithRefId)]
pub struct FileInfo {
pub id: String,
pub object: String,
pub bytes: i64,
pub created_at: i64,
pub filename: String,
pub purpose: String,
}
impl From<FineTuneFileInfo> for FileInfo{
fn from(value: FineTuneFileInfo) -> Self {
FileInfo{
id: value.id,
object: value.object,
bytes: value.bytes,
created_at: value.created_at,
filename: value.filename,
purpose: value.purpose,
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone, WithRefId, Constructor)]
pub struct FileDeleteRequest{
#[id]
file_id:String
}
impl From<FileInfo> for FileDeleteRequest {
fn from(value: FileInfo) -> Self {
FileDeleteRequest{
file_id:value.id
}
}
}
impl ByUrlRequest<DeleteResponse> for FileDeleteRequest{
const ENDPOINT: &'static str = "/files/";
const SUFFIX: &'static str = "";
fn builder(client: &OpenAiClient, final_url: String) -> RequestBuilder {
client.client.delete(final_url)
}
}
#[derive(Serialize, Deserialize, Debug, Clone, WithRefId, Constructor)]
pub struct FileInfoRequest{
#[id]
file_id:String
}
impl ByUrlRequest<FileInfo> for FileInfoRequest{
const ENDPOINT: &'static str = "/files/";
const SUFFIX: &'static str = "";
}
#[derive(Serialize, Deserialize, Debug, Clone, WithRefId, Constructor)]
pub struct FileDownloadRequest{
#[id]
file_id:String
}
impl DownloadRequest for FileDownloadRequest{
const ENDPOINT: &'static str = "/files/";
const SUFFIX: &'static str = "/content";
}
impl From<FileInfo> for FileDownloadRequest {
fn from(value: FileInfo) -> Self {
FileDownloadRequest{
file_id:value.id
}
}
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct FileUploadRequest{
file:PathBuf,
purpose:String
}
impl FormRequest<FileInfo> for FileUploadRequest{
const ENDPOINT: &'static str = "/files";
}
impl FileUploadRequest {
pub fn new(file:PathBuf, purpose:String) ->Result<FileUploadRequest,Error>{
if file.exists() {
Ok(
FileUploadRequest {
file,
purpose
}
)
}else {
Err(Error::new(ErrorKind::NotFound, "File does not exist"))
}
}
pub fn with_str(file:&str,purpose:&str)->Result<FileUploadRequest,Error>{
let path = PathBuf::from(file);
if path.exists() {
Ok(
FileUploadRequest {
file: path,
purpose: purpose.to_string()
}
)
}else {
Err(io::Error::new(ErrorKind::NotFound, "File does not exist"))
}
}
}
#[async_trait]
impl AsyncTryFrom<FileUploadRequest> for Form{
type Error = io::Error;
async fn try_from(value: FileUploadRequest) -> anyhow::Result<Self, Self::Error> {
let form =
Form::new()
.part("purpose",Part::text(value.purpose))
.part("file",file_to_part(&value.file).await?);
Ok(form)
}
}