gemini-webapi 1.6.1__tar.gz → 1.17.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 (50) hide show
  1. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/.github/workflows/github-release.yml +1 -1
  2. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/.github/workflows/pypi-publish.yml +5 -5
  3. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/.gitignore +1 -1
  4. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/PKG-INFO +213 -56
  5. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/README.md +206 -51
  6. gemini_webapi-1.17.0/assets/sample.pdf +0 -0
  7. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/pyproject.toml +4 -3
  8. gemini_webapi-1.17.0/src/gemini_webapi/__init__.py +6 -0
  9. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/src/gemini_webapi/client.py +331 -154
  10. gemini_webapi-1.17.0/src/gemini_webapi/components/__init__.py +3 -0
  11. gemini_webapi-1.17.0/src/gemini_webapi/components/gem_mixin.py +288 -0
  12. gemini_webapi-1.17.0/src/gemini_webapi/constants.py +85 -0
  13. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/src/gemini_webapi/exceptions.py +32 -0
  14. gemini_webapi-1.17.0/src/gemini_webapi/types/__init__.py +7 -0
  15. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/src/gemini_webapi/types/candidate.py +16 -1
  16. gemini_webapi-1.17.0/src/gemini_webapi/types/gem.py +132 -0
  17. gemini_webapi-1.17.0/src/gemini_webapi/types/grpc.py +34 -0
  18. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/src/gemini_webapi/types/image.py +14 -9
  19. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/src/gemini_webapi/types/modeloutput.py +4 -0
  20. gemini_webapi-1.17.0/src/gemini_webapi/utils/__init__.py +14 -0
  21. gemini_webapi-1.17.0/src/gemini_webapi/utils/decorators.py +52 -0
  22. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/src/gemini_webapi/utils/get_access_token.py +80 -24
  23. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/src/gemini_webapi/utils/load_browser_cookies.py +10 -4
  24. gemini_webapi-1.17.0/src/gemini_webapi/utils/logger.py +37 -0
  25. gemini_webapi-1.17.0/src/gemini_webapi/utils/parsing.py +79 -0
  26. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/src/gemini_webapi/utils/rotate_1psidts.py +9 -5
  27. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/src/gemini_webapi/utils/upload_file.py +30 -9
  28. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/src/gemini_webapi.egg-info/PKG-INFO +213 -56
  29. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/src/gemini_webapi.egg-info/SOURCES.txt +8 -1
  30. gemini_webapi-1.17.0/src/gemini_webapi.egg-info/requires.txt +4 -0
  31. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/tests/test_client_features.py +86 -34
  32. gemini_webapi-1.17.0/tests/test_gem_mixin.py +88 -0
  33. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/tests/test_save_image.py +15 -9
  34. gemini_webapi-1.6.1/src/gemini_webapi/__init__.py +0 -4
  35. gemini_webapi-1.6.1/src/gemini_webapi/constants.py +0 -23
  36. gemini_webapi-1.6.1/src/gemini_webapi/types/__init__.py +0 -3
  37. gemini_webapi-1.6.1/src/gemini_webapi/utils/__init__.py +0 -10
  38. gemini_webapi-1.6.1/src/gemini_webapi/utils/logger.py +0 -39
  39. gemini_webapi-1.6.1/src/gemini_webapi.egg-info/requires.txt +0 -3
  40. gemini_webapi-1.6.1/tests/test_rotate_cookies.py +0 -26
  41. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/.github/dependabot.yml +0 -0
  42. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/.vscode/launch.json +0 -0
  43. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/.vscode/settings.json +0 -0
  44. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/LICENSE +0 -0
  45. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/assets/banner.png +0 -0
  46. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/assets/favicon.png +0 -0
  47. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/assets/logo.svg +0 -0
  48. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/setup.cfg +0 -0
  49. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/src/gemini_webapi.egg-info/dependency_links.txt +0 -0
  50. {gemini_webapi-1.6.1 → gemini_webapi-1.17.0}/src/gemini_webapi.egg-info/top_level.txt +0 -0
@@ -11,7 +11,7 @@ jobs:
11
11
  permissions:
12
12
  contents: write
13
13
  steps:
14
- - uses: actions/checkout@v4
14
+ - uses: actions/checkout@v5
15
15
  - uses: ncipollo/release-action@v1
16
16
  with:
17
17
  body: ${{ github.event.head_commit.message }}
