Merge pull request #4 from andreban/feat/api-show

feat: implement api/show endpoint
This commit is contained in:
2026-02-02 12:24:23 +00:00
committed by GitHub
6 changed files with 183 additions and 1 deletions

View File

@@ -162,6 +162,7 @@ When the model decides to call a tool, the response `message.tool_calls` field w
| `chat(request)` | Chat conversation (streaming) | | `chat(request)` | Chat conversation (streaming) |
| `pull(request)` | Pull/download a model (streaming) | | `pull(request)` | Pull/download a model (streaming) |
| `delete(request)` | Delete a model from the server | | `delete(request)` | Delete a model from the server |
| `show_model(request)` | Show information about a model |
| `embed(request)` | Generate vector embeddings | | `embed(request)` | Generate vector embeddings |
**`OllamaClient::builder(server_address)`** -- `.connection_timeout(Duration)`, `.build()` **`OllamaClient::builder(server_address)`** -- `.connection_timeout(Duration)`, `.build()`
@@ -185,6 +186,8 @@ let client = OllamaClient::builder("http://localhost:11434")
**`EmbedRequest::builder(model)`** -- `.input()`, `.inputs()`, `.truncate()`, `.dimensions()`, `.keep_alive()`, `.options()` **`EmbedRequest::builder(model)`** -- `.input()`, `.inputs()`, `.truncate()`, `.dimensions()`, `.keep_alive()`, `.options()`
**`ShowModelRequest::new(model)`** -- `.verbose()`
### Generation Options ### Generation Options
Configure sampling parameters via `Options::builder()`: Configure sampling parameters via `Options::builder()`:
@@ -212,6 +215,7 @@ The `examples/` directory contains runnable programs:
| `tool_call` | Function calling / tool use | | `tool_call` | Function calling / tool use |
| `pull` | Download a model | | `pull` | Download a model |
| `delete` | Delete a model | | `delete` | Delete a model |
| `show_model` | Show model information |
| `embed` | Generate text embeddings | | `embed` | Generate text embeddings |
| `tags` | List available models | | `tags` | List available models |
| `ps` | List running models | | `ps` | List running models |

37
examples/show_model.rs Normal file
View File

@@ -0,0 +1,37 @@
use ollama_rs::OllamaClient;
use ollama_rs::types::show::ShowModelRequest;
use std::error::Error;
#[tokio::main]
async fn main() -> Result<(), Box<dyn Error>> {
let client = OllamaClient::default();
let model = "qwen3:8b";
println!("Requesting info for model: {}", model);
let request = ShowModelRequest::new(model.to_string());
let response = client.show_model(request).await?;
println!("Model Info:");
println!(
" License: {}",
response
.license
.as_deref()
.unwrap_or("N/A")
.lines()
.next()
.unwrap_or("")
); // First line only
println!(
" Modelfile: {} bytes",
response.modelfile.as_ref().map(|s| s.len()).unwrap_or(0)
);
println!(
" Parameters: {}",
response.parameters.as_ref().map(|s| s.len()).unwrap_or(0)
);
println!(" Template: {:?}", response.template.is_some());
println!(" Details: {:?}", response.details);
Ok(())
}

View File

@@ -98,6 +98,7 @@ use crate::{
generate::{GenerateRequest, GenerateResponse}, generate::{GenerateRequest, GenerateResponse},
ps::PsResponse, ps::PsResponse,
pull::{PullRequest, PullResponse}, pull::{PullRequest, PullResponse},
show::{ShowModelRequest, ShowModelResponse},
tags::TagsResponse, tags::TagsResponse,
version::VersionResponse, version::VersionResponse,
}, },
@@ -456,6 +457,43 @@ impl OllamaClient {
let request_address = format!("{}/api/pull", self.server_address); let request_address = format!("{}/api/pull", self.server_address);
self.stream_response(request_address, request) self.stream_response(request_address, request)
} }
/// Shows information about a model.
///
/// Calls `POST /api/show`.
///
/// # Errors
///
/// Returns [`OllamaError::NetworkError`] if the server is unreachable or returns
/// a non-success status code.
///
/// # Examples
///
/// ```no_run
/// # use ollama_rs::OllamaClient;
/// # use ollama_rs::types::show::ShowModelRequest;
/// # async fn run() -> ollama_rs::error::OllamaResult<()> {
/// let client = OllamaClient::default();
/// let request = ShowModelRequest::new("llama3".to_string());
///
/// let response = client.show_model(request).await?;
/// println!("Model info: {:?}", response);
/// # Ok(())
/// # }
/// ```
pub async fn show_model(&self, request: ShowModelRequest) -> OllamaResult<ShowModelResponse> {
let request_address = format!("{}/api/show", self.server_address);
info!("Show model: {}", request.name);
Ok(self
.client
.post(request_address)
.json(&request)
.send()
.await?
.error_for_status()?
.json()
.await?)
}
} }
/// A builder for constructing an [`OllamaClient`] with custom configuration. /// A builder for constructing an [`OllamaClient`] with custom configuration.

