Loading repository data…
Loading repository data…
HanaokaYuzu / repository
✨ Reverse-engineered Python API for Google Gemini web app
A reverse-engineered asynchronous Python wrapper for the Google Gemini web app (formerly Bard).
asyncio to run generation tasks and return outputs efficiently.[!NOTE]
This package requires Python 3.10 or higher.
Install or update the package with pip.
pip install -U gemini_webapi
Optionally, the package offers a way to automatically import cookies from your local browser via optional dependency browser-cookie3. To enable this feature, install gemini_webapi[browser] instead. Supported platforms and browsers can be found here.
pip install -U gemini_webapi[browser]
[!TIP]
If
browser-cookie3is installed, you can skip this step and go directly to the usage section. Just make sure you are logged in to https://gemini.google.com in your browser.
Network tab, and refresh the page__Secure-1PSID and __Secure-1PSIDTS[!NOTE]
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_PATHenvironment variable to specify the path where auto-refreshed cookies are stored. Make sure the path is writable by the application.Here's part of a sample
docker-compose.ymlfile:
services:
main:
environment:
GEMINI_COOKIE_PATH: /tmp/gemini_webapi
volumes:
- ./gemini_cookies:/tmp/gemini_webapi
[!NOTE]
The API's auto-cookie-refreshing feature doesn't require
browser-cookie3and is enabled by default. It allows you to keep the API service running without worrying about cookie expiration.This feature may require you to log in to your Google account again in the browser. This is expected behavior and won't affect the API's functionality.
To avoid this, it's recommended to get cookies from a separate browser session and close it as soon as possible for best utilization (e.g. a fresh login in the browser's private mode). More details can be found here.
Import the required packages and initialize a client with your cookies from the previous step. After successful initialization, the API will automatically refresh __Secure-1PSIDTS in the background as long as the process is alive.
import asyncio
from gemini_webapi import GeminiClient
# Replace "COOKIE VALUE HERE" with your actual cookie values.
# Leave Secure_1PSIDTS empty if it's not available for your account.
Secure_1PSID = "COOKIE VALUE HERE"
Secure_1PSIDTS = "COOKIE VALUE HERE"
async def main():
# If browser-cookie3 is installed, simply use `client = GeminiClient()`
client = GeminiClient(Secure_1PSID, Secure_1PSIDTS, proxy=None)
await client.init(timeout=30, auto_close=False, close_delay=300, auto_refresh=True)
asyncio.run(main())
[!TIP]
auto_closeandclose_delayare 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 a chatbot, it's recommended to setauto_closetoTruewith a reasonableclose_delayvalue for better resource management.
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.
async def main():
response = await client.generate_content("Hello World!")
print(response.text)
asyncio.run(main())
[!TIP]
Simply use
print(response)to get the same output if you just want to see the response text.
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 a text prompt.
async def main():
response = await client.generate_content(
"Introduce the contents of these two files. Is there any connection between them?",
files=["assets/sample.pdf", Path("assets/banner.png")],
)
print(response.text)
asyncio.run(main())
If you want to keep the conversation continuous, use GeminiClient.start_chat to create a gemini_webapi.ChatSession object and send messages through it. The conversation history will be handled automatically and updated after each turn.
async def main():
chat = client.start_chat()
response1 = await chat.send_message(
"Introduce the contents of these two files. Is there any connection between them?",
files=["assets/sample.pdf", Path("assets/banner.png")],
)
print(response1.text)
response2 = await chat.send_message(
"Use image generation tool to modify the banner with another font and design."
)
print(response2.text, response2.images, sep="\n\n----------------------------------\n\n")
asyncio.run(main())
[!TIP]
Same as
GeminiClient.generate_content,ChatSession.send_messagealso acceptsimageas an optional argument.
To manually retrieve previous conversations, you can pass a previous ChatSession's metadata to GeminiClient.start_chat when creating a new ChatSession. Alternatively, you can persist previous metadata to a file or database if you need to access it after the current Python process has exited.
async def main():
# Start a new chat session
chat = client.start_chat()
response = await chat.send_message("Fine weather today")
# Save chat's metadata
previous_session = chat.metadata
# Load the previous conversation
previous_chat = client.start_chat(metadata=previous_session)
response = await previous_chat.send_message("What was my previous message?")
print(response)
asyncio.run(main())
You can read the conversation history of a specific chat by calling GeminiClient.read_chat with the chat ID. It returns a ChatHistory object containing a list of ChatTurn objects ordered from newest to oldest.
async def main():
chat = client.start_chat()
await chat.send_message("What is the capital of France?")
# Read the chat history
history = await client.read_chat(chat.cid)
if history:
for turn in history.turns:
print(f"[{turn.role.upper()}] {turn.text}")
print("\n----------------------------------\n")
asyncio.run(main())
To list all recent chats, use GeminiClient.list_chats:
async def main():
chats = client.list_chats()
if chats:
for chat_info in chats:
print(f"{chat_info.cid}: {chat_info.title}")
asyncio.run(main())
You can delete a specific chat