whackw-kali/chatgpt-image-cli

GitHub: whackw-kali/chatgpt-image-cli

通过逆向 OpenClaw 的浏览器 OAuth 认证流程,实现在无需 API Key 的情况下调用 ChatGPT gpt-image-2 免费生成图片的命令行工具。

Stars: 0 | Forks: 0

# ChatGPT Image CLI ## 快速导航 - [人类使用指南](#人类使用指南human-usage-guide) — 手动操作步骤 - [AI Agent 使用指南](#ai-agent-使用指南ai-agent-usage-guide) — AI 工具调用方式 - [完整技术文档](#完整技术文档full-technical-documentation) — 逆向细节、API 数据流 # 人类使用指南 ## 环境要求 | 项目 | 要求 | |-------------|------------------| | Python | 3.8+ | | 系统 | macOS / Linux / Windows | | 浏览器 | 能打开 ChatGPT 授权页 | | ChatGPT 账号 | ChatGPT 账号(Plus 订阅限额更高) | ## 安装 ``` # 克隆仓库 / Clone the repo git clone https://github.com/whackw-kali/chatgpt-image-cli.git cd chatgpt-image-cli # 直接运行(无需安装依赖,仅用 Python 标准库) # 直接运行(无依赖,仅限 Python stdlib) python chatgpt_image.py --help ``` ## 使用步骤 ### 第一步:OAuth 登录 ``` python chatgpt_image.py login ``` **操作流程:** ``` $ python chatgpt_image.py login Starting browser OAuth flow... Opening browser for authentication... If browser doesn't open, go to: https://auth.openai.com/oauth/authorize?... Waiting for authentication callback... ``` 1. 浏览器自动打开 ChatGPT 授权页 2. 输入账号密码,点击「授权」 3. 页面提示「Authentication Complete」,脚本自动继续 4. 看到「Login successful! Tokens saved.」即完成 **Token 存储位置:** - 独立 token:`~/.chatgpt_image_tokens.json` - OpenClaw token:`~/.openclaw/agents/main/agent/auth-profiles.json` ### 第二步:生成图片 ``` # 基本用法(单张)/ Basic (single image) python chatgpt_image.py generate "一只可爱的橘猫" -o cat.png # 生成多张(最多4张)/ Multiple images (max 4) python chatgpt_image.py generate "赛博朋克城市夜景" -n 4 -o cyberpunk.png # 指定尺寸 / Specify size python chatgpt_image.py generate "山水画" --size 3840x2160 -o landscape.png ``` **支持的尺寸:** | 尺寸 | 说明 | |-------------|-------------------| | `1024x1024` | 正方形(默认) | | `1536x1024` | 横版 3:2 | | `1024x1536` | 竖版 2:3 | | `2048x2048` | 正方形高清 | | `2048x1152` | 横版 16:9 | | `3840x2160` | 横版 4K | | `2160x3840` | 竖版 4K | ### 第三步:查看 token 状态 ``` python chatgpt_image.py status ``` **输出示例:** ``` OpenClaw: Logged in as eyJhbG...NiIs... Token expires in 14310.2 minutes. Own token: Logged in. Token expires in 58.3 minutes. ``` ## 命令速查 | 命令 | 说明 | |---------------|-------------------| | `python chatgpt_image.py login` | OAuth 登录(首次使用) | | `python chatgpt_image.py generate "描述" -o out.png` | 生成单张图片 | | `python chatgpt_image.py generate "描述" -n 4 -o out.png` | 生成多张图片 | | `python chatgpt_image.py status` | 查看登录状态 | ## 常见问题 | 问题 | 原因 | 解决方案 | |-----------------|-------------|-------------------| | "fetch failed \| other side closed" | Token 过期 | `python chatgpt_image.py login` | | "Token expired" | access_token 过期 | 同上 | | 浏览器没打开 | headless 环境 | 手动复制终端输出的 URL | | 端口被占用 | 1455 端口被占 | 脚本自动找空闲端口,通常不影响 | # AI Agent 使用指南 ## 工具定位 本工具可作为 AI Agent 的**图片生成工具**,通过子进程调用 `chatgpt_image.py`,传入 prompt 和输出路径,返回生成的图片文件路径。 ## 集成方式 ### 方式一:子进程调用(推荐) AI Agent 通过 `terminal` 工具调用脚本。 **Prompt 模板:** ``` 调用以下命令生成图片: Run: python ~/hermesAgent/chatgpt-image-cli/chatgpt_image.py generate "图片描述 / Image description" -o /tmp/output.png 返回生成的图片路径。/ Return the generated image path. ``` **完整调用流程:** ``` # 1. 检查 token 是否有效 / Check if token is valid # 运行 / Run: python chatgpt_image.py status # 解析输出判断 / Parse output to check if OpenClaw or local token is valid # 2. 生成图片 / Generate image # 运行 / Run: python chatgpt_image.py generate "描述 / description" -o /path/to/output.png # 脚本输出 "Saved:" 即成功 / Script output "Saved:" means success # 3. 返回图片路径 / Return image path # 图片已保存在指定路径 / Image saved at specified path ``` ### 方式二:读取 OpenClaw Token 直接调用 API 如果需要完全自主控制 API 调用流程,可直接读取 OpenClaw 的 token。 **读取 Token:** ``` import json from pathlib import Path auth_file = Path.home() / ".openclaw/agents/main/agent/auth-profiles.json" with open(auth_file) as f: data = json.load(f) for profile in data.get("profiles", {}).values(): if profile.get("provider") == "openai-codex": access_token = profile["access"] refresh_token = profile["refresh"] expires_ms = profile["expires"] # 毫秒时间戳 / millisecond timestamp break ``` **调用图片生成 API:** ``` import urllib.request import json request_body = { "model": "gpt-5.5", "input": [{ "role": "user", "content": [{"type": "input_text", "text": "图片描述 / Image description"}] }], "instructions": "You are an image generation assistant.", "tools": [{"type": "image_generation"}], "store": False, "stream": True } headers = { "Authorization": f"Bearer {access_token}", "Content-Type": "application/json", "Accept": "text/event-stream" } req = urllib.request.Request( "https://chatgpt.com/backend-api/codex/responses", data=json.dumps(request_body).encode(), headers=headers, method="POST" ) with urllib.request.urlopen(req, timeout=300) as resp: for line in resp: event_data = json.loads(line.decode("utf-8").strip()[6:]) if event_data.get("type") == "response.output_item.done": item = event_data.get("item", {}) if item.get("type") == "image_generation_call": import base64 image_bytes = base64.b64decode(item["result"]) with open("output.png", "wb") as f: f.write(image_bytes) ``` ### 方式三:集成到 Hermes Agent Skill 创建 skill 文件让 AI Agent 学会调用。 **Skill 路径:** `skill/SKILL.md`(已包含在项目中) ``` ## 使用触发条件 / Trigger Conditions 用户要求生成图片,且提到以下关键词之一: User wants image generation with keywords: - "ChatGPT 图片生成 / ChatGPT image" - "gpt-image" - "DALL-E" - "AI 画图 / AI draw" - "生成一张图片 / Generate an image" - "帮我画 / Draw for me" ## 调用命令 / Call Command python ~/hermesAgent/chatgpt-image-cli/chatgpt_image.py generate "用户描述 / User description" -o /tmp/img_$(date +%s).png ## 输出处理 / Output Handling 1. 检查命令输出包含 "Saved:" / Check output contains "Saved:" 2. 从输出中提取图片路径 / Extract image path from output 3. 返回图片路径给用户 / Return image path to user ## Token 状态检查 / Token Status Check python chatgpt_image.py status ## 过期处理 / Expired Token Handling 如果 token 过期("fetch failed"),提示用户运行: If token expired ("fetch failed"), tell user to run: python chatgpt_image.py login ``` ## Token 优先级说明 AI Agent 调用时,脚本按以下顺序尝试获取 token。 ``` 1. ~/.openclaw/agents/main/agent/auth-profiles.json (OpenClaw 已登录的 ChatGPT token) 2. ~/.chatgpt_image_tokens.json (本工具独立 OAuth 登录的 token) ``` 优先使用 OpenClaw token,无需额外登录。 ## 流式响应关键事件 | 事件 type | 含义 | 处理 | |-----------|---------------|---------------| | `response.created` | 开始生成 | 记录 response_id | | `response.output_item.done` + `image_generation_call` | 图片生成完成 | 提取 base64,保存 PNG | | `response.completed` | 生成结束 | 退出循环 | | `error` / `response.failed` | 生成失败 | 打印错误信息 | | `data: [DONE]` | 流结束 | 退出循环 | # 完整技术文档 ## 逆向工程过程 ### 背景 OpenClaw 支持通过浏览器 OAuth 登录 ChatGPT,使用 `gpt-image-2` 免费生成图片。token 存储在本地文件,复用该 token 即可绕过 API Key 直接调用。 ### 逆向步骤 ``` 步骤 1 / Step 1: 找到 OpenClaw 的 token 存储 / Find OpenClaw token storage ~/.openclaw/agents/main/agent/auth-profiles.json 步骤 2 / Step 2: 分析 token 数据结构 / Analyze token data structure - access_token: OAuth access token - refresh_token: 用于刷新 / Used to refresh - expires: 过期时间(毫秒时间戳)/ expiration (millisecond timestamp) - provider: "openai-codex" 步骤 3 / Step 3: 抓取 OpenClaw 的网络请求 / Capture OpenClaw network requests - 通过 openclaw infer image generate 命令 / via openclaw infer image generate - 分析 HTTP 请求头、请求体、响应格式 / analyze HTTP headers, body, response format 步骤 4 / Step 4: 提取关键信息 / Extract key info - Auth Base: https://auth.openai.com - Client ID: app_EMoamEEZ73f0CkXaXp7hrann - Redirect: http://localhost:1455/auth/callback - Codex API: https://chatgpt.com/backend-api/codex/responses - Scope: openid profile email offline_access ``` ### 逆向结果汇总 | 组件 | 值 | |-----------------|-----------| | Client ID | `app_EMoamEEZ73f0CkXaXp7hrann` | | Auth Base | `https://auth.openai.com` | | Token Endpoint | `https://auth.openai.com/oauth/token` | | Authorize Endpoint | `https://auth.openai.com/oauth/authorize` | | Codex API | `https://chatgpt.com/backend-api/codex/responses` | | 认证方式 | OAuth PKCE (Proof Key for Code Exchange) | ## 技术架构 ``` ┌─────────────────────────────────────────────────────────────────┐ │ 用户空间 / User Space │ │ ┌──────────────┐ ┌─────────────────┐ ┌──────────────┐ │ │ │ 浏览器 │◄──►│ 本地 HTTP Server │◄──►│ OAuth 授权页 │ │ │ │ (手动操作) │ │ (localhost:1455) │ │ auth.openai │ │ │ └──────────────┘ └─────────────────┘ └──────────────┘ │ │ ▲ │ │ ┌──────────────┐ │ ┌────────────────┐ │ │ │ chatgpt_ │───────────┘ │ OpenClaw │ │ │ │ image.py │◄─────────────────────────│ auth-profiles │ │ │ │ (本工具) │ 读取/写入 token │ .json │ │ │ └──────────────┘ └────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ ChatGPT API 空间 / ChatGPT API Space │ │ ┌───────────────────────┐ ┌──────────────────────────────┐ │ │ │ POST /oauth/token │ │ POST /backend-api/ │ │ │ │ (换取 token) │ │ codex/responses (生成图片) │ │ │ └───────────────────────┘ └──────────────────────────────┘ │ └─────────────────────────────────────────────────────────────────┘ ``` ## PKCE OAuth 详细流程 ### 流程图 ``` Client (本工具) Auth Server Browser │ │ 1. 生成 code_verifier (64字节随机 / 64-byte random) │ 2. 计算 code_challenge = BASE64URL(SHA256(verifier)) │ 3. 启动本地 HTTP Server (localhost:1455) │ │ 4. 构造授权 URL,打开浏览器 ──────────────────────────► │ ?response_type=code │ &client_id=app_EMoamEEZ73f0CkXaXp7hrann │ &redirect_uri=http://localhost:1455/auth/callback │ &scope=openid profile email offline_access │ &code_challenge=xxx │ &code_challenge_method=S256 │ &state=随机防CSRF / random CSRF protection │ │ ◄──────────────────── 5. 显示登录页 / Show login page │ ◄──────────────────── 6. 用户授权 / User authorizes │ │ 7. 浏览器重定向 / Browser redirects │ localhost:1455/auth/callback?code=xxx&state=yyy │◄────────────────────────────────────────────────────────────── │ │ 8. POST /oauth/token (用 code + code_verifier 换 token) │─────────────────────────────────────────────────────────────► │ │ 9. 收到 access_token + refresh_token + expires_in ◄──────── │ │ 10. 保存到 ~/.chatgpt_image_tokens.json ``` ### code_verifier 和 code_challenge 生成 ``` import base64 import hashlib import secrets # code_verifier: 64字节随机字符串 / 64-byte random string code_verifier = secrets.token_urlsafe(64) # code_challenge: SHA256 → Base64URL(去掉 padding / remove padding) code_challenge = base64.urlsafe_b64encode( hashlib.sha256(code_verifier.encode()).digest() ).decode().rstrip("=") ``` ### 授权 URL 参数 ``` params = { "response_type": "code", "client_id": "app_EMoamEEZ73f0CkXaXp7hrann", "redirect_uri": "http://localhost:1455/auth/callback", "scope": "openid profile email offline_access", "code_challenge": code_challenge, # 上面计算的值 "code_challenge_method": "S256", # 固定 / fixed "state": secrets.token_hex(16), # 防 CSRF / CSRF protection "id_token_add_organizations": "true", "codex_cli_simplified_flow": "true", "originator": "chatgpt-image-cli", } auth_url = f"https://auth.openai.com/oauth/authorize?{urllib.parse.urlencode(params)}" ``` ### Token 交换请求 ``` # POST https://auth.openai.com/oauth/token data = { "grant_type": "authorization_code", "client_id": "app_EMoamEEZ73f0CkXaXp7hrann", "code": authorization_code, "code_verifier": code_verifier, "redirect_uri": "http://localhost:1455/auth/callback", } # 响应 / Response { "access_token": "eyJhbGc...", "refresh_token": "rt_aaM74...", "expires_in": 3600, "token_type": "Bearer" } ``` ## API 调用详解 ### 请求 ``` POST https://chatgpt.com/backend-api/codex/responses Authorization: Bearer Content-Type: application/json Accept: text/event-stream ``` ### 请求体 ``` { "model": "gpt-5.5", "input": [{ "role": "user", "content": [ {"type": "input_text", "text": "一只可爱的橘猫 / A cute orange cat"} ] }], "instructions": "You are an image generation assistant.", "tools": [{"type": "image_generation"}], "store": false, "stream": true } ``` | 字段 | 说明 | |-------------|-------------------| | `model` | 内部名,映射到 `gpt-image-2` | | `input[].content[].text` | 图片描述 prompt | | `tools[].type` | 固定 `image_generation` 触发生成 | | `stream` | `true` = SSE 流式响应 | ### SSE 响应解析 ``` for line in resp: # resp 是 HTTP 响应流 / resp is HTTP stream line = line.decode("utf-8").strip() if not line.startswith("data: "): continue event = json.loads(line[6:]) # 去掉 "data: " 前缀 / remove "data: " prefix # 图片生成完成 / Image generation done if event.get("type") == "response.output_item.done": item = event.get("item", {}) if item.get("type") == "image_generation_call": image_base64 = item.get("result") image_bytes = base64.b64decode(image_base64) with open("output.png", "wb") as f: f.write(image_bytes) # 完成信号 / Completion signal if event.get("type") == "response.completed": break ``` ## Token 管理 ### Token 数据结构 ``` @dataclass class TokenData: access_token: str # 调用 API 用 / for API calls refresh_token: str # 过期时刷新用 / for refresh when expired expires_at: float # Unix 时间戳(秒)/ Unix timestamp (seconds) ``` ### 验证逻辑 ``` def is_token_valid(tokens: TokenData) -> bool: # 提前 60 秒判定过期 / Consider expired 60 seconds early return time.time() < (tokens.expires_at - 60) ``` ### 刷新流程 ``` Token 过期 → 用 refresh_token 换新 access_token → 更新 token 文件 → 重试 API 调用 ``` ### OpenClaw Token 格式 ``` { "profiles": { "openai-codex:邮箱@gmail.com": { "type": "oauth", "provider": "openai-codex", "access": "eyJhbGc...", "refresh": "rt_aaM74...", "expires": 1778338608095, // 毫秒时间戳 / millisecond timestamp "email": "邮箱@gmail.com" } } } ``` ## 项目文件结构 ``` chatgpt-image-cli/ ├── chatgpt_image.py # 主脚本(人类和 AI 共同使用)/ Main script (for human and AI) ├── skill/ │ └── SKILL.md # AI Agent Skill 文档 / AI Agent Skill documentation └── README.md # 本文档 / This document ``` ## 许可证 MIT
标签:AIGC, AI绘画, API数据流, ChatGPT, ChatGPT Plus, GPT-Image-2, IP 地址批量处理, OAuth认证, OpenAI, Promptflow, Python, 二进制发布, 云资产清单, 免API Key, 免费资源, 内存规避, 图片生成, 开源工具, 无后门, 浏览器自动化, 白嫖, 绕过API限制, 网络安全, 脚本, 逆向工具, 逆向工程, 隐私保护