sarufi_rs/
lib.rs

1use reqwest::{Client, ClientBuilder, header::HeaderMap};
2
3pub use errors::ApiError;
4pub use bot::{Bot};
5use serde_json::{ Value};
6use std::{collections::HashMap};
7use std::fs::File;
8use std::io::BufReader;
9
10mod errors;
11mod utils;
12mod api;
13mod bot;
14mod test;
15
16use crate::api::SarufiApiError;
17
18
19
20/// API struct. Exposes function to interact with the Sarufi API 🥷
21/// #[derive(Debug, Serialize, Deserialize)]
22pub struct SarufiAPI {
23    client: Client,
24}
25
26
27impl SarufiAPI {
28    /// Creates a new instance of SarufiAPI using the provided api key
29    /// this function panics if the api_key is empty 🤒
30    pub fn new<S: Into<String>>(api_key: S) -> Result<SarufiAPI, ApiError> {
31        let owned_key = api_key.into();
32
33        utils::validate_keys(&owned_key)?;
34
35        let mut default_headers = HeaderMap::new();
36        default_headers.insert("Authorization", format!("Bearer {}", owned_key).parse().unwrap());
37        default_headers.insert("Content-Type", "application/json".parse().unwrap());
38
39
40        let client = ClientBuilder::new().default_headers(default_headers).build()?;
41
42        Ok(SarufiAPI { client })
43    }
44
45    
46    pub async fn get_bot(&self, id: usize) -> Result<Bot, ApiError> {
47            let url = utils::api_url(&format!("/chatbot/{}", id));
48            
49            let response = self.client.get(&url).send().await?;
50
51            if response.status().is_success() {
52                let  result = response.json::<Bot>().await?;
53                Ok(result)
54            } else {
55                let error = response.json::<SarufiApiError>().await?;
56                Err(ApiError::GenericError(error.message()))
57            }
58  
59        }
60
61    pub async fn get_all_bots(&self) -> Result<Vec<Bot>, ApiError> {
62            let url = utils::api_url("/chatbots");
63            let response = self.client.get(&url).send().await?;
64
65            if response.status().is_success() {
66                let result = response.json::<Vec<Bot>>().await?;
67                Ok(result)
68            } else {
69                let error = response.json::<SarufiApiError>().await?;
70                Err(ApiError::GenericError(error.message()))
71            }
72  
73        }
74     
75        pub async fn _fetch_response(&self, bot_id: usize, chat_id: &str, message: &str, message_type: &str, channel: &str) -> Result<String, ApiError> {
76            let _url = utils::api_url("/conversation");
77        
78            if  channel == "whatsapp" {
79                let _url = utils::api_url("/conversation/whatsapp");  
80            }
81
82            let mut data = HashMap::new();
83            data.insert("bot_id".to_owned(), Value::Number(serde_json::Number::from(bot_id)));
84            data.insert("chat_id".to_owned(), Value::String(chat_id.to_owned()));
85            data.insert("message".to_owned(), Value::String(message.to_owned()));
86            data.insert("message_type".to_owned(), Value::String(message_type.to_owned()));
87            data.insert("channel".to_owned(), Value::String(channel.to_owned()));
88        
89            let response = self.client.post(&_url).json(&Value::Object(data.into_iter().collect())).send().await?;
90        
91            if response.status().is_success() {
92               
93                let json_string = response.text().await.unwrap();
94                let json_value: Value = serde_json::from_str(&json_string).unwrap();
95                let result = & json_value["message"][0];
96               
97                Ok(result.to_string())
98            } else {
99                let error = response.json::<SarufiApiError>().await?;
100                Err(ApiError::GenericError(error.message()))
101            }
102        }
103        
104        pub async fn chat(&self, bot_id: usize) -> Result<String, ApiError> {
105            let chat_id = utils::generate_uuid().to_string();
106            println!("Chat ID: {:?}", chat_id);
107            let message = "Hello";
108            let message_type = "text";
109            let channel = "general";
110
111            let response = self._fetch_response(bot_id, &chat_id, message, message_type, channel).await.unwrap();
112
113            Ok(response)
114        }
115
116        pub async fn chat_status(&self, bot_id: usize, chat_id: &str) -> Result<String, ApiError> {
117            let url = utils::api_url("/allchannels/status");
118        
119            let mut data = HashMap::new();
120            data.insert("bot_id".to_owned(), Value::Number(serde_json::Number::from(bot_id)));
121            data.insert("chat_id".to_owned(), Value::String(chat_id.to_owned()));
122        
123            let response = self.client.post(&url).json(&Value::Object(data.into_iter().collect())).send().await?;
124        
125            if response.status().is_success() {
126                let json_string = response.text().await.unwrap();
127                Ok(json_string)
128            } else {
129                let error = response.json::<SarufiApiError>().await?;
130                Err(ApiError::GenericError(error.message()))
131            }
132        }
133
134        pub async fn update_conversation_state(&self, bot_id: usize, chat_id: &str, next_state: &str) -> Result<String, ApiError> {
135
136            let url = utils::api_url("/conversation-state");
137        
138            let mut data = HashMap::new();
139            data.insert("bot_id".to_owned(), Value::Number(serde_json::Number::from(bot_id)));
140            data.insert("chat_id".to_owned(), Value::String(chat_id.to_owned()));
141            data.insert("next_state".to_owned(), Value::String(next_state.to_owned()));
142
143            let response = self.client.post(&url).json(&Value::Object(data.into_iter().collect())).send().await?;
144
145            if response.status().is_success() {
146                let json_string = response.text().await.unwrap();
147                // let json_value: Value = serde_json::from_str(&json_string).unwrap();
148                // let result = & json_value["message"][0];
149               
150                Ok(json_string)
151            } else {
152                let error = response.json::<SarufiApiError>().await?;
153                Err(ApiError::GenericError(error.message()))
154            }
155            
156        
157        }
158        pub async fn delete_bot(&self, id: usize) -> Result<(), ApiError> {
159            let url = utils::api_url(&format!("/chatbot/{}", id));
160            let response = self.client.delete(&url).send().await?;
161
162            if response.status().is_success() {
163     
164                Ok(())
165            } else {
166                let error = response.json::<SarufiApiError>().await?;
167                Err(ApiError::GenericError(error.message()))
168            }
169  
170        }
171
172        /// Creates a new bot
173        pub async fn create_bot(&self, 
174            name: &str,
175            description: Option<&str>,
176            industry: Option<&str>,
177            flow: Option<HashMap<String, Value>>,
178            intents: Option<HashMap<String, Vec<String>>>,
179            webhook_url: Option<&str>,
180            webhook_trigger_intents: Option<Vec<String>>,
181            visible_on_community: Option<bool>) -> Result<Bot, ApiError> {
182
183            let url = utils::api_url("/chatbot");
184            let mut data = HashMap::new();
185
186            data.insert("name".to_owned(), Value::String(name.to_owned()));
187    
188            if let Some(description) = description {
189                data.insert("description".to_owned(), Value::String(description.to_owned()));
190            }
191        
192            if let Some(industry) = industry {
193                data.insert("industry".to_owned(), Value::String(industry.to_owned()));
194            }
195        
196            if let Some(flow) = flow {
197                data.insert("flow".to_owned(), Value::Object(flow.into_iter().collect()));
198            }
199        
200            if let Some(intents) = intents {
201                data.insert(
202                    "intents".to_owned(),
203                    Value::Object(
204                        intents
205                            .into_iter()
206                            .map(|(k, v)| (k, Value::Array(v.into_iter().map(Value::String).collect())))
207                            .collect(),
208                    ),
209                );
210            }
211        
212            if let Some(webhook_url) = webhook_url {
213                data.insert("webhook_url".to_owned(), Value::String(webhook_url.to_owned()));
214            }
215        
216            if let Some(webhook_trigger_intents) = webhook_trigger_intents {
217                data.insert(
218                    "webhook_trigger_intents".to_owned(),
219                    Value::Array(webhook_trigger_intents.into_iter().map(Value::String).collect()),
220                );
221            }
222
223            if let Some(visible_on_community) = visible_on_community {
224                data.insert("visible_on_community".to_owned(), Value::Bool(visible_on_community));
225            }
226        
227            let response = self.client.post(&url).json(&Value::Object(data.into_iter().collect())).send().await?;
228            
229         
230            if response.status().is_success() {
231                
232                let mut result = response.json::<Bot>().await?;
233
234                // do you really need to check this?, seems to be working fine without it
235                if let Some(e_metrics) = result.evaluation_metrics {
236                    
237                    result.evaluation_metrics = Some(e_metrics);
238                }
239
240                if let Some(confidence_threshold) = result.confidence_threshold {
241                    
242                    result.confidence_threshold = Some(confidence_threshold);
243                }
244                // let json_string = response.text().await?;
245                // let json_value: Value = serde_json::from_str(&json_string).unwrap();
246                // let pretty_json = serde_json::to_string_pretty(&json_value).unwrap();
247                // println!("{}", pretty_json);
248               
249                Ok(result)
250            } else {
251                let error = response.json::<SarufiApiError>().await?;
252                Err(ApiError::GenericError(error.message()))
253            }
254            
255
256        }
257
258
259        pub async fn create_bot_from_file(
260            &self,
261            file_path: &str,
262        ) -> Result<Bot, ApiError> {
263            let file = File::open(file_path)?;
264            let reader = BufReader::new(file);
265            let data: Value = serde_json::from_reader(reader)?;
266            let data = data.as_object().ok_or_else(|| ApiError::GenericError("Invalid JSON".to_owned()))?;
267            print!("{:?}", data);
268        
269            let url = utils::api_url("/chatbot");
270            let response = self.client.post(&url).json(&data).send().await?;
271        
272            if response.status().is_success() {
273                let mut result = response.json::<Bot>().await?;
274        
275                if let Some(e_metrics) = result.evaluation_metrics {
276                    result.evaluation_metrics = Some(e_metrics);
277                }
278        
279                if let Some(confidence_threshold) = result.confidence_threshold {
280                    result.confidence_threshold = Some(confidence_threshold);
281                }
282        
283                Ok(result)
284            } else {
285                let error = response.json::<SarufiApiError>().await?;
286                Err(ApiError::GenericError(error.message()))
287            }
288        }
289
290        pub async fn update_bot(&self, 
291            id: usize,
292            name: &str,
293            description: Option<&str>,
294            industry: Option<&str>,
295            flow: Option<HashMap<String, Value>>,
296            intents: Option<HashMap<String, Vec<String>>>,
297            webhook_url: Option<&str>,
298            webhook_trigger_intents: Option<Vec<String>>,
299            visible_on_community: Option<bool>) -> Result<Bot, ApiError> {
300
301            let url = utils::api_url(&format!("/chatbot/{}", id));
302            let mut data = HashMap::new();
303
304            data.insert("name".to_owned(), Value::String(name.to_owned()));
305    
306            if let Some(description) = description {
307                data.insert("description".to_owned(), Value::String(description.to_owned()));
308            }
309        
310            if let Some(industry) = industry {
311                data.insert("industry".to_owned(), Value::String(industry.to_owned()));
312            }
313        
314            if let Some(flow) = flow {
315                data.insert("flow".to_owned(), Value::Object(flow.into_iter().collect()));
316            }
317        
318            if let Some(intents) = intents {
319                data.insert(
320                    "intents".to_owned(),
321                    Value::Object(
322                        intents
323                            .into_iter()
324                            .map(|(k, v)| (k, Value::Array(v.into_iter().map(Value::String).collect())))
325                            .collect(),
326                    ),
327                );
328            }
329        
330            if let Some(webhook_url) = webhook_url {
331                data.insert("webhook_url".to_owned(), Value::String(webhook_url.to_owned()));
332            }
333        
334            if let Some(webhook_trigger_intents) = webhook_trigger_intents {
335                data.insert(
336                    "webhook_trigger_intents".to_owned(),
337                    Value::Array(webhook_trigger_intents.into_iter().map(Value::String).collect()),
338                );
339            }
340
341            if let Some(visible_on_community) = visible_on_community {
342                data.insert("visible_on_community".to_owned(), Value::Bool(visible_on_community));
343            }
344        
345            let response = self.client.put(&url).json(&Value::Object(data.into_iter().collect())).send().await?;
346         
347            if response.status().is_success() {
348                let result = response.json::<Bot>().await?;
349                Ok(result)
350            } else {
351                let error = response.json::<SarufiApiError>().await?;
352                Err(ApiError::GenericError(error.message()))
353            }
354          
355        }
356
357   
358}
359
360