gemini-webapi 1.15.2__py3-none-any.whl → 1.16.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- gemini_webapi/client.py +0 -11
- gemini_webapi/constants.py +1 -0
- gemini_webapi/utils/get_access_token.py +37 -9
- gemini_webapi/utils/load_browser_cookies.py +10 -4
- gemini_webapi/utils/rotate_1psidts.py +5 -1
- {gemini_webapi-1.15.2.dist-info → gemini_webapi-1.16.0.dist-info}/METADATA +13 -11
- {gemini_webapi-1.15.2.dist-info → gemini_webapi-1.16.0.dist-info}/RECORD +10 -10
- {gemini_webapi-1.15.2.dist-info → gemini_webapi-1.16.0.dist-info}/WHEEL +0 -0
- {gemini_webapi-1.15.2.dist-info → gemini_webapi-1.16.0.dist-info}/licenses/LICENSE +0 -0
- {gemini_webapi-1.15.2.dist-info → gemini_webapi-1.16.0.dist-info}/top_level.txt +0 -0
gemini_webapi/client.py
CHANGED
|
@@ -32,7 +32,6 @@ from .utils import (
|
|
|
32
32
|
parse_file_name,
|
|
33
33
|
rotate_1psidts,
|
|
34
34
|
get_access_token,
|
|
35
|
-
load_browser_cookies,
|
|
36
35
|
running,
|
|
37
36
|
rotate_tasks,
|
|
38
37
|
logger,
|
|
@@ -101,20 +100,10 @@ class GeminiClient(GemMixin):
|
|
|
101
100
|
self.refresh_interval: float = 540
|
|
102
101
|
self.kwargs = kwargs
|
|
103
102
|
|
|
104
|
-
# Validate cookies
|
|
105
103
|
if secure_1psid:
|
|
106
104
|
self.cookies["__Secure-1PSID"] = secure_1psid
|
|
107
105
|
if secure_1psidts:
|
|
108
106
|
self.cookies["__Secure-1PSIDTS"] = secure_1psidts
|
|
109
|
-
else:
|
|
110
|
-
try:
|
|
111
|
-
cookies = load_browser_cookies(domain_name="google.com")
|
|
112
|
-
if not (cookies and cookies.get("__Secure-1PSID")):
|
|
113
|
-
raise ValueError(
|
|
114
|
-
"Failed to load cookies from local browser. Please pass cookie values manually."
|
|
115
|
-
)
|
|
116
|
-
except ImportError:
|
|
117
|
-
pass
|
|
118
107
|
|
|
119
108
|
async def init(
|
|
120
109
|
self,
|
gemini_webapi/constants.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import os
|
|
1
2
|
import re
|
|
2
3
|
import asyncio
|
|
3
4
|
from asyncio import Task
|
|
@@ -88,7 +89,11 @@ async def get_access_token(
|
|
|
88
89
|
)
|
|
89
90
|
|
|
90
91
|
# Cached cookies in local file
|
|
91
|
-
cache_dir =
|
|
92
|
+
cache_dir = (
|
|
93
|
+
(GEMINI_COOKIE_PATH := os.getenv("GEMINI_COOKIE_PATH"))
|
|
94
|
+
and Path(GEMINI_COOKIE_PATH)
|
|
95
|
+
or (Path(__file__).parent / "temp")
|
|
96
|
+
)
|
|
92
97
|
if "__Secure-1PSID" in base_cookies:
|
|
93
98
|
filename = f".cached_1psidts_{base_cookies['__Secure-1PSID']}.txt"
|
|
94
99
|
cache_file = cache_dir / filename
|
|
@@ -126,17 +131,35 @@ async def get_access_token(
|
|
|
126
131
|
|
|
127
132
|
# Browser cookies (if browser-cookie3 is installed)
|
|
128
133
|
try:
|
|
134
|
+
valid_browser_cookies = 0
|
|
129
135
|
browser_cookies = load_browser_cookies(
|
|
130
136
|
domain_name="google.com", verbose=verbose
|
|
131
137
|
)
|
|
132
|
-
if browser_cookies
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
138
|
+
if browser_cookies:
|
|
139
|
+
for browser, cookies in browser_cookies.items():
|
|
140
|
+
if secure_1psid := cookies.get("__Secure-1PSID"):
|
|
141
|
+
if (
|
|
142
|
+
"__Secure-1PSID" in base_cookies
|
|
143
|
+
and base_cookies["__Secure-1PSID"] != secure_1psid
|
|
144
|
+
):
|
|
145
|
+
if verbose:
|
|
146
|
+
logger.debug(
|
|
147
|
+
f"Skipping loading local browser cookies from {browser}. "
|
|
148
|
+
f"__Secure-1PSID does not match the one provided."
|
|
149
|
+
)
|
|
150
|
+
continue
|
|
151
|
+
|
|
152
|
+
local_cookies = {"__Secure-1PSID": secure_1psid}
|
|
153
|
+
if secure_1psidts := cookies.get("__Secure-1PSIDTS"):
|
|
154
|
+
local_cookies["__Secure-1PSIDTS"] = secure_1psidts
|
|
155
|
+
if nid := cookies.get("NID"):
|
|
156
|
+
local_cookies["NID"] = nid
|
|
157
|
+
tasks.append(Task(send_request(local_cookies, proxy=proxy)))
|
|
158
|
+
valid_browser_cookies += 1
|
|
159
|
+
if verbose:
|
|
160
|
+
logger.debug(f"Loaded local browser cookies from {browser}")
|
|
161
|
+
|
|
162
|
+
if valid_browser_cookies == 0 and verbose:
|
|
140
163
|
logger.debug(
|
|
141
164
|
"Skipping loading local browser cookies. Login to gemini.google.com in your browser first."
|
|
142
165
|
)
|
|
@@ -149,6 +172,11 @@ async def get_access_token(
|
|
|
149
172
|
if verbose:
|
|
150
173
|
logger.warning(f"Skipping loading local browser cookies. {e}")
|
|
151
174
|
|
|
175
|
+
if not tasks:
|
|
176
|
+
raise AuthError(
|
|
177
|
+
"No valid cookies available for initialization. Please pass __Secure-1PSID and __Secure-1PSIDTS manually."
|
|
178
|
+
)
|
|
179
|
+
|
|
152
180
|
for i, future in enumerate(asyncio.as_completed(tasks)):
|
|
153
181
|
try:
|
|
154
182
|
response, request_cookies = await future
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
from http.cookiejar import CookieJar
|
|
2
|
+
|
|
1
3
|
from .logger import logger
|
|
2
4
|
|
|
3
5
|
|
|
@@ -15,8 +17,9 @@ def load_browser_cookies(domain_name: str = "", verbose=True) -> dict:
|
|
|
15
17
|
|
|
16
18
|
Returns
|
|
17
19
|
-------
|
|
18
|
-
`dict`
|
|
19
|
-
Dictionary with
|
|
20
|
+
`dict[str, dict]`
|
|
21
|
+
Dictionary with browser as keys and their cookies for the specified domain as values.
|
|
22
|
+
Only browsers that have cookies for the specified domain will be included.
|
|
20
23
|
"""
|
|
21
24
|
|
|
22
25
|
import browser_cookie3 as bc3
|
|
@@ -35,8 +38,11 @@ def load_browser_cookies(domain_name: str = "", verbose=True) -> dict:
|
|
|
35
38
|
bc3.safari,
|
|
36
39
|
]:
|
|
37
40
|
try:
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
jar: CookieJar = cookie_fn(domain_name=domain_name)
|
|
42
|
+
if jar:
|
|
43
|
+
cookies[cookie_fn.__name__] = {
|
|
44
|
+
cookie.name: cookie.value for cookie in jar
|
|
45
|
+
}
|
|
40
46
|
except bc3.BrowserCookieError:
|
|
41
47
|
pass
|
|
42
48
|
except PermissionError as e:
|
|
@@ -32,7 +32,11 @@ async def rotate_1psidts(cookies: dict, proxy: str | None = None) -> str:
|
|
|
32
32
|
If request failed with other status codes.
|
|
33
33
|
"""
|
|
34
34
|
|
|
35
|
-
path =
|
|
35
|
+
path = (
|
|
36
|
+
(GEMINI_COOKIE_PATH := os.getenv("GEMINI_COOKIE_PATH"))
|
|
37
|
+
and Path(GEMINI_COOKIE_PATH)
|
|
38
|
+
or (Path(__file__).parent / "temp")
|
|
39
|
+
)
|
|
36
40
|
path.mkdir(parents=True, exist_ok=True)
|
|
37
41
|
filename = f".cached_1psidts_{cookies['__Secure-1PSID']}.txt"
|
|
38
42
|
path = path / filename
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: gemini-webapi
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.16.0
|
|
4
4
|
Summary: ✨ An elegant async Python wrapper for Google Gemini web app
|
|
5
5
|
Author: UZQueen
|
|
6
6
|
License: GNU AFFERO GENERAL PUBLIC LICENSE
|
|
@@ -679,7 +679,7 @@ License-File: LICENSE
|
|
|
679
679
|
Requires-Dist: httpx[http2]~=0.28.1
|
|
680
680
|
Requires-Dist: loguru~=0.7.3
|
|
681
681
|
Requires-Dist: orjson~=3.11.1
|
|
682
|
-
Requires-Dist: pydantic~=2.
|
|
682
|
+
Requires-Dist: pydantic~=2.12.2
|
|
683
683
|
Dynamic: license-file
|
|
684
684
|
|
|
685
685
|
<p align="center">
|
|
@@ -713,7 +713,7 @@ A reverse-engineered asynchronous python wrapper for [Google Gemini](https://gem
|
|
|
713
713
|
## Features
|
|
714
714
|
|
|
715
715
|
- **Persistent Cookies** - Automatically refreshes cookies in background. Optimized for always-on services.
|
|
716
|
-
- **Image Generation** - Natively supports generating and
|
|
716
|
+
- **Image Generation** - Natively supports generating and editing images with natural language.
|
|
717
717
|
- **System Prompt** - Supports customizing model's system prompt with [Gemini Gems](https://gemini.google.com/gems/view).
|
|
718
718
|
- **Extension Support** - Supports generating contents with [Gemini extensions](https://gemini.google.com/extensions) on, like YouTube and Gmail.
|
|
719
719
|
- **Classified Outputs** - Categorizes texts, thoughts, web images and AI generated images in the response.
|
|
@@ -740,7 +740,7 @@ A reverse-engineered asynchronous python wrapper for [Google Gemini](https://gem
|
|
|
740
740
|
- [Delete a custom gem](#delete-a-custom-gem)
|
|
741
741
|
- [Retrieve model's thought process](#retrieve-models-thought-process)
|
|
742
742
|
- [Retrieve images in response](#retrieve-images-in-response)
|
|
743
|
-
- [Generate
|
|
743
|
+
- [Generate and edit images](#generate-and-edit-images)
|
|
744
744
|
- [Generate contents with Gemini extensions](#generate-contents-with-gemini-extensions)
|
|
745
745
|
- [Check and switch to other reply candidates](#check-and-switch-to-other-reply-candidates)
|
|
746
746
|
- [Logging Configuration](#logging-configuration)
|
|
@@ -777,15 +777,17 @@ pip install -U browser-cookie3
|
|
|
777
777
|
|
|
778
778
|
> [!NOTE]
|
|
779
779
|
>
|
|
780
|
-
> If your application is deployed in a containerized environment (e.g. Docker), you may want to persist the cookies with a volume to avoid re-authentication every time the container rebuilds.
|
|
780
|
+
> If your application is deployed in a containerized environment (e.g. Docker), you may want to persist the cookies with a volume to avoid re-authentication every time the container rebuilds. You can set `GEMINI_COOKIE_PATH` environment variable to specify the path where auto-refreshed cookies are stored. Make sure the path is writable by the application.
|
|
781
781
|
>
|
|
782
782
|
> Here's part of a sample `docker-compose.yml` file:
|
|
783
783
|
|
|
784
784
|
```yaml
|
|
785
785
|
services:
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
786
|
+
main:
|
|
787
|
+
environment:
|
|
788
|
+
GEMINI_COOKIE_PATH: /tmp/gemini_webapi
|
|
789
|
+
volumes:
|
|
790
|
+
- ./gemini_cookies:/tmp/gemini_webapi
|
|
789
791
|
```
|
|
790
792
|
|
|
791
793
|
> [!NOTE]
|
|
@@ -1064,13 +1066,13 @@ async def main():
|
|
|
1064
1066
|
asyncio.run(main())
|
|
1065
1067
|
```
|
|
1066
1068
|
|
|
1067
|
-
### Generate
|
|
1069
|
+
### Generate and edit images
|
|
1068
1070
|
|
|
1069
|
-
You can ask Gemini to generate and
|
|
1071
|
+
You can ask Gemini to generate and edit images with Nano Banana, Google's latest image model, simply by natural language.
|
|
1070
1072
|
|
|
1071
1073
|
> [!IMPORTANT]
|
|
1072
1074
|
>
|
|
1073
|
-
> Google has some limitations on the image generation feature in Gemini, so its availability could be different per region/account. Here's a summary copied from [official documentation](https://support.google.com/gemini/answer/14286560) (as of
|
|
1075
|
+
> Google has some limitations on the image generation feature in Gemini, so its availability could be different per region/account. Here's a summary copied from [official documentation](https://support.google.com/gemini/answer/14286560) (as of Sep 10, 2025):
|
|
1074
1076
|
>
|
|
1075
1077
|
> > This feature’s availability in any specific Gemini app is also limited to the supported languages and countries of that app.
|
|
1076
1078
|
> >
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
gemini_webapi/__init__.py,sha256=7ELCiUoI10ea3daeJxnv0UwqLVKpM7rxsgOZsPMstO8,150
|
|
2
|
-
gemini_webapi/client.py,sha256=
|
|
3
|
-
gemini_webapi/constants.py,sha256=
|
|
2
|
+
gemini_webapi/client.py,sha256=YlgBiIQWkxCjPaqMQ1Zs-MvRz6ww0U3uqdS__azqvwA,26827
|
|
3
|
+
gemini_webapi/constants.py,sha256=ZzyZRqwJsqjvDdj3GYIdk0SpQVbKa1Vd5NwEsvIz6pI,2685
|
|
4
4
|
gemini_webapi/exceptions.py,sha256=qkXrIpr0L7LtGbq3VcTO8D1xZ50pJtt0dDRp5I3uDSg,1038
|
|
5
5
|
gemini_webapi/components/__init__.py,sha256=wolxuAJJ32-jmHOKgpsesexP7hXea1JMo5vI52wysTI,48
|
|
6
6
|
gemini_webapi/components/gem_mixin.py,sha256=WPJkYDS4yQpLMBNQ94LQo5w59RgkllWaSiHsFG1k5GU,8795
|
|
@@ -12,13 +12,13 @@ gemini_webapi/types/image.py,sha256=NhW1QY2Agzb6UbrIjZLnqxqukabDSGbmoCsVguzko10,
|
|
|
12
12
|
gemini_webapi/types/modeloutput.py,sha256=h07kQOkL5r-oPLvZ59uVtO1eP4FGy5ZpzuYQzAeQdr8,1196
|
|
13
13
|
gemini_webapi/utils/__init__.py,sha256=RIU1MBqYNjih0XMMt7wCxAA-X9KVF53nDbAjaxaGTo8,352
|
|
14
14
|
gemini_webapi/utils/decorators.py,sha256=AuY6sU1_6_ZqeL92dTAi3eRPQ7zubB5VuBZEiz16aBM,1741
|
|
15
|
-
gemini_webapi/utils/get_access_token.py,sha256=
|
|
16
|
-
gemini_webapi/utils/load_browser_cookies.py,sha256=
|
|
15
|
+
gemini_webapi/utils/get_access_token.py,sha256=VjrHW8VMN3LPs6zCdXQtraWygurOjTY0SJZhe49aQwc,7265
|
|
16
|
+
gemini_webapi/utils/load_browser_cookies.py,sha256=OHCfe27DpV_rloIDgW9Xpeb0mkfzbYONNiholw0ElXU,1791
|
|
17
17
|
gemini_webapi/utils/logger.py,sha256=0VcxhVLhHBRDQutNCpapP1y_MhPoQ2ud1uIFLqxC3Z8,958
|
|
18
|
-
gemini_webapi/utils/rotate_1psidts.py,sha256=
|
|
18
|
+
gemini_webapi/utils/rotate_1psidts.py,sha256=XjEeQnZS3ZI6wOl0Zb5CvsbIrg0BVVNas7cE6f3x_XE,1802
|
|
19
19
|
gemini_webapi/utils/upload_file.py,sha256=SJOMr6kryK_ClrKmqI96fqZBNFOMPsyAvFINAGAU3rk,1468
|
|
20
|
-
gemini_webapi-1.
|
|
21
|
-
gemini_webapi-1.
|
|
22
|
-
gemini_webapi-1.
|
|
23
|
-
gemini_webapi-1.
|
|
24
|
-
gemini_webapi-1.
|
|
20
|
+
gemini_webapi-1.16.0.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
|
21
|
+
gemini_webapi-1.16.0.dist-info/METADATA,sha256=vRnA79JpF9eMcgjzCqbpok_UGTvw5EPYKRO1bFtjZ5Q,61426
|
|
22
|
+
gemini_webapi-1.16.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
23
|
+
gemini_webapi-1.16.0.dist-info/top_level.txt,sha256=dtWtug_ZrmnUqCYuu8NmGzTgWglHeNzhHU_hXmqZGWE,14
|
|
24
|
+
gemini_webapi-1.16.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|