1use std::{
6 collections::{BTreeMap, HashMap},
7 fmt::Debug,
8};
9
10type Map = BTreeMap<String, Box<dyn ParamFull>>;
11
12#[derive(Default, Debug)]
32pub struct Parameters {
33 map: Map,
34}
35
36impl Clone for Parameters {
37 fn clone(&self) -> Self {
38 let mut map = Map::new();
39 for (key, value) in self.map.iter() {
40 map.insert(key.clone(), value.boxed_clone());
41 }
42 Self { map }
43 }
44}
45
46impl PartialEq for Parameters {
47 fn eq(&self, other: &Self) -> bool {
48 self.map.keys().len() == other.map.keys().len()
49 && self.map.iter().all(|(k, v)| {
50 if let Some(other_v) = other.map.get(k) {
51 v.get() == other_v.get()
52 } else {
53 false
54 }
55 })
56 }
57}
58
59pub trait Param: Send + Sync {
60 fn get(&self) -> String;
61}
62
63#[doc(hidden)]
65pub trait ParamFull: Param + Debug + Send + Sync {
66 #[doc(hidden)]
67 fn boxed_clone(&self) -> Box<dyn ParamFull + Send>;
68}
69
70impl<T: Param + Debug + Clone + 'static> ParamFull for T {
71 #[doc(hidden)]
72 fn boxed_clone(&self) -> Box<dyn ParamFull + Send> {
73 Box::new(self.clone())
74 }
75}
76#[derive(Debug, Clone)]
77struct StringParam {
78 value: String,
79}
80
81impl StringParam {
82 fn new(value: String) -> Self {
83 Self { value }
84 }
85}
86
87impl Param for StringParam {
88 fn get(&self) -> String {
89 self.value.clone()
90 }
91}
92
93const TEXT_KEY: &str = "text";
94
95impl Parameters {
96 pub fn new() -> Parameters {
98 Default::default()
99 }
100 pub fn new_with_text<T: Into<String>>(text: T) -> Parameters {
102 let mut map = Map::new();
103 map.insert(
104 TEXT_KEY.to_string(),
105 Box::new(StringParam::new(text.into())),
106 );
107 Parameters { map }
108 }
109 pub fn with<K: Into<String>, V: Into<String>>(&self, key: K, value: V) -> Parameters {
111 let mut copy = self.clone();
112 copy.map
113 .insert(key.into(), Box::new(StringParam::new(value.into())));
114 copy
115 }
116
117 pub fn with_dynamic<K: Into<String>, V: ParamFull>(&self, key: K, value: V) -> Parameters {
119 let mut copy = self.clone();
120 copy.map.insert(key.into(), value.boxed_clone());
121 copy
122 }
123
124 pub fn with_text<K: Into<String>>(&self, text: K) -> Parameters {
126 self.with(TEXT_KEY, text)
127 }
128
129 pub fn combine(&self, other: &Parameters) -> Parameters {
131 let mut copy = self.clone();
132 for (key, value) in other.map.iter() {
133 copy.map.insert(key.clone(), value.boxed_clone());
134 }
135 copy
136 }
137 pub fn get(&self, key: &str) -> Option<String> {
139 self.map.get(key).map(|param| param.get())
140 }
141
142 pub fn get_text(&self) -> Option<String> {
143 self.get(TEXT_KEY)
144 }
145
146 pub(crate) fn to_tera(&self) -> tera::Context {
147 let mut context = tera::Context::new();
148 for (key, value) in self.map.iter() {
149 context.insert(key, &value.get());
150 }
151 context
152 }
153
154 fn from_seq<K, V, M>(m: M) -> Self
155 where
156 K: Into<String>,
157 V: Into<String>,
158 M: IntoIterator<Item = (K, V)>,
159 {
160 let mut map = Map::new();
161 for (k, v) in m.into_iter() {
162 map.insert(k.into(), Box::new(StringParam::new(v.into())));
163 }
164 Parameters { map }
165 }
166}
167
168impl From<String> for Parameters {
169 fn from(text: String) -> Self {
170 Parameters::new_with_text(text)
171 }
172}
173
174impl From<&str> for Parameters {
175 fn from(text: &str) -> Self {
176 Parameters::new_with_text(text)
177 }
178}
179
180impl From<HashMap<String, String>> for Parameters {
181 fn from(map: HashMap<String, String>) -> Self {
182 Parameters::from_seq(map.into_iter())
183 }
184}
185
186impl From<BTreeMap<String, String>> for Parameters {
187 fn from(map: BTreeMap<String, String>) -> Self {
188 Parameters::from_seq(map.into_iter())
189 }
190}
191
192impl From<Vec<(String, String)>> for Parameters {
193 fn from(data: Vec<(String, String)>) -> Self {
194 Parameters::from_seq(data.into_iter())
195 }
196}
197
198impl From<Vec<(&str, &str)>> for Parameters {
199 fn from(data: Vec<(&str, &str)>) -> Self {
200 Parameters::from_seq(data)
201 }
202}
203
204#[macro_export]
238macro_rules! parameters {
239 () => {
240 $crate::Parameters::new()
241 };
242 ($text:expr) => {
243 llm_chain::Parameters::new_with_text($text)
244 };
245 ($($key:expr => $value:expr),+$(,)?) => {{
246 let mut params = $crate::Parameters::new();
247 $(
248 params = params.with($key, $value);
249 )+
250 params
251 }};
252}