use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize)]
pub struct OllamaChatRequest {
pub model: String,
pub messages: Vec<OllamaMessage>,
pub stream: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OllamaMessage {
pub role: String,
pub content: String,
}
impl OllamaMessage {
#[allow(dead_code)] pub fn new(role: impl Into<String>, content: impl Into<String>) -> Self {
Self {
role: role.into(),
content: content.into(),
}
}
}
#[derive(Debug, Clone, Deserialize)]
#[allow(dead_code)] pub struct OllamaChatResponse {
pub model: String,
pub created_at: String,
pub message: OllamaMessage,
pub done: bool,
#[serde(default)]
pub total_duration: u64,
#[serde(default)]
pub load_duration: u64,
#[serde(default)]
pub prompt_eval_count: u32,
#[serde(default)]
pub eval_count: u32,
}
#[derive(Debug, Clone, Deserialize)]
pub struct OllamaModelListResponse {
pub models: Vec<OllamaModelInfo>,
}
#[derive(Debug, Clone, Deserialize)]
#[allow(dead_code)] pub struct OllamaModelInfo {
pub name: String,
#[serde(default)]
pub size: u64,
#[serde(default)]
pub modified_at: String,
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_ollama_chat_request_serialize() {
let req = OllamaChatRequest {
model: "deepseek-r1".to_string(),
messages: vec![
OllamaMessage::new("system", "You are a helpful assistant"),
OllamaMessage::new("user", "Hello"),
],
stream: false,
};
let json = serde_json::to_string(&req).unwrap();
assert!(json.contains("\"model\":\"deepseek-r1\""));
assert!(json.contains("\"stream\":false"));
assert!(json.contains("\"messages\""));
assert!(json.contains("\"role\":\"system\""));
assert!(json.contains("\"role\":\"user\""));
assert!(json.contains("You are a helpful assistant"));
assert!(json.contains("Hello"));
let parsed: serde_json::Value = serde_json::from_str(&json).unwrap();
assert_eq!(parsed["messages"].as_array().unwrap().len(), 2);
}
#[test]
fn test_ollama_chat_response_deserialize() {
let json = r#"{
"model": "deepseek-r1",
"created_at": "2024-01-01T00:00:00Z",
"message": {
"role": "assistant",
"content": "Hello!"
},
"done": true,
"total_duration": 1000000000,
"prompt_eval_count": 10,
"eval_count": 20
}"#;
let resp: OllamaChatResponse = serde_json::from_str(json).unwrap();
assert_eq!(resp.model, "deepseek-r1");
assert_eq!(resp.created_at, "2024-01-01T00:00:00Z");
assert_eq!(resp.message.role, "assistant");
assert_eq!(resp.message.content, "Hello!");
assert!(resp.done);
assert_eq!(resp.total_duration, 1000000000);
assert_eq!(resp.prompt_eval_count, 10);
assert_eq!(resp.eval_count, 20);
}
#[test]
fn test_ollama_chat_response_default_fields() {
let json = r#"{
"model": "llama3",
"created_at": "2024-01-01T00:00:00Z",
"message": {
"role": "assistant",
"content": "Hi"
},
"done": true
}"#;
let resp: OllamaChatResponse = serde_json::from_str(json).unwrap();
assert_eq!(resp.model, "llama3");
assert_eq!(resp.total_duration, 0);
assert_eq!(resp.load_duration, 0);
assert_eq!(resp.prompt_eval_count, 0);
assert_eq!(resp.eval_count, 0);
}
#[test]
fn test_ollama_model_list_deserialize() {
let json = r#"{
"models": [
{"name": "deepseek-r1:latest", "size": 4000000000, "modified_at": "2024-01-01T00:00:00Z"},
{"name": "llama2:latest", "size": 3800000000, "modified_at": "2024-01-02T00:00:00Z"}
]
}"#;
let resp: OllamaModelListResponse = serde_json::from_str(json).unwrap();
assert_eq!(resp.models.len(), 2);
assert_eq!(resp.models[0].name, "deepseek-r1:latest");
assert_eq!(resp.models[0].size, 4000000000);
assert_eq!(resp.models[1].name, "llama2:latest");
assert_eq!(resp.models[1].size, 3800000000);
}
#[test]
fn test_ollama_model_info_default_fields() {
let json = r#"{
"models": [
{"name": "deepseek-r1:latest"}
]
}"#;
let resp: OllamaModelListResponse = serde_json::from_str(json).unwrap();
assert_eq!(resp.models.len(), 1);
assert_eq!(resp.models[0].name, "deepseek-r1:latest");
assert_eq!(resp.models[0].size, 0);
assert_eq!(resp.models[0].modified_at, "");
}
#[test]
fn test_ollama_message_helpers() {
let msg = OllamaMessage::new("user", "Hello, world!");
assert_eq!(msg.role, "user");
assert_eq!(msg.content, "Hello, world!");
let json = serde_json::to_string(&msg).unwrap();
let parsed: OllamaMessage = serde_json::from_str(&json).unwrap();
assert_eq!(parsed.role, "user");
assert_eq!(parsed.content, "Hello, world!");
}
#[test]
fn test_ollama_message_roles() {
let roles = vec!["system", "user", "assistant", "tool"];
for role in roles {
let msg = OllamaMessage::new(role, "test content");
assert_eq!(msg.role, role);
}
}
}