1#![doc = include_str!("../README.MD")]
2#![warn(missing_docs)]
3#[cfg_attr(not(any(feature = "ollama", feature = "llama.cpp")), deny(warnings))]
4mod error;
5pub mod prelude;
6
7#[cfg(feature = "llama.cpp")]
8pub mod llama_cpp;
9#[cfg(feature = "ollama")]
10pub mod ollama;
11
12#[cfg(feature = "template")]
13pub mod template;
14
15use std::{future::Future, pin::Pin};
16
17pub use error::Error;
19use futures::Stream;
20
21pub type Result<T> = std::result::Result<T, Error>;
23
24pub enum Format
26{
27  Text,
29  Json,
31}
32
33pub struct Prompt
35{
36  pub prompt: String,
38  pub assistant: Option<String>,
40  pub system: Option<String>,
42  pub format: Format,
44  #[cfg(feature = "image")]
46  pub image: Option<kproc_values::Image>,
47}
48
49impl Prompt
50{
51  pub fn prompt(prompt: impl Into<String>) -> Self
53  {
54    let prompt = prompt.into();
55    Self {
56      prompt,
57      assistant: None,
58      system: None,
59      format: Format::Text,
60      #[cfg(feature = "image")]
61      image: None,
62    }
63  }
64  pub fn system(mut self, system: impl Into<String>) -> Self
66  {
67    self.system = Some(system.into());
68    self
69  }
70  pub fn format(mut self, format: impl Into<Format>) -> Self
72  {
73    self.format = format.into();
74    self
75  }
76  #[cfg(feature = "image")]
78  pub fn image(mut self, image: impl Into<kproc_values::Image>) -> Self
79  {
80    self.image = Some(image.into());
81    self
82  }
83}
84
85pub type StringStream = Pin<Box<dyn Stream<Item = Result<String>> + Send>>;
87
88pub(crate) fn pin_stream<T: 'static + Send + Stream<Item = Result<String>>>(t: T) -> StringStream
90{
91  Box::pin(t)
92}
93
94pub trait LargeLanguageModel
96{
97  fn infer_stream(
99    &self,
100    prompt: Prompt,
101  ) -> Result<impl Future<Output = Result<StringStream>> + Send>;
102  fn infer(&self, prompt: Prompt) -> Result<impl Future<Output = Result<String>> + Send>
105  {
106    use futures::stream::StreamExt;
107    let stream = self.infer_stream(prompt)?;
108    Ok(async {
109      let mut result: String = Default::default();
110      let mut stream = Box::pin(stream.await?);
111      while let Some(next_token) = stream.next().await
112      {
113        if result.is_empty()
114        {
115          result = next_token?;
116        }
117        else
118        {
119          result.push_str(&next_token?);
120        }
121      }
122      Ok(result)
123    })
124  }
125}