use serde::{Deserialize, Serialize};
use crate::{error::OllamaError, generation::parameters::LogprobsData, Ollama};
use request::GenerationRequest;
pub mod request;
#[cfg_attr(docsrs, doc(cfg(feature = "stream")))]
#[cfg(feature = "stream")]
pub type GenerationResponseStream = std::pin::Pin<
Box<
dyn tokio_stream::Stream<Item = crate::error::Result<GenerationResponseStreamChunk>> + Send,
>,
>;
pub type GenerationResponseStreamChunk = Vec<GenerationResponse>;
#[derive(Serialize)]
struct WithStreamField<T> {
stream: bool,
#[serde(flatten)]
rest: T,
}
impl Ollama {
#[cfg_attr(docsrs, doc(cfg(feature = "stream")))]
#[cfg(feature = "stream")]
pub async fn generate_stream(
&self,
request: GenerationRequest<'_>,
) -> crate::error::Result<GenerationResponseStream> {
use tokio_stream::StreamExt;
use crate::error::OllamaError;
let url = format!("{}api/generate", self.url_str());
let builder = self.reqwest_client.post(url);
#[cfg(feature = "headers")]
let builder = builder.headers(self.request_headers.clone());
let res = builder
.json(&WithStreamField {
stream: true,
rest: request,
})
.send()
.await?;
if !res.status().is_success() {
return Err(OllamaError::Other(
res.text().await.unwrap_or_else(|e| e.to_string()),
));
}
let stream = Box::new(res.bytes_stream().map(|res| match res {
Ok(bytes) => {
let res = serde_json::Deserializer::from_slice(&bytes).into_iter();
let res = res
.filter_map(Result::ok) .collect::<Vec<GenerationResponse>>();
Ok(res)
}
Err(e) => Err(OllamaError::Other(format!("Failed to read response: {e}"))),
}));
Ok(std::pin::Pin::from(stream))
}
pub async fn generate(
&self,
request: GenerationRequest<'_>,
) -> crate::error::Result<GenerationResponse> {
let url = format!("{}api/generate", self.url_str());
let builder = self.reqwest_client.post(url);
#[cfg(feature = "headers")]
let builder = builder.headers(self.request_headers.clone());
let res = builder
.json(&WithStreamField {
stream: false,
rest: request,
})
.send()
.await?;
if !res.status().is_success() {
return Err(OllamaError::Other(
res.text().await.unwrap_or_else(|e| e.to_string()),
));
}
let res = res.bytes().await?;
let res = serde_json::from_slice::<GenerationResponse>(&res)?;
Ok(res)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GenerationContext(pub Vec<i32>);
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GenerationResponse {
pub model: String,
pub created_at: String,
pub response: String,
pub done: bool,
pub context: Option<GenerationContext>,
pub total_duration: Option<u64>,
pub load_duration: Option<u64>,
pub prompt_eval_count: Option<u64>,
pub prompt_eval_duration: Option<u64>,
pub eval_count: Option<u64>,
pub eval_duration: Option<u64>,
pub thinking: Option<String>,
pub logprobs: Option<Vec<LogprobsData>>,
}