gemini-image 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,17 @@
1
+ # 瀏覽器
2
+ HEADLESS=false
3
+ PROFILE_DIR=profiles
4
+ GEMINI_URL=https://gemini.google.com/app
5
+
6
+ # Stealth
7
+ STEALTH_LANGUAGE=zh-TW,zh,en-US,en
8
+ STEALTH_TIMEZONE=Asia/Taipei
9
+
10
+ # 服務
11
+ HOST=0.0.0.0
12
+ PORT=8070
13
+ QUEUE_MAX_SIZE=10
14
+ DEFAULT_TIMEOUT=180
15
+
16
+ # 心跳
17
+ HEARTBEAT_INTERVAL=300
@@ -0,0 +1,24 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+
7
+ permissions:
8
+ id-token: write
9
+
10
+ jobs:
11
+ publish:
12
+ runs-on: ubuntu-latest
13
+ environment: pypi
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - name: Install uv
18
+ uses: astral-sh/setup-uv@v4
19
+
20
+ - name: Build package
21
+ run: uv build
22
+
23
+ - name: Publish to PyPI
24
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,29 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ${{ matrix.os }}
12
+ strategy:
13
+ matrix:
14
+ os: [ubuntu-latest, windows-latest, macos-latest]
15
+ python-version: ["3.11", "3.12", "3.13"]
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Install uv
20
+ uses: astral-sh/setup-uv@v4
21
+
22
+ - name: Set up Python
23
+ run: uv python install ${{ matrix.python-version }}
24
+
25
+ - name: Install dependencies
26
+ run: uv sync --extra dev
27
+
28
+ - name: Run tests
29
+ run: uv run pytest tests/ -v
@@ -0,0 +1,9 @@
1
+ __pycache__/
2
+ *.pyc
3
+ .env
4
+ profiles/
5
+ *.egg-info/
6
+ dist/
7
+ .venv/
8
+ logs/
9
+ bin/
@@ -0,0 +1,14 @@
1
+ Metadata-Version: 2.4
2
+ Name: gemini-image
3
+ Version: 0.1.0
4
+ Summary: Gemini 圖片生成 API 服務
5
+ Requires-Python: >=3.11
6
+ Requires-Dist: fastapi>=0.115
7
+ Requires-Dist: httpx>=0.27
8
+ Requires-Dist: playwright>=1.49
9
+ Requires-Dist: python-dotenv>=1.0
10
+ Requires-Dist: uvicorn[standard]>=0.30
11
+ Provides-Extra: dev
12
+ Requires-Dist: httpx>=0.27; extra == 'dev'
13
+ Requires-Dist: pytest-asyncio>=0.24; extra == 'dev'
14
+ Requires-Dist: pytest>=8.0; extra == 'dev'
@@ -0,0 +1,167 @@
1
+ # Gemini Image
2
+
3
+ 使用 Playwright 自動化 Gemini 網頁版生成含繁體中文文字的圖片。提供 **CLI 工具**和 **HTTP API** 兩種使用方式。
4
+
5
+ 自動移除 Gemini 可見水印(使用 [GeminiWatermarkTool](https://github.com/allenk/GeminiWatermarkTool))。
6
+
7
+ ## 安裝
8
+
9
+ ### 一行安裝(推薦)
10
+
11
+ ```bash
12
+ uv tool install git+https://github.com/yazelin/gemini-image.git && playwright install chromium
13
+ ```
14
+
15
+ 或用 pipx:
16
+
17
+ ```bash
18
+ pipx install git+https://github.com/yazelin/gemini-image.git && playwright install chromium
19
+ ```
20
+
21
+ 安裝完成後 `gemini-image` 指令全域可用。
22
+
23
+ ### 從原始碼安裝
24
+
25
+ ```bash
26
+ git clone https://github.com/yazelin/gemini-image.git
27
+ cd gemini-image
28
+ bash scripts/setup.sh
29
+ ```
30
+
31
+ ## 首次登入 Google
32
+
33
+ 首次使用需手動登入一次,之後 session 自動持久化:
34
+
35
+ ```bash
36
+ gemini-image login
37
+ ```
38
+
39
+ 在彈出的瀏覽器中登入 Google 帳號,確認進入 Gemini 頁面,按 Enter 關閉。
40
+
41
+ ## 使用方式
42
+
43
+ ### CLI 工具
44
+
45
+ ```bash
46
+ # 生成圖片
47
+ gemini-image generate "A cute cat sitting on a windowsill" -o cat.png
48
+
49
+ # 生成圖片 + 自動去水印
50
+ gemini-image generate "A poster with text '歡迎光臨'" -o poster.png --no-watermark
51
+
52
+ # 查看說明
53
+ gemini-image --help
54
+ gemini-image generate --help
55
+ ```
56
+
57
+ ### HTTP API
58
+
59
+ ```bash
60
+ # 啟動 API 服務
61
+ gemini-image serve
62
+
63
+ # 或直接用 uvicorn
64
+ uv run uvicorn src.main:app --host 0.0.0.0 --port 8070
65
+ ```
66
+
67
+ #### POST /api/generate
68
+
69
+ ```bash
70
+ curl -X POST http://localhost:8070/api/generate \
71
+ -H "Content-Type: application/json" \
72
+ -d '{"prompt": "A poster with text 歡迎來到台北, modern design"}'
73
+ ```
74
+
75
+ 回傳:
76
+
77
+ ```json
78
+ {
79
+ "success": true,
80
+ "images": ["data:image/png;base64,..."],
81
+ "prompt": "...",
82
+ "elapsed_seconds": 27.8
83
+ }
84
+ ```
85
+
86
+ API 模式會自動去水印。
87
+
88
+ #### GET /api/health
89
+
90
+ ```json
91
+ {
92
+ "status": "ok",
93
+ "browser_alive": true,
94
+ "logged_in": true,
95
+ "queue_size": 0,
96
+ "uptime_seconds": 3600
97
+ }
98
+ ```
99
+
100
+ #### POST /api/new-chat
101
+
102
+ 手動重置 Gemini 對話(除錯用)。
103
+
104
+ ### systemd 服務部署
105
+
106
+ ```bash
107
+ # 確認 .env 中 HEADLESS=true
108
+ sudo bash scripts/install-service.sh
109
+ ```
110
+
111
+ ## AI Agent 整合
112
+
113
+ ### 作為 MCP 工具
114
+
115
+ 在你的 AI agent 中呼叫 CLI:
116
+
117
+ ```bash
118
+ gemini-image generate "detailed prompt here" -o /path/to/output.png --no-watermark
119
+ ```
120
+
121
+ ### 作為 HTTP API
122
+
123
+ ```python
124
+ import httpx
125
+ resp = httpx.post("http://localhost:8070/api/generate", json={"prompt": "..."}, timeout=200)
126
+ data = resp.json()
127
+ if data["success"]:
128
+ images = data["images"] # base64 list
129
+ ```
130
+
131
+ ## 環境變數
132
+
133
+ | 變數 | 說明 | 預設 |
134
+ |------|------|------|
135
+ | `HEADLESS` | 無頭模式(首次登入設 false) | `false` |
136
+ | `PROFILE_DIR` | 瀏覽器 session 目錄 | `profiles` |
137
+ | `GEMINI_URL` | Gemini 網址 | `https://gemini.google.com/app` |
138
+ | `PORT` | API 服務埠 | `8070` |
139
+ | `DEFAULT_TIMEOUT` | 生圖超時秒數 | `180` |
140
+ | `QUEUE_MAX_SIZE` | 最大排隊數 | `10` |
141
+ | `HEARTBEAT_INTERVAL` | 心跳檢查間隔秒數 | `300` |
142
+
143
+ ## 去水印
144
+
145
+ 使用 [GeminiWatermarkTool](https://github.com/allenk/GeminiWatermarkTool)(反向 Alpha 混合 + AI 降噪)移除 Gemini 右下角可見水印。
146
+
147
+ - **首次使用時自動下載**對應平台的 binary(Windows/Linux/macOS)
148
+ - 快取位置:`~/.gemini-image/bin/`
149
+ - API 模式:自動去水印
150
+ - CLI 模式:加 `--no-watermark` 參數
151
+
152
+ 注意:不可見的 SynthID 浮水印無法移除。
153
+
154
+ ## 已知限制
155
+
156
+ - 一次只能處理一個生圖請求(其他排隊)
157
+ - Google 登入過期需手動重新登入(`gemini-image login`)
158
+ - Gemini 改版可能導致 DOM selector 失效,需手動更新 `src/selectors.py`
159
+ - 違反 Google 服務條款,帳號有被封風險
160
+ - 生圖耗時約 20-60 秒,視 Gemini 伺服器負載而定
161
+
162
+ ## 開發
163
+
164
+ ```bash
165
+ uv sync --extra dev
166
+ uv run pytest -v
167
+ ```
@@ -0,0 +1,243 @@
1
+ # Gemini Image API 設計規格
2
+
3
+ ## 概述
4
+
5
+ 獨立的圖片生成 API 服務,使用 Playwright 瀏覽器自動化操作 Gemini 網頁版(Nano Banana / Gemini 3 Pro Image),生成含繁體中文文字的圖片,供多個內部系統透過 HTTP API 呼叫。
6
+
7
+ ## 需求
8
+
9
+ - **使用場景**:多個內部系統共用(CTOS-Lite、其他專案)
10
+ - **併發量**:低量(< 10 張/小時)
11
+ - **圖片用途**:混合(社群圖文、文件插圖等),由呼叫端決定 prompt
12
+ - **認證**:無認證,內網部署不對外暴露
13
+ - **回傳格式**:Base64 JSON
14
+ - **選擇 Gemini 的原因**:唯一能正確渲染繁體中文文字的圖片生成模型
15
+
16
+ ## 技術棧
17
+
18
+ | 元件 | 技術 |
19
+ |------|------|
20
+ | API 框架 | Python FastAPI |
21
+ | 瀏覽器自動化 | Playwright(Chromium) |
22
+ | 套件管理 | uv + hatchling |
23
+ | 部署 | systemd 服務 |
24
+
25
+ ## 目錄結構
26
+
27
+ ```
28
+ gemini-image-api/
29
+ ├── src/
30
+ │ ├── main.py # FastAPI 入口、lifespan 管理
31
+ │ ├── config.py # 環境變數設定
32
+ │ ├── browser.py # Playwright 瀏覽器管理(啟動、stealth、session)
33
+ │ ├── gemini.py # Gemini 頁面互動(輸入、等待、擷取圖片)
34
+ │ ├── selectors.py # DOM CSS selector 集中管理
35
+ │ └── queue.py # asyncio 請求佇列
36
+ ├── profiles/ # 瀏覽器 session 持久化目錄
37
+ ├── pyproject.toml
38
+ ├── .env.example
39
+ └── Dockerfile # 可選
40
+ ```
41
+
42
+ ## 架構
43
+
44
+ ```
45
+ POST /api/generate {"prompt": "..."}
46
+
47
+ asyncio.Queue(排隊,maxsize=10)
48
+
49
+ 單一 Worker
50
+
51
+ browser.py — 持久化 Chromium context(已登入 Gemini)
52
+
53
+ gemini.py — 輸入 prompt → 送出 → 等待圖片生成 → 從 DOM 擷取
54
+
55
+ 回傳 {"images": ["data:image/png;base64,..."]}
56
+ ```
57
+
58
+ ## 瀏覽器管理(browser.py)
59
+
60
+ ### 啟動策略
61
+
62
+ - 使用 `chromium.launch_persistent_context()` 將 Google 登入狀態存在 `profiles/` 目錄
63
+ - 首次啟動:`HEADLESS=false`,手動登入 Google,之後改 `HEADLESS=true`
64
+ - 服務啟動時自動開瀏覽器,服務關閉時自動清理
65
+
66
+ ### Stealth 防偵測
67
+
68
+ 參考 Project Golem 的 BrowserLauncher:
69
+
70
+ - 偽裝 `navigator.webdriver` 為 false
71
+ - 設定真實 User-Agent、語言(zh-TW)、時區(Asia/Taipei)
72
+ - 偽裝 WebGL vendor/renderer
73
+ - 擋掉不必要的資源(字體、追蹤腳本)減少流量
74
+
75
+ ### Session 保活
76
+
77
+ - 定時心跳(每 5 分鐘檢查頁面是否還活著)
78
+ - 偵測到 Google 登入過期 → log 警告,API 回傳 503
79
+ - 不自動重新登入(安全考量,需人工介入)
80
+
81
+ ### 頁面管理
82
+
83
+ - 單一分頁複用,每次生圖完點擊「新對話」重置
84
+ - 避免開太多分頁導致記憶體膨脹
85
+
86
+ ## Gemini 頁面互動(gemini.py)
87
+
88
+ ### 互動流程
89
+
90
+ 1. 確認頁面就緒(輸入框可用)
91
+ 2. 在輸入框輸入 prompt
92
+ 3. 按 Enter 或點擊送出按鈕
93
+ 4. 等待回應完成(偵測「停止生成」按鈕消失)
94
+ 5. 從回應區域擷取圖片元素
95
+ 6. 將圖片轉為 base64
96
+ 7. 點擊「新對話」重置狀態
97
+
98
+ ### 圖片擷取策略
99
+
100
+ Gemini 生成的圖片可能以幾種形式出現:
101
+
102
+ - `<img src="data:image/...">`(直接 base64)
103
+ - `<img src="https://...">`(遠端 URL)
104
+ - `<canvas>` 元素
105
+
106
+ 統一用 `page.evaluate()` 在瀏覽器端把圖片繪製到 canvas → 匯出 base64,不管原始格式都能處理。
107
+
108
+ ### 容錯機制
109
+
110
+ | 情況 | 處理 |
111
+ |------|------|
112
+ | Gemini 拒絕生圖(內容審查) | 偵測拒絕訊息文字,回傳 `error: "content_blocked"` |
113
+ | 回應超時(預設 60 秒) | 回傳 408 `error: "timeout"` |
114
+ | DOM 結構變了找不到元素 | 回傳 502 `error: "browser_error"` + 詳細 log |
115
+ | Gemini 回了文字沒有圖 | 回傳 `error: "no_image"`,附帶 Gemini 的文字回應 |
116
+
117
+ ## DOM Selector 管理(selectors.py)
118
+
119
+ 所有 CSS selector 集中管理,Gemini 改版時只需更新此檔案:
120
+
121
+ ```python
122
+ SELECTORS = {
123
+ "input": "div[contenteditable='true']",
124
+ "send": "button[aria-label='Send']",
125
+ "response": "div.response-container",
126
+ "images": "img.generated-image",
127
+ "new_chat": "button[aria-label='New chat']",
128
+ "stop": "button[aria-label='Stop']",
129
+ }
130
+ ```
131
+
132
+ 注意:以上為示意值,實際 selector 需在開發時對照真實 Gemini DOM 確認。
133
+
134
+ ## 請求佇列(queue.py)
135
+
136
+ - `asyncio.Queue(maxsize=10)` 排隊緩衝
137
+ - 超過 10 個排隊 → 429 Too Many Requests
138
+ - 單一 worker 循環取任務 → 操作瀏覽器 → 回傳結果
139
+ - 每個請求帶 timeout,佇列等待超過 timeout 回 408
140
+
141
+ ## API 介面
142
+
143
+ ### POST /api/generate
144
+
145
+ ```json
146
+ // Request
147
+ {
148
+ "prompt": "畫一張台北101的夜景海報,標題寫「歡迎來到台北」",
149
+ "timeout": 60
150
+ }
151
+
152
+ // Response 成功
153
+ {
154
+ "success": true,
155
+ "images": ["data:image/png;base64,..."],
156
+ "prompt": "畫一張...",
157
+ "elapsed_seconds": 12.3
158
+ }
159
+
160
+ // Response 失敗
161
+ {
162
+ "success": false,
163
+ "error": "content_blocked",
164
+ "message": "Gemini 拒絕生成此內容"
165
+ }
166
+ ```
167
+
168
+ ### GET /api/health
169
+
170
+ ```json
171
+ {
172
+ "status": "ok",
173
+ "browser_alive": true,
174
+ "logged_in": true,
175
+ "queue_size": 2,
176
+ "uptime_seconds": 3600
177
+ }
178
+ ```
179
+
180
+ ### POST /api/new-chat
181
+
182
+ 手動重置 Gemini 對話(除錯用),回傳 `{"success": true}`。
183
+
184
+ ## 環境變數
185
+
186
+ ```bash
187
+ # 瀏覽器
188
+ HEADLESS=false # 首次登入設 false,之後改 true
189
+ PROFILE_DIR=profiles # 瀏覽器 session 目錄
190
+ GEMINI_URL=https://gemini.google.com/app
191
+
192
+ # Stealth
193
+ STEALTH_LANGUAGE=zh-TW,zh,en-US,en
194
+ STEALTH_TIMEZONE=Asia/Taipei
195
+
196
+ # 服務
197
+ HOST=0.0.0.0
198
+ PORT=8070
199
+ QUEUE_MAX_SIZE=10
200
+ DEFAULT_TIMEOUT=60
201
+
202
+ # 心跳
203
+ HEARTBEAT_INTERVAL=300 # 秒
204
+ ```
205
+
206
+ ## 部署
207
+
208
+ ### 首次啟動(手動登入)
209
+
210
+ ```bash
211
+ cd ~/SDD/gemini-image-api
212
+ uv sync
213
+ playwright install chromium
214
+ HEADLESS=false uv run uvicorn src.main:app --port 8070
215
+ # 在彈出的瀏覽器中手動登入 Google
216
+ # 登入完成後關閉服務,修改 .env 中 HEADLESS=true
217
+ ```
218
+
219
+ ### 正式運行
220
+
221
+ ```bash
222
+ uv run uvicorn src.main:app --host 0.0.0.0 --port 8070
223
+ ```
224
+
225
+ ### systemd 服務
226
+
227
+ 提供 `scripts/install-service.sh`,跟 CTOS-Lite 同樣模式。
228
+
229
+ ### 部署位置
230
+
231
+ ```
232
+ ~/SDD/gemini-image-api/ # 獨立 repo,獨立部署
233
+ ~/SDD/ctos-lite/ # 透過內網 HTTP 呼叫 gemini-image-api
234
+ ```
235
+
236
+ ## 已知風險與限制
237
+
238
+ 1. **Google ToS 違規** — 瀏覽器自動化操作 Gemini 違反使用條款,帳號有被封風險
239
+ 2. **DOM 會變** — Gemini 改版時 selector 需要手動更新,服務可能突然壞掉
240
+ 3. **登入過期** — Google session 過期需人工重新登入,無法自動化
241
+ 4. **單一瀏覽器瓶頸** — 同時只能處理一個生圖請求,其他排隊等待
242
+ 5. **圖片擷取不保證** — Gemini 回傳圖片的 DOM 結構可能變化
243
+ 6. **內容審查** — Gemini 對人像、版權角色等有嚴格限制,部分 prompt 會被拒絕