gemini-calo


Namegemini-calo JSON
Version 0.1.2 PyPI version JSON
download
home_pagehttps://github.com/state-alchemists/gemini-calo
SummaryA Fastapi Based Proxy for Gemini API
upload_time2025-08-18 08:20:37
maintainerNone
docs_urlNone
authorGo Frendi Gunawan
requires_python<4.0.0,>=3.10
licenseAGPL-3.0-or-later
keywords
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Gemini Calo

**Gemini Calo** is a powerful, yet simple, FastAPI-based proxy server for Google's Gemini API. It provides a seamless way to add a layer of authentication, logging, and monitoring to your Gemini API requests. It's designed to be run as a standalone server or integrated into your existing FastAPI applications.

One of its key features is providing an OpenAI-compatible endpoint, allowing you to use Gemini models with tools and libraries that are built for the OpenAI API.

## Key Features

*   **Authentication:** Secure your Gemini API access with an additional layer of API key authentication.
*   **Request Logging:** Detailed logging of all incoming requests and outgoing responses.
*   **OpenAI Compatibility:** Use Gemini models through an OpenAI-compatible `/v1/chat/completions` endpoint.
*   **Round-Robin API Keys:** Distribute your requests across multiple Gemini API keys.
*   **Easy Integration:** Use it as a standalone server or mount it into your existing FastAPI project.
*   **Extensible:** Easily add your own custom middleware to suit your needs.

## How It's Useful

-   **Centralized API Key Management:** Instead of hardcoding your Gemini API keys in various clients, you can manage them in one place.
-   **Security:** Protect your expensive Gemini API keys by exposing only a proxy key to your users or client applications.
-   **Monitoring & Observability:** The logging middleware gives you insight into how your API is being used, helping you debug issues and monitor usage patterns.
-   **Seamless Migration:** If you have existing tools that use the OpenAI API, you can switch to using Google's Gemini models without significant code changes.

## Running the Built-in Server

You can quickly get the proxy server up and running with just a few steps.

### 1. Installation

Install the package using pip:

```bash
pip install gemini-calo
```

### 2. Configuration

The server is configured through environment variables. You can create a `.env` file in your working directory to store them.

*   `GEMINI_CALO_API_KEYS`: A comma-separated list of your Google Gemini API keys. The proxy will rotate through these keys for outgoing requests.
*   `GEMINI_CALO_PROXY_API_KEYS`: (Optional) A comma-separated list of API keys that clients must provide to use the proxy. If not set, the proxy will be open to anyone.
*   `GEMINI_CALO_HTTP_PORT`: (Optional) The port on which the server will run. Defaults to `8000`.

**Example `.env` file:**

```
GEMINI_CALO_API_KEYS=your_gemini_key_1,your_gemini_key_2
GEMINI_CALO_PROXY_API_KEYS=my_secret_proxy_key_1,my_secret_proxy_key_2
GEMINI_CALO_HTTP_PORT=8080
```

### 3. Running the Server

Once configured, you can start the server with the `gemini-calo` command:

```bash
gemini-calo
```

The server will start on the configured port (e.g., `http://0.0.0.0:8080`).

## Integrating with an Existing FastAPI Application

If you have an existing FastAPI application, you can easily integrate Gemini Calo's proxy functionality into it.

```python
from fastapi import FastAPI
from gemini_calo.proxy import GeminiProxyService
from gemini_calo.middlewares.auth import auth_middleware
from gemini_calo.middlewares.logging import logging_middleware
from functools import partial
import os

# Your existing FastAPI app
app = FastAPI()

# 1. Initialize the GeminiProxyService
gemini_api_keys = os.getenv("GEMINI_CALO_API_KEYS", "").split(",")
proxy_service = GeminiProxyService(gemini_api_keys=gemini_api_keys)

# 2. (Optional) Add Authentication Middleware
proxy_api_keys = os.getenv("GEMINI_CALO_PROXY_API_KEYS", "").split(",")
if proxy_api_keys:
    auth_middleware_with_keys = partial(auth_middleware, user_api_key_checker=proxy_api_keys)
    app.middleware("http")(auth_middleware_with_keys)

# 3. (Optional) Add Logging Middleware
app.middleware("http")(logging_middleware)

# 4. Mount the Gemini and OpenAI routers
app.include_router(proxy_service.gemini_router)
app.include_router(proxy_service.openai_router)

@app.get("/health")
def health_check():
    return {"status": "ok"}

# Now you can run your app as usual with uvicorn
# uvicorn your_app_file:app --reload
```

