Skip to main content

gemini_chat_api/
enums.rs

1//! Enums and constants for Gemini API endpoints, headers, and models.
2
3use reqwest::header::{
4    HeaderMap, HeaderName, HeaderValue, ACCEPT, ACCEPT_LANGUAGE, CONTENT_TYPE, ORIGIN, REFERER,
5    USER_AGENT,
6};
7
8/// API endpoints for Google Gemini.
9#[derive(Debug, Clone, Copy)]
10pub enum Endpoint {
11    /// Initialize session and get SNlM0e token.
12    Init,
13    /// Generate chat response.
14    Generate,
15    /// Rotate authentication cookies.
16    RotateCookies,
17    /// Upload files/images.
18    Upload,
19}
20
21impl Endpoint {
22    /// Get the URL for this endpoint.
23    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
33/// Get headers for Gemini chat requests.
34pub 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    // Chrome-like User-Agent (critical for authentication)
54    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    // Browser headers
59    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
90/// Get headers for cookie rotation requests.
91pub 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
97/// Get headers for file upload requests.
98pub 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/// Available Gemini model configurations.
108#[derive(Debug, Clone, Default)]
109pub enum Model {
110    /// Unspecified model - uses default.
111    #[default]
112    Unspecified,
113    /// Gemini 2.0 Flash
114    G2_0Flash,
115    /// Gemini 2.0 Flash Thinking
116    G2_0FlashThinking,
117    /// Gemini 2.5 Flash
118    G2_5Flash,
119    /// Gemini 2.5 Pro
120    G2_5Pro,
121    /// Gemini 2.0 Experimental Advanced (requires advanced subscription)
122    G2_0ExpAdvanced,
123    /// Gemini 2.5 Experimental Advanced (requires advanced subscription)
124    G2_5ExpAdvanced,
125    /// Gemini 3.0 Pro
126    G3_0Pro,
127    /// Gemini 3.0 Flash
128    G3_0Flash,
129    /// Gemini 3.0 Flash Thinking
130    G3_0Thinking,
131}
132
133impl Model {
134    /// Get the model name string.
135    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    /// Get model-specific headers (for x-goog-ext-525001261-jspb header).
151    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    /// Whether this model requires advanced subscription.
180    pub fn is_advanced_only(&self) -> bool {
181        matches!(self, Model::G2_0ExpAdvanced | Model::G2_5ExpAdvanced)
182    }
183
184    /// Create model from name string.
185    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}