zexadev/gemini-web2api-go
GitHub: zexadev/gemini-web2api-go
将 Google Gemini 网页端协议逆向反代为 OpenAI 兼容 API 的 Go 服务,免 API Key 即可调用。
Stars: 13 | Forks: 1
# gemini-web2api-go
[](LICENSE)
[](https://golang.org)
[](Dockerfile)
中文 | [English](README_EN.md)
把 Google Gemini 网页端反代成 OpenAI 兼容 API。**单二进制**,**零账号**(匿名可跑,挂 Google cookie 可解锁 Pro),**Chrome 146 真指纹**,**SQLite 持久化**,自带**中文管理面板**。
## 这是什么
把这种调用:
```
[OpenAI SDK / Cherry Studio / Cursor / dify / newapi / ...]
↓ http://localhost:8083/v1/chat/completions
[gemini-web2api-go]
↓ 逆向 gemini.google.com 网页协议
[Google Gemini 网页端]
```
不是 Google 官方 API([generativelanguage.googleapis.com](https://generativelanguage.googleapis.com))的二次封装——**直接反代浏览器协议**,所以**不需要 Google API Key、不需要付费配额**。
## 跟参考实现的区别
社区有一份单文件 Python 参考实现(同名 `gemini-web2api`,stdlib only)。本项目协议层照搬,但工程能力差异较大:
| 维度 | Python 单文件版 | gemini-web2api-go |
|---|---|---|
| 部署 | `python gemini_web2api.py` | 单二进制(~25MB Docker 镜像) |
| 依赖 | stdlib only | 编译产物零外部依赖 |
| 指纹 | urllib 默认(Google 视作 SDK) | **utls Chrome 146**(视作浏览器) |
| API 鉴权 | ❌ 裸奔 | ✅ Bearer token / x-api-key |
| 持久化 | ❌ 无 | ✅ SQLite,30 天明细 + 永久聚合 |
| 管理面板 | ❌ | ✅ 中文 Web UI(仪表盘 / 请求记录 / 代理池 / 设置) |
| 限流保护 | ❌ | ✅ 每 IP slot 独立并发/RPM/RPH 限额 |
| 代理池 | 单一静态代理 | ✅ 运行时增删改 + 失败熔断 + 轮询调度 |
| 隐私 | n/a | ✅ Prompt/Response 内容**永不入库**,只存元数据 |
## 快速开始
### 编译
```
go build -o gemini-web2api-go .
./gemini-web2api-go --port 8083 --admin-token your-admin-token
```
### Docker
```
docker compose up -d --build
```
启动后会看到 banner:
```
gemini-web2api-go v3.0.0
Listening: http://0.0.0.0:8083
Base URL: http://localhost:8083/v1
API key: sk-gemini-XX...XXXX (mutable in admin UI)
Admin UI: http://localhost:8083/admin (token auth)
Impersonate: chrome_146
Tokenizer: tiktoken cl100k_base
Per-IP 限流: 并发=5 / RPM=30 / RPH=80
```
### 调用
```
curl http://localhost:8083/v1/chat/completions \
-H "Authorization: Bearer sk-gemini-..." \
-H "Content-Type: application/json" \
-d '{
"model": "gemini-3.5-flash",
"messages": [{"role": "user", "content": "Hello!"}]
}'
```
OpenAI Python SDK 也直接能用:
```
from openai import OpenAI
client = OpenAI(
base_url="http://localhost:8083/v1",
api_key="sk-gemini-..." # admin 面板里看
)
resp = client.chat.completions.create(
model="gemini-3.5-flash-thinking",
messages=[{"role": "user", "content": "解释量子纠缠"}]
)
print(resp.choices[0].message.content)
```
## 管理面板
`http://localhost:8083/admin`,用 `--admin-token` 登录。
- **仪表盘** — 24h KPI + 请求量/P50 延迟双轴趋势图 + 模型/代理分组统计 + IP 限流用量 + 一键连通性诊断
- **请求记录** — 明细列表(仅元数据,无 prompt/response 内容),状态/模型筛选 + 分页
- **代理池** — 运行时增删改 + 启用/禁用 + 失败次数熔断(每代理是独立 IP slot)
- **设置** — API Key 显示/复制/旋转/自定义 + 限流配置查看
## 模型
| 模型 | 描述 | 输出长度 |
|---|---|---|
| `gemini-3.5-flash` | 快速通用 | ~12k 字符 |
| `gemini-3.5-flash-thinking` | 深度思考,最长输出 | **~20k 字符** |
| `gemini-3.5-flash-thinking-lite` | 自适应思考深度 | ~15k 字符 |
| `gemini-3.1-pro` | Pro 模型(需 cookie 才走真 Pro 路由)| ~12k 字符 |
| `gemini-auto` | 自动选模型 | varies |
| `gemini-flash-lite` | 轻量极速 | ~10k 字符 |
模型名后加 `@think=N` 可覆盖思考深度(`0` 最深 ↔ `4` 最浅):
```
gemini-3.5-flash-thinking@think=2
```
## 配置
`config.json`(可选,CLI flag 优先):
```
{
"port": 8083,
"host": "0.0.0.0",
"impersonate": "chrome_146",
"db_path": "./data/gemini.db",
"retention_days": 30,
"admin_enabled": true,
"admin_token": "",
"request_timeout_sec": 180,
"retry_attempts": 3,
"default_model": "gemini-3.5-flash",
"per_ip_concurrent": 5,
"per_ip_rpm": 30,
"per_ip_rph": 80
}
```
支持的 impersonate:`chrome_146`(默认)/ `chrome_144` / `chrome_133` / `firefox_147` / `safari_16_0` / `safari_ios_17_0`
环境变量:
- `ADMIN_TOKEN` — 管理面板登录 token
- `API_KEY` — 锁定 `/v1/*` API key(不会显示在 admin UI 的"自定义"按钮里)
## Pro 模型 (可选)
匿名可调所有模型,但 `gemini-3.1-pro` 不挂 cookie 会被路由回 Flash。挂一个 free Google 账号 cookie 即可走真 Pro 路由(不需要付费订阅):
1. 浏览器登录 [gemini.google.com](https://gemini.google.com)
2. DevTools (F12) → Application → Cookies → `https://gemini.google.com`
3. 复制:`SID` / `HSID` / `SSID` / `APISID` / `SAPISID` / `__Secure-1PSID`
4. `cookie.txt`:
```
SID=...; HSID=...; SSID=...; APISID=...; SAPISID=...; __Secure-1PSID=...
```
5. 启动加 `--cookie-file cookie.txt`
## 代理池(白嫖路线核心)
**为什么需要**:实测单 IP 累积 **~100 次** Gemini 网页请求就会被重定向到 `google.com/sorry/index`,所有后续请求 **6-24 小时**内全部失败。
**怎么解决**:在管理面板「代理池」页面加多个代理,**每个代理是一个独立的 IP slot**,享有独立的并发/RPM/RPH 配额。N 个代理 = N 倍总容量。
支持的代理协议:
- `http://user:pass@host:port`
- `https://user:pass@host:port`
- `socks5://user:pass@host:port`
- `socks5h://user:pass@host:port`(远程 DNS 解析,绕开本地 DNS 污染)
**自动调度规则**:
- 配了代理后,**不会再退回直连**(避免代理满了把主机 IP 也打爆)
- 失败 5 次自动熔断(管理面板可手动重置)
- 全部代理满 → 返回 HTTP 429(不消耗 Google 配额,等空位再重试)
## 指纹模拟
直连场景(无代理)走 [bogdanfinn/tls-client](https://github.com/bogdanfinn/tls-client),TLS 握手 + HTTP/2 SETTINGS 帧 + ALPS 全部对齐真实 Chrome 146。Google 风控视角下,跟真浏览器无法区分。
走代理场景换用 stdlib `net/http` + `http.ProxyURL`(兼容性最佳),但应用层 header(`Sec-CH-UA` / `Sec-Fetch-*` / `User-Agent`)仍按 Chrome 146 真实值伪装。
**实测意外**:朴素 SDK 调用(如 Python urllib)触发风控时拿到 **HTTP 429**;伪装成 Chrome 后触发风控拿到 **HTTP 302** 跳转到 `google.com/sorry/index`(CAPTCHA 验证页)。两者本质都是 IP 黑名单,但 302 证明 Google 真的把我们认成了浏览器。
## 隐私
- **Prompt 和 response 内容永不入库**——只存元数据:模型、代理 ID、延迟、token 数、状态码、错误类型
- 历史 `prompt_preview` / `response_preview` 列从老版本迁移时自动 DROP
- Token 数用 [tiktoken-go](https://github.com/pkoukk/tiktoken-go) cl100k_base BPE 分词器精确计算(中英文都准),不是 `len/4` 估算
- Gemini 网页端不返回真 token 数(实测响应里没有任何 token/usage 字段,只能本地估算)
## OpenAI 协议覆盖
| 路径 | 状态 | 备注 |
|---|---|---|
| `POST /v1/chat/completions` | ✅ | 含 `stream: true` SSE |
| `POST /v1/responses` | ✅ | OpenAI Responses API(Codex CLI 用) |
| `GET /v1/models` | ✅ | 列出 6 个模型 |
| Function calling | ⚠️ | Prompt 级实现(让模型输出 ` ```tool_call``` ` 块再 regex 解析),不是真协议层。模型偶尔不按格式返回 |
| Vision / 图片输入 | ❌ | 网页协议不支持文件上传 |
| Audio | ❌ | 网页协议不支持 |
## 项目结构
```
main.go 入口 + flag 解析 + 路由注册
config.go 配置加载 + DEFAULT_CONFIG
client.go tls-client (chrome146) + stdlib (代理) 双 client
gemini.go 80 槽位 payload + StreamGenerate + wrb.fr 流解析
messages.go OpenAI messages → prompt + tool_call 解析
server.go /v1/* + 限流入口 + metrics 写入
ratelimit.go 每 IP slot 独立并发/RPM/RPH 限流器
tokenizer.go tiktoken cl100k_base 单例
apikey.go API key 管理(locked / runtime-mutable 双轨)
db.go SQLite schema + sessions + requests + kv
proxy.go 代理池 CRUD + 容量调度 + 熔断
scheduler.go 小时/天聚合 + 数据保留
admin.go /admin/api/* 鉴权 + REST 接口
admin_ui.go embed admin_ui/ 静态文件
admin_ui/index.html 单页中文 admin(Chart.js CDN)
Dockerfile multi-stage (alpine builder → distroless runtime)
docker-compose.yml 单容器,sqlite volume,本地 8083 暴露
```
## 限制
- **匿名访问**:单 IP 受 Google 限流,约 100 次/几小时被拦 6-24 小时 → 配代理池放大产能
- **Pro 路由**:要 free Google 账号 cookie,不需要付费订阅
- **Function calling**:prompt 级实现,模型不一定每次都按格式返回(OpenAI 真协议层我们做不到)
- **多模态**:暂不支持(网页协议本身限制)
- **token 数**:用 tiktoken 估算(Gemini 真 tokenizer 未公开),跟真值偏差 ±20% 以内
## 致谢
- 社区 Python 单文件参考实现(同名 `gemini-web2api`)—— 协议层(80 槽位 payload、wrb.fr 解析、模型 ID 映射)的参考来源
- [bogdanfinn/tls-client](https://github.com/bogdanfinn/tls-client) — Chrome 真指纹 TLS 库
- [pkoukk/tiktoken-go](https://github.com/pkoukk/tiktoken-go) — BPE tokenizer
- [modernc.org/sqlite](https://gitlab.com/cznic/sqlite) — 纯 Go SQLite(CGO-free,alpine 直接编)
## License
MIT — 详见 [LICENSE](LICENSE)
标签:AI API, API网关, EVTX分析, Golang, OpenAI兼容, 反向代理, 安全编程, 日志审计, 请求拦截