@@ -59,14 +59,11 @@ class GeminiClient:
5959 def __init__ (
6060 self ,
6161 auto_cookies : bool = False ,
62- token : str = None ,
6362 session : Optional [httpx .AsyncClient ] = None ,
6463 cookies : Optional [dict ] = {},
64+ cookie_fp : str = None ,
6565 timeout : int = 30 ,
6666 proxies : Optional [dict ] = {},
67- language : Optional [str ] = None ,
68- verify : bool = True ,
69- latency : int = 10 ,
7067 auto_close = True ,
7168 close_delay : int = 60 ,
7269 ):
@@ -89,19 +86,16 @@ def __init__(
8986 auto_close (bool): If True, the session will automatically close after a specified delay. Defaults to True.
9087 close_delay (int): The delay in seconds before the session is automatically closed, applicable if auto_close is True. Defaults to 60.
9188 """
92- self .auto_cookies = auto_cookies
93- self .latency = latency
94- self .running = False
89+ self ._nonce = None
90+ self ._sid = None
9591 self ._reqid = int ("" .join (random .choices (string .digits , k = 4 )))
92+ self .running = False
9693 self .cookies = cookies
97- self ._get_cookies (auto_cookies )
94+ self .cookie_fp = cookie_fp
95+ self .auto_cookies = auto_cookies
9896 self .proxies = proxies or {}
9997 self .timeout = timeout
10098 self .session = session
101- self .token = token
102- self .token = self .get_nonce_value ()
103- self .language = language or os .getenv ("GEMINI_LANGUAGE" )
104- self .verify = verify
10599 self .auto_close = auto_close
106100 self .close_delay = close_delay
107101
@@ -110,17 +104,13 @@ async def async_init(
110104 ) -> None :
111105 """
112106 Initializes the asynchronous session with optional auto-close functionality.
113-
114- Args:
115- auto_close (bool): Flag to enable automatic session closure.
116- close_delay (int): Delay in seconds before automatically closing the session.
117107 """
118- self .session = await self ._create_async_session (
119- auto_close = self . auto_close , close_delay = self . close_delay
120- )
108+ self .session = await self ._create_async_session ()
109+
110+
121111
122112 async def _create_async_session (
123- self , auto_close : bool , close_delay : int
113+ self
124114 ) -> httpx .AsyncClient :
125115 """
126116 Initializes or configures the httpx.AsyncClient session with predefined session headers, proxies, and cookies.
@@ -133,16 +123,19 @@ async def _create_async_session(
133123 """
134124 if self .session is not None :
135125 return self .session
136-
137- print (self .cookies )
138- if not self .cookies :
126+ if self .cookies :
127+ self .session .cookies .update (self .cookies )
128+ elif self .cookie_fp :
129+ self ._load_cookies_from_file (self .cookie_fp )
130+ elif not self .cookies :
139131 raise ValueError ("Failed to set session. 'cookies' dictionary is empty." )
140132
141133 self .session = httpx .AsyncClient (
142134 headers = HEADERS ,
143135 cookies = self .cookies ,
144- proxies = self .proxies ,
145136 timeout = self .timeout ,
137+ auto_close = self .auto_close ,
138+ close_delay = self .close_delay
146139 )
147140
148141 if hasattr (self , "session" ):
@@ -151,6 +144,23 @@ async def _create_async_session(
151144 self .running = False
152145
153146 return self .session
147+
148+ def _load_cookies_from_file (self , file_path : str ) -> None :
149+ """Loads cookies from a file and updates the session."""
150+ try :
151+ if file_path .endswith (".json" ):
152+ with open (file_path , "r" ) as file :
153+ cookies = json .load (file )
154+ else :
155+ with open (file_path , "r" ) as file :
156+ content = file .read ()
157+ try :
158+ cookies = eval (content )
159+ except NameError :
160+ cookies = json .loads (content .replace ("'" , '"' ))
161+ self .session .cookies .update (cookies )
162+ except Exception as e :
163+ print (f"Error loading cookie file: { e } " )
154164
155165 async def close (self ):
156166 if self .session :
@@ -189,21 +199,31 @@ def check_session_headers(self) -> None:
189199 else :
190200 print ("Session not initialized." )
191201
192- def get_nonce_value (self ) -> str :
202+ def _set_sid_and_nonce (self ):
193203 """
194- Get the Nonce Token value from the Gemini API response .
204+ Retrieves the session ID (SID) and a SNlM0e nonce value from the application page .
195205 """
196- error_message = "Nonce token value not found or response status is not 200."
206+ try :
207+ response = requests .get (f"{ HOST } /app" , cookies = self .cookies )
208+ response .raise_for_status ()
197209
198- with requests .Session () as session :
199- response = session .get (HOST , timeout = self .timeout , proxies = self .proxies )
200- if response .status_code == 200 :
201- match = re .search (r'nonce="([^"]+)"' , response .text )
202- if match :
203- return match .group (1 )
204- raise Exception (error_message )
210+ sid_match , nonce_match = self .extract_sid_nonce (response .text )
211+
212+ if sid_match and nonce_match :
213+ self ._sid = sid_match .group (1 )
214+ self ._nonce = nonce_match .group (1 )
215+ else :
216+ raise ValueError (
217+ "Failed to parse SID or SNlM0e nonce from the response.\n Refresh the Gemini web page or access Gemini in a new incognito browser to resend cookies."
218+ )
219+
205220
206- def _get_cookies (self , auto_cookies : bool ) -> None :
221+ except requests .RequestException as e :
222+ raise ConnectionError (f"Request failed: { e } " )
223+ except ValueError as e :
224+ raise e # Re-raise the exception after it's caught
225+ except Exception as e :
226+ raise RuntimeError (f"An unexpected error occurred: { e } " )
207227 """
208228 Updates the instance's cookies attribute with Gemini API tokens, either from environment variables or by extracting them from the browser, based on the auto_cookies flag. If self.cookies already contains cookies, it will use these existing cookies and not attempt to update them.
209229 """
@@ -216,30 +236,12 @@ def _get_cookies(self, auto_cookies: bool) -> None:
216236 print ("Using existing cookies." )
217237 return # Exit the method if cookies already exist
218238
219- # Attempt to load cookies automatically from the browser if necessary
220- if auto_cookies and not self .cookies :
221- try :
222- self ._get_cookies_from_browser ()
223- except Exception as e :
224- raise Exception ("Failed to extract cookies from browser." ) from e
225-
226- # Warning if no cookies are available and auto_cookies is False
227- if not auto_cookies and not self .cookies :
228- print (
229- "Cookie loading issue, try setting auto_cookies to True. Restart browser, log out, log in for Gemini Web UI to work. Keep a single browser open."
230- )
231- try :
232- self .auto_cookies = True
233- self ._get_cookies_from_browser ()
234- except Exception as e :
235- print (e )
236-
237- # Raise an exception if still no cookies
238- if not self .cookies :
239- raise Exception (
240- "Gemini cookies must be provided through environment variables or extracted from the browser with auto_cookies enabled."
241- )
242-
239+ @staticmethod
240+ def extract_sid_nonce (response_text ):
241+ sid_match = re .search (r'"FdrFJe":"([\d-]+)"' , response_text )
242+ nonce_match = re .search (r'"SNlM0e":"(.*?)"' , response_text )
243+ return sid_match , nonce_match
244+
243245 def _get_cookies_from_browser (self ) -> dict :
244246 """
245247 Attempts to extract specific Gemini cookies from the cookies stored by web browsers on the current system.
@@ -278,34 +280,7 @@ def _get_cookies_from_browser(self) -> dict:
278280 "Failed to get cookies. Set 'cookies' argument or 'auto_cookies' as True."
279281 )
280282
281- def _update_cookies (self , update_cookie_list : List [str ] = None ):
282- """
283- Updates specified cookies in the httpx client. If update_cookie_list is not provided,
284- updates all cookies stored in self.cookies.
285283
286- Parameters:
287- - update_cookie_list (List[str], optional): A list of cookie names to update.
288- If None, updates all cookies from self.cookies.
289- """
290- self ._get_cookies (True )
291-
292- cookies_to_update = (
293- {k : self .cookies [k ] for k in update_cookie_list }
294- if update_cookie_list is not None
295- else self .cookies
296- )
297-
298- try :
299- for cookie_name , cookie_value in cookies_to_update .items ():
300- if cookie_value :
301- self .session .cookies .set (cookie_name , cookie_value )
302- print (f"Succefully update cookies: { cookies_to_update } " )
303- else :
304- print (
305- f"Warning: Cookie value for { cookie_name } is missing; skipping update."
306- )
307- except Exception as e :
308- print (f"An error occurred while updating cookies: { e } " )
309284
310285 def _construct_params (self , sid : str ) -> str :
311286 """
0 commit comments