Spaces:
Sleeping
Sleeping
| # 使用 FastAPI 搭建 Gemini API 转发代理教程 | |
| ## 1. 项目简介 | |
| 本项目旨在搭建一个基于 FastAPI 的通用 API 转发代理,主要用于转发对 Google Gemini API(特别是其 OpenAI 兼容 API)的请求。通过此代理,您可以解决直接访问 Gemini API 可能遇到的地域限制、集中管理 API 密钥以及处理客户端请求头兼容性等问题。 | |
| ## 2. 核心功能 | |
| * **代理认证**:代理自身支持 API 密钥认证,确保只有授权客户端才能使用代理服务。 | |
| * **请求转发**:接收来自客户端的 HTTP 请求(GET, POST, PUT, DELETE),并将其转发到预配置的目标 API。 | |
| * **请求/响应处理**:处理请求头、查询参数和请求体,并将目标 API 的响应原封不动地返回给客户端。 | |
| * **环境变量配置**:支持通过 `.env` 文件配置代理自身的认证密钥 (`PROXY_API_KEY`)、目标 API 的基 URL (`GEMINI_BASE_URL`) 和认证信息 (`GEMINI_API_KEY`)。 | |
| * **健康检查**:提供一个简单的 `/health` 端点,用于验证代理服务是否正常运行。 | |
| * **User-Agent 修改**:强制将转发请求的 `User-Agent` 头设置为 `curl/8.7.1`,以解决某些客户端(如 Postman)可能遇到的兼容性问题。 | |
| ## 3. 技术栈 | |
| * **Python 3.9+** | |
| * **FastAPI**:高性能 Python Web 框架。 | |
| * **Uvicorn**:ASGI 服务器。 | |
| * **httpx**:异步 HTTP 客户端。 | |
| * **python-dotenv**:环境变量管理。 | |
| ## 4. 环境搭建与部署 | |
| ### 4.1. 创建虚拟环境并安装依赖 | |
| 建议使用 `conda` 或 `venv` 创建独立的 Python 虚拟环境: | |
| ```bash | |
| conda create -n airs python=3.9 | |
| conda activate airs | |
| ``` | |
| 在项目根目录创建 `requirements.txt` 文件,并添加以下内容: | |
| ``` | |
| fastapi | |
| uvicorn[standard] | |
| httpx | |
| python-dotenv | |
| ``` | |
| 然后安装依赖: | |
| ```bash | |
| pip install -r requirements.txt | |
| ``` | |
| ### 4.2. 配置环境变量 | |
| 在项目根目录创建 `.env` 文件,并配置代理自身的 API 密钥、Gemini API 密钥和 OpenAI 兼容 API 的 Base URL: | |
| ```dotenv | |
| PROXY_API_KEY="YOUR_PROXY_API_KEY" | |
| GEMINI_API_KEY="YOUR_GEMINI_API_KEY" | |
| GEMINI_BASE_URL="https://generativelanguage.googleapis.com/v1beta/openai" | |
| ``` | |
| 请将 `YOUR_PROXY_API_KEY` 替换为您为代理设置的密钥,将 `YOUR_GEMINI_API_KEY` 替换为您的实际 Gemini API 密钥。 | |
| ### 4.3. `app.py` 代码实现 | |
| 创建 `app.py` 文件,并添加以下代码: | |
| ```python | |
| # uvicorn app:app --host 0.0.0.0 --port 7860 --reload | |
| from fastapi import FastAPI, Request, HTTPException, Depends, status | |
| from fastapi.responses import Response | |
| from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials | |
| import httpx | |
| import os | |
| from dotenv import load_dotenv | |
| # 加载环境变量 | |
| load_dotenv() | |
| # 从环境变量获取代理自身的API密钥 | |
| PROXY_API_KEY = os.getenv("PROXY_API_KEY") | |
| # 定义HTTPBearer安全方案 | |
| security = HTTPBearer() | |
| # 依赖函数:验证代理的API密钥 | |
| def verify_proxy_api_key(credentials: HTTPAuthorizationCredentials = Depends(security)): | |
| if not PROXY_API_KEY or credentials.credentials != PROXY_API_KEY: | |
| raise HTTPException( | |
| status_code=status.HTTP_401_UNAUTHORIZED, | |
| detail="Invalid or missing proxy API key", | |
| headers={"WWW-Authenticate": "Bearer"}, | |
| ) | |
| return credentials.credentials | |
| app = FastAPI(title="Gemini Proxy API") | |
| @app.get("/") | |
| def greet_json(): | |
| return {"Hello": "World!"} | |
| # 3. 健康检查接口(可选,用于验证服务是否正常) | |
| @app.get("/health") | |
| async def health_check(): | |
| return {"status": "ok", "message": "Proxy service is running."} | |
| # 1. 配置Gemini真实信息 | |
| GEMINI_API_KEY = os.getenv("GEMINI_API_KEY") | |
| GEMINI_BASE_URL = os.getenv("GEMINI_BASE_URL") | |
| print(f"Using Gemini Base URL: {GEMINI_BASE_URL}") | |
| print(f"Using Gemini API Key: {GEMINI_API_KEY}") | |
| # 2. 通用转发接口(匹配Gemini的/predict等端点,路径动态匹配) | |
| @app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE"]) | |
| async def proxy_gemini(request: Request, path: str, proxy_api_key: str = Depends(verify_proxy_api_key)): # 添加代理认证依赖 | |
| # 拼接Gemini真实请求URL | |
| gemini_url = f"{GEMINI_BASE_URL}/{path}" | |
| # 提取客户端请求的headers和body,透传给Gemini | |
| client_headers = dict(request.headers) | |
| # 移除FastAPI自带的Host头,避免Gemini校验报错 | |
| client_headers.pop("host", None) | |
| # 将User-Agent改为curl/8.7.1,以模拟curl请求 | |
| client_headers["User-Agent"] = "curl/8.7.1" | |
| # 添加Authorization头,用于Gemini的OpenAI兼容API | |
| if GEMINI_API_KEY: | |
| client_headers["Authorization"] = f"Bearer {GEMINI_API_KEY}" | |
| try: | |
| # 读取客户端请求体 | |
| client_body = await request.body() | |
| # 使用httpx异步客户端发起请求 | |
| async with httpx.AsyncClient() as client: | |
| response = await client.request( | |
| method=request.method, | |
| url=gemini_url, | |
| headers=client_headers, | |
| content=client_body, | |
| timeout=30 | |
| ) | |
| # 将Gemini的响应透传给客户端 | |
| return Response( | |
| content=response.content, | |
| status_code=response.status_code, | |
| headers=dict(response.headers) | |
| ) | |
| except httpx.RequestError as e: | |
| raise HTTPException(status_code=500, detail=f"转发请求失败:{str(e)}") | |
| except httpx.HTTPStatusError as e: | |
| raise HTTPException(status_code=e.response.status_code, detail=f"目标API返回错误:{e.response.text}") | |
| except Exception as e: | |
| raise HTTPException(status_code=500, detail=f"转发失败:{str(e)}") | |
| ``` | |
| ### 4.4. 运行应用程序 | |
| 在项目根目录,激活您的虚拟环境并运行 FastAPI 应用: | |
| ```bash | |
| conda activate airs | |
| uvicorn app:app --host 0.0.0.0 --port 7860 --reload | |
| ``` | |
| 应用程序将在 `http://0.0.0.0:7860` 上运行。 | |
| ## 5. 如何使用代理 | |
| ### 5.1. 健康检查 | |
| 您可以通过访问 `/health` 端点来检查代理服务是否正常运行: | |
| ```bash | |
| curl -X GET http://0.0.0.0:7860/health | |
| ``` | |
| 预期响应: | |
| ```json | |
| {"status":"ok","message":"Proxy service is running."} | |
| ``` | |
| ### 5.2. 调用 Gemini OpenAI 兼容 API | |
| 要通过代理调用 Gemini 模型(例如 `gemini-2.5-flash-preview-05-20`),您需要向代理的 `/v1/chat/completions` 端点发送一个 POST 请求,并在请求体中指定模型名称和消息。**同时,您需要在请求头中包含代理自身的 API 密钥。** | |
| 以下是一个 `curl` 命令示例(请将 `YOUR_PROXY_API_KEY` 替换为您的实际代理密钥): | |
| ```bash | |
| curl -X POST http://0.0.0.0:7860/v1/chat/completions \ | |
| -H "Content-Type: application/json" \ | |
| -H "Authorization: Bearer YOUR_PROXY_API_KEY" \ | |
| -d '{ | |
| "model": "gemini-2.5-flash-preview-05-20", | |
| "messages": [ | |
| { | |
| "role": "user", | |
| "content": "你好,请介绍一下你自己。" | |
| } | |
| ], | |
| "temperature": 0.7 | |
| }' | |
| ``` | |
| 如果您将代理部署到 Hugging Face Spaces,例如部署在 `https://airsltd-superproxy.hf.space`,则 `curl` 命令应如下所示: | |
| ```bash | |
| curl -X POST https://airsltd-superproxy.hf.space/v1/chat/completions \ | |
| --header 'Content-Type: application/json' \ | |
| --header 'Authorization: Bearer YOUR_PROXY_API_KEY' \ | |
| --data '{ | |
| "model": "gemini-2.5-flash-preview-05-20", | |
| "messages": [ | |
| { | |
| "role": "user", | |
| "content": "你好,请介绍一下你自己。" | |
| } | |
| ], | |
| "temperature": 0.7 | |
| }' | |
| ``` | |
| ## 6. 常见问题与解决方案 | |
| * **代理认证失败 (401 Unauthorized)**: | |
| * **问题**:当您尝试调用代理时,收到 `401 Unauthorized` 错误,并提示“Invalid or missing proxy API key”。 | |
| * **原因**:这表示您没有在请求头中提供正确的 `Authorization: Bearer YOUR_PROXY_API_KEY`,或者 `PROXY_API_KEY` 环境变量未在代理部署环境中正确设置。 | |
| * **解决方案**:确保您的客户端请求包含正确的 `Authorization: Bearer YOUR_PROXY_API_KEY` 头,并且 `YOUR_PROXY_API_KEY` 与 `.env` 文件中配置的值一致。如果部署在 Hugging Face Spaces,请确保 Space 的环境变量中已设置 `PROXY_API_KEY`。 | |
| * **“User location is not supported for the API use.”**:此错误来自 Gemini API,表明您的请求源 IP 地址所在的区域不受 Gemini API 支持。这通常发生在本地测试时。部署代理到支持的区域(例如 Hugging Face Spaces)可以解决此问题。 | |
| * **Postman “Error: incorrect header check”**:此错误通常是由于 Postman 自动添加的某些请求头与部署环境或代理不兼容。本项目已通过强制设置 `User-Agent: curl/8.7.1` 来尝试解决此问题。如果问题仍然存在,请检查 Postman 发送的其他请求头,并尝试禁用非必要的头部。 | |