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;
16
17pub use error::Error;
19use futures::Stream;
20
21pub type Result<T> = std::result::Result<T, Error>;
23
24#[derive(Debug)]
26pub enum Format
27{
28 Text,
30 Json,
32}
33
34#[derive(Debug)]
36pub struct Prompt
37{
38 pub prompt: String,
40 pub assistant: Option<String>,
42 pub system: Option<String>,
44 pub format: Format,
46 #[cfg(feature = "image")]
48 pub image: Option<kproc_values::Image>,
49}
50
51impl Prompt
52{
53 pub fn prompt(prompt: impl Into<String>) -> Self
55 {
56 let prompt = prompt.into();
57 Self {
58 prompt,
59 assistant: None,
60 system: None,
61 format: Format::Text,
62 #[cfg(feature = "image")]
63 image: None,
64 }
65 }
66 pub fn system(mut self, system: impl Into<String>) -> Self
68 {
69 self.system = Some(system.into());
70 self
71 }
72 pub fn format(mut self, format: impl Into<Format>) -> Self
74 {
75 self.format = format.into();
76 self
77 }
78 #[cfg(feature = "image")]
80 pub fn image(mut self, image: impl Into<kproc_values::Image>) -> Self
81 {
82 self.image = Some(image.into());
83 self
84 }
85}
86
87pub type StringStream = ccutils::futures::BoxedStream<Result<String>>;
89
90pub(crate) fn pin_stream<T: 'static + Send + Stream<Item = Result<String>>>(t: T) -> StringStream
92{
93 Box::pin(t)
94}
95
96pub trait LargeLanguageModel
98{
99 fn infer_stream(
101 &self,
102 prompt: Prompt,
103 ) -> Result<impl Future<Output = Result<StringStream>> + Send>;
104 fn infer(&self, prompt: Prompt) -> Result<impl Future<Output = Result<String>> + Send>
107 {
108 use futures::stream::StreamExt;
109 let stream = self.infer_stream(prompt)?;
110 Ok(async {
111 let mut result: String = Default::default();
112 let mut stream = Box::pin(stream.await?);
113 while let Some(next_token) = stream.next().await
114 {
115 if result.is_empty()
116 {
117 result = next_token?;
118 }
119 else
120 {
121 result.push_str(&next_token?);
122 }
123 }
124 Ok(result)
125 })
126 }
127}