## How the Middleware Works

Middleware in FastAPI are functions that process every request before it reaches the specific path operation and every response before it is sent back to the client. Gemini Calo includes two useful middlewares by default.

### Logging Middleware (`logging_middleware`)

This middleware logs the details of every incoming request and outgoing response, including headers and body content. This is invaluable for debugging and monitoring. It's designed to handle both standard and streaming responses correctly.

### Authentication Middleware (`auth_middleware`)

This middleware protects your proxy endpoints. It checks for an API key in the `Authorization` header (as a Bearer token) or the `x-goog-api-key` header. It then validates this key against the list of keys you provided in the `GEMINI_CALO_PROXY_API_KEYS` environment variable. If the key is missing or invalid, it returns a `401 Unauthorized` error.

### Adding Your Own Middleware

Because Gemini Calo is built on FastAPI, you can easily add your own custom middleware. For example, you could add a middleware for rate limiting, CORS, or custom header injection.

#### Advanced Middleware: Modifying Request Body and Headers

Here is a more advanced example that intercepts a request, modifies its JSON body, adds a new header, and then forwards it to the actual endpoint. This can be useful for injecting default values, adding metadata, or transforming request payloads.

**Important:** Reading the request body consumes it. To allow the endpoint to read the body again, we must reconstruct the request with the modified body.

