1use rand::Rng;
2use reqwest::header;
3use serde::{Deserialize, Serialize};
4use serde_json::json;
5
6#[derive(Debug, Serialize, Deserialize)]
7pub struct ChatSession {
8 request_id: i32,
9 snlm0e: String,
10 cfb2h: String,
11 last_conversation_id: String,
12 last_response_id: String,
13 last_choice_id: String,
14}
15
16impl ChatSession {
17 pub async fn new() -> Self {
18 let mut client = reqwest::Client::builder();
19 if let Ok(proxy) = std::env::var("https_proxy") {
20 client = client.proxy(reqwest::Proxy::https(&proxy).unwrap());
21 }
22 let mut headers = header::HeaderMap::new();
23 let secure_1psid = std::env::var("Secure_1PSID").unwrap();
24 let secure_1psid = format!("__Secure-1PSID={secure_1psid}");
25 headers.insert(
26 "Cookie",
27 header::HeaderValue::from_str(&secure_1psid).unwrap(),
28 );
29 let response = client
30 .user_agent("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36")
31 .default_headers(headers)
32 .build()
33 .unwrap()
34 .get("https://bard.google.com/").send().await.unwrap();
35 let response_text = response.text().await.unwrap();
36 let snlm0e_search_result = regex::Regex::new(r#"SNlM0e":"(.*?)""#)
37 .unwrap()
38 .captures(&response_text);
39 let cfb2h_search_result = regex::Regex::new(r#"cfb2h":"(.*?)""#)
40 .unwrap()
41 .captures(&response_text);
42 if snlm0e_search_result.is_none() || cfb2h_search_result.is_none() {
43 panic!("Cannot find snlm0e or cfb2h");
44 } else {
45 let snlm0e = snlm0e_search_result
46 .unwrap()
47 .get(1)
48 .unwrap()
49 .as_str()
50 .to_string();
51 let cfb2h = cfb2h_search_result
52 .unwrap()
53 .get(1)
54 .unwrap()
55 .as_str()
56 .to_string();
57 let request_id = rand::thread_rng().gen_range(100000..999999);
58 ChatSession {
59 request_id,
60 snlm0e,
61 cfb2h,
62 last_conversation_id: "".to_string(),
63 last_response_id: "".to_string(),
64 last_choice_id: "".to_string(),
65 }
66 }
67 }
68
69 fn parse_response(&self, response: &str) -> (String, String, String, String) {
70 let mut lines = response.split('\n');
71 let the_line = lines.find(|it| it.contains("wrb.fr")).unwrap();
72 let parsed_line = serde_json::from_str::<Vec<Vec<serde_json::Value>>>(the_line).unwrap();
73 let inner_str = parsed_line[0][2].as_str().unwrap();
74 let inner = serde_json::from_str::<Vec<Vec<serde_json::Value>>>(&inner_str).unwrap();
75 let text_response = inner[0][0].as_str().unwrap();
76 let c_and_r = [inner[1][0].as_str().unwrap(), inner[1][1].as_str().unwrap()];
77 let rc = inner[4][0].as_array().unwrap()[0].as_str().unwrap();
78 return (
79 text_response.to_string(),
80 c_and_r[0].to_string(),
81 c_and_r[1].to_string(),
82 rc.to_string(),
83 );
84 }
85
86 pub async fn send_message(&mut self, text: &str) -> String {
87 let input_text_struct = json!([
88 [text.to_string()],
89 null,
90 [
91 self.last_conversation_id.clone(),
92 self.last_response_id.clone(),
93 self.last_choice_id.clone(),
94 ],
95 ]);
96 let input_text = serde_json::to_string(&input_text_struct).unwrap();
97 let mut params = Vec::new();
98 params.push(("bl", self.cfb2h.clone()));
99 params.push(("_reqid", self.request_id.to_string()));
100 params.push(("rt", "c".to_string()));
101 params.push((
102 "f.req",
103 serde_json::to_string(&json!([null, input_text])).unwrap(),
104 ));
105 params.push(("at", self.snlm0e.clone()));
106 let mut client = reqwest::Client::builder();
107 if let Ok(proxy) = std::env::var("https_proxy") {
108 client = client.proxy(reqwest::Proxy::https(&proxy).unwrap());
109 }
110 let mut headers = header::HeaderMap::new();
111 let secure_1psid = std::env::var("Secure_1PSID").unwrap();
112 let secure_1psid = format!("__Secure-1PSID={secure_1psid}");
113 headers.insert(
114 "Cookie",
115 header::HeaderValue::from_str(&secure_1psid).unwrap(),
116 );
117 let resp = client
118 .default_headers(headers)
119 .build()
120 .unwrap()
121 .post("https://bard.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate")
122 .header("Content-Type", "application/x-www-form-urlencoded")
123 .form(¶ms)
124 .send()
125 .await
126 .unwrap();
127 let resp_text = resp.text().await.unwrap();
128 let (text_response, conversation_id, response_id, choice_id) =
129 self.parse_response(&resp_text);
130 self.last_conversation_id = conversation_id;
131 self.last_response_id = response_id;
132 self.last_choice_id = choice_id;
133 self.request_id += 100000;
134 text_response
135 }
136}
137
138#[cfg(test)]
139mod tests {
140 use super::*;
141
142 #[tokio::test]
143 async fn it_works() {
144 let mut session = ChatSession::new().await;
145 let response = session.send_message("Hello").await;
146 println!("{}", response);
147 }
148}