@@ -24,9 +24,9 @@ jobs:
24
24
  name: Build package
25
25
  runs-on: ubuntu-latest
26
26
  steps:
27
- - uses: actions/checkout@v4
27
+ - uses: actions/checkout@v5
28
28
  - name: Set up Python
29
- uses: actions/setup-python@v5
29
+ uses: actions/setup-python@v6
30
30
  with:
31
31
  python-version: '3.x'
32
32
  - name: Install dependencies
@@ -36,7 +36,7 @@ jobs:
36
36
  - name: Build package
37
37
  run: python -m build
38
38
  - name: Archive production artifacts
39
- uses: actions/upload-artifact@v4.4.0
39
+ uses: actions/upload-artifact@v4.6.2
40
40
  with:
41
41
  name: dist
42
42
  path: dist
@@ -52,9 +52,9 @@ jobs:
52
52
  id-token: write # IMPORTANT: this permission is mandatory for trusted publishing
53
53
  steps:
54
54
  - name: Retrieve built artifacts
55
- uses: actions/download-artifact@v4.1.8
55
+ uses: actions/download-artifact@v5.0.0
56
56
  with:
57
57
  name: dist
58
58
  path: dist
59
59
  - name: Publish package distributions to PyPI
60
- uses: pypa/gh-action-pypi-publish@v1.10.1
60
+ uses: pypa/gh-action-pypi-publish@v1.13.0
@@ -201,4 +201,4 @@ Temporary Items
201
201
  .apdisk
202
202
 
203
203
  # Temporary files
204
- temp/
204
+ .temp/
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.1
1
+ Metadata-Version: 2.4
2
2
  Name: gemini-webapi
3
- Version: 1.6.1
3
+ Version: 1.17.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
@@ -676,9 +676,11 @@ Classifier: Programming Language :: Python :: 3.12
676
676
  Requires-Python: >=3.10
677
677
  Description-Content-Type: text/markdown
678
678
  License-File: LICENSE
679
- Requires-Dist: httpx>=0.25.2
680
- Requires-Dist: pydantic>=2.5.3
681
- Requires-Dist: loguru>=0.7.2
679
+ Requires-Dist: httpx[http2]~=0.28.1
680
+ Requires-Dist: loguru~=0.7.3
681
+ Requires-Dist: orjson~=3.11.1
682
+ Requires-Dist: pydantic~=2.12.2
683
+ Dynamic: license-file
682
684
 
683
685
  <p align="center">
684
686
  <img src="https://raw.githubusercontent.com/HanaokaYuzu/Gemini-API/master/assets/banner.png" width="55%" alt="Gemini Banner" align="center">
