Playwright 開著一個已登入的瀏覽器操作真正的 Gemini 網頁版,你的程式只要打一個
google-genai 相容的 HTTP 端點。多掛幾個帳號,它們就成為一組 worker pool。
你已經在付 Gemini 的訂閱費,網頁版整天生圖、回答問題都沒問題。但只要換成排程工作、 Cloudflare Worker 或 Telegram 機器人想做同一件事,你就得回頭去買按量計費的 API 額度,買的是你早就擁有的能力。
這個服務夾在中間:一個無頭瀏覽器維持登入狀態,呼叫端只要講普通的 HTTP。一份登入、 多個消費端、不按張計費。輸出的圖會自動去掉可見浮水印,而且是從下載按鈕取原始尺寸, 不是抓網頁上那張被縮過的算圖。
/v1beta/models/{model}:generateContent 走 Google GenAI 的格式,用 google-genai 的程式只要改 base_url 就能跑。
/api/edit 會上傳一張參考圖再回傳編輯後的結果,這是 SDK 相容端點表達不出來的路徑。
每個 worker 是自己的瀏覽器、自己的 Google 帳號。請求輪流分派,沒有哪一個方案會先撞到上限。
每個呼叫端發一把金鑰、隨時停用,看各 worker 近 24 小時的成功率,手動重跑一筆請求,翻歷史紀錄都不必連進主機。
請用 uv 或 pipx,直接 pip install 不會給 Playwright 隔離環境,瀏覽器會裝不起來。
uv tool install gemini-web
gemini-web install # 下載 Playwright 要驅動的 Chromium
gemini-web login # 開真的瀏覽器,登入 Google 後按 Enter
登入這步需要桌面環境(或透過 SSH 的 X forwarding),因為密碼要你自己輸入。
登入狀態存在 ~/.gemini-web/profiles/,之後就一直沿用。
要加第二個帳號是 gemini-web login -w 1,第三個是
-w 2,依此類推。
gemini-web serve --host 0.0.0.0 --port 8070
要常駐的話,scripts/install-service.sh 裡有現成的 systemd unit。
# 文字對話
curl -X POST http://localhost:8070/api/chat \
-H 'Content-Type: application/json' \
-H 'x-goog-api-key: gmw_<你的金鑰>' \
-d '{"prompt": "解釋量子力學"}'
# 文字生圖
curl -X POST http://localhost:8070/api/generate \
-H 'Content-Type: application/json' \
-H 'x-goog-api-key: gmw_<你的金鑰>' \
-d '{"prompt": "畫一張台北 101 海報"}'
# 參考圖編輯(丟一張照片進去,拿一張改過的圖出來)
curl -X POST http://localhost:8070/api/edit \
-H 'Content-Type: application/json' \
-H 'x-goog-api-key: gmw_<你的金鑰>' \
-d '{"prompt": "redraw as a 3x3 sticker sheet", "reference_image": "data:image/png;base64,..."}'
或是原本的 SDK 程式碼不動,只把位址指過來:
from google import genai
client = genai.Client(
api_key="gmw_<你的金鑰>",
http_options={"api_version": "v1beta", "base_url": "http://localhost:8070"},
)
print(client.models.generate_content(model="gemini-2.5-flash", contents="Hello").text)
| 端點 | 做什麼 |
|---|---|
POST /api/chat | 丟文字,回文字。 |
POST /api/generate | 文字生圖,回 base64,浮水印已經去掉。 |
POST /api/edit | 參考圖加 prompt 生圖。唯一會上傳檔案的端點。 |
POST /v1beta/models/{model}:generateContent | Google GenAI 相容,另有串流版本。 |
GET /api/health | 各 worker 的存活、登入、忙碌狀態與排隊深度。不含帳號名稱,因為這支是公開的。 |
只要你發過任何一把金鑰,上面每個端點都會要求帶
x-goog-api-key。在第一把金鑰出現之前服務維持開放,
本機開發不會被擋,但只要對外可達,第一天就該發金鑰。瀏覽器路燒的是登入帳號的
訂閱額度,而且沒有任何每把金鑰的速率限制會救你。
把 WORKER_COUNT=N 設起來,服務就會開 N 個瀏覽器,各自吃
自己的 profile 目錄,也就是各自一個 Google 帳號。每個 worker 一次處理一筆請求,
所以 N 同時是你的併行度,也是你分攤用量的額度數。實測每個 worker 大約佔 0.6 到 0.7 GB
記憶體。
| 派工模式 | 行為 | 什麼時候用 |
|---|---|---|
round-robin(預設) | 每筆請求換下一個 worker。 | 想把用量平均攤開,沒有哪個方案會先撞上限。 |
spillover | worker 0 全包,其餘只在它忙碌時才動。 | 想把備用帳號留著不動。 |
模式是管理後台 Overview 的一個下拉選單,設定存在資料庫裡,重啟後沿用。
擴充帳號之前有件事值得先知道:同一個 Gemini 網頁,在不同帳號長得不一樣。 選單項目會有出入,第一次使用上傳功能的帳號會多跳一個同意條款對話框,生成好的圖有時是 blob、有時要按下載鈕。所以「只有某一個 worker 壞掉、其他都好」是正常現象,而且元凶 通常不是登入。後台那欄每個 worker 的 24 小時成功率就是為此而存在,讓這件事一眼看得見, 而不是被 fallback 蓋過去。
/admin,用密碼加上一個 HMAC 簽章的 session cookie 保護:
gmw_<token>,可停用或刪除。原始值只顯示一次,伺服器只留 sha256。環境變數 API_KEYS 裡的金鑰仍然有效,會以唯讀方式列出。
瀏覽器路是每個帳號單線、一次 30 到 120 秒,而且 Gemini 一改版就可能壞。如果某個
呼叫端受不了這種脆弱,設定 GEMINI_OFFICIAL_API_KEY,服務
就能改把請求交給官方 Gemini Developer API:大約 10 秒,按量計費。
GEMINI_OFFICIAL_MODE=off:完全不用。fallback(預設):只有瀏覽器路失敗後才頂上。primary:一律直接走官方,跳過瀏覽器。?official=1 可以強制單次走官方路。
付費路一律要求有效金鑰,所以開放的端點永遠不會被拿去衝你的帳單。但反過來要留意:
在 fallback 模式下,壞掉的 worker 從外面完全看不出來,
呼叫端照樣拿到圖,只是那張圖是按量計費生出來的。後台那欄成功率就是為了看穿這件事。
這是為了自己的 homelab 做的東西,與 Google 無任何隸屬、背書或支援關係。 它用一個真實已登入的瀏覽器 session 自動化消費者版的 Gemini 網頁,那不是 Google 文件裡寫過、也不是它認可的使用方式。
src/selectors.py 裡某個選擇器一過期,對應的功能就直接停擺,直到有人去修。