Skip to content
This repository was archived by the owner on Jun 12, 2024. It is now read-only.

Commit eed73ad

Browse files
committed
fix: async client on process
1 parent 683d4af commit eed73ad

File tree

1 file changed

+61
-86
lines changed

1 file changed

+61
-86
lines changed

gemini/client.py renamed to gemini/async.py

Lines changed: 61 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -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.\nRefresh 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

Comments
 (0)