View File

@@ -9,7 +9,7 @@
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
/// Detailed metadata about a model, returned by the tags and ps endpoints. /// Detailed metadata about a model, returned by the tags, ps, and show endpoints.
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct ModelDetails { pub struct ModelDetails {
/// The model file format (e.g., `"gguf"`). /// The model file format (e.g., `"gguf"`).

View File

@@ -9,6 +9,7 @@
//! | [`embed`] | `POST /api/embed` | Generate vector embeddings | //! | [`embed`] | `POST /api/embed` | Generate vector embeddings |
//! | [`generate`] | `POST /api/generate` | Single-prompt text generation | //! | [`generate`] | `POST /api/generate` | Single-prompt text generation |
//! | [`pull`] | `POST /api/pull` | Download models from the registry | //! | [`pull`] | `POST /api/pull` | Download models from the registry |
//! | [`show`] | `POST /api/show` | Show model details |
//! | [`tags`] | `GET /api/tags` | List available models | //! | [`tags`] | `GET /api/tags` | List available models |
//! | [`ps`] | `GET /api/ps` | List currently loaded/running models | //! | [`ps`] | `GET /api/ps` | List currently loaded/running models |
//! | [`version`] | `GET /api/version` | Query the server version | //! | [`version`] | `GET /api/version` | Query the server version |
@@ -24,5 +25,6 @@ pub mod embed;
pub mod generate; pub mod generate;
pub mod ps; pub mod ps;
pub mod pull; pub mod pull;
pub mod show;
pub mod tags; pub mod tags;
pub mod version; pub mod version;

101
src/types/show.rs Normal file
View File

@@ -0,0 +1,101 @@
//! Types for the show model information endpoint (`POST /api/show`).
//!
//! Use [`ShowModelRequest`] to construct a request and pass it to
//! [`OllamaClient::show_model`](crate::OllamaClient::show_model).
use serde::{Deserialize, Serialize};
use super::common::ModelDetails;
/// A request to the show model endpoint (`POST /api/show`).
#[derive(Debug, Serialize)]
pub struct ShowModelRequest {
/// The name of the model to retrieve information for.
pub name: String,
/// Whether to return full model details (e.g. system prompt, template).
#[serde(skip_serializing_if = "Option::is_none")]
pub verbose: Option<bool>,
}
impl ShowModelRequest {
/// Creates a new request for the given model name.
pub fn new(name: String) -> Self {
Self {
name,
verbose: None,
}
}
/// Enables verbose output, returning full model details.
pub fn verbose(mut self) -> Self {
self.verbose = Some(true);
self
}
}
/// A response from the show model endpoint.
#[derive(Debug, Deserialize)]
pub struct ShowModelResponse {
/// The license of the model.
pub license: Option<String>,
/// The modelfile content.
pub modelfile: Option<String>,
/// The model parameters (e.g., stop tokens, temperature defaults).
pub parameters: Option<String>,
/// The prompt template.
pub template: Option<String>,
/// The system prompt.
pub system: Option<String>,
/// Detailed model metadata.
pub details: Option<ModelDetails>,
/// Additional model information.
pub model_info: Option<serde_json::Map<String, serde_json::Value>>,
}
#[cfg(test)]
mod tests {
use super::*;
use serde_json::json;
#[test]
fn request_new_serialized() {
let request = ShowModelRequest::new("llama3".to_string());
let json = serde_json::to_value(&request).unwrap();
assert_eq!(json, json!({"name": "llama3"}));
}
#[test]
fn request_verbose_serialized() {
let request = ShowModelRequest::new("llama3".to_string()).verbose();
let json = serde_json::to_value(&request).unwrap();
assert_eq!(json, json!({"name": "llama3", "verbose": true}));
}
#[test]
fn response_deserialization() {
let json = json!({
"license": "MIT",
"modelfile": "FROM llama3",
"parameters": "temperature 0.7",
"template": "Please answer:",
"system": "You are helpful",
"details": {
"format": "gguf",
"family": "llama",
"families": ["llama"],
"parameter_size": "8B",
"quantization_level": "Q4_0"
}
});
let response: ShowModelResponse = serde_json::from_value(json).unwrap();
assert_eq!(response.license, Some("MIT".to_string()));
assert_eq!(response.modelfile, Some("FROM llama3".to_string()));
assert_eq!(response.parameters, Some("temperature 0.7".to_string()));
assert_eq!(response.template, Some("Please answer:".to_string()));
assert_eq!(response.system, Some("You are helpful".to_string()));
let details = response.details.unwrap();
assert_eq!(details.format, "gguf");
assert_eq!(details.family, "llama");
}
}