@@ -711,9 +713,10 @@ A reverse-engineered asynchronous python wrapper for [Google Gemini](https://gem
711
713
  ## Features
712
714
 
713
715
  - **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.
716
+ - **Image Generation** - Natively supports generating and editing images with natural language.
717
+ - **System Prompt** - Supports customizing model's system prompt with [Gemini Gems](https://gemini.google.com/gems/view).
715
718
  - **Extension Support** - Supports generating contents with [Gemini extensions](https://gemini.google.com/extensions) on, like YouTube and Gmail.
716
- - **Classified Outputs** - Automatically categorizes texts, web images and AI generated images in the response.
719
+ - **Classified Outputs** - Categorizes texts, thoughts, web images and AI generated images in the response.
717
720
  - **Official Flavor** - Provides a simple and elegant interface inspired by [Google Generative AI](https://ai.google.dev/tutorials/python_quickstart)'s official API.
718
721
  - **Asynchronous** - Utilizes `asyncio` to run generating tasks and return outputs efficiently.
719
722
 
@@ -725,16 +728,22 @@ A reverse-engineered asynchronous python wrapper for [Google Gemini](https://gem
725
728
  - [Authentication](#authentication)
726
729
  - [Usage](#usage)
727
730
  - [Initialization](#initialization)
728
- - [Generate contents from text](#generate-contents-from-text)
729
- - [Generate contents from image](#generate-contents-from-image)
731
+ - [Generate contents](#generate-contents)
732
+ - [Generate contents with files](#generate-contents-with-files)
730
733
  - [Conversations across multiple turns](#conversations-across-multiple-turns)
731
734
  - [Continue previous conversations](#continue-previous-conversations)
735
+ - [Select language model](#select-language-model)
736
+ - [Apply system prompt with Gemini Gems](#apply-system-prompt-with-gemini-gems)
737
+ - [Manage Custom Gems](#manage-custom-gems)
738
+ - [Create a custom gem](#create-a-custom-gem)
739
+ - [Update an existing gem](#update-an-existing-gem)
740
+ - [Delete a custom gem](#delete-a-custom-gem)
741
+ - [Retrieve model's thought process](#retrieve-models-thought-process)
732
742
  - [Retrieve images in response](#retrieve-images-in-response)
733
- - [Generate images with ImageFx](#generate-images-with-imagefx)
734
- - [Save images to local files](#save-images-to-local-files)
743
+ - [Generate and edit images](#generate-and-edit-images)
735
744
  - [Generate contents with Gemini extensions](#generate-contents-with-gemini-extensions)
736
745
  - [Check and switch to other reply candidates](#check-and-switch-to-other-reply-candidates)
737
- - [Control log level](#control-log-level)
746
+ - [Logging Configuration](#logging-configuration)
738
747
  - [References](#references)
739
748
  - [Stargazers](#stargazers)
740
749
 
@@ -746,13 +755,13 @@ A reverse-engineered asynchronous python wrapper for [Google Gemini](https://gem
746
755
 
747
756
  Install/update the package with pip.
748
757
 
749
- ```bash
758
+ ```sh
750
759
  pip install -U gemini_webapi
751
760
  ```
752
761
 
753
762
  Optionally, package offers a way to automatically import cookies from your local browser. To enable this feature, install `browser-cookie3` as well. Supported platforms and browsers can be found [here](https://github.com/borisbabic/browser_cookie3?tab=readme-ov-file#contribute).
754
763
 
755
- ```bash
764
+ ```sh
756
765
  pip install -U browser-cookie3
757
766
  ```
758
767
 
@@ -768,15 +777,17 @@ pip install -U browser-cookie3
768
777
 
769
778
  > [!NOTE]
770
779
  >
771
- > 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.
772
781
  >
773
782
  > Here's part of a sample `docker-compose.yml` file:
774
783
 
775
784
  ```yaml
776
785
  services:
777
786
  main:
787
+ environment:
788
+ GEMINI_COOKIE_PATH: /tmp/gemini_webapi
778
789
  volumes:
779
- - ./gemini_cookies:/usr/local/lib/python3.12/site-packages/gemini_webapi/utils/temp
790
+ - ./gemini_cookies:/tmp/gemini_webapi
780
791
  ```
781
792
 
782
793
  > [!NOTE]
@@ -804,7 +815,7 @@ Secure_1PSIDTS = "COOKIE VALUE HERE"
804
815
 
805
816
  async def main():
806
817
  # If browser-cookie3 is installed, simply use `client = GeminiClient()`
807
- client = GeminiClient(Secure_1PSID, Secure_1PSIDTS, proxies=None)
818
+ client = GeminiClient(Secure_1PSID, Secure_1PSIDTS, proxy=None)
808
819
  await client.init(timeout=30, auto_close=False, close_delay=300, auto_refresh=True)
809
820
 
810
821
  asyncio.run(main())
@@ -814,9 +825,9 @@ asyncio.run(main())
814
825
  >
815
826
  > `auto_close` and `close_delay` are optional arguments for automatically closing the client after a certain period of inactivity. This feature is disabled by default. In an always-on service like chatbot, it's recommended to set `auto_close` to `True` combined with reasonable seconds of `close_delay` for better resource management.
816
827
 
817
- ### Generate contents from text
828
+ ### Generate contents
818
829
 
819
- Ask a one-turn quick question by calling `GeminiClient.generate_content`.
830
+ Ask a single-turn question by calling `GeminiClient.generate_content`, which returns a `gemini_webapi.ModelOutput` object containing the generated text, images, thoughts, and conversation metadata.
820
831
 
821
832
  ```python
822
833
  async def main():
@@ -830,15 +841,15 @@ asyncio.run(main())
830
841
  >
831
842
  > Simply use `print(response)` to get the same output if you just want to see the response text
832
843
 
833
- ### Generate contents from image
844
+ ### Generate contents with files
834
845
 
835
- 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.
846
+ 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.
836
847
 
837
848
  ```python
838
849
  async def main():
839
850
  response = await client.generate_content(
840
- "Describe each of these images",
841
- images=["assets/banner.png", "assets/favicon.png"],
851
+ "Introduce the contents of these two files. Is there any connection between them?",
852
+ files=["assets/sample.pdf", Path("assets/banner.png")],
842
853
  )
843
854
  print(response.text)
844
855
 
@@ -847,14 +858,20 @@ asyncio.run(main())
847
858
 
848
859
  ### Conversations across multiple turns
849
860
 
850
- If you want to keep conversation continuous, please use `GeminiClient.start_chat` to create a `ChatSession` object and send messages through it. The conversation history will be automatically handled and get updated after each turn.
861
+ If you want to keep conversation continuous, please use `GeminiClient.start_chat` to create a `gemini_webapi.ChatSession` object and send messages through it. The conversation history will be automatically handled and get updated after each turn.
851
862
 
852
863
  ```python
853
864
  async def main():
854
865
  chat = client.start_chat()
855
- response1 = await chat.send_message("Briefly introduce Europe")
856
- response2 = await chat.send_message("What's the population there?")
857
- print(response1.text, response2.text, sep="\n\n----------------------------------\n\n")
866
+ response1 = await chat.send_message(
867
+ "Introduce the contents of these two files. Is there any connection between them?",
868
+ files=["assets/sample.pdf", Path("assets/banner.png")],
869
+ )
870
+ print(response1.text)
871
+ response2 = await chat.send_message(
872
+ "Use image generation tool to modify the banner with another font and design."
873
+ )
874
+ print(response2.text, response2.images, sep="\n\n----------------------------------\n\n")
858
875
 
859
876
  asyncio.run(main())
860
877
  ```
@@ -884,72 +901,208 @@ async def main():
884
901
  asyncio.run(main())
885
902
  ```
886
903
 
887
- ### Retrieve images in response
904
+ ### Select language model
905
+
906
+ You can specify which language model to use by passing `model` argument to `GeminiClient.generate_content` or `GeminiClient.start_chat`. The default value is `unspecified`.
907
+
908
+ Currently available models (as of November 20, 2025):
888
909
 
889
- Images in the API's output are stored as a list of `Image` objects. You can access the image title, URL, and description by calling `image.title`, `image.url` and `image.alt` respectively.
910
+ - `unspecified` - Default model
911
+ - `gemini-3.0-pro` - Gemini 3.0 Pro
912
+ - `gemini-2.5-pro` - Gemini 2.5 Pro
913
+ - `gemini-2.5-flash` - Gemini 2.5 Flash
890
914
 
891
915
  ```python
916
+ from gemini_webapi.constants import Model
917
+
892
918
  async def main():
893
- response = await client.generate_content("Send me some pictures of cats")
894
- for image in response.images:
895
- print(image, "\n\n----------------------------------\n")
919
+ response1 = await client.generate_content(
920
+ "What's you language model version? Reply version number only.",
921
+ model=Model.G_2_5_FLASH,
922
+ )
923
+ print(f"Model version ({Model.G_2_5_FLASH.model_name}): {response1.text}")
924
+
925
+ chat = client.start_chat(model="gemini-2.5-pro")
926
+ response2 = await chat.send_message("What's you language model version? Reply version number only.")
927
+ print(f"Model version (gemini-2.5-pro): {response2.text}")
896
928
 
897
929
  asyncio.run(main())
898
930
  ```
899
931
 
900
- ### Generate images with ImageFx
932
+ ### Apply system prompt with Gemini Gems
901
933
 
902
- 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.
934
+ System prompt can be applied to conversations via [Gemini Gems](https://gemini.google.com/gems/view). To use a gem, you can pass `gem` argument to `GeminiClient.generate_content` or `GeminiClient.start_chat`. `gem` can be either a string of gem id or a `gemini_webapi.Gem` object. Only one gem can be applied to a single conversation.
903
935
 
904
- > [!IMPORTANT]
936
+ > [!TIP]
905
937
  >
906
- > 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):
938
+ > There are some system predefined gems that by default are not shown to users (and therefore may not work properly). Use `client.fetch_gems(include_hidden=True)` to include them in the fetch result.
939
+
940
+ ```python
941
+ async def main():
942
+ # Fetch all gems for the current account, including both predefined and user-created ones
943
+ await client.fetch_gems(include_hidden=False)
944
+
945
+ # Once fetched, gems will be cached in `GeminiClient.gems`
946
+ gems = client.gems
947
+
948
+ # Get the gem you want to use
949
+ system_gems = gems.filter(predefined=True)
950
+ coding_partner = system_gems.get(id="coding-partner")
951
+
952
+ response1 = await client.generate_content(
953
+ "what's your system prompt?",
954
+ model=Model.G_2_5_FLASH,
955
+ gem=coding_partner,
956
+ )
957
+ print(response1.text)
958
+
959
+ # Another example with a user-created custom gem
960
+ # Gem ids are consistent strings. Store them somewhere to avoid fetching gems every time
961
+ your_gem = gems.get(name="Your Gem Name")
962
+ your_gem_id = your_gem.id
963
+ chat = client.start_chat(gem=your_gem_id)
964
+ response2 = await chat.send_message("what's your system prompt?")
965
+ print(response2)
966
+ ```
967
+
968
+ ### Manage Custom Gems
969
+
970
+ You can create, update, and delete your custom gems programmatically with the API. Note that predefined system gems cannot be modified or deleted.
971
+
972
+ #### Create a custom gem
973
+
974
+ Create a new custom gem with a name, system prompt (instructions), and optional description:
975
+
976
+ ```python
977
+ async def main():
978
+ # Create a new custom gem
979
+ new_gem = await client.create_gem(
980
+ name="Python Tutor",
981
+ prompt="You are a helpful Python programming tutor.",
982
+ description="A specialized gem for Python programming"
983
+ )
984
+
985
+ print(f"Custom gem created: {new_gem}")
986
+
987
+ # Use the newly created gem in a conversation
988
+ response = await client.generate_content(
989
+ "Explain how list comprehensions work in Python",
990
+ gem=new_gem
991
+ )
992
+ print(response.text)
993
+
994
+ asyncio.run(main())
995
+ ```
996
+
997
+ #### Update an existing gem
998
+
999
+ > [!NOTE]
907
1000
  >
908
- > > 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**.
909
- > >
910
- > > This feature’s availability in any specific Gemini app is also limited to the supported languages and countries of that app.
911
- > >
912
- > > For now, this feature isn’t available to users under 18.
1001
+ > When updating a gem, you must provide all parameters (name, prompt, description) even if you only want to change one of them.
913
1002
 
914
1003
  ```python
915
1004
  async def main():
916
- response = await client.generate_content("Generate some pictures of cats")
1005
+ # Get a custom gem (assuming you have one named "Python Tutor")
1006
+ await client.fetch_gems()
1007
+ python_tutor = client.gems.get(name="Python Tutor")
1008
+
1009
+ # Update the gem with new instructions
1010
+ updated_gem = await client.update_gem(
1011
+ gem=python_tutor, # Can also pass gem ID string
1012
+ name="Advanced Python Tutor",
1013
+ prompt="You are an expert Python programming tutor.",
1014
+ description="An advanced Python programming assistant"
1015
+ )
1016
+
1017
+ print(f"Custom gem updated: {updated_gem}")
1018
+
1019
+ asyncio.run(main())
1020
+ ```
1021
+
1022
+ #### Delete a custom gem
1023
+
1024
+ ```python
1025
+ async def main():
1026
+ # Get the gem to delete
1027
+ await client.fetch_gems()
1028
+ gem_to_delete = client.gems.get(name="Advanced Python Tutor")
1029
+
1030
+ # Delete the gem
1031
+ await client.delete_gem(gem_to_delete) # Can also pass gem ID string
1032
+ print(f"Custom gem deleted: {gem_to_delete.name}")
1033
+
1034
+ asyncio.run(main())
1035
+ ```
1036
+
1037
+ ### Retrieve model's thought process
1038
+
1039
+ When using models with thinking capabilities, the model's thought process will be populated in `ModelOutput.thoughts`.
1040
+
1041
+ ```python
1042
+ async def main():
1043
+ response = await client.generate_content(
1044
+ "What's 1+1?", model="gemini-2.5-pro"
1045
+ )
1046
+ print(response.thoughts)
1047
+ print(response.text)
1048
+
1049
+ asyncio.run(main())
1050
+ ```
1051
+
1052
+ ### Retrieve images in response
1053
+
1054
+ Images in the API's output are stored as a list of `gemini_webapi.Image` objects. You can access the image title, URL, and description by calling `Image.title`, `Image.url` and `Image.alt` respectively.
1055
+
1056
+ ```python
1057
+ async def main():
1058
+ response = await client.generate_content("Send me some pictures of cats")
917
1059
  for image in response.images:
918
1060
  print(image, "\n\n----------------------------------\n")
919
1061
 
920
1062
  asyncio.run(main())
921
1063
  ```
922
1064
 
923
- > [!NOTE]
924
- >
925
- > 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.
1065
+ ### Generate and edit images
926
1066
 
927
- ### Save images to local files
1067
+ You can ask Gemini to generate and edit images with Nano Banana, Google's latest image model, simply by natural language.
928
1068
 
929
- 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`.
1069
+ > [!IMPORTANT]
1070
+ >
1071
+ > 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):
1072
+ >
1073
+ > > This feature’s availability in any specific Gemini app is also limited to the supported languages and countries of that app.
1074
+ > >
1075
+ > > For now, this feature isn’t available to users under 18.
1076
+ > >
1077
+ > > To use this feature, you must be signed in to Gemini Apps.
1078
+
1079
+ 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`.
930
1080
 
931
1081
  ```python
932
1082
  async def main():
933
1083
  response = await client.generate_content("Generate some pictures of cats")
934
1084
  for i, image in enumerate(response.images):
935
1085
  await image.save(path="temp/", filename=f"cat_{i}.png", verbose=True)
1086
+ print(image, "\n\n----------------------------------\n")
936
1087
 
937
1088
  asyncio.run(main())
938
1089
  ```
939
1090
 
1091
+ > [!NOTE]
1092
+ >
1093
+ > 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.
1094
+
940
1095
  ### Generate contents with Gemini extensions
941
1096
 
942
1097
  > [!IMPORTANT]
943
1098
  >
944
- > 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):
1099
+ > 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):
945
1100
  >
946
- > > To use extensions in Gemini Apps:
947
- > >
948
- > > 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.
1101
+ > > To connect apps to Gemini, you must have​​​​ Gemini Apps Activity on.
949
1102
  > >
950
- > > Have Gemini Apps Activity on. Extensions are only available when Gemini Apps Activity is turned on.
1103
+ > > To use this feature, you must be signed in to Gemini Apps.
951
1104
  > >
952
- > > Important: For now, extensions are available in **English, Japanese, and Korean** only.
1105
+ > > Important: If you’re under 18, Google Workspace and Maps apps currently only work with English prompts in Gemini.
953
1106
 
954
1107
  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.
955
1108
 
@@ -970,7 +1123,7 @@ asyncio.run(main())
970
1123
 
971
1124
  ### Check and switch to other reply candidates
972
1125
 
973
- A response from Gemini usually contains multiple reply candidates with different generated contents. You can check all candidates and choose one to continue the conversation. By default, the first candidate will be chosen automatically.
1126
+ A response from Gemini sometimes contains multiple reply candidates with different generated contents. You can check all candidates and choose one to continue the conversation. By default, the first candidate will be chosen.
974
1127
 
975
1128
  ```python
976
1129
  async def main():
@@ -991,9 +1144,9 @@ async def main():
991
1144
  asyncio.run(main())
992
1145
  ```
993
1146
 
994
- ### Control log level
1147
+ ### Logging Configuration
995
1148
 
996
- You can set the log level of the package to one of the following values: `DEBUG`, `INFO`, `WARNING`, `ERROR` and `CRITICAL`. The default value is `INFO`.
1149
+ This package uses [loguru](https://loguru.readthedocs.io/en/stable/) for logging, and exposes a function `set_log_level` to control log level. You can set log level to one of the following values: `DEBUG`, `INFO`, `WARNING`, `ERROR` and `CRITICAL`. The default value is `INFO`.
997
1150
 
998
1151
  ```python
999
1152
  from gemini_webapi import set_log_level
@@ -1001,6 +1154,10 @@ from gemini_webapi import set_log_level
1001
1154
  set_log_level("DEBUG")
1002
1155
  ```
1003
1156
 
1157
+ > [!NOTE]
1158
+ >
1159
+ > Calling `set_log_level` for the first time will **globally** remove all existing loguru handlers. You may want to configure logging directly with loguru to avoid this issue and have more advanced control over logging behaviors.
1160
+
1004
1161
  ## References
1005
1162
 
1006
1163
  [Google AI Studio](https://ai.google.dev/tutorials/ai-studio_quickstart)