openai_interface/models/
list.rs1pub mod request {
9 use url::Url;
10
11 use crate::{
12 errors::OapiError,
13 rest::get::{Get, GetNoStream},
14 };
15
16 #[derive(Debug, Clone, Copy, Default)]
19 pub struct ListModelsRequest;
20
21 impl Get for ListModelsRequest {
22 fn build_url(&self, base_url: &str) -> Result<String, OapiError> {
24 let mut url =
25 Url::parse(base_url.trim_end_matches('/')).map_err(OapiError::UrlError)?;
26 url.path_segments_mut()
27 .map_err(|_| OapiError::UrlCannotBeBase(base_url.to_string()))?
28 .push("models");
29
30 Ok(url.to_string())
31 }
32 }
33
34 impl GetNoStream for ListModelsRequest {
35 type Response = super::response::ListModelsResponse;
36 }
37}
38
39pub mod response {
40 use serde::Deserialize;
41
42 #[derive(Debug, Deserialize, Clone)]
44 pub struct ListModelsResponse {
45 pub data: Vec<crate::models::Model>,
47 pub object: Option<String>,
50 }
51
52 crate::impl_from_str!(ListModelsResponse);
53}
54
55#[cfg(test)]
56mod tests {
57 use super::request::ListModelsRequest;
58 use crate::rest::get::{Get, GetNoStream};
59
60 #[test]
61 fn test_build_url() {
62 let request = ListModelsRequest;
63 let url = request.build_url("https://api.openai.com/v1/").unwrap();
64 assert_eq!(url, "https://api.openai.com/v1/models");
65 }
66
67 #[test]
73 fn test_parse_list_response() {
74 let content = r#"{"object":"list","data":[{"id":"deepseek-v4-flash","object":"model","owned_by":"deepseek"},{"id":"deepseek-v4-pro","object":"model","owned_by":"deepseek"},{"id":"deepseek-v4-flash-vision-exp","object":"model","owned_by":"deepseek"}]}"#;
75
76 let response: super::response::ListModelsResponse = content.parse().unwrap();
77 assert_eq!(response.data.len(), 3);
78 assert_eq!(response.data[0].id, "deepseek-v4-flash");
79 assert_eq!(response.data[0].object, crate::models::ModelObject::Model);
80 assert_eq!(response.data[0].owned_by, "deepseek");
81 assert_eq!(response.data[0].created, None);
82 assert_eq!(response.data[0].shutdown_date, None);
83 assert_eq!(response.data[2].id, "deepseek-v4-flash-vision-exp");
84 }
85
86 #[tokio::test]
89 async fn test_query_deepseek_models() -> Result<(), anyhow::Error> {
90 let Some(api_key) = std::env::var("DEEPSEEK_API_KEY")
91 .ok()
92 .map(|key| key.trim().to_string())
93 .filter(|key| !key.is_empty())
94 else {
95 println!("Skipping: set DEEPSEEK_API_KEY to run this test");
96 return Ok(());
97 };
98
99 const DEEPSEEK_BASE_URL: &str = "https://api.deepseek.com";
100
101 let response = ListModelsRequest
102 .get_response(
103 &crate::rest::default_client(),
104 DEEPSEEK_BASE_URL,
105 &crate::rest::RequestOptions::bearer(&api_key),
106 )
107 .await?;
108 assert!(!response.data.is_empty());
109 println!("DeepSeek models: {:?}", response.data);
110 Ok(())
111 }
112}