```python
from fastapi import FastAPI, Request
from starlette.datastructures import MutableHeaders
import json

app = FastAPI()

# This middleware will add a 'user_id' to the request body
# and a 'X-Request-ID' to the headers.
async def modify_request_middleware(request: Request, call_next):
    # Get the original request body
    body = await request.body()
    
    # Modify headers
    request_headers = MutableHeaders(request.headers)
    request_headers["X-Request-ID"] = "some-unique-id"
    
    # Modify body (if it's JSON)
    new_body = body
    if body and request.headers.get("content-type") == "application/json":
        try:
            json_body = json.loads(body)
            # Add or modify a key
            json_body["user_id"] = "injected-user-123"
            new_body = json.dumps(json_body).encode()
        except json.JSONDecodeError:
            # Body is not valid JSON, pass it through
            pass

    # To pass the modified body and headers, we need to create a new Request object.
    # We do this by defining a new 'receive' channel.
    async def receive():
        return {"type": "http.request", "body": new_body, "more_body": False}

    # We replace the original request's scope with the modified headers
    request.scope["headers"] = request_headers.raw

    # Create the new request object and pass it to the next middleware/endpoint
    new_request = Request(request.scope, receive)
    response = await call_next(new_request)
    
    return response

app.middleware("http")(modify_request_middleware)

# ... then add the Gemini Calo proxy and routers as shown above
```

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/state-alchemists/gemini-calo",
    "name": "gemini-calo",
    "maintainer": null,
    "docs_url": null,
    "requires_python": "<4.0.0,>=3.10",
    "maintainer_email": null,
    "keywords": null,
    "author": "Go Frendi Gunawan",
    "author_email": "gofrendiasgard@gmail.com",
    "download_url": "https://files.pythonhosted.org/packages/db/91/79e3b6dee7e551253e1240a29b9768226d94c4adba07669e67fe8f50e23a/gemini_calo-0.1.2.tar.gz",
    "platform": null,
    "description": "# Gemini Calo\n\n**Gemini Calo** is a powerful, yet simple, FastAPI-based proxy server for Google's Gemini API. It provides a seamless way to add a layer of authentication, logging, and monitoring to your Gemini API requests. It's designed to be run as a standalone server or integrated into your existing FastAPI applications.\n\nOne of its key features is providing an OpenAI-compatible endpoint, allowing you to use Gemini models with tools and libraries that are built for the OpenAI API.\n\n## Key Features\n\n*   **Authentication:** Secure your Gemini API access with an additional layer of API key authentication.\n*   **Request Logging:** Detailed logging of all incoming requests and outgoing responses.\n*   **OpenAI Compatibility:** Use Gemini models through an OpenAI-compatible `/v1/chat/completions` endpoint.\n*   **Round-Robin API Keys:** Distribute your requests across multiple Gemini API keys.\n*   **Easy Integration:** Use it as a standalone server or mount it into your existing FastAPI project.\n*   **Extensible:** Easily add your own custom middleware to suit your needs.\n\n## How It's Useful\n\n-   **Centralized API Key Management:** Instead of hardcoding your Gemini API keys in various clients, you can manage them in one place.\n-   **Security:** Protect your expensive Gemini API keys by exposing only a proxy key to your users or client applications.\n-   **Monitoring & Observability:** The logging middleware gives you insight into how your API is being used, helping you debug issues and monitor usage patterns.\n-   **Seamless Migration:** If you have existing tools that use the OpenAI API, you can switch to using Google's Gemini models without significant code changes.\n\n## Running the Built-in Server\n\nYou can quickly get the proxy server up and running with just a few steps.\n\n### 1. Installation\n\nInstall the package using pip:\n\n```bash\npip install gemini-calo\n```\n\n### 2. Configuration\n\nThe server is configured through environment variables. You can create a `.env` file in your working directory to store them.\n\n*   `GEMINI_CALO_API_KEYS`: A comma-separated list of your Google Gemini API keys. The proxy will rotate through these keys for outgoing requests.\n*   `GEMINI_CALO_PROXY_API_KEYS`: (Optional) A comma-separated list of API keys that clients must provide to use the proxy. If not set, the proxy will be open to anyone.\n*   `GEMINI_CALO_HTTP_PORT`: (Optional) The port on which the server will run. Defaults to `8000`.\n\n**Example `.env` file:**\n\n```\nGEMINI_CALO_API_KEYS=your_gemini_key_1,your_gemini_key_2\nGEMINI_CALO_PROXY_API_KEYS=my_secret_proxy_key_1,my_secret_proxy_key_2\nGEMINI_CALO_HTTP_PORT=8080\n```\n\n### 3. Running the Server\n\nOnce configured, you can start the server with the `gemini-calo` command:\n\n```bash\ngemini-calo\n```\n\nThe server will start on the configured port (e.g., `http://0.0.0.0:8080`).\n\n## Integrating with an Existing FastAPI Application\n\nIf you have an existing FastAPI application, you can easily integrate Gemini Calo's proxy functionality into it.\n\n```python\nfrom fastapi import FastAPI\nfrom gemini_calo.proxy import GeminiProxyService\nfrom gemini_calo.middlewares.auth import auth_middleware\nfrom gemini_calo.middlewares.logging import logging_middleware\nfrom functools import partial\nimport os\n\n# Your existing FastAPI app\napp = FastAPI()\n\n# 1. Initialize the GeminiProxyService\ngemini_api_keys = os.getenv(\"GEMINI_CALO_API_KEYS\", \"\").split(\",\")\nproxy_service = GeminiProxyService(gemini_api_keys=gemini_api_keys)\n\n# 2. (Optional) Add Authentication Middleware\nproxy_api_keys = os.getenv(\"GEMINI_CALO_PROXY_API_KEYS\", \"\").split(\",\")\nif proxy_api_keys:\n    auth_middleware_with_keys = partial(auth_middleware, user_api_key_checker=proxy_api_keys)\n    app.middleware(\"http\")(auth_middleware_with_keys)\n\n# 3. (Optional) Add Logging Middleware\napp.middleware(\"http\")(logging_middleware)\n\n# 4. Mount the Gemini and OpenAI routers\napp.include_router(proxy_service.gemini_router)\napp.include_router(proxy_service.openai_router)\n\n@app.get(\"/health\")\ndef health_check():\n    return {\"status\": \"ok\"}\n\n# Now you can run your app as usual with uvicorn\n# uvicorn your_app_file:app --reload\n```\n\n## How the Middleware Works\n\nMiddleware in FastAPI are functions that process every request before it reaches the specific path operation and every response before it is sent back to the client. Gemini Calo includes two useful middlewares by default.\n\n### Logging Middleware (`logging_middleware`)\n\nThis middleware logs the details of every incoming request and outgoing response, including headers and body content. This is invaluable for debugging and monitoring. It's designed to handle both standard and streaming responses correctly.\n\n### Authentication Middleware (`auth_middleware`)\n\nThis middleware protects your proxy endpoints. It checks for an API key in the `Authorization` header (as a Bearer token) or the `x-goog-api-key` header. It then validates this key against the list of keys you provided in the `GEMINI_CALO_PROXY_API_KEYS` environment variable. If the key is missing or invalid, it returns a `401 Unauthorized` error.\n\n### Adding Your Own Middleware\n\nBecause Gemini Calo is built on FastAPI, you can easily add your own custom middleware. For example, you could add a middleware for rate limiting, CORS, or custom header injection.\n\n#### Advanced Middleware: Modifying Request Body and Headers\n\nHere is a more advanced example that intercepts a request, modifies its JSON body, adds a new header, and then forwards it to the actual endpoint. This can be useful for injecting default values, adding metadata, or transforming request payloads.\n\n**Important:** Reading the request body consumes it. To allow the endpoint to read the body again, we must reconstruct the request with the modified body.\n\n```python\nfrom fastapi import FastAPI, Request\nfrom starlette.datastructures import MutableHeaders\nimport json\n\napp = FastAPI()\n\n# This middleware will add a 'user_id' to the request body\n# and a 'X-Request-ID' to the headers.\nasync def modify_request_middleware(request: Request, call_next):\n    # Get the original request body\n    body = await request.body()\n    \n    # Modify headers\n    request_headers = MutableHeaders(request.headers)\n    request_headers[\"X-Request-ID\"] = \"some-unique-id\"\n    \n    # Modify body (if it's JSON)\n    new_body = body\n    if body and request.headers.get(\"content-type\") == \"application/json\":\n        try:\n            json_body = json.loads(body)\n            # Add or modify a key\n            json_body[\"user_id\"] = \"injected-user-123\"\n            new_body = json.dumps(json_body).encode()\n        except json.JSONDecodeError:\n            # Body is not valid JSON, pass it through\n            pass\n\n    # To pass the modified body and headers, we need to create a new Request object.\n    # We do this by defining a new 'receive' channel.\n    async def receive():\n        return {\"type\": \"http.request\", \"body\": new_body, \"more_body\": False}\n\n    # We replace the original request's scope with the modified headers\n    request.scope[\"headers\"] = request_headers.raw\n\n    # Create the new request object and pass it to the next middleware/endpoint\n    new_request = Request(request.scope, receive)\n    response = await call_next(new_request)\n    \n    return response\n\napp.middleware(\"http\")(modify_request_middleware)\n\n# ... then add the Gemini Calo proxy and routers as shown above\n```\n",
    "bugtrack_url": null,
    "license": "AGPL-3.0-or-later",
    "summary": "A Fastapi Based Proxy for Gemini API",
    "version": "0.1.2",
    "project_urls": {
        "Documentation": "https://github.com/state-alchemists/gemini-calo",
        "Homepage": "https://github.com/state-alchemists/gemini-calo",
        "Repository": "https://github.com/state-alchemists/gemini-calo"
    },
    "split_keywords": [],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "76b056a5caa74d1cd070c3cd98ebbf6b43bb6e784a2de5f76ae84226d657516d",
                "md5": "2567d26ab83709ddbcb2ae70308c5540",
                "sha256": "bad7e09a31c1097c045c5579e2e6042301949fff2c1add0a3dbf4c27f49e86d0"
            },
            "downloads": -1,
            "filename": "gemini_calo-0.1.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "2567d26ab83709ddbcb2ae70308c5540",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": "<4.0.0,>=3.10",
            "size": 9087,
            "upload_time": "2025-08-18T08:20:35",
            "upload_time_iso_8601": "2025-08-18T08:20:35.607515Z",
            "url": "https://files.pythonhosted.org/packages/76/b0/56a5caa74d1cd070c3cd98ebbf6b43bb6e784a2de5f76ae84226d657516d/gemini_calo-0.1.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "db9179e3b6dee7e551253e1240a29b9768226d94c4adba07669e67fe8f50e23a",
                "md5": "9b79624c7313c121d371df35a5fbf794",
                "sha256": "06ae84de3808c647774ad687ab30c5a5c0df02e08b790320c7f52610e08e5395"
            },
            "downloads": -1,
            "filename": "gemini_calo-0.1.2.tar.gz",
            "has_sig": false,
            "md5_digest": "9b79624c7313c121d371df35a5fbf794",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": "<4.0.0,>=3.10",
            "size": 9231,
            "upload_time": "2025-08-18T08:20:37",
            "upload_time_iso_8601": "2025-08-18T08:20:37.425041Z",
            "url": "https://files.pythonhosted.org/packages/db/91/79e3b6dee7e551253e1240a29b9768226d94c4adba07669e67fe8f50e23a/gemini_calo-0.1.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-08-18 08:20:37",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "state-alchemists",
    "github_project": "gemini-calo",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": false,
    "lcname": "gemini-calo"
}
        
Elapsed time: 0.41686s