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.
- gemini_image-0.1.0/.env.example +17 -0
- gemini_image-0.1.0/.github/workflows/publish.yml +24 -0
- gemini_image-0.1.0/.github/workflows/test.yml +29 -0
- gemini_image-0.1.0/.gitignore +9 -0
- gemini_image-0.1.0/PKG-INFO +14 -0
- gemini_image-0.1.0/README.md +167 -0
- gemini_image-0.1.0/docs/design.md +243 -0
- gemini_image-0.1.0/docs/plan.md +1245 -0
- gemini_image-0.1.0/pyproject.toml +28 -0
- gemini_image-0.1.0/scripts/install-service.sh +32 -0
- gemini_image-0.1.0/scripts/setup.sh +78 -0
- gemini_image-0.1.0/src/__init__.py +0 -0
- gemini_image-0.1.0/src/browser.py +159 -0
- gemini_image-0.1.0/src/cli.py +161 -0
- gemini_image-0.1.0/src/config.py +47 -0
- gemini_image-0.1.0/src/gemini.py +232 -0
- gemini_image-0.1.0/src/main.py +156 -0
- gemini_image-0.1.0/src/queue.py +64 -0
- gemini_image-0.1.0/src/selectors.py +25 -0
- gemini_image-0.1.0/src/watermark.py +151 -0
- gemini_image-0.1.0/tests/__init__.py +0 -0
- gemini_image-0.1.0/tests/test_api.py +65 -0
- gemini_image-0.1.0/tests/test_config.py +28 -0
- gemini_image-0.1.0/tests/test_queue.py +46 -0
- gemini_image-0.1.0/tests/test_watermark.py +90 -0
- gemini_image-0.1.0/uv.lock +760 -0
|
@@ -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,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 會被拒絕
|