Spaces:
Sleeping
Sleeping
update
Browse files- .clinerules +4 -2
- app.py +21 -3
- articles/fastapi-gemini-proxy-tutorial.md +235 -0
- memory-bank/activeContext.md +29 -0
- memory-bank/productContext.md +21 -0
- memory-bank/progress.md +29 -0
- memory-bank/projectBrief.md +34 -0
- memory-bank/systemPatterns.md +36 -0
- memory-bank/techContext.md +47 -0
- requirements.txt +1 -0
.clinerules
CHANGED
|
@@ -1,9 +1,11 @@
|
|
| 1 |
# 自定义指令
|
| 2 |
CUSTOM_INSTRUCTIONS = """
|
| 3 |
# 自动激活conda环境
|
| 4 |
-
#
|
| 5 |
# 这确保了所有后续的Python相关命令都在正确的环境中执行。
|
| 6 |
-
|
|
|
|
|
|
|
| 7 |
"""
|
| 8 |
|
| 9 |
|
|
|
|
| 1 |
# 自定义指令
|
| 2 |
CUSTOM_INSTRUCTIONS = """
|
| 3 |
# 自动激活conda环境
|
| 4 |
+
# 在每次会话开始时,自动检查当前conda环境。如果不是 'airs',则激活它。
|
| 5 |
# 这确保了所有后续的Python相关命令都在正确的环境中执行。
|
| 6 |
+
if [ -z "$CONDA_DEFAULT_ENV" ] || [ "$CONDA_DEFAULT_ENV" != "airs" ]; then
|
| 7 |
+
conda activate airs
|
| 8 |
+
fi
|
| 9 |
"""
|
| 10 |
|
| 11 |
|
app.py
CHANGED
|
@@ -1,13 +1,31 @@
|
|
| 1 |
# uvicorn app:app --host 0.0.0.0 --port 7860 --reload
|
| 2 |
|
| 3 |
-
from fastapi import FastAPI, Request, HTTPException
|
| 4 |
from fastapi.responses import Response # 导入Response
|
|
|
|
| 5 |
import httpx # 使用httpx替代requests,因为requests是同步的,而FastAPI是异步的
|
| 6 |
import os
|
| 7 |
from dotenv import load_dotenv
|
| 8 |
|
| 9 |
-
#
|
| 10 |
load_dotenv()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
app = FastAPI(title="Gemini Proxy API")
|
| 12 |
|
| 13 |
@app.get("/")
|
|
@@ -27,7 +45,7 @@ print(f"Using Gemini API Key: {GEMINI_API_KEY}")
|
|
| 27 |
|
| 28 |
# 2. 通用转发接口(匹配Gemini的/predict等端点,路径动态匹配)
|
| 29 |
@app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
|
| 30 |
-
async def proxy_gemini(request: Request, path: str):
|
| 31 |
# 拼接Gemini真实请求URL
|
| 32 |
gemini_url = f"{GEMINI_BASE_URL}/{path}"
|
| 33 |
|
|
|
|
| 1 |
# uvicorn app:app --host 0.0.0.0 --port 7860 --reload
|
| 2 |
|
| 3 |
+
from fastapi import FastAPI, Request, HTTPException, Depends, status
|
| 4 |
from fastapi.responses import Response # 导入Response
|
| 5 |
+
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials # 导入HTTPBearer和HTTPAuthorizationCredentials
|
| 6 |
import httpx # 使用httpx替代requests,因为requests是同步的,而FastAPI是异步的
|
| 7 |
import os
|
| 8 |
from dotenv import load_dotenv
|
| 9 |
|
| 10 |
+
# 加载环境变量
|
| 11 |
load_dotenv()
|
| 12 |
+
|
| 13 |
+
# 从环境变量获取代理自身的API密钥
|
| 14 |
+
PROXY_API_KEY = os.getenv("PROXY_API_KEY")
|
| 15 |
+
|
| 16 |
+
# 定义HTTPBearer安全方案
|
| 17 |
+
security = HTTPBearer()
|
| 18 |
+
|
| 19 |
+
# 依赖函数:验证代理的API密钥
|
| 20 |
+
def verify_proxy_api_key(credentials: HTTPAuthorizationCredentials = Depends(security)):
|
| 21 |
+
if not PROXY_API_KEY or credentials.credentials != PROXY_API_KEY:
|
| 22 |
+
raise HTTPException(
|
| 23 |
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
| 24 |
+
detail="Invalid or missing proxy API key",
|
| 25 |
+
headers={"WWW-Authenticate": "Bearer"},
|
| 26 |
+
)
|
| 27 |
+
return credentials.credentials
|
| 28 |
+
|
| 29 |
app = FastAPI(title="Gemini Proxy API")
|
| 30 |
|
| 31 |
@app.get("/")
|
|
|
|
| 45 |
|
| 46 |
# 2. 通用转发接口(匹配Gemini的/predict等端点,路径动态匹配)
|
| 47 |
@app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
|
| 48 |
+
async def proxy_gemini(request: Request, path: str, proxy_api_key: str = Depends(verify_proxy_api_key)): # 添加代理认证依赖
|
| 49 |
# 拼接Gemini真实请求URL
|
| 50 |
gemini_url = f"{GEMINI_BASE_URL}/{path}"
|
| 51 |
|
articles/fastapi-gemini-proxy-tutorial.md
ADDED
|
@@ -0,0 +1,235 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 使用 FastAPI 搭建 Gemini API 转发代理教程
|
| 2 |
+
|
| 3 |
+
## 1. 项目简介
|
| 4 |
+
|
| 5 |
+
本项目旨在搭建一个基于 FastAPI 的通用 API 转发代理,主要用于转发对 Google Gemini API(特别是其 OpenAI 兼容 API)的请求。通过此代理,您可以解决直接访问 Gemini API 可能遇到的地域限制、集中管理 API 密钥以及处理客户端请求头兼容性等问题。
|
| 6 |
+
|
| 7 |
+
## 2. 核心功能
|
| 8 |
+
|
| 9 |
+
* **代理认证**:代理自身支持 API 密钥认证,确保只有授权客户端才能使用代理服务。
|
| 10 |
+
* **请求转发**:接收来自客户端的 HTTP 请求(GET, POST, PUT, DELETE),并将其转发到预配置的目标 API。
|
| 11 |
+
* **请求/响应处理**:处理请求头、查询参数和请求体,并将目标 API 的响应原封不动地返回给客户端。
|
| 12 |
+
* **环境变量配置**:支持通过 `.env` 文件配置代理自身的认证密钥 (`PROXY_API_KEY`)、目标 API 的基 URL (`GEMINI_BASE_URL`) 和认证信息 (`GEMINI_API_KEY`)。
|
| 13 |
+
* **健康检查**:提供一个简单的 `/health` 端点,用于验证代理服务是否正常运行。
|
| 14 |
+
* **User-Agent 修改**:强制将转发请求的 `User-Agent` 头设置为 `curl/8.7.1`,以解决某些客户端(如 Postman)可能遇到的兼容性问题。
|
| 15 |
+
|
| 16 |
+
## 3. 技术栈
|
| 17 |
+
|
| 18 |
+
* **Python 3.9+**
|
| 19 |
+
* **FastAPI**:高性能 Python Web 框架。
|
| 20 |
+
* **Uvicorn**:ASGI 服务器。
|
| 21 |
+
* **httpx**:异步 HTTP 客户端。
|
| 22 |
+
* **python-dotenv**:环境变量管理。
|
| 23 |
+
|
| 24 |
+
## 4. 环境搭建与部署
|
| 25 |
+
|
| 26 |
+
### 4.1. 创建虚拟环境并安装依赖
|
| 27 |
+
|
| 28 |
+
建议使用 `conda` 或 `venv` 创建独立的 Python 虚拟环境:
|
| 29 |
+
|
| 30 |
+
```bash
|
| 31 |
+
conda create -n airs python=3.9
|
| 32 |
+
conda activate airs
|
| 33 |
+
```
|
| 34 |
+
|
| 35 |
+
在项目根目录创建 `requirements.txt` 文件,并添加以下内容:
|
| 36 |
+
|
| 37 |
+
```
|
| 38 |
+
fastapi
|
| 39 |
+
uvicorn[standard]
|
| 40 |
+
httpx
|
| 41 |
+
python-dotenv
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
然后安装依赖:
|
| 45 |
+
|
| 46 |
+
```bash
|
| 47 |
+
pip install -r requirements.txt
|
| 48 |
+
```
|
| 49 |
+
|
| 50 |
+
### 4.2. 配置环境变量
|
| 51 |
+
|
| 52 |
+
在项目根目录创建 `.env` 文件,并配置代理自身的 API 密钥、Gemini API 密钥和 OpenAI 兼容 API 的 Base URL:
|
| 53 |
+
|
| 54 |
+
```dotenv
|
| 55 |
+
PROXY_API_KEY="YOUR_PROXY_API_KEY"
|
| 56 |
+
GEMINI_API_KEY="YOUR_GEMINI_API_KEY"
|
| 57 |
+
GEMINI_BASE_URL="https://generativelanguage.googleapis.com/v1beta/openai"
|
| 58 |
+
```
|
| 59 |
+
|
| 60 |
+
请将 `YOUR_PROXY_API_KEY` 替换为您为代理设置的密钥,将 `YOUR_GEMINI_API_KEY` 替换为您的实际 Gemini API 密钥。
|
| 61 |
+
|
| 62 |
+
### 4.3. `app.py` 代码实现
|
| 63 |
+
|
| 64 |
+
创建 `app.py` 文件,并添加以下代码:
|
| 65 |
+
|
| 66 |
+
```python
|
| 67 |
+
# uvicorn app:app --host 0.0.0.0 --port 7860 --reload
|
| 68 |
+
|
| 69 |
+
from fastapi import FastAPI, Request, HTTPException, Depends, status
|
| 70 |
+
from fastapi.responses import Response
|
| 71 |
+
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
|
| 72 |
+
import httpx
|
| 73 |
+
import os
|
| 74 |
+
from dotenv import load_dotenv
|
| 75 |
+
|
| 76 |
+
# 加载环境变量
|
| 77 |
+
load_dotenv()
|
| 78 |
+
|
| 79 |
+
# 从环境变量获取代理自身的API密钥
|
| 80 |
+
PROXY_API_KEY = os.getenv("PROXY_API_KEY")
|
| 81 |
+
|
| 82 |
+
# 定义HTTPBearer安全方案
|
| 83 |
+
security = HTTPBearer()
|
| 84 |
+
|
| 85 |
+
# 依赖函数:验证代理的API密钥
|
| 86 |
+
def verify_proxy_api_key(credentials: HTTPAuthorizationCredentials = Depends(security)):
|
| 87 |
+
if not PROXY_API_KEY or credentials.credentials != PROXY_API_KEY:
|
| 88 |
+
raise HTTPException(
|
| 89 |
+
status_code=status.HTTP_401_UNAUTHORIZED,
|
| 90 |
+
detail="Invalid or missing proxy API key",
|
| 91 |
+
headers={"WWW-Authenticate": "Bearer"},
|
| 92 |
+
)
|
| 93 |
+
return credentials.credentials
|
| 94 |
+
|
| 95 |
+
app = FastAPI(title="Gemini Proxy API")
|
| 96 |
+
|
| 97 |
+
@app.get("/")
|
| 98 |
+
def greet_json():
|
| 99 |
+
return {"Hello": "World!"}
|
| 100 |
+
|
| 101 |
+
# 3. 健康检查接口(可选,用于验证服务是否正常)
|
| 102 |
+
@app.get("/health")
|
| 103 |
+
async def health_check():
|
| 104 |
+
return {"status": "ok", "message": "Proxy service is running."}
|
| 105 |
+
|
| 106 |
+
# 1. 配置Gemini真实信息
|
| 107 |
+
GEMINI_API_KEY = os.getenv("GEMINI_API_KEY")
|
| 108 |
+
GEMINI_BASE_URL = os.getenv("GEMINI_BASE_URL")
|
| 109 |
+
print(f"Using Gemini Base URL: {GEMINI_BASE_URL}")
|
| 110 |
+
print(f"Using Gemini API Key: {GEMINI_API_KEY}")
|
| 111 |
+
|
| 112 |
+
# 2. 通用转发接口(匹配Gemini的/predict等端点,路径动态匹配)
|
| 113 |
+
@app.api_route("/{path:path}", methods=["GET", "POST", "PUT", "DELETE"])
|
| 114 |
+
async def proxy_gemini(request: Request, path: str, proxy_api_key: str = Depends(verify_proxy_api_key)): # 添加代理认证依赖
|
| 115 |
+
# 拼接Gemini真实请求URL
|
| 116 |
+
gemini_url = f"{GEMINI_BASE_URL}/{path}"
|
| 117 |
+
|
| 118 |
+
# 提取客户端请求的headers和body,透传给Gemini
|
| 119 |
+
client_headers = dict(request.headers)
|
| 120 |
+
# 移除FastAPI自带的Host头,避免Gemini校验报错
|
| 121 |
+
client_headers.pop("host", None)
|
| 122 |
+
|
| 123 |
+
# 将User-Agent改为curl/8.7.1,以模拟curl请求
|
| 124 |
+
client_headers["User-Agent"] = "curl/8.7.1"
|
| 125 |
+
|
| 126 |
+
# 添加Authorization头,用于Gemini的OpenAI兼容API
|
| 127 |
+
if GEMINI_API_KEY:
|
| 128 |
+
client_headers["Authorization"] = f"Bearer {GEMINI_API_KEY}"
|
| 129 |
+
|
| 130 |
+
try:
|
| 131 |
+
# 读取客户端请求体
|
| 132 |
+
client_body = await request.body()
|
| 133 |
+
|
| 134 |
+
# 使用httpx异步客户端发起请求
|
| 135 |
+
async with httpx.AsyncClient() as client:
|
| 136 |
+
response = await client.request(
|
| 137 |
+
method=request.method,
|
| 138 |
+
url=gemini_url,
|
| 139 |
+
headers=client_headers,
|
| 140 |
+
content=client_body,
|
| 141 |
+
timeout=30
|
| 142 |
+
)
|
| 143 |
+
|
| 144 |
+
# 将Gemini的响应透传给客户端
|
| 145 |
+
return Response(
|
| 146 |
+
content=response.content,
|
| 147 |
+
status_code=response.status_code,
|
| 148 |
+
headers=dict(response.headers)
|
| 149 |
+
)
|
| 150 |
+
|
| 151 |
+
except httpx.RequestError as e:
|
| 152 |
+
raise HTTPException(status_code=500, detail=f"转发请求失败:{str(e)}")
|
| 153 |
+
except httpx.HTTPStatusError as e:
|
| 154 |
+
raise HTTPException(status_code=e.response.status_code, detail=f"目标API返回错误:{e.response.text}")
|
| 155 |
+
except Exception as e:
|
| 156 |
+
raise HTTPException(status_code=500, detail=f"转发失败:{str(e)}")
|
| 157 |
+
```
|
| 158 |
+
|
| 159 |
+
### 4.4. 运行应用程序
|
| 160 |
+
|
| 161 |
+
在项目根目录,激活您的虚拟环境并运行 FastAPI 应用:
|
| 162 |
+
|
| 163 |
+
```bash
|
| 164 |
+
conda activate airs
|
| 165 |
+
uvicorn app:app --host 0.0.0.0 --port 7860 --reload
|
| 166 |
+
```
|
| 167 |
+
|
| 168 |
+
应用程序将在 `http://0.0.0.0:7860` 上运行。
|
| 169 |
+
|
| 170 |
+
## 5. 如何使用代理
|
| 171 |
+
|
| 172 |
+
### 5.1. 健康检查
|
| 173 |
+
|
| 174 |
+
您可以通过访问 `/health` 端点来检查代理服务是否正常运行:
|
| 175 |
+
|
| 176 |
+
```bash
|
| 177 |
+
curl -X GET http://0.0.0.0:7860/health
|
| 178 |
+
```
|
| 179 |
+
|
| 180 |
+
预期响应:
|
| 181 |
+
|
| 182 |
+
```json
|
| 183 |
+
{"status":"ok","message":"Proxy service is running."}
|
| 184 |
+
```
|
| 185 |
+
|
| 186 |
+
### 5.2. 调用 Gemini OpenAI 兼容 API
|
| 187 |
+
|
| 188 |
+
要通过代理调用 Gemini 模型(例如 `gemini-2.5-flash-preview-05-20`),您需要向代理的 `/v1/chat/completions` 端点发送一个 POST 请求,并在请求体中指定模型名称和消息。**同时,您需要在请求头中包含代理自身的 API 密钥。**
|
| 189 |
+
|
| 190 |
+
以下是一个 `curl` 命令示例(请将 `YOUR_PROXY_API_KEY` 替换为您的实际代理密钥):
|
| 191 |
+
|
| 192 |
+
```bash
|
| 193 |
+
curl -X POST http://0.0.0.0:7860/v1/chat/completions \
|
| 194 |
+
-H "Content-Type: application/json" \
|
| 195 |
+
-H "Authorization: Bearer YOUR_PROXY_API_KEY" \
|
| 196 |
+
-d '{
|
| 197 |
+
"model": "gemini-2.5-flash-preview-05-20",
|
| 198 |
+
"messages": [
|
| 199 |
+
{
|
| 200 |
+
"role": "user",
|
| 201 |
+
"content": "你好,请介绍一下你自己。"
|
| 202 |
+
}
|
| 203 |
+
],
|
| 204 |
+
"temperature": 0.7
|
| 205 |
+
}'
|
| 206 |
+
```
|
| 207 |
+
|
| 208 |
+
如果您将代理部署到 Hugging Face Spaces,例如部署在 `https://airsltd-superproxy.hf.space`,则 `curl` 命令应如下所示:
|
| 209 |
+
|
| 210 |
+
```bash
|
| 211 |
+
curl -X POST https://airsltd-superproxy.hf.space/v1/chat/completions \
|
| 212 |
+
--header 'Content-Type: application/json' \
|
| 213 |
+
--header 'Authorization: Bearer YOUR_PROXY_API_KEY' \
|
| 214 |
+
--data '{
|
| 215 |
+
"model": "gemini-2.5-flash-preview-05-20",
|
| 216 |
+
"messages": [
|
| 217 |
+
{
|
| 218 |
+
"role": "user",
|
| 219 |
+
"content": "你好,请介绍一下你自己。"
|
| 220 |
+
}
|
| 221 |
+
],
|
| 222 |
+
"temperature": 0.7
|
| 223 |
+
}'
|
| 224 |
+
```
|
| 225 |
+
|
| 226 |
+
## 6. 常见问题与解决方案
|
| 227 |
+
|
| 228 |
+
* **代理认证失败 (401 Unauthorized)**:
|
| 229 |
+
* **问题**:当您尝试调用代理时,收到 `401 Unauthorized` 错误,并提示“Invalid or missing proxy API key”。
|
| 230 |
+
* **原因**:这表示您没有在请求头中提供正确的 `Authorization: Bearer YOUR_PROXY_API_KEY`,或者 `PROXY_API_KEY` 环境变量未在代理部署环境中正确设置。
|
| 231 |
+
* **解决方案**:确保您的客户端请求包含正确的 `Authorization: Bearer YOUR_PROXY_API_KEY` 头,并且 `YOUR_PROXY_API_KEY` 与 `.env` 文件中配置的值一致。如果部署在 Hugging Face Spaces,请确保 Space 的环境变量中已设置 `PROXY_API_KEY`。
|
| 232 |
+
|
| 233 |
+
* **“User location is not supported for the API use.”**:此错误来自 Gemini API,表明您的请求源 IP 地址所在的区域不受 Gemini API 支持。这通常发生在本地测试时。部署代理到支持的区域(例如 Hugging Face Spaces)可以解决此问题。
|
| 234 |
+
|
| 235 |
+
* **Postman “Error: incorrect header check”**:此错误通常是由于 Postman 自动添加的某些请求头与部署环境或代理不兼容。本项目已通过强制设置 `User-Agent: curl/8.7.1` 来尝试解决此问题。如果问题仍然存在,请检查 Postman 发送的其他请求头,并尝试禁用非必要的头部。
|
memory-bank/activeContext.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 活跃背景 (activeContext.md)
|
| 2 |
+
|
| 3 |
+
## 当前工作焦点
|
| 4 |
+
* **API 转发代理的实现和调试**:主要工作是构建一个 FastAPI 应用程序,用于转发对 Google Gemini API(OpenAI 兼容接口)的请求。
|
| 5 |
+
* **解决客户端兼容性问题**:处理 Postman 等客户端在与代理交互时可能遇到的头部相关问题。
|
| 6 |
+
|
| 7 |
+
## 最近的更改
|
| 8 |
+
* **`app.py` 修改**:
|
| 9 |
+
* 引入 `httpx` 和 `Response`。
|
| 10 |
+
* 将 `GEMINI_BASE_URL` 从硬编码改为从环境变量加载。
|
| 11 |
+
* 将 `/health` 端点移到通用代理路由之前,以确保其正确匹配。
|
| 12 |
+
* 修改了 API 密钥的传递方式,从 URL 查询参数改为 `Authorization: Bearer` 头。
|
| 13 |
+
* 强制将转发请求的 `User-Agent` 头设置为 `curl/8.7.1`。
|
| 14 |
+
* **`requirements.txt` 更新**:添加了 `httpx` 和 `python-dotenv` 依赖。
|
| 15 |
+
* **`.clinerules` 更新**:添加了自动激活 `conda` 环境 `airs` 的自定义指令。
|
| 16 |
+
|
| 17 |
+
## 下一步
|
| 18 |
+
* **验证 Postman 兼容性**:用户需要再次尝试使用 Postman 调用部署的代理,以确认 `User-Agent` 头部修改是否解决了“incorrect header check”错误。
|
| 19 |
+
* **本地测试环境问题**:如果本地测试仍然遇到“User location is not supported for the API use.”错误,需要明确告知用户这是 Gemini API 的地域限制,而非代理代码问题。
|
| 20 |
+
|
| 21 |
+
## 活跃决策和考虑
|
| 22 |
+
* **API 密钥传递方式**:从 URL 查询参数改为 `Authorization` 头是符合 OpenAI 兼容 API 规范的正确做法。
|
| 23 |
+
* **`User-Agent` 强制修改**:这是一个临时的解决方案,用于解决特定客户端(Postman)与部署环境之间的兼容性问题。如果未来出现其他客户端问题,可能需要更灵活的头部处理策略。
|
| 24 |
+
* **路由顺序**:确保特定路由在通用路由之前定义是 FastAPI 应用中的重要考虑因素。
|
| 25 |
+
|
| 26 |
+
## 学习和项目洞察
|
| 27 |
+
* **FastAPI 路由匹配机制**:理解路由定义顺序对匹配行为的影响至关重要。
|
| 28 |
+
* **HTTP 头部的重要性**:客户端和服务器之间的 HTTP 头部兼容性可能导致意想不到的问题,尤其是在代理场景中。
|
| 29 |
+
* **API 地域限制**:外部 API 的地域限制是部署代理时需要考虑的重要因素。
|
memory-bank/productContext.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 产品背景 (productContext.md)
|
| 2 |
+
|
| 3 |
+
## 项目存在的原因
|
| 4 |
+
本项目旨在解决直接访问某些 API(如 Google Gemini API)可能遇到的问题,包括:
|
| 5 |
+
* **地域限制**:某些 API 可能对特定地理位置的请求有限制。通过部署在特定区域的代理,可以绕过这些限制。
|
| 6 |
+
* **认证管理**:集中管理 API 密钥,避免在多个客户端应用中重复配置和暴露敏感信息。
|
| 7 |
+
* **请求修改**:在请求转发过程中,可以对请求头、请求体等进行修改,以适应目标 API 的要求或解决兼容性问题(例如修改 `User-Agent`)。
|
| 8 |
+
* **简化客户端集成**:为客户端提供一个统一的、本地化的 API 端点,简化其与复杂外部 API 的集成。
|
| 9 |
+
|
| 10 |
+
## 解决的问题
|
| 11 |
+
* **Gemini API 地域访问限制**:通过将代理部署在 Gemini API 支持的区域,解决本地开发环境可能无法直接访问的问题。
|
| 12 |
+
* **API 密钥安全**:将 API 密钥存储在代理服务器的环境变量中,减少客户端暴露密钥的风险。
|
| 13 |
+
* **Postman 头部兼容性**:通过修改 `User-Agent` 等请求头,解决 Postman 等工具在与某些 API 或部署环境交互时可能出现的兼容性问题。
|
| 14 |
+
|
| 15 |
+
## 工作方式
|
| 16 |
+
客户端向 FastAPI 代理发送请求,代理接收请求后,根据预设的配置(环境变量中的 `GEMINI_BASE_URL` 和 `GEMINI_API_KEY`),对请求进行必要的修改(例如添加 `Authorization` 头,修改 `User-Agent`),然后将请求转发到实际的目标 API。目标 API 的响应再由代理原封不动地返回给客户端。
|
| 17 |
+
|
| 18 |
+
## 用户体验目标
|
| 19 |
+
* **透明性**:客户端无需感知代理的存在,感觉就像直接与目标 API 交互。
|
| 20 |
+
* **可靠性**:代理能够稳定、高效地转发请求,减少因网络或兼容性问题导致的失败。
|
| 21 |
+
* **易用性**:配置简单,易于部署和维护。
|
memory-bank/progress.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 进度 (progress.md)
|
| 2 |
+
|
| 3 |
+
## 已完成的工作
|
| 4 |
+
* **FastAPI 代理应用初始化**:创建了基本的 FastAPI 应用程序结构。
|
| 5 |
+
* **依赖管理**:配置了 `requirements.txt` 并安装了必要的依赖(`fastapi`, `uvicorn`, `httpx`, `python-dotenv`)。
|
| 6 |
+
* **环境变量配置**:实现了从 `.env` 文件加载 `GEMINI_API_KEY` 和 `GEMINI_BASE_URL`。
|
| 7 |
+
* **通用转发逻辑**:实现了 `/{path:path}` 通用路由,能够捕获并转发所有 HTTP 方法的请求。
|
| 8 |
+
* **健康检查端点**:添加并修复了 `/health` 端点,确保其独立于上游 API 正常工作。
|
| 9 |
+
* **API 密钥传递**:将 Gemini API 密钥的传递方式从 URL 查询参数修改为 `Authorization: Bearer` 头,以符合 OpenAI 兼容 API 的要求。
|
| 10 |
+
* **User-Agent 修改**:强制将转发请求的 `User-Agent` 头设置为 `curl/8.7.1`,以解决潜在的客户端兼容性问题。
|
| 11 |
+
* **`.clinerules` 更新**:添加了自动激活 `conda` 环境 `airs` 的自定义指令。
|
| 12 |
+
* **部署环境验证**:通过 `curl` 命令验证了部署在 Hugging Face Spaces 上的代理功能正常。
|
| 13 |
+
|
| 14 |
+
## 待完成的工作
|
| 15 |
+
* **Postman 客户端兼容性验证**:用户需要再次尝试使用 Postman 调用部署的代理,以确认 `User-Agent` 头部修改是否解决了“incorrect header check”错误。
|
| 16 |
+
* **本地测试地域限制说明**:如果用户在本地测试时仍然遇到“User location is not supported for the API use.”错误,需要明确告知这是 Gemini API 的地域限制,而非代理代码问题。
|
| 17 |
+
|
| 18 |
+
## 当前状态
|
| 19 |
+
代理应用程序的核心功能已完成并部署验证。主要剩余任务是解决特定客户端(Postman)的兼容性问题,并向用户明确本地测试可能遇到的地域限制。
|
| 20 |
+
|
| 21 |
+
## 已知问题
|
| 22 |
+
* **本地测试地域限制**:在某些地域,直接从本地机器访问 Gemini API 可能会遇到“User location is not supported for the API use.”错误。
|
| 23 |
+
* **Postman 头部兼容性**:Postman 客户端在调用部署的代理时,曾出现“Error: incorrect header check”错误,已尝试通过修改 `User-Agent` 头部来解决。
|
| 24 |
+
|
| 25 |
+
## 项目决策演变
|
| 26 |
+
* 最初使用 `requests` 库,后改为 `httpx` 以支持异步。
|
| 27 |
+
* API 密钥最初通过 URL 查询参数传递,后改为 `Authorization` 头。
|
| 28 |
+
* 健康检查端点最初被通用路由覆盖,后调整了路由顺序。
|
| 29 |
+
* 为了解决 Postman 问题,增加了强制修改 `User-Agent` 头的逻辑。
|
memory-bank/projectBrief.md
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 项目简报 (projectBrief.md)
|
| 2 |
+
|
| 3 |
+
## 项目名称
|
| 4 |
+
FastAPI API 转发代理 (SuperProxy)
|
| 5 |
+
|
| 6 |
+
## 项目目标
|
| 7 |
+
搭建一个通用的 FastAPI 应用程序,作为 API 转发代理。主要目标是转发对 Google Gemini API 的请求,特别是其 OpenAI 兼容 API。
|
| 8 |
+
|
| 9 |
+
## 核心功能
|
| 10 |
+
1. 接收来自客户端的 HTTP 请求(GET, POST, PUT, DELETE)。
|
| 11 |
+
2. 将这些请求转发到预配置的目标 API(例如 Gemini API)。
|
| 12 |
+
3. 处理请求头、查询参数和请求体。
|
| 13 |
+
4. 将目标 API 的响应(状态码、头部、响应体)返回给客户端。
|
| 14 |
+
5. 支持通过环境变量配置目标 API 的基 URL 和认证信息。
|
| 15 |
+
6. 提供一个简单的健康检查端点。
|
| 16 |
+
|
| 17 |
+
## 关键技术
|
| 18 |
+
* Python
|
| 19 |
+
* FastAPI
|
| 20 |
+
* Uvicorn
|
| 21 |
+
* httpx (异步 HTTP 客户端)
|
| 22 |
+
* python-dotenv (环境变量管理)
|
| 23 |
+
|
| 24 |
+
## 部署环境
|
| 25 |
+
Hugging Face Spaces (或任何支持 FastAPI 应用的 Python 环境)
|
| 26 |
+
|
| 27 |
+
## 当前状态
|
| 28 |
+
* FastAPI 代理应用已基本实现。
|
| 29 |
+
* 已配置通过环境变量 `GEMINI_BASE_URL` 和 `GEMINI_API_KEY` 转发到 Gemini 的 OpenAI 兼容 API。
|
| 30 |
+
* 已修复健康检查端点。
|
| 31 |
+
* 已将转发请求的 `User-Agent` 头修改为 `curl/8.7.1`。
|
| 32 |
+
* 在部署环境 (Hugging Face Spaces) 中,代理功能已通过 `curl` 命令验证成功。
|
| 33 |
+
* 在本地测试时,Gemini API 返回“User location is not supported for the API use.”错误,这可能是由于本地 IP 地址的区域限制。
|
| 34 |
+
* Postman 客户端在调用部署的代理时遇到“Error: incorrect header check”错误,这可能与 Postman 自动生成的头部有关。
|
memory-bank/systemPatterns.md
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 系统模式 (systemPatterns.md)
|
| 2 |
+
|
| 3 |
+
## 系统架构
|
| 4 |
+
本项目采用简单的客户端-代理-目标 API 的三层架构。
|
| 5 |
+
|
| 6 |
+
```mermaid
|
| 7 |
+
graph LR
|
| 8 |
+
Client[客户端 (e.g., Postman, curl)] --> Proxy[FastAPI 代理 (SuperProxy)]
|
| 9 |
+
Proxy --> TargetAPI[目标 API (e.g., Google Gemini API)]
|
| 10 |
+
```
|
| 11 |
+
|
| 12 |
+
## 关键技术决策
|
| 13 |
+
* **FastAPI**:选择 FastAPI 作为 Web 框架,因为它提供了高性能、易于使用的异步 API 开发能力,非常适合构建轻量级代理服务。
|
| 14 |
+
* **httpx**:选择 `httpx` 作为 HTTP 客户端库,因为它支持异步请求,与 FastAPI 的异步特性完美结合,避免了阻塞。
|
| 15 |
+
* **环境变量配置**:使用 `python-dotenv` 管理敏感信息(如 API 密钥)和可配置参数(如目标 API 基 URL),增强了安全性和灵活性。
|
| 16 |
+
* **通用路由**:采用 `/{path:path}` 通用路由来捕获所有传入请求,实现灵活的转发,无需为每个目标 API 端点单独定义路由。
|
| 17 |
+
|
| 18 |
+
## 设计模式
|
| 19 |
+
* **代理模式 (Proxy Pattern)**:本项目是代理模式的经典应用,FastAPI 应用程序充当客户端和目标 API 之间的代理,控制对目标 API 的访问并进行请求/响应转换。
|
| 20 |
+
* **配置即代码 (Configuration as Code)**:通过 `.env` 文件管理配置,使得部署和环境切换更加便捷和可控。
|
| 21 |
+
|
| 22 |
+
## 组件关系
|
| 23 |
+
* **FastAPI 应用 (`app.py`)**:核心组件,负责路由、请求解析、请求转发和响应处理。
|
| 24 |
+
* **httpx 客户端**:在 FastAPI 应用内部使用,负责向目标 API 发送实际的 HTTP 请求。
|
| 25 |
+
* **python-dotenv**:在应用启动时加载 `.env` 文件中的环境变量,供 FastAPI 应用使用。
|
| 26 |
+
* **客户端**:可以是任何 HTTP 客户端(浏览器、Postman、`curl`、自定义应用),向 FastAPI 代理发送请求。
|
| 27 |
+
* **目标 API**:本项目中特指 Google Gemini API(OpenAI 兼容接口),是代理请求的最终目的地。
|
| 28 |
+
|
| 29 |
+
## 关键实现路径
|
| 30 |
+
1. **请求接收**:FastAPI 的 `@app.api_route("/{path:path}")` 装饰器捕获所有传入请求。
|
| 31 |
+
2. **请求解析**:`Request` 对象用于获取请求方法、头部、查询参数和请求体。
|
| 32 |
+
3. **头部处理**:移除 `Host` 头,添加 `Authorization: Bearer` 头,并强制设置 `User-Agent`。
|
| 33 |
+
4. **URL 构建**:根据 `GEMINI_BASE_URL` 和传入的 `path` 构建目标 API 的完整 URL。
|
| 34 |
+
5. **请求转发**:使用 `httpx.AsyncClient().request()` 异步发送请求到目标 API。
|
| 35 |
+
6. **响应处理**:将目标 API 的 `content`、`status_code` 和 `headers` 封装成 `FastAPI.Response` 返回给客户端。
|
| 36 |
+
7. **错误处理**:捕获 `httpx.RequestError` 和 `httpx.HTTPStatusError`,并转换为 `HTTPException` 返回给客户端。
|
memory-bank/techContext.md
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 技术背景 (techContext.md)
|
| 2 |
+
|
| 3 |
+
## 使用的技术
|
| 4 |
+
* **Python 3.9+**:作为主要的开发语言。
|
| 5 |
+
* **FastAPI 0.120.0+**:高性能的 Python Web 框架,用于构建 API 代理。
|
| 6 |
+
* **Uvicorn**:ASGI 服务器,用于运行 FastAPI 应用程序。
|
| 7 |
+
* **httpx 0.28.1+**:异步 HTTP 客户端,用于向目标 API 发送请求。
|
| 8 |
+
* **python-dotenv**:用于从 `.env` 文件加载环境变量。
|
| 9 |
+
|
| 10 |
+
## 开发环境设置
|
| 11 |
+
1. **Python 环境**:建议使用 `conda` 或 `venv` 创建独立的 Python 虚拟环境。
|
| 12 |
+
```bash
|
| 13 |
+
conda create -n airs python=3.9
|
| 14 |
+
conda activate airs
|
| 15 |
+
```
|
| 16 |
+
2. **依赖安装**:通过 `requirements.txt` 安装所有项目依赖。
|
| 17 |
+
```bash
|
| 18 |
+
pip install -r requirements.txt
|
| 19 |
+
```
|
| 20 |
+
3. **环境变量**:在项目根目录创建 `.env` 文件,并配置以下变量:
|
| 21 |
+
```
|
| 22 |
+
GEMINI_API_KEY="YOUR_GEMINI_API_KEY"
|
| 23 |
+
GEMINI_BASE_URL="https://generativelanguage.googleapis.com/v1beta/openai"
|
| 24 |
+
```
|
| 25 |
+
请将 `YOUR_GEMINI_API_KEY` 替换为您的实际 Gemini API 密钥。
|
| 26 |
+
|
| 27 |
+
## 技术约束
|
| 28 |
+
* **FastAPI 路由匹配顺序**:通用路由 `/{path:path}` 必须放在特定路由(如 `/health`)之后,否则会优先匹配通用路由。
|
| 29 |
+
* **异步 HTTP 请求**:由于 FastAPI 是异步框架,使用 `httpx` 这样的异步 HTTP 客户端是最佳实践,以避免阻塞事件循环。
|
| 30 |
+
* **API 密钥安全**:API 密钥不应直接硬编码在代码中,而应通过环境变量安全管理。
|
| 31 |
+
* **Hugging Face Spaces 部署**:部署到 Hugging Face Spaces 时,需要确保 `.env` 文件中的环境变量已正确配置,并且 `app.py` 中的 `uvicorn` 启动命令与 Space 的配置兼容。
|
| 32 |
+
|
| 33 |
+
## 依赖管理
|
| 34 |
+
项目依赖通过 `requirements.txt` 文件进行管理:
|
| 35 |
+
```
|
| 36 |
+
fastapi
|
| 37 |
+
uvicorn[standard]
|
| 38 |
+
httpx
|
| 39 |
+
python-dotenv
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
## 工具使用模式
|
| 43 |
+
* **`uvicorn`**:用于本地开发和部署时启动 FastAPI 应用。
|
| 44 |
+
`uvicorn app:app --host 0.0.0.0 --port 7860 --reload`
|
| 45 |
+
* **`pip` / `pip3`**:用于安装 Python 依赖。
|
| 46 |
+
* **`curl` / Postman**:用于测试 API 代理功能。
|
| 47 |
+
* **`.clinerules`**:用于配置 Cline 的自定义指令,例如自动激活 `conda` 环境。
|
requirements.txt
CHANGED
|
@@ -2,3 +2,4 @@ fastapi
|
|
| 2 |
uvicorn[standard]
|
| 3 |
httpx
|
| 4 |
python-dotenv
|
|
|
|
|
|
| 2 |
uvicorn[standard]
|
| 3 |
httpx
|
| 4 |
python-dotenv
|
| 5 |
+
python-jose
|