pub mod request {
use std::collections::HashMap;
use url::Url;
use crate::{
errors::OapiError,
rest::delete::{Delete, DeleteNoStream},
};
#[derive(Debug, Default)]
pub struct DeleteRequest<'a> {
pub file_id: &'a str,
pub extra_query: HashMap<&'a str, &'a str>,
}
impl Delete for DeleteRequest<'_> {
fn build_url(&self, base_url: &str) -> Result<String, crate::errors::OapiError> {
let mut url =
Url::parse(base_url.trim_end_matches('/')).map_err(OapiError::UrlError)?;
url.path_segments_mut()
.map_err(|_| OapiError::UrlCannotBeBase(base_url.to_string()))?
.push("files")
.push(self.file_id);
for (key, value) in &self.extra_query {
url.query_pairs_mut().append_pair(key, value);
}
Ok(url.to_string())
}
}
impl<'a> DeleteNoStream for DeleteRequest<'a> {
type Response = super::response::FileDeleted;
}
}
pub mod response {
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct FileDeleted {
pub id: String,
pub deleted: bool,
pub object: FileDeletedObject,
}
#[derive(Debug, Deserialize, Serialize, Clone)]
#[serde(rename_all = "snake_case")]
pub enum FileDeletedObject {
File,
}
crate::impl_from_str!(FileDeleted);
}
#[cfg(test)]
mod tests {
use anyhow::{Context, anyhow};
use crate::{
files::{delete::request::DeleteRequest, list::request::ListFilesRequest},
rest::{RequestOptions, default_client, delete::DeleteNoStream, get::GetNoStream},
};
const MODELSTUDIO_BASE_URL: &str = "https://dashscope.aliyuncs.com/compatible-mode/v1/";
fn modelstudio_key() -> Option<String> {
std::env::var("QWEN_API_KEY")
.ok()
.map(|key| key.trim().to_string())
.filter(|key| !key.is_empty())
}
#[tokio::test]
async fn test_modelstudio_delete_files() -> anyhow::Result<()> {
let Some(api_key) = modelstudio_key() else {
println!("Skipping: set QWEN_API_KEY to run this test");
return Ok(());
};
let client = default_client();
let list_request = ListFilesRequest::default();
let list_response = list_request
.get_response(
&client,
MODELSTUDIO_BASE_URL,
&RequestOptions::bearer(&api_key),
)
.await
.with_context(|| anyhow!("Failed to list files."))?;
let files = list_response
.data
.iter()
.filter_map(|file_object| {
let name = file_object.filename.as_str();
let file_id = file_object.id.as_str();
if name.starts_with("test") {
Some(file_id)
} else {
None
}
})
.collect::<Vec<&str>>();
let futures = files
.iter()
.map(|file| {
let client = client.clone();
let api_key = api_key.clone();
async move {
let delete_request = DeleteRequest {
file_id: file,
..Default::default()
};
delete_request
.get_response(
&client,
MODELSTUDIO_BASE_URL,
&RequestOptions::bearer(&api_key),
)
.await
.with_context(|| anyhow!("Failed to delete file {}", file))
}
})
.collect::<Vec<_>>();
let results = futures_util::future::join_all(futures).await;
for result in results {
result?;
}
Ok(())
}
}