openai_rust/resources/
models.rs1use std::{collections::BTreeMap, fmt::Write as _, sync::Arc};
2
3use serde::Deserialize;
4use serde_json::Value;
5
6use crate::{
7 OpenAIError,
8 core::{request::RequestOptions, response::ApiResponse, runtime::ClientRuntime},
9 error::ErrorKind,
10};
11
12#[derive(Clone, Debug)]
14pub struct Models {
15 runtime: Arc<ClientRuntime>,
16}
17
18impl Models {
19 pub(crate) fn new(runtime: Arc<ClientRuntime>) -> Self {
20 Self { runtime }
21 }
22
23 pub fn retrieve(&self, model_id: &str) -> Result<ApiResponse<Model>, OpenAIError> {
25 let model_id = encode_path_id(validate_path_id("model_id", model_id)?);
26 self.runtime.execute_json(
27 "GET",
28 format!("/models/{model_id}"),
29 RequestOptions::default(),
30 )
31 }
32
33 pub fn list(&self) -> Result<ApiResponse<ModelsPage>, OpenAIError> {
35 self.runtime
36 .execute_json("GET", "/models", RequestOptions::default())
37 }
38
39 pub fn delete(&self, model_id: &str) -> Result<ApiResponse<DeletedModel>, OpenAIError> {
41 let model_id = encode_path_id(validate_path_id("model_id", model_id)?);
42 self.runtime.execute_json(
43 "DELETE",
44 format!("/models/{model_id}"),
45 RequestOptions::default(),
46 )
47 }
48}
49
50#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
52pub struct Model {
53 pub id: String,
54 #[serde(default)]
55 pub object: String,
56 #[serde(default)]
57 pub created: Option<i64>,
58 #[serde(default)]
59 pub owned_by: Option<String>,
60 #[serde(flatten)]
61 pub extra: BTreeMap<String, Value>,
62}
63
64#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
66pub struct ModelsPage {
67 #[serde(default)]
68 pub object: String,
69 #[serde(default)]
70 pub data: Vec<Model>,
71 #[serde(flatten)]
72 pub extra: BTreeMap<String, Value>,
73}
74
75impl ModelsPage {
76 pub fn has_next_page(&self) -> bool {
77 false
78 }
79
80 pub fn next_after(&self) -> Option<&str> {
81 None
82 }
83}
84
85#[derive(Clone, Debug, Default, Deserialize, PartialEq)]
87pub struct DeletedModel {
88 pub id: String,
89 #[serde(default)]
90 pub object: String,
91 pub deleted: bool,
92 #[serde(flatten)]
93 pub extra: BTreeMap<String, Value>,
94}
95
96fn validate_path_id<'a>(label: &str, value: &'a str) -> Result<&'a str, OpenAIError> {
97 if value.trim().is_empty() {
98 return Err(OpenAIError::new(
99 ErrorKind::Validation,
100 format!("{label} cannot be blank"),
101 ));
102 }
103 Ok(value)
104}
105
106fn encode_path_id(value: &str) -> String {
107 let mut encoded = String::with_capacity(value.len());
108 for byte in value.bytes() {
109 if matches!(
110 byte,
111 b'A'..=b'Z'
112 | b'a'..=b'z'
113 | b'0'..=b'9'
114 | b'-'
115 | b'.'
116 | b'_'
117 | b'~'
118 | b'!'
119 | b'$'
120 | b'&'
121 | b'\''
122 | b'('
123 | b')'
124 | b'*'
125 | b'+'
126 | b','
127 | b';'
128 | b'='
129 | b':'
130 | b'@'
131 ) {
132 encoded.push(byte as char);
133 } else {
134 let _ = write!(&mut encoded, "%{byte:02X}");
135 }
136 }
137 encoded
138}