gemini-webapi 1.9.0__tar.gz → 1.10.0__tar.gz

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.
Files changed (37) hide show
  1. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/PKG-INFO +32 -38
  2. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/README.md +29 -36
  3. gemini_webapi-1.10.0/assets/sample.pdf +0 -0
  4. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi/client.py +23 -23
  5. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi/constants.py +4 -4
  6. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi/utils/__init__.py +1 -1
  7. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi/utils/upload_file.py +27 -6
  8. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi.egg-info/PKG-INFO +32 -38
  9. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi.egg-info/SOURCES.txt +1 -0
  10. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/tests/test_client_features.py +9 -22
  11. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/.github/dependabot.yml +0 -0
  12. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/.github/workflows/github-release.yml +0 -0
  13. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/.github/workflows/pypi-publish.yml +0 -0
  14. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/.gitignore +0 -0
  15. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/.vscode/launch.json +0 -0
  16. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/.vscode/settings.json +0 -0
  17. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/LICENSE +0 -0
  18. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/assets/banner.png +0 -0
  19. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/assets/favicon.png +0 -0
  20. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/assets/logo.svg +0 -0
  21. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/pyproject.toml +0 -0
  22. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/setup.cfg +0 -0
  23. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi/__init__.py +0 -0
  24. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi/exceptions.py +0 -0
  25. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi/types/__init__.py +0 -0
  26. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi/types/candidate.py +0 -0
  27. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi/types/image.py +0 -0
  28. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi/types/modeloutput.py +0 -0
  29. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi/utils/get_access_token.py +0 -0
  30. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi/utils/load_browser_cookies.py +0 -0
  31. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi/utils/logger.py +0 -0
  32. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi/utils/rotate_1psidts.py +0 -0
  33. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi.egg-info/dependency_links.txt +0 -0
  34. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi.egg-info/requires.txt +0 -0
  35. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/src/gemini_webapi.egg-info/top_level.txt +0 -0
  36. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/tests/test_rotate_cookies.py +0 -0
  37. {gemini_webapi-1.9.0 → gemini_webapi-1.10.0}/tests/test_save_image.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: gemini-webapi
3
- Version: 1.9.0
3
+ Version: 1.10.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,6 +679,7 @@ License-File: LICENSE
679
679
  Requires-Dist: httpx[http2]~=0.28.1
680
680
  Requires-Dist: pydantic~=2.10.5
681
681
  Requires-Dist: loguru~=0.7.3
682
+ Dynamic: license-file
682
683
 
683
684
  <p align="center">
684
685
  <img src="https://raw.githubusercontent.com/HanaokaYuzu/Gemini-API/master/assets/banner.png" width="55%" alt="Gemini Banner" align="center">
