1use reqwest::header::{
4 HeaderMap, HeaderName, HeaderValue, ACCEPT, ACCEPT_LANGUAGE, CONTENT_TYPE, ORIGIN, REFERER,
5 USER_AGENT,
6};
7
8#[derive(Debug, Clone, Copy)]
10pub enum Endpoint {
11 Init,
13 Generate,
15 RotateCookies,
17 Upload,
19}
20
21impl Endpoint {
22 pub fn url(&self) -> &'static str {
24 match self {
25 Endpoint::Init => "https://gemini.google.com/app",
26 Endpoint::Generate => "https://gemini.google.com/_/BardChatUi/data/assistant.lamda.BardFrontendService/StreamGenerate",
27 Endpoint::RotateCookies => "https://accounts.google.com/RotateCookies",
28 Endpoint::Upload => "https://content-push.googleapis.com/upload",
29 }
30 }
31}
32
33pub fn gemini_headers() -> HeaderMap {
35 let mut headers = HeaderMap::new();
36 headers.insert(
37 CONTENT_TYPE,
38 HeaderValue::from_static("application/x-www-form-urlencoded;charset=utf-8"),
39 );
40
41 headers.insert(
42 ORIGIN,
43 HeaderValue::from_static("https://gemini.google.com"),
44 );
45 headers.insert(
46 REFERER,
47 HeaderValue::from_static("https://gemini.google.com/"),
48 );
49 headers.insert(
50 HeaderName::from_static("x-same-domain"),
51 HeaderValue::from_static("1"),
52 );
53 headers.insert(
55 USER_AGENT,
56 HeaderValue::from_static("Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"),
57 );
58 headers.insert(ACCEPT, HeaderValue::from_static("*/*"));
60 headers.insert(ACCEPT_LANGUAGE, HeaderValue::from_static("en-US,en;q=0.9"));
61 headers.insert(
62 HeaderName::from_static("sec-ch-ua"),
63 HeaderValue::from_static(
64 "\"Not_A Brand\";v=\"8\", \"Chromium\";v=\"120\", \"Google Chrome\";v=\"120\"",
65 ),
66 );
67 headers.insert(
68 HeaderName::from_static("sec-ch-ua-mobile"),
69 HeaderValue::from_static("?0"),
70 );
71 headers.insert(
72 HeaderName::from_static("sec-ch-ua-platform"),
73 HeaderValue::from_static("\"Windows\""),
74 );
75 headers.insert(
76 HeaderName::from_static("sec-fetch-dest"),
77 HeaderValue::from_static("empty"),
78 );
79 headers.insert(
80 HeaderName::from_static("sec-fetch-mode"),
81 HeaderValue::from_static("cors"),
82 );
83 headers.insert(
84 HeaderName::from_static("sec-fetch-site"),
85 HeaderValue::from_static("same-origin"),
86 );
87 headers
88}
89
90pub fn rotate_cookies_headers() -> HeaderMap {
92 let mut headers = HeaderMap::new();
93 headers.insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
94 headers
95}
96
97pub fn upload_headers() -> HeaderMap {
99 let mut headers = HeaderMap::new();
100 headers.insert(
101 HeaderName::from_static("push-id"),
102 HeaderValue::from_static("feeds/mcudyrk2a4khkz"),
103 );
104 headers
105}
106
107#[derive(Debug, Clone, Default)]
109pub enum Model {
110 #[default]
112 Unspecified,
113 G2_0Flash,
115 G2_0FlashThinking,
117 G2_5Flash,
119 G2_5Pro,
121 G2_0ExpAdvanced,
123 G2_5ExpAdvanced,
125 G3_0Pro,
127 G3_0Flash,
129 G3_0Thinking,
131}
132
133impl Model {
134 pub fn name(&self) -> &'static str {
136 match self {
137 Model::Unspecified => "unspecified",
138 Model::G2_0Flash => "gemini-2.0-flash",
139 Model::G2_0FlashThinking => "gemini-2.0-flash-thinking",
140 Model::G2_5Flash => "gemini-2.5-flash",
141 Model::G2_5Pro => "gemini-2.5-pro",
142 Model::G2_0ExpAdvanced => "gemini-2.0-exp-advanced",
143 Model::G2_5ExpAdvanced => "gemini-2.5-exp-advanced",
144 Model::G3_0Pro => "gemini-3.0-pro",
145 Model::G3_0Flash => "gemini-3.0-flash",
146 Model::G3_0Thinking => "gemini-3.0-flash-thinking",
147 }
148 }
149
150 pub fn headers(&self) -> Option<HeaderMap> {
152 let header_value = match self {
153 Model::Unspecified => return None,
154 Model::G2_0Flash => r#"[1,null,null,null,"f299729663a2343f"]"#,
155 Model::G2_0FlashThinking => r#"[null,null,null,null,"7ca48d02d802f20a"]"#,
156 Model::G2_5Flash => r#"[1,null,null,null,"35609594dbe934d8"]"#,
157 Model::G2_5Pro => r#"[1,null,null,null,"2525e3954d185b3c"]"#,
158 Model::G2_0ExpAdvanced => r#"[null,null,null,null,"b1e46a6037e6aa9f"]"#,
159 Model::G2_5ExpAdvanced => r#"[null,null,null,null,"203e6bb81620bcfe"]"#,
160 Model::G3_0Pro => {
161 r#"[1,null,null,null,"e6fa609c3fa255c0",null,null,0,[4],null,null,2]"#
162 }
163 Model::G3_0Thinking => {
164 r#"[1,null,null,null,"e051ce1aa80aa576",null,null,0,[4],null,null,2]"#
165 }
166 Model::G3_0Flash => {
167 r#"[1,null,null,null,"56fdd199312815e2",null,null,0,[4],null,null,2]"#
168 }
169 };
170
171 let mut headers = HeaderMap::new();
172 headers.insert(
173 HeaderName::from_static("x-goog-ext-525001261-jspb"),
174 HeaderValue::from_str(header_value).unwrap(),
175 );
176 Some(headers)
177 }
178
179 pub fn is_advanced_only(&self) -> bool {
181 matches!(self, Model::G2_0ExpAdvanced | Model::G2_5ExpAdvanced)
182 }
183
184 pub fn from_name(name: &str) -> Option<Self> {
186 match name {
187 "unspecified" => Some(Model::Unspecified),
188 "gemini-2.0-flash" => Some(Model::G2_0Flash),
189 "gemini-2.0-flash-thinking" => Some(Model::G2_0FlashThinking),
190 "gemini-2.5-flash" => Some(Model::G2_5Flash),
191 "gemini-2.5-pro" => Some(Model::G2_5Pro),
192 "gemini-2.0-exp-advanced" => Some(Model::G2_0ExpAdvanced),
193 "gemini-2.5-exp-advanced" => Some(Model::G2_5ExpAdvanced),
194 "gemini-3.0-pro" => Some(Model::G3_0Pro),
195 "gemini-3.0-flash" => Some(Model::G3_0Flash),
196 "gemini-3.0-thinking" => Some(Model::G3_0Thinking),
197 _ => None,
198 }
199 }
200}