1use crate::chat::Message as ChatMessage;
16use crate::client::ModelClient;
17use crate::client::handle_error_response;
18use crate::client::json_lines_stream;
19use crate::error::{OllamaError, Result};
20use serde::{Deserialize, Serialize};
21use std::collections::HashMap;
22use tokio_stream::Stream;
23
24#[derive(Debug, Clone, Serialize, Deserialize)]
26pub struct ModelInfo {
27 pub name: String,
28 pub model: String,
29 pub modified_at: String,
30 pub size: u64,
31 pub digest: String,
32 pub details: ModelDetails,
33 #[serde(skip_serializing_if = "Option::is_none")]
35 pub remote_model: Option<String>,
36 #[serde(skip_serializing_if = "Option::is_none")]
38 pub remote_host: Option<String>,
39}
40
41#[derive(Debug, Clone, Serialize, Deserialize)]
43pub struct ModelDetails {
44 pub parent_model: String,
45 pub format: String,
46 pub family: String,
47 pub families: Option<Vec<String>>,
48 pub parameter_size: String,
49 pub quantization_level: String,
50}
51
52#[derive(Debug, Clone, Serialize, Deserialize)]
54pub struct ListModelsResponse {
55 pub models: Vec<ModelInfo>,
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize, Default)]
60pub struct ShowModelRequest {
61 pub model: String,
62 #[serde(skip_serializing_if = "Option::is_none")]
63 pub verbose: Option<bool>,
64}
65
66#[derive(Debug, Clone, Serialize, Deserialize)]
68pub struct ShowModelResponse {
69 #[serde(default)]
70 pub modelfile: String,
71 #[serde(default)]
72 pub parameters: String,
73 #[serde(default)]
74 pub template: String,
75 pub details: ModelDetails,
76 #[serde(skip_serializing_if = "Option::is_none")]
77 pub model_info: Option<HashMap<String, serde_json::Value>>,
78 #[serde(skip_serializing_if = "Option::is_none")]
79 pub capabilities: Option<Vec<String>>,
80}
81
82#[derive(Debug, Clone, Serialize, Deserialize)]
84pub struct CopyModelRequest {
85 pub source: String,
86 pub destination: String,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize)]
91pub struct DeleteModelRequest {
92 pub model: String,
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize, Default)]
97pub struct PullModelRequest {
98 pub model: String,
99 #[serde(skip_serializing_if = "Option::is_none")]
100 pub insecure: Option<bool>,
101 #[serde(skip_serializing_if = "Option::is_none")]
102 pub stream: Option<bool>,
103}
104
105#[derive(Debug, Clone, Serialize, Deserialize)]
107pub struct PushModelRequest {
108 pub model: String,
109 #[serde(skip_serializing_if = "Option::is_none")]
110 pub insecure: Option<bool>,
111 #[serde(skip_serializing_if = "Option::is_none")]
112 pub stream: Option<bool>,
113}
114
115#[derive(Debug, Clone, Serialize, Deserialize)]
117pub struct CreateModelRequest {
118 pub model: String,
119 #[serde(skip_serializing_if = "Option::is_none")]
120 pub from: Option<String>,
121 #[serde(skip_serializing_if = "Option::is_none")]
122 pub files: Option<HashMap<String, String>>,
123 #[serde(skip_serializing_if = "Option::is_none")]
124 pub adapters: Option<HashMap<String, String>>,
125 #[serde(skip_serializing_if = "Option::is_none")]
126 pub template: Option<String>,
127 #[serde(skip_serializing_if = "Option::is_none")]
128 pub license: Option<License>,
129 #[serde(skip_serializing_if = "Option::is_none")]
130 pub system: Option<String>,
131 #[serde(skip_serializing_if = "Option::is_none")]
132 pub parameters: Option<HashMap<String, serde_json::Value>>,
133 #[serde(skip_serializing_if = "Option::is_none")]
134 pub messages: Option<Vec<ChatMessage>>,
135 #[serde(skip_serializing_if = "Option::is_none")]
136 pub stream: Option<bool>,
137 #[serde(skip_serializing_if = "Option::is_none")]
138 pub quantize: Option<String>,
139}
140
141#[derive(Debug, Clone, Serialize, Deserialize)]
143#[serde(untagged)]
144pub enum License {
145 Single(String),
146 Multiple(Vec<String>),
147}
148
149#[derive(Debug, Clone, Serialize, Deserialize)]
151pub struct RunningModel {
152 pub name: String,
153 pub model: String,
154 pub size: u64,
155 pub digest: String,
156 pub details: ModelDetails,
157 pub expires_at: String,
158 pub size_vram: u64,
159}
160
161#[derive(Debug, Clone, Serialize, Deserialize)]
163pub struct ListRunningModelsResponse {
164 pub models: Vec<RunningModel>,
165}
166
167#[derive(Debug, Clone, Serialize, Deserialize)]
169pub struct VersionResponse {
170 pub version: String,
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize)]
175pub struct StatusResponse {
176 pub status: String,
177}
178
179impl ModelClient {
180 pub async fn list_models(&self) -> Result<Vec<ModelInfo>> {
182 let url = self
183 .base_url
184 .join("api/tags")
185 .map_err(OllamaError::UrlError)?;
186 let response = self
187 .client
188 .get(url)
189 .send()
190 .await
191 .map_err(OllamaError::RequestError)?;
192
193 let models: ListModelsResponse = self.handle_response(response, None).await?;
194 Ok(models.models)
195 }
196
197 pub async fn show_model(&self, request: ShowModelRequest) -> Result<ShowModelResponse> {
199 let url = self
200 .base_url
201 .join("api/show")
202 .map_err(OllamaError::UrlError)?;
203 let response = self
204 .client
205 .post(url)
206 .json(&request)
207 .send()
208 .await
209 .map_err(OllamaError::RequestError)?;
210
211 self.handle_response(response, Some(&request.model)).await
212 }
213
214 pub async fn copy_model(&self, request: CopyModelRequest) -> Result<()> {
216 let url = self
217 .base_url
218 .join("api/copy")
219 .map_err(OllamaError::UrlError)?;
220 let response = self
221 .client
222 .post(url)
223 .json(&request)
224 .send()
225 .await
226 .map_err(OllamaError::RequestError)?;
227
228 self.handle_void_response(response).await
229 }
230
231 pub async fn delete_model(&self, request: DeleteModelRequest) -> Result<()> {
233 let url = self
234 .base_url
235 .join("api/delete")
236 .map_err(OllamaError::UrlError)?;
237 let response = self
238 .client
239 .delete(url)
240 .json(&request)
241 .send()
242 .await
243 .map_err(OllamaError::RequestError)?;
244
245 self.handle_void_response(response).await
246 }
247
248 pub async fn pull_model(
250 &self,
251 mut request: PullModelRequest,
252 ) -> Result<impl Stream<Item = Result<StatusResponse>> + '_> {
253 let url = self
254 .base_url
255 .join("api/pull")
256 .map_err(OllamaError::UrlError)?;
257 request.stream = Some(true);
258
259 let response = self
260 .client
261 .post(url)
262 .json(&request)
263 .send()
264 .await
265 .map_err(OllamaError::RequestError)?;
266
267 if !response.status().is_success() {
268 return Err(handle_error_response(response, Some(&request.model)).await);
269 }
270
271 Ok(json_lines_stream(response))
272 }
273
274 pub async fn push_model(
276 &self,
277 request: PushModelRequest,
278 ) -> Result<impl Stream<Item = Result<StatusResponse>> + '_> {
279 let url = self
280 .base_url
281 .join("api/push")
282 .map_err(OllamaError::UrlError)?;
283 let response = self
284 .client
285 .post(url)
286 .json(&request)
287 .send()
288 .await
289 .map_err(OllamaError::RequestError)?;
290
291 if !response.status().is_success() {
292 return Err(handle_error_response(response, Some(&request.model)).await);
293 }
294
295 Ok(json_lines_stream(response))
296 }
297
298 pub async fn create_model(
300 &self,
301 request: CreateModelRequest,
302 ) -> Result<impl Stream<Item = Result<StatusResponse>> + '_> {
303 let url = self
304 .base_url
305 .join("api/create")
306 .map_err(OllamaError::UrlError)?;
307 let response = self
308 .client
309 .post(url)
310 .json(&request)
311 .send()
312 .await
313 .map_err(OllamaError::RequestError)?;
314
315 if !response.status().is_success() {
316 return Err(handle_error_response(response, Some(&request.model)).await);
317 }
318
319 Ok(json_lines_stream(response))
320 }
321
322 #[cfg(feature = "local")]
324 pub async fn list_running_models(&self) -> Result<Vec<RunningModel>> {
325 let url = self
326 .base_url
327 .join("api/ps")
328 .map_err(OllamaError::UrlError)?;
329 let response = self
330 .client
331 .get(url)
332 .send()
333 .await
334 .map_err(OllamaError::RequestError)?;
335
336 let models: ListRunningModelsResponse = self.handle_response(response, None).await?;
337 Ok(models.models)
338 }
339}