@@ -711,7 +712,7 @@ A reverse-engineered asynchronous python wrapper for [Google Gemini](https://gem
711
712
  ## Features
712
713
 
713
714
  - **Persistent Cookies** - Automatically refreshes cookies in background. Optimized for always-on services.
714
- - **ImageFx Support** - Supports retrieving images generated by ImageFx, Google's latest AI image generator.
715
+ - **Image Generation** - Natively supports generating and modifying images with natural language.
715
716
  - **Extension Support** - Supports generating contents with [Gemini extensions](https://gemini.google.com/extensions) on, like YouTube and Gmail.
716
717
  - **Classified Outputs** - Automatically categorizes texts, web images and AI generated images in the response.
717
718
  - **Official Flavor** - Provides a simple and elegant interface inspired by [Google Generative AI](https://ai.google.dev/tutorials/python_quickstart)'s official API.
@@ -727,13 +728,12 @@ A reverse-engineered asynchronous python wrapper for [Google Gemini](https://gem
727
728
  - [Initialization](#initialization)
728
729
  - [Select language model](#select-language-model)
729
730
  - [Generate contents from text](#generate-contents-from-text)
730
- - [Generate contents from image](#generate-contents-from-image)
731
+ - [Generate contents with files](#generate-contents-with-files)
731
732
  - [Conversations across multiple turns](#conversations-across-multiple-turns)
732
733
  - [Continue previous conversations](#continue-previous-conversations)
733
734
  - [Retrieve model's thought process](#retrieve-models-thought-process)
734
735
  - [Retrieve images in response](#retrieve-images-in-response)
735
- - [Generate images with ImageFx](#generate-images-with-imagefx)
736
- - [Save images to local files](#save-images-to-local-files)
736
+ - [Generate images with Imagen3](#generate-images-with-imagen3)
737
737
  - [Generate contents with Gemini extensions](#generate-contents-with-gemini-extensions)
738
738
  - [Check and switch to other reply candidates](#check-and-switch-to-other-reply-candidates)
739
739
  - [Control log level](#control-log-level)
@@ -867,15 +867,15 @@ asyncio.run(main())
867
867
  >
868
868
  > Simply use `print(response)` to get the same output if you just want to see the response text
869
869
 
870
- ### Generate contents from image
870
+ ### Generate contents with files
871
871
 
872
- Gemini supports image recognition and generating contents from images. Optionally, you can pass images in a list of file data in `bytes` or their paths in `str` or `pathlib.Path` to `GeminiClient.generate_content` together with text prompt.
872
+ Gemini supports file input, including images and documents. Optionally, you can pass files as a list of paths in `str` or `pathlib.Path` to `GeminiClient.generate_content` together with text prompt.
873
873
 
874
874
  ```python
875
875
  async def main():
876
876
  response = await client.generate_content(
877
- "Describe each of these images",
878
- images=["assets/banner.png", "assets/favicon.png"],
877
+ "Introduce the contents of these two files. Is there any connection between them?",
878
+ files=["assets/sample.pdf", Path("assets/banner.png")],
879
879
  )
880
880
  print(response.text)
881
881
 
@@ -889,9 +889,15 @@ If you want to keep conversation continuous, please use `GeminiClient.start_chat
889
889
  ```python
890
890
  async def main():
891
891
  chat = client.start_chat()
892
- response1 = await chat.send_message("Briefly introduce Europe")
893
- response2 = await chat.send_message("What's the population there?")
894
- print(response1.text, response2.text, sep="\n\n----------------------------------\n\n")
892
+ response1 = await chat.send_message(
893
+ "Introduce the contents of these two files. Is there any connection between them?",
894
+ files=["assets/sample.pdf", Path("assets/banner.png")],
895
+ )
896
+ print(response1.text)
897
+ response2 = await chat.send_message(
898
+ "Use image generation tool to modify the banner with another font and design."
899
+ )
900
+ print(response2.text, response2.images, sep="\n\n----------------------------------\n\n")
895
901
 
896
902
  asyncio.run(main())
897
903
  ```
@@ -949,24 +955,27 @@ async def main():
949
955
  asyncio.run(main())
950
956
  ```
951
957
 
952
- ### Generate images with ImageFx
958
+ ### Generate images with Imagen3
953
959
 
954
- In February 2022, Google introduced a new AI image generator called ImageFx and integrated it into Gemini. You can ask Gemini to generate images with ImageFx simply by natural language.
960
+ You can ask Gemini to generate and modify images with Imagen3, Google's latest AI image generator, simply by natural language.
955
961
 
956
962
  > [!IMPORTANT]
957
963
  >
958
- > 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 February 15th, 2024):
964
+ > 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 March 19th, 2025):
959
965
  >
960
- > > Image generation in Gemini Apps is available in most countries, except in the European Economic Area (EEA), Switzerland, and the UK. It’s only available for **English prompts**.
961
- > >
962
966
  > > This feature’s availability in any specific Gemini app is also limited to the supported languages and countries of that app.
963
967
  > >
964
968
  > > For now, this feature isn’t available to users under 18.
969
+ > >
970
+ > > To use this feature, you must be signed in to Gemini Apps.
971
+
972
+ You can save images returned from Gemini to local by calling `Image.save()`. Optionally, you can specify the file path and file name by passing `path` and `filename` arguments to the function and skip images with invalid file names by passing `skip_invalid_filename=True`. Works for both `WebImage` and `GeneratedImage`.
965
973
 
966
974
  ```python
967
975
  async def main():
968
976
  response = await client.generate_content("Generate some pictures of cats")
969
- for image in response.images:
977
+ for i, image in enumerate(response.images):
978
+ await image.save(path="temp/", filename=f"cat_{i}.png", verbose=True)
970
979
  print(image, "\n\n----------------------------------\n")
971
980
 
972
981
  asyncio.run(main())
@@ -976,32 +985,17 @@ asyncio.run(main())
976
985
  >
977
986
  > by default, when asked to send images (like the previous example), Gemini will send images fetched from web instead of generating images with AI model, unless you specifically require to "generate" images in your prompt. In this package, web images and generated images are treated differently as `WebImage` and `GeneratedImage`, and will be automatically categorized in the output.
978
987
 
979
- ### Save images to local files
980
-
981
- You can save images returned from Gemini to local files under `/temp` by calling `Image.save()`. Optionally, you can specify the file path and file name by passing `path` and `filename` arguments to the function and skip images with invalid file names by passing `skip_invalid_filename=True`. Works for both `WebImage` and `GeneratedImage`.
982
-
983
- ```python
984
- async def main():
985
- response = await client.generate_content("Generate some pictures of cats")
986
- for i, image in enumerate(response.images):
987
- await image.save(path="temp/", filename=f"cat_{i}.png", verbose=True)
988
-
989
- asyncio.run(main())
990
- ```
991
-
992
988
  ### Generate contents with Gemini extensions
993
989
 
994
990
  > [!IMPORTANT]
995
991
  >
996
- > To access Gemini extensions in API, you must activate them on the [Gemini website](https://gemini.google.com/extensions) first. Same as image generation, Google also has limitations on the availability of Gemini extensions. Here's a summary copied from [official documentation](https://support.google.com/gemini/answer/13695044) (as of February 18th, 2024):
992
+ > To access Gemini extensions in API, you must activate them on the [Gemini website](https://gemini.google.com/extensions) first. Same as image generation, Google also has limitations on the availability of Gemini extensions. Here's a summary copied from [official documentation](https://support.google.com/gemini/answer/13695044) (as of March 19th, 2025):
997
993
  >
998
- > > To use extensions in Gemini Apps:
999
- > >
1000
- > > Sign in with your personal Google Account that you manage on your own. Extensions, including the Google Workspace extension, are currently not available to Google Workspace accounts for school, business, or other organizations.
994
+ > > To connect apps to Gemini, you must have​​​​ Gemini Apps Activity on.
1001
995
  > >
1002
- > > Have Gemini Apps Activity on. Extensions are only available when Gemini Apps Activity is turned on.
996
+ > > To use this feature, you must be signed in to Gemini Apps.
1003
997
  > >
1004
- > > Important: For now, extensions are available in **English, Japanese, and Korean** only.
998
+ > > Important: If you’re under 18, Google Workspace and Maps apps currently only work with English prompts in Gemini.
1005
999
 
1006
1000
  After activating extensions for your account, you can access them in your prompts either by natural language or by starting your prompt with "@" followed by the extension keyword.
1007
1001
 
@@ -29,7 +29,7 @@ A reverse-engineered asynchronous python wrapper for [Google Gemini](https://gem
29
29
  ## Features
30
30
 
31
31
  - **Persistent Cookies** - Automatically refreshes cookies in background. Optimized for always-on services.
32
- - **ImageFx Support** - Supports retrieving images generated by ImageFx, Google's latest AI image generator.
32
+ - **Image Generation** - Natively supports generating and modifying images with natural language.
33
33
  - **Extension Support** - Supports generating contents with [Gemini extensions](https://gemini.google.com/extensions) on, like YouTube and Gmail.
34
34
  - **Classified Outputs** - Automatically categorizes texts, web images and AI generated images in the response.
35
35
  - **Official Flavor** - Provides a simple and elegant interface inspired by [Google Generative AI](https://ai.google.dev/tutorials/python_quickstart)'s official API.
@@ -45,13 +45,12 @@ A reverse-engineered asynchronous python wrapper for [Google Gemini](https://gem
45
45
  - [Initialization](#initialization)
46
46
  - [Select language model](#select-language-model)
47
47
  - [Generate contents from text](#generate-contents-from-text)
48
- - [Generate contents from image](#generate-contents-from-image)
48
+ - [Generate contents with files](#generate-contents-with-files)
49
49
  - [Conversations across multiple turns](#conversations-across-multiple-turns)
50
50
  - [Continue previous conversations](#continue-previous-conversations)
51
51
  - [Retrieve model's thought process](#retrieve-models-thought-process)
52
52
  - [Retrieve images in response](#retrieve-images-in-response)
53
- - [Generate images with ImageFx](#generate-images-with-imagefx)
54
- - [Save images to local files](#save-images-to-local-files)
53
+ - [Generate images with Imagen3](#generate-images-with-imagen3)
55
54
  - [Generate contents with Gemini extensions](#generate-contents-with-gemini-extensions)
56
55
  - [Check and switch to other reply candidates](#check-and-switch-to-other-reply-candidates)
57
56
  - [Control log level](#control-log-level)
@@ -185,15 +184,15 @@ asyncio.run(main())
185
184
  >
186
185
  > Simply use `print(response)` to get the same output if you just want to see the response text
187
186
 
188
- ### Generate contents from image
187
+ ### Generate contents with files
189
188
 
190
- Gemini supports image recognition and generating contents from images. Optionally, you can pass images in a list of file data in `bytes` or their paths in `str` or `pathlib.Path` to `GeminiClient.generate_content` together with text prompt.
189
+ Gemini supports file input, including images and documents. Optionally, you can pass files as a list of paths in `str` or `pathlib.Path` to `GeminiClient.generate_content` together with text prompt.
191
190
 
192
191
  ```python
193
192
  async def main():
194
193
  response = await client.generate_content(
195
- "Describe each of these images",
196
- images=["assets/banner.png", "assets/favicon.png"],
194
+ "Introduce the contents of these two files. Is there any connection between them?",
195
+ files=["assets/sample.pdf", Path("assets/banner.png")],
197
196
  )
198
197
  print(response.text)
199
198
 
@@ -207,9 +206,15 @@ If you want to keep conversation continuous, please use `GeminiClient.start_chat
207
206
  ```python
208
207
  async def main():
209
208
  chat = client.start_chat()
210
- response1 = await chat.send_message("Briefly introduce Europe")
211
- response2 = await chat.send_message("What's the population there?")
212
- print(response1.text, response2.text, sep="\n\n----------------------------------\n\n")
209
+ response1 = await chat.send_message(
210
+ "Introduce the contents of these two files. Is there any connection between them?",
211
+ files=["assets/sample.pdf", Path("assets/banner.png")],
212
+ )
213
+ print(response1.text)
214
+ response2 = await chat.send_message(
215
+ "Use image generation tool to modify the banner with another font and design."
216
+ )
217
+ print(response2.text, response2.images, sep="\n\n----------------------------------\n\n")
213
218
 
214
219
  asyncio.run(main())
215
220
  ```
@@ -267,24 +272,27 @@ async def main():
267
272
  asyncio.run(main())
268
273
  ```
269
274
 
270
- ### Generate images with ImageFx
275
+ ### Generate images with Imagen3
271
276
 
272
- In February 2022, Google introduced a new AI image generator called ImageFx and integrated it into Gemini. You can ask Gemini to generate images with ImageFx simply by natural language.
277
+ You can ask Gemini to generate and modify images with Imagen3, Google's latest AI image generator, simply by natural language.
273
278
 
274
279
  > [!IMPORTANT]
275
280
  >
276
- > 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 February 15th, 2024):
281
+ > 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 March 19th, 2025):
277
282
  >
278
- > > Image generation in Gemini Apps is available in most countries, except in the European Economic Area (EEA), Switzerland, and the UK. It’s only available for **English prompts**.
279
- > >
280
283
  > > This feature’s availability in any specific Gemini app is also limited to the supported languages and countries of that app.
281
284
  > >
282
285
  > > For now, this feature isn’t available to users under 18.
286
+ > >
287
+ > > To use this feature, you must be signed in to Gemini Apps.
288
+
289
+ You can save images returned from Gemini to local by calling `Image.save()`. Optionally, you can specify the file path and file name by passing `path` and `filename` arguments to the function and skip images with invalid file names by passing `skip_invalid_filename=True`. Works for both `WebImage` and `GeneratedImage`.
283
290
 
284
291
  ```python
285
292
  async def main():
286
293
  response = await client.generate_content("Generate some pictures of cats")
287
- for image in response.images:
294
+ for i, image in enumerate(response.images):
295
+ await image.save(path="temp/", filename=f"cat_{i}.png", verbose=True)
288
296
  print(image, "\n\n----------------------------------\n")
289
297
 
290
298
  asyncio.run(main())
@@ -294,32 +302,17 @@ asyncio.run(main())
294
302
  >
295
303
  > by default, when asked to send images (like the previous example), Gemini will send images fetched from web instead of generating images with AI model, unless you specifically require to "generate" images in your prompt. In this package, web images and generated images are treated differently as `WebImage` and `GeneratedImage`, and will be automatically categorized in the output.
296
304
 
297
- ### Save images to local files
298
-
299
- You can save images returned from Gemini to local files under `/temp` by calling `Image.save()`. Optionally, you can specify the file path and file name by passing `path` and `filename` arguments to the function and skip images with invalid file names by passing `skip_invalid_filename=True`. Works for both `WebImage` and `GeneratedImage`.
300
-
301
- ```python
302
- async def main():
303
- response = await client.generate_content("Generate some pictures of cats")
304
- for i, image in enumerate(response.images):
305
- await image.save(path="temp/", filename=f"cat_{i}.png", verbose=True)
306
-
307
- asyncio.run(main())
308
- ```
309
-
310
305
  ### Generate contents with Gemini extensions
311
306
 
312
307
  > [!IMPORTANT]
313
308
  >
314
- > To access Gemini extensions in API, you must activate them on the [Gemini website](https://gemini.google.com/extensions) first. Same as image generation, Google also has limitations on the availability of Gemini extensions. Here's a summary copied from [official documentation](https://support.google.com/gemini/answer/13695044) (as of February 18th, 2024):
309
+ > To access Gemini extensions in API, you must activate them on the [Gemini website](https://gemini.google.com/extensions) first. Same as image generation, Google also has limitations on the availability of Gemini extensions. Here's a summary copied from [official documentation](https://support.google.com/gemini/answer/13695044) (as of March 19th, 2025):
315
310
  >
316
- > > To use extensions in Gemini Apps:
317
- > >
318
- > > Sign in with your personal Google Account that you manage on your own. Extensions, including the Google Workspace extension, are currently not available to Google Workspace accounts for school, business, or other organizations.
311
+ > > To connect apps to Gemini, you must have​​​​ Gemini Apps Activity on.
319
312
  > >
320
- > > Have Gemini Apps Activity on. Extensions are only available when Gemini Apps Activity is turned on.
313
+ > > To use this feature, you must be signed in to Gemini Apps.
321
314
  > >
322
- > > Important: For now, extensions are available in **English, Japanese, and Korean** only.
315
+ > > Important: If you’re under 18, Google Workspace and Maps apps currently only work with English prompts in Gemini.
323
316
 
324
317
  After activating extensions for your account, you can access them in your prompts either by natural language or by starting your prompt with "@" followed by the extension keyword.
325
318
 
Binary file
@@ -13,6 +13,7 @@ from .exceptions import AuthError, APIError, TimeoutError, GeminiError
13
13
  from .types import WebImage, GeneratedImage, Candidate, ModelOutput
14
14
  from .utils import (
15
15
  upload_file,
16
+ parse_file_name,
16
17
  rotate_1psidts,
17
18
  get_access_token,
18
19
  load_browser_cookies,
@@ -263,7 +264,7 @@ class GeminiClient:
263
264
  async def generate_content(
264
265
  self,
265
266
  prompt: str,
266
- images: list[bytes | str | Path] | None = None,
267
+ files: list[str | Path] | None = None,
267
268
  model: Model | str = Model.UNSPECIFIED,
268
269
  chat: Optional["ChatSession"] = None,
269
270
  **kwargs,
@@ -275,8 +276,8 @@ class GeminiClient:
275
276
  ----------
276
277
  prompt: `str`
277
278
  Prompt provided by user.
278
- images: `list[bytes | str | Path]`, optional
279
- List of image file paths or file data in bytes.
279
+ files: `list[str | Path]`, optional
280
+ List of file paths to be attached.
280
281
  model: `Model` | `str`, optional
281
282
  Specify the model to use for generation.
282
283
  Pass either a `gemini_webapi.constants.Model` enum or a model name string.
@@ -324,17 +325,17 @@ class GeminiClient:
324
325
  None,
325
326
  json.dumps(
326
327
  [
327
- images
328
+ files
328
329
  and [
329
330
  prompt,
330
331
  0,
331
332
  None,
332
333
  [
333
334
  [
334
- [await upload_file(image, self.proxy)],
335
- "filename.jpg",
335
+ [await upload_file(file, self.proxy)],
336
+ parse_file_name(file),
336
337
  ]
337
- for image in images
338
+ for file in files
338
339
  ],
339
340
  ]
340
341
  or [prompt],
@@ -361,18 +362,17 @@ class GeminiClient:
361
362
  try:
362
363
  response_json = json.loads(response.text.split("\n")[2])
363
364
 
364
- # Plain request
365
- body = json.loads(response_json[0][2])
366
-
367
- if not body[4]:
368
- # Request with thinking models
369
- body = json.loads(response_json[1][2])
370
-
371
- if not body[4]:
372
- # Request with Gemini extensions enabled
373
- body = json.loads(response_json[4][2])
374
-
375
- if not body[4]:
365
+ body = None
366
+ for part in response_json:
367
+ try:
368
+ main_part = json.loads(part[2])
369
+ if main_part[4]:
370
+ body = main_part
371
+ break
372
+ except (IndexError, TypeError, ValueError):
373
+ continue
374
+
375
+ if not body:
376
376
  raise Exception
377
377
  except Exception:
378
378
  await self.close()
@@ -551,7 +551,7 @@ class ChatSession:
551
551
  async def send_message(
552
552
  self,
553
553
  prompt: str,
554
- images: list[bytes | str | Path] | None = None,
554
+ files: list[str | Path] | None = None,
555
555
  **kwargs,
556
556
  ) -> ModelOutput:
557
557
  """
@@ -562,8 +562,8 @@ class ChatSession:
562
562
  ----------
563
563
  prompt: `str`
564
564
  Prompt provided by user.
565
- images: `list[bytes | str | Path]`, optional
566
- List of image file paths or file data in bytes.
565
+ files: `list[str | Path]`, optional
566
+ List of file paths to be attached.
567
567
  kwargs: `dict`, optional
568
568
  Additional arguments which will be passed to the post request.
569
569
  Refer to `httpx.AsyncClient.request` for more information.
@@ -588,7 +588,7 @@ class ChatSession:
588
588
  """
589
589
 
590
590
  return await self.geminiclient.generate_content(
591
- prompt=prompt, images=images, model=self.model, chat=self, **kwargs
591
+ prompt=prompt, files=files, model=self.model, chat=self, **kwargs
592
592
  )
593
593
 
594
594
  def choose_candidate(self, index: int) -> ModelOutput:
@@ -44,7 +44,7 @@ class Model(Enum):
44
44
  "gemini-2.0-flash-thinking-with-apps",
45
45
  {"x-goog-ext-525001261-jspb": '[null,null,null,null,"f8f8f5ea629f5d37"]'},
46
46
  False,
47
- )
47
+ ) # Deprecated, should be removed in the future
48
48
  G_2_0_EXP_ADVANCED = (
49
49
  "gemini-2.0-exp-advanced",
50
50
  {"x-goog-ext-525001261-jspb": '[null,null,null,null,"b1e46a6037e6aa9f"]'},
@@ -54,17 +54,17 @@ class Model(Enum):
54
54
  "gemini-1.5-flash",
55
55
  {"x-goog-ext-525001261-jspb": '[null,null,null,null,"418ab5ea040b5c43"]'},
56
56
  False,
57
- )
57
+ ) # Deprecated, should be removed in the future
58
58
  G_1_5_PRO = (
59
59
  "gemini-1.5-pro",
60
60
  {"x-goog-ext-525001261-jspb": '[null,null,null,null,"9d60dfae93c9ff1f"]'},
61
61
  True,
62
- )
62
+ ) # Deprecated, should be removed in the future
63
63
  G_1_5_PRO_RESEARCH = (
64
64
  "gemini-1.5-pro-research",
65
65
  {"x-goog-ext-525001261-jspb": '[null,null,null,null,"e5a44cb1dae2b489"]'},
66
66
  True,
67
- )
67
+ ) # Deprecated, should be removed in the future
68
68
 
69
69
  def __init__(self, name, header, advanced_only):
70
70
  self.model_name = name
@@ -1,6 +1,6 @@
1
1
  from asyncio import Task
2
2
 
3
- from .upload_file import upload_file # noqa: F401
3
+ from .upload_file import upload_file, parse_file_name # noqa: F401
4
4
  from .rotate_1psidts import rotate_1psidts # noqa: F401
5
5
  from .get_access_token import get_access_token # noqa: F401
6
6
  from .load_browser_cookies import load_browser_cookies # noqa: F401
@@ -7,14 +7,14 @@ from ..constants import Endpoint, Headers
7
7
 
8
8
 
9
9
  @validate_call
10
- async def upload_file(file: bytes | str | Path, proxy: str | None = None) -> str:
10
+ async def upload_file(file: str | Path, proxy: str | None = None) -> str:
11
11
  """
12
12
  Upload a file to Google's server and return its identifier.
13
13
 
14
14
  Parameters
15
15
  ----------
16
- file : `bytes` | `str` | `Path`
17
- File data in bytes, or path to the file to be uploaded.
16
+ file : `str` | `Path`
17
+ Path to the file to be uploaded.
18
18
  proxy: `str`, optional
19
19
  Proxy URL.
20
20
 
@@ -30,9 +30,8 @@ async def upload_file(file: bytes | str | Path, proxy: str | None = None) -> str
30
30
  If the upload request failed.
31
31
  """
32
32
 
33
- if not isinstance(file, bytes):
34
- with open(file, "rb") as f:
35
- file = f.read()
33
+ with open(file, "rb") as f:
34
+ file = f.read()
36
35
 
37
36
  async with AsyncClient(http2=True, proxy=proxy) as client:
38
37
  response = await client.post(
@@ -43,3 +42,25 @@ async def upload_file(file: bytes | str | Path, proxy: str | None = None) -> str
43
42
  )
44
43
  response.raise_for_status()
45
44
  return response.text
45
+
46
+
47
+ def parse_file_name(file: str | Path) -> str:
48
+ """
49
+ Parse the file name from the given path.
50
+
51
+ Parameters
52
+ ----------
53
+ file : `str` | `Path`
54
+ Path to the file.
55
+
56
+ Returns
57
+ -------
58
+ `str`
59
+ File name with extension.
60
+ """
61
+
62
+ file = Path(file)
63
+ if not file.is_file():
64
+ raise ValueError(f"{file} is not a valid file.")
65
+
66
+ return file.name
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: gemini-webapi
3
- Version: 1.9.0
3
+ Version: 1.10.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,6 +679,7 @@ License-File: LICENSE
679
679
  Requires-Dist: httpx[http2]~=0.28.1
680
680
  Requires-Dist: pydantic~=2.10.5
681
681
  Requires-Dist: loguru~=0.7.3
682
+ Dynamic: license-file
682
683
 
683
684
  <p align="center">
684
685
  <img src="https://raw.githubusercontent.com/HanaokaYuzu/Gemini-API/master/assets/banner.png" width="55%" alt="Gemini Banner" align="center">
@@ -711,7 +712,7 @@ A reverse-engineered asynchronous python wrapper for [Google Gemini](https://gem
711
712
  ## Features
712
713
 
713
714
  - **Persistent Cookies** - Automatically refreshes cookies in background. Optimized for always-on services.
714
- - **ImageFx Support** - Supports retrieving images generated by ImageFx, Google's latest AI image generator.
715
+ - **Image Generation** - Natively supports generating and modifying images with natural language.
715
716
  - **Extension Support** - Supports generating contents with [Gemini extensions](https://gemini.google.com/extensions) on, like YouTube and Gmail.
716
717
  - **Classified Outputs** - Automatically categorizes texts, web images and AI generated images in the response.
717
718
  - **Official Flavor** - Provides a simple and elegant interface inspired by [Google Generative AI](https://ai.google.dev/tutorials/python_quickstart)'s official API.
@@ -727,13 +728,12 @@ A reverse-engineered asynchronous python wrapper for [Google Gemini](https://gem
727
728
  - [Initialization](#initialization)
728
729
  - [Select language model](#select-language-model)
729
730
  - [Generate contents from text](#generate-contents-from-text)
730
- - [Generate contents from image](#generate-contents-from-image)
731
+ - [Generate contents with files](#generate-contents-with-files)
731
732
  - [Conversations across multiple turns](#conversations-across-multiple-turns)
732
733
  - [Continue previous conversations](#continue-previous-conversations)
733
734
  - [Retrieve model's thought process](#retrieve-models-thought-process)
734
735
  - [Retrieve images in response](#retrieve-images-in-response)
735
- - [Generate images with ImageFx](#generate-images-with-imagefx)
736
- - [Save images to local files](#save-images-to-local-files)
736
+ - [Generate images with Imagen3](#generate-images-with-imagen3)
737
737
  - [Generate contents with Gemini extensions](#generate-contents-with-gemini-extensions)
738
738
  - [Check and switch to other reply candidates](#check-and-switch-to-other-reply-candidates)
739
739
  - [Control log level](#control-log-level)
@@ -867,15 +867,15 @@ asyncio.run(main())
867
867
  >
868
868
  > Simply use `print(response)` to get the same output if you just want to see the response text
869
869
 
870
- ### Generate contents from image
870
+ ### Generate contents with files
871
871
 
872
- Gemini supports image recognition and generating contents from images. Optionally, you can pass images in a list of file data in `bytes` or their paths in `str` or `pathlib.Path` to `GeminiClient.generate_content` together with text prompt.
872
+ Gemini supports file input, including images and documents. Optionally, you can pass files as a list of paths in `str` or `pathlib.Path` to `GeminiClient.generate_content` together with text prompt.
873
873
 
874
874
  ```python
875
875
  async def main():
876
876
  response = await client.generate_content(
877
- "Describe each of these images",
878
- images=["assets/banner.png", "assets/favicon.png"],
877
+ "Introduce the contents of these two files. Is there any connection between them?",
878
+ files=["assets/sample.pdf", Path("assets/banner.png")],
879
879
  )
880
880
  print(response.text)
881
881
 
@@ -889,9 +889,15 @@ If you want to keep conversation continuous, please use `GeminiClient.start_chat
889
889
  ```python
890
890
  async def main():
891
891
  chat = client.start_chat()
892
- response1 = await chat.send_message("Briefly introduce Europe")
893
- response2 = await chat.send_message("What's the population there?")
894
- print(response1.text, response2.text, sep="\n\n----------------------------------\n\n")
892
+ response1 = await chat.send_message(
893
+ "Introduce the contents of these two files. Is there any connection between them?",
894
+ files=["assets/sample.pdf", Path("assets/banner.png")],
895
+ )
896
+ print(response1.text)
897
+ response2 = await chat.send_message(
898
+ "Use image generation tool to modify the banner with another font and design."
899
+ )
900
+ print(response2.text, response2.images, sep="\n\n----------------------------------\n\n")
895
901
 
896
902
  asyncio.run(main())
897
903
  ```
@@ -949,24 +955,27 @@ async def main():
949
955
  asyncio.run(main())
950
956
  ```
951
957
 
952
- ### Generate images with ImageFx
958
+ ### Generate images with Imagen3
953
959
 
954
- In February 2022, Google introduced a new AI image generator called ImageFx and integrated it into Gemini. You can ask Gemini to generate images with ImageFx simply by natural language.
960
+ You can ask Gemini to generate and modify images with Imagen3, Google's latest AI image generator, simply by natural language.
955
961
 
956
962
  > [!IMPORTANT]
957
963
  >
958
- > 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 February 15th, 2024):
964
+ > 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 March 19th, 2025):
959
965
  >
960
- > > Image generation in Gemini Apps is available in most countries, except in the European Economic Area (EEA), Switzerland, and the UK. It’s only available for **English prompts**.
961
- > >
962
966
  > > This feature’s availability in any specific Gemini app is also limited to the supported languages and countries of that app.
963
967
  > >
964
968
  > > For now, this feature isn’t available to users under 18.
969
+ > >
970
+ > > To use this feature, you must be signed in to Gemini Apps.
971
+
972
+ You can save images returned from Gemini to local by calling `Image.save()`. Optionally, you can specify the file path and file name by passing `path` and `filename` arguments to the function and skip images with invalid file names by passing `skip_invalid_filename=True`. Works for both `WebImage` and `GeneratedImage`.
965
973
 
966
974
  ```python
967
975
  async def main():
968
976
  response = await client.generate_content("Generate some pictures of cats")
969
- for image in response.images:
977
+ for i, image in enumerate(response.images):
978
+ await image.save(path="temp/", filename=f"cat_{i}.png", verbose=True)
970
979
  print(image, "\n\n----------------------------------\n")
971
980
 
972
981
  asyncio.run(main())
@@ -976,32 +985,17 @@ asyncio.run(main())
976
985
  >
977
986
  > by default, when asked to send images (like the previous example), Gemini will send images fetched from web instead of generating images with AI model, unless you specifically require to "generate" images in your prompt. In this package, web images and generated images are treated differently as `WebImage` and `GeneratedImage`, and will be automatically categorized in the output.
978
987
 
979
- ### Save images to local files
980
-
981
- You can save images returned from Gemini to local files under `/temp` by calling `Image.save()`. Optionally, you can specify the file path and file name by passing `path` and `filename` arguments to the function and skip images with invalid file names by passing `skip_invalid_filename=True`. Works for both `WebImage` and `GeneratedImage`.
982
-
983
- ```python
984
- async def main():
985
- response = await client.generate_content("Generate some pictures of cats")
986
- for i, image in enumerate(response.images):
987
- await image.save(path="temp/", filename=f"cat_{i}.png", verbose=True)
988
-
989
- asyncio.run(main())
990
- ```
991
-
992
988
  ### Generate contents with Gemini extensions
993
989
 
994
990
  > [!IMPORTANT]
995
991
  >
996
- > To access Gemini extensions in API, you must activate them on the [Gemini website](https://gemini.google.com/extensions) first. Same as image generation, Google also has limitations on the availability of Gemini extensions. Here's a summary copied from [official documentation](https://support.google.com/gemini/answer/13695044) (as of February 18th, 2024):
992
+ > To access Gemini extensions in API, you must activate them on the [Gemini website](https://gemini.google.com/extensions) first. Same as image generation, Google also has limitations on the availability of Gemini extensions. Here's a summary copied from [official documentation](https://support.google.com/gemini/answer/13695044) (as of March 19th, 2025):
997
993
  >
998
- > > To use extensions in Gemini Apps:
999
- > >
1000
- > > Sign in with your personal Google Account that you manage on your own. Extensions, including the Google Workspace extension, are currently not available to Google Workspace accounts for school, business, or other organizations.
994
+ > > To connect apps to Gemini, you must have​​​​ Gemini Apps Activity on.
1001
995
  > >
1002
- > > Have Gemini Apps Activity on. Extensions are only available when Gemini Apps Activity is turned on.
996
+ > > To use this feature, you must be signed in to Gemini Apps.
1003
997
  > >
1004
- > > Important: For now, extensions are available in **English, Japanese, and Korean** only.
998
+ > > Important: If you’re under 18, Google Workspace and Maps apps currently only work with English prompts in Gemini.
1005
999
 
1006
1000
  After activating extensions for your account, you can access them in your prompts either by natural language or by starting your prompt with "@" followed by the extension keyword.
1007
1001
 
@@ -10,6 +10,7 @@ pyproject.toml
10
10
  assets/banner.png
11
11
  assets/favicon.png
12
12
  assets/logo.svg
13
+ assets/sample.pdf
13
14
  src/gemini_webapi/__init__.py
14
15
  src/gemini_webapi/client.py
15
16
  src/gemini_webapi/constants.py
@@ -32,17 +32,9 @@ class TestGeminiClient(unittest.IsolatedAsyncioTestCase):
32
32
 
33
33
  @logger.catch(reraise=True)
34
34
  async def test_thinking_model(self):
35
- response = await self.geminiclient.generate_content(
36
- "What's 1+1?", model=Model.G_2_0_FLASH_THINKING
37
- )
38
- logger.debug(response.thoughts)
39
- logger.debug(response.text)
40
-
41
- @logger.catch(reraise=True)
42
- async def test_thinking_with_apps(self):
43
35
  response = await self.geminiclient.generate_content(
44
36
  "Tell me a fact about today in history and illustrate it with a youtube video",
45
- model=Model.G_2_0_FLASH_THINKING_WITH_APPS,
37
+ model=Model.G_2_0_FLASH_THINKING,
46
38
  )
47
39
  logger.debug(response.thoughts)
48
40
  logger.debug(response.text)
@@ -61,10 +53,10 @@ class TestGeminiClient(unittest.IsolatedAsyncioTestCase):
61
53
  logger.debug(f"Model version ({model.model_name}): {response.text}")
62
54
 
63
55
  @logger.catch(reraise=True)
64
- async def test_upload_image(self):
56
+ async def test_upload_files(self):
65
57
  response = await self.geminiclient.generate_content(
66
- "Describe these images",
67
- images=[Path("assets/banner.png"), "assets/favicon.png"],
58
+ "Introduce the contents of these two files. Is there any connection between them?",
59
+ files=["assets/sample.pdf", Path("assets/banner.png")],
68
60
  )
69
61
  logger.debug(response.text)
70
62
 
@@ -92,11 +84,14 @@ class TestGeminiClient(unittest.IsolatedAsyncioTestCase):
92
84
  chat = self.geminiclient.start_chat()
93
85
  response1 = await chat.send_message(
94
86
  "What's the difference between these two images?",
95
- images=["assets/banner.png", "assets/favicon.png"],
87
+ files=["assets/banner.png", "assets/favicon.png"],
96
88
  )
97
89
  logger.debug(response1.text)
98
- response2 = await chat.send_message("Tell me more.")
90
+ response2 = await chat.send_message(
91
+ "Use image generation tool to modify the banner with another font and design."
92
+ )
99
93
  logger.debug(response2.text)
94
+ logger.debug(response2.images)
100
95
 
101
96
  @logger.catch(reraise=True)
102
97
  async def test_send_web_image(self):
@@ -120,14 +115,6 @@ class TestGeminiClient(unittest.IsolatedAsyncioTestCase):
120
115
  self.assertTrue(image.url)
121
116
  logger.debug(image)
122
117
 
123
- @logger.catch(reraise=True)
124
- async def test_image_generation_failure(self):
125
- response = await self.geminiclient.generate_content(
126
- "Generate some pictures of people"
127
- )
128
- self.assertFalse(response.images)
129
- logger.debug(response.text)
130
-
131
118
  @logger.catch(reraise=True)
132
119
  async def test_card_content(self):
133
120
  response = await self.geminiclient.generate_content("How is today's weather?")
File without changes
File without changes
File without changes