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}