1use std::pin::Pin;
4
5use crate::parser::{GenericStreamParser, StreamEventExt};
6use crate::types::Thinking;
7use crate::Result;
8use bytes::Bytes;
9use futures::Stream;
10use ollama_sdk_macros::FromBytes;
11use serde::{Deserialize, Serialize};
12
13use super::ThinkingLevel;
14
15#[derive(Serialize, Default, Debug, Clone)]
21pub struct GenerateRequest {
22 pub model: String,
24 #[serde(skip_serializing_if = "Option::is_none")]
26 pub prompt: Option<String>,
27 #[serde(skip_serializing_if = "Option::is_none")]
29 pub suffix: Option<String>,
30 #[serde(skip_serializing_if = "Option::is_none")]
32 pub images: Option<Vec<String>>,
33 #[serde(skip_serializing_if = "Option::is_none")]
35 pub system: Option<String>,
36 pub stream: bool,
39 #[serde(skip_serializing_if = "Option::is_none")]
41 pub think: Option<Thinking>,
42 #[serde(skip_serializing_if = "Option::is_none")]
44 pub raw: Option<bool>,
45 #[serde(skip_serializing_if = "Option::is_none")]
47 pub options: Option<GenerateOptions>,
48}
49
50#[derive(Serialize, Default, Debug, Clone)]
52pub struct GenerateOptions {
53 #[serde(skip_serializing_if = "Option::is_none")]
55 pub seed: Option<u8>,
56 #[serde(skip_serializing_if = "Option::is_none")]
58 pub temperature: Option<f32>,
59 #[serde(skip_serializing_if = "Option::is_none")]
61 pub top_k: Option<u8>,
62 #[serde(skip_serializing_if = "Option::is_none")]
64 pub top_p: Option<f32>,
65 #[serde(skip_serializing_if = "Option::is_none")]
67 pub min_p: Option<f32>,
68 #[serde(skip_serializing_if = "Option::is_none")]
70 pub stop: Option<Vec<String>>,
71 #[serde(skip_serializing_if = "Option::is_none")]
73 pub num_ctx: Option<u16>,
74 #[serde(skip_serializing_if = "Option::is_none")]
76 pub num_predict: Option<u16>,
77}
78
79#[derive(Deserialize, Serialize, Default, FromBytes, Debug, Clone)]
83pub struct GenerateResponse {
84 pub model: String,
86 pub created_at: String,
88 pub response: String,
90 #[serde(default)]
92 pub thinking: String,
93 pub done: bool,
95 #[serde(default)]
97 pub done_reason: Option<String>,
98 #[serde(default)]
100 pub total_duration: u64,
101 #[serde(default)]
103 pub load_duration: u64,
104 #[serde(default)]
106 pub prompt_eval_count: u64,
107 #[serde(default)]
109 pub prompt_eval_duration: u64,
110 #[serde(default)]
112 pub eval_count: u64,
113 #[serde(default)]
115 pub eval_duration: u64,
116}
117
118#[derive(Serialize, Default, Debug, Clone)]
123pub struct SimpleGenerateRequest {
124 pub model: String,
126 pub prompt: Option<String>,
128 pub suffix: Option<String>,
130 pub images: Option<Vec<String>>,
132 pub system: Option<String>,
134 pub think: Option<Thinking>,
136 pub raw: Option<bool>,
138 pub options: Option<GenerateOptions>,
140}
141
142impl SimpleGenerateRequest {
143 pub fn new(model: String, prompt: String) -> Self {
145 Self {
146 model,
147 prompt: Some(prompt),
148 ..Default::default()
149 }
150 }
151
152 pub fn enable_thinking(mut self) -> Self {
154 self.think = Thinking::Boolean(true).into();
155 self
156 }
157
158 pub fn disable_thinking(mut self) -> Self {
160 self.think = Thinking::Boolean(false).into();
161 self
162 }
163
164 pub fn set_thinking_level(mut self, level: ThinkingLevel) -> Self {
166 self.think = Thinking::Level(level).into();
167 self
168 }
169
170 pub fn system(mut self, system: String) -> Self {
172 self.system = Some(system);
173 self
174 }
175
176 pub fn images(mut self, images: Vec<String>) -> Self {
178 self.images = Some(images);
179 self
180 }
181
182 pub fn options(mut self, options: GenerateOptions) -> Self {
184 self.options = Some(options);
185 self
186 }
187}
188
189impl From<SimpleGenerateRequest> for GenerateRequest {
190 fn from(request: SimpleGenerateRequest) -> GenerateRequest {
192 GenerateRequest {
193 model: request.model,
194 prompt: request.prompt,
195 suffix: request.suffix,
196 images: request.images,
197 system: request.system,
198 think: request.think,
199 raw: request.raw,
200 options: request.options,
201 stream: false,
202 }
203 }
204}
205
206#[derive(Serialize, Default, Debug, Clone)]
211pub struct StreamingGenerateRequest {
212 pub model: String,
214 pub prompt: Option<String>,
216 pub suffix: Option<String>,
218 pub images: Option<Vec<String>>,
220 pub system: Option<String>,
222 pub think: Option<Thinking>,
224 pub raw: Option<bool>,
226 pub options: Option<GenerateOptions>,
228}
229
230impl StreamingGenerateRequest {
231 pub fn new(model: String, prompt: String) -> Self {
233 Self {
234 model,
235 prompt: Some(prompt),
236 ..Default::default()
237 }
238 }
239
240 pub fn enable_thinking(mut self) -> Self {
242 self.think = Thinking::Boolean(true).into();
243 self
244 }
245
246 pub fn disable_thinking(mut self) -> Self {
248 self.think = Thinking::Boolean(false).into();
249 self
250 }
251
252 pub fn set_thinking_level(mut self, level: ThinkingLevel) -> Self {
254 self.think = Thinking::Level(level).into();
255 self
256 }
257
258 pub fn system(mut self, system: String) -> Self {
260 self.system = Some(system);
261 self
262 }
263
264 pub fn images(mut self, images: Vec<String>) -> Self {
266 self.images = Some(images);
267 self
268 }
269
270 pub fn options(mut self, options: GenerateOptions) -> Self {
272 self.options = Some(options);
273 self
274 }
275}
276
277impl From<StreamingGenerateRequest> for GenerateRequest {
278 fn from(request: StreamingGenerateRequest) -> GenerateRequest {
280 GenerateRequest {
281 model: request.model,
282 prompt: request.prompt,
283 suffix: request.suffix,
284 images: request.images,
285 system: request.system,
286 think: request.think,
287 raw: request.raw,
288 options: request.options,
289 stream: true,
290 }
291 }
292}
293
294#[derive(Deserialize, Serialize, Debug)]
296#[serde(untagged)]
297pub enum GenerateStreamEvent {
298 MessageChunk(GenerateResponse),
300 Error(String),
302 Partial {
304 partial: String,
306 error: Option<String>,
308 },
309}
310
311pub struct GenerateStream {
313 pub inner: Pin<Box<dyn Stream<Item = Result<GenerateStreamEvent>> + Send>>,
314}
315
316impl Stream for GenerateStream {
317 type Item = Result<GenerateStreamEvent>;
318
319 fn poll_next(
320 mut self: std::pin::Pin<&mut Self>,
321 cx: &mut std::task::Context<'_>,
322 ) -> std::task::Poll<Option<Self::Item>> {
323 self.inner.as_mut().poll_next(cx)
324 }
325}
326
327impl GenerateStream {
328 pub fn from_bytes_stream<S>(stream: S) -> Self
329 where
330 S: Stream<Item = Result<Bytes>> + Send + Unpin + 'static,
331 {
332 let parser = GenericStreamParser::<S, GenerateResponse, GenerateStreamEvent>::new(stream);
333 GenerateStream {
334 inner: Box::pin(parser),
335 }
336 }
337}
338
339impl StreamEventExt<GenerateResponse> for GenerateStreamEvent {
340 fn from_message(msg: GenerateResponse) -> Self {
341 GenerateStreamEvent::MessageChunk(msg)
342 }
343
344 fn from_error(err: String) -> Self {
345 GenerateStreamEvent::Error(err)
346 }
347
348 fn partial(partial: String, error: Option<String>) -> Self {
349 GenerateStreamEvent::Partial { partial, error }
350 }
351}