autoreg-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
@@ -0,0 +1,99 @@
|
||||
# ChatGPT DALL-E Image Generation API Pattern (2026-07-30)
|
||||
|
||||
## Auth: Cookie-only, NO Bearer token
|
||||
|
||||
ChatGPT web auth is **cookie-based**, not Bearer token. The session token from DB works as a cookie:
|
||||
|
||||
```python
|
||||
headers = {
|
||||
"Content-Type": "application/json",
|
||||
"User-Agent": "Mozilla/5.0 ... Chrome/[REDACTED-IP] Safari/537.36",
|
||||
"Origin": "https://chatgpt.com",
|
||||
"Referer": "https://chatgpt.com/",
|
||||
"Accept": "text/event-stream",
|
||||
}
|
||||
if csrf_token:
|
||||
headers["X-CSRF-Token"] = csrf_token.split("|")[0] # Before the pipe
|
||||
|
||||
cookies = {
|
||||
"__Secure-next-auth.session-token": session_token,
|
||||
}
|
||||
if csrf_token:
|
||||
cookies["__Host-next-auth.csrf-token"] = csrf_token
|
||||
```
|
||||
|
||||
**Do NOT** use `Authorization: Bearer ...` — returns 403.
|
||||
|
||||
## CSRF Token Format
|
||||
|
||||
CSRF token from DB: `bad91657060abdd7517223227f1a51...%7C2a80b3e7...`
|
||||
|
||||
- For header `X-CSRF-Token`: use the part BEFORE `%7C` (or `|`)
|
||||
- For cookie `__Host-next-auth.csrf-token`: use the FULL value
|
||||
|
||||
## Endpoint: SSE Streaming
|
||||
|
||||
```python
|
||||
POST https://chatgpt.com/backend-api/conversation
|
||||
Body: {
|
||||
"action": "next",
|
||||
"messages": [{
|
||||
"id": "<uuid>",
|
||||
"author": {"role": "user"},
|
||||
"content": {"content_type": "text", "parts": ["Generate an image: {prompt}"]}
|
||||
}],
|
||||
"model": "auto",
|
||||
"parent_message_id": "<uuid>",
|
||||
"conversation_id": None,
|
||||
"history_and_training_disabled": False,
|
||||
"timezone_offset_min": 180,
|
||||
}
|
||||
```
|
||||
|
||||
The response is **SSE (text/event-stream)**, NOT JSON. Parse as:
|
||||
|
||||
```python
|
||||
for line in resp.text.split('\n'):
|
||||
if line.startswith('data: '):
|
||||
data_str = line[6:]
|
||||
if data_str == '[DONE]':
|
||||
break
|
||||
data = json.loads(data_str)
|
||||
# Image URLs appear as markdown  in message parts
|
||||
```
|
||||
|
||||
## Extracting Image URLs from SSE
|
||||
|
||||
3 extraction methods, tried in order:
|
||||
|
||||
1. **Parse SSE lines** → message.content.parts → regex for `` and raw image URLs
|
||||
2. **Full-text regex** over entire response: `r'!\[.*?\]\((https?://[^\)]+)\)'`
|
||||
3. **Domain search**: `r'https?://(?:oaistatic|files\.oaiusercontent)\.com[^\s<>"\']+'`
|
||||
|
||||
## Rate Limits & Token Expiry
|
||||
|
||||
- Session tokens from `__Secure-next-auth.session-token` expire in ~1 week
|
||||
- Free plan accounts may NOT have DALL-E access (returns text responses, not images)
|
||||
- 429 rate limit = 1-2 minute cooldown between requests
|
||||
- Each image generation burns credits on paid plans
|
||||
|
||||
## Round-Robin Pattern
|
||||
|
||||
```python
|
||||
_account_idx = 0
|
||||
_lock = asyncio.Lock()
|
||||
|
||||
async def _get_next_account() -> tuple[dict, int]:
|
||||
global _account_idx
|
||||
async with _lock:
|
||||
idx = _account_idx % len(ACCOUNTS)
|
||||
_account_idx += 1
|
||||
return ACCOUNTS[idx], idx
|
||||
```
|
||||
|
||||
## Full Implementation
|
||||
|
||||
See `C:/Users/User/Desktop/GPT-AUTOREG/image_api_server.py` — FastAPI server on `:8400` with:
|
||||
- `GET /health` — account count + status
|
||||
- `GET /accounts` — list accounts with index + token status
|
||||
- `POST /generate` — `{"prompt": "...", "account_index": null}` → `{"success": bool, "images": [...], "account_used": "...", "error": "..."}`
|
||||
Reference in New Issue
Block a user