akashyadav758 Claude Opus 4.8 (1M context) commited on
Commit
8ea09fa
Β·
1 Parent(s): 4a66c44

Add HOWTOUSE.md and docs/ for fast, error-free new setup

Browse files

HOWTOUSE.md: per-service API endpoints + correct payloads + curl examples (key as
placeholder, never the real value). docs/: architecture, persistence, api-gateway,
deployment, troubleshooting β€” documents everything added on top of the base image so a
fresh HF or Docker deploy doesn't hit the errors we already solved.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

HOWTOUSE.md ADDED
@@ -0,0 +1,93 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # How to use the API
2
+
3
+ One base URL fronts all three services. Every `/gpt`, `/gemini`, `/flow` call needs the
4
+ `API_KEY` as a Bearer token. The monitor UI (`/`) needs no key.
5
+
6
+ - **Base URL:** `https://akash1313-selfapi.hf.space`
7
+ - **Auth header:** `Authorization: Bearer YOUR_API_KEY` *(your real key is in the gitignored `./api-key`)*
8
+
9
+ > ⚠️ **You must be logged in** to ChatGPT / Gemini / Flow inside the browser
10
+ > (`https://akash1313-selfapi.hf.space/`) for real responses. The servers reply even when
11
+ > logged out, but with `extensionConnected:false` / empty data. Check first:
12
+ > ```bash
13
+ > curl -H "Authorization: Bearer YOUR_API_KEY" https://akash1313-selfapi.hf.space/gpt/health
14
+ > ```
15
+ > `extensionConnected:true` = ready.
16
+
17
+ ---
18
+
19
+ ## ChatGPT β€” `/gpt`
20
+
21
+ | Endpoint | Method | Body |
22
+ |----------|--------|------|
23
+ | `/gpt/health` | GET | β€” |
24
+ | `/gpt/api/chat` | POST | `{"prompt": "...", "wait_for_response": true}` |
25
+ | `/gpt/api/chat/bulk` | POST | `{"prompts": ["...","..."], "delay_seconds": 2}` |
26
+ | `/gpt/v1/chat/completions` | POST | OpenAI-compatible (see below) |
27
+
28
+ ```bash
29
+ # Simple chat
30
+ curl -X POST https://akash1313-selfapi.hf.space/gpt/api/chat \
31
+ -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
32
+ -d '{"prompt":"Write a haiku about the sea","wait_for_response":true}'
33
+
34
+ # OpenAI-compatible (drop-in for OpenAI SDKs β€” set base_url=.../gpt/v1)
35
+ curl -X POST https://akash1313-selfapi.hf.space/gpt/v1/chat/completions \
36
+ -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
37
+ -d '{"model":"gpt-5","messages":[{"role":"user","content":"hello"}],"stream":false}'
38
+ ```
39
+ Optional fields: `"model"`, `"thinking_effort"`, `"conversation_id"` (continue a thread).
40
+
41
+ ---
42
+
43
+ ## Gemini β€” `/gemini` (form-encoded, not JSON)
44
+
45
+ | Endpoint | Method | Body |
46
+ |----------|--------|------|
47
+ | `/gemini/status` | GET | β€” |
48
+ | `/gemini/chat` | POST (form) | `prompt`, `user_id`, `new_chat`, `stream` |
49
+ | `/gemini/music` | POST (form) | `prompt` |
50
+ | `/gemini/reset` | POST | β€” |
51
+ | `/gemini/output/<file>` | GET | β€” (generated media) |
52
+
53
+ ```bash
54
+ curl -X POST https://akash1313-selfapi.hf.space/gemini/chat \
55
+ -H "Authorization: Bearer YOUR_API_KEY" \
56
+ -d "prompt=Explain quantum entanglement simply&new_chat=true"
57
+ ```
58
+
59
+ ---
60
+
61
+ ## Flow (video / image) β€” `/flow` (JSON)
62
+
63
+ | Endpoint | Method | Body |
64
+ |----------|--------|------|
65
+ | `/flow/health` | GET | β€” |
66
+ | `/flow/generate/video` | POST | `{"prompt":"...","aspect":"portrait","duration":10,"count":1}` |
67
+ | `/flow/generate/image` | POST | `{"prompt":"...","aspect":"portrait","count":1}` |
68
+ | `/flow/upload/image` Β· `/flow/upload/video` | POST | multipart file |
69
+ | `/flow/download/<filename>` | GET | β€” |
70
+
71
+ ```bash
72
+ # Text-to-video (aspect: portrait|landscape ; duration: 4,6,8,10)
73
+ curl -X POST https://akash1313-selfapi.hf.space/flow/generate/video \
74
+ -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
75
+ -d '{"prompt":"a cat surfing a wave, cinematic","aspect":"landscape","duration":8}'
76
+
77
+ # Text-to-image
78
+ curl -X POST https://akash1313-selfapi.hf.space/flow/generate/image \
79
+ -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" \
80
+ -d '{"prompt":"neon city at night","aspect":"square"}'
81
+ ```
82
+
83
+ ---
84
+
85
+ ## Auth errors
86
+
87
+ | Code | Meaning |
88
+ |------|---------|
89
+ | `401` | Missing/wrong key |
90
+ | `503` | `API_KEY` not set on the server (gateway disabled, fail-closed) |
91
+ | `502` | Backend server not reachable (still booting / crashed β€” check `/chrome.log`) |
92
+
93
+ Rotate the key anytime: change the `API_KEY` secret in the Space settings (auto-restarts).
docs/README.md ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # docs/ β€” what's new & how to set it up fast
2
+
3
+ Reference for everything added on top of the base Chrome Space, so a fresh deploy (HF **or**
4
+ Docker) goes quick and error-free. Read in order:
5
+
6
+ | File | Covers |
7
+ |------|--------|
8
+ | [architecture.md](architecture.md) | One container: Chrome + extensions + monitor/gateway + 3 servers. Ports. |
9
+ | [persistence.md](persistence.md) | Staying logged in: Neon Postgres (HF) vs Docker volume (self-host). |
10
+ | [api-gateway.md](api-gateway.md) | The single gateway, `/gpt /gemini /flow` routing, `API_KEY` auth. |
11
+ | [deployment.md](deployment.md) | Deploy steps, required secrets, HF tokens, Docker build stages. |
12
+ | [troubleshooting.md](troubleshooting.md) | Every error we hit and its fix. **Check here first.** |
13
+
14
+ For **calling** the API see [`../HOWTOUSE.md`](../HOWTOUSE.md). For a quick start see
15
+ [`../SETUP.md`](../SETUP.md).
16
+
17
+ ## Required secrets (set these or things silently break)
18
+
19
+ | Secret | Where | Without it |
20
+ |--------|-------|-----------|
21
+ | `DATABASE_URL` | HF only (Neon Postgres) | Logins lost on every restart |
22
+ | `API_KEY` | HF + Docker `.env` | All `/gpt /gemini /flow` return `503` |
23
+
24
+ Local credential notes live in gitignored files: `hf-token`, `neon-db`, `api-key`.
docs/api-gateway.md ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # API gateway
2
+
3
+ The `monitor` Go binary (port 3001) is also a reverse-proxy gateway. HF exposes only one public
4
+ port, so all three backend APIs are reached under one base URL by path prefix.
5
+
6
+ ## Routing (`monitor/main.go`)
7
+
8
+ | Public prefix | β†’ forwards to | Prefix stripped |
9
+ |---------------|---------------|-----------------|
10
+ | `/gpt/…` | `127.0.0.1:9225` | `/gpt/api/chat` β†’ `/api/chat` |
11
+ | `/gemini/…` | `127.0.0.1:8000` | `/gemini/chat` β†’ `/chat` |
12
+ | `/flow/…` | `127.0.0.1:8101` | `/flow/generate/video` β†’ `/generate/video` |
13
+
14
+ `gatewayHandler(prefix, target)` builds one `httputil.ReverseProxy` whose `Director` rewrites the
15
+ host and strips the prefix. The monitor's own routes (`/`, `/api/*`, `/chrome.log`) are untouched.
16
+
17
+ ## Auth β€” `API_KEY` (fail-closed)
18
+
19
+ `authOK()` gates the three prefixes:
20
+ - Reads `API_KEY` from env once at startup.
21
+ - Requires `Authorization: Bearer <API_KEY>` (also accepts `?key=`).
22
+ - **Unset `API_KEY` β†’ every gateway call returns `503`** (so accounts are never accidentally open).
23
+ - Wrong/missing key β†’ `401`.
24
+ - The monitor UI stays open (no key) so the live view keeps working.
25
+
26
+ Set it: HF secret `API_KEY` (Settings) or Docker `.env` `API_KEY=…`. Use a long random string,
27
+ e.g. `openssl rand -hex 24`.
28
+
29
+ ## Why not a separate Space for the servers?
30
+ The extensions dial `ws://127.0.0.1:9225/9226/9227` β€” hardcoded localhost
31
+ (`*/background.js`). A second Space is a different machine with a different `127.0.0.1`, so its
32
+ servers could never receive the extension connections. Hence: one container, gateway out front.
33
+
34
+ ## Adding a new route
35
+ 1. Server listens on a new localhost port inside the container.
36
+ 2. Launch it in `start_hf.sh` (step 6a).
37
+ 3. Add `http.HandleFunc("/x/", gatewayHandler("/x", "http://127.0.0.1:PORT"))` in `monitor/main.go`.
docs/architecture.md ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Architecture β€” one container, everything inside
2
+
3
+ Everything runs in **one container** built from the root `Dockerfile`. The extensions inside
4
+ Chrome dial their servers on hardcoded `127.0.0.1` ports, so the servers **must** share Chrome's
5
+ localhost β€” a separate machine/Space can never reach them. That's why there's a single image, not
6
+ microservices.
7
+
8
+ ```
9
+ https://…hf.space (only port 3001 is public)
10
+ β”‚
11
+ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”
12
+ β”‚ monitor :3001 β”‚ UI + API gateway (one Go binary)
13
+ β”‚ / /chrome.log β”‚ (open, no key)
14
+ β”‚ /gpt /gemini /flowβ”‚ (API-key gated β†’ localhost)
15
+ β””β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”˜
16
+ 9225 β”€β”€β”€β”˜ 8000β”‚ └─── 8101
17
+ (chatgpt) (gemini) (flow)
18
+ β”‚ β”‚ β”‚
19
+ ws 9225 ws 9226 ws 9227 ◄── extensions dial in (localhost)
20
+ └──────── Chrome (headless) + 3 unpacked extensions β”€β”€β”€β”€β”€β”€β”€β”€β”˜
21
+ CDP 9222 Β· socat proxy 9223 Β· profile in /home/chrome/data
22
+ ```
23
+
24
+ ## Port map (all on the container's 127.0.0.1)
25
+
26
+ | Port | Who | Purpose |
27
+ |------|-----|---------|
28
+ | 3001 | monitor | UI + API gateway (**only published port**) |
29
+ | 9222 | Chrome | DevTools Protocol (CDP) |
30
+ | 9223 | socat | CDP proxied for external tools |
31
+ | 9225 | chatgpt server | HTTP API **and** extension WS (same port) |
32
+ | 8000 / 9226 | gemini server | HTTP API / extension cookie-WS |
33
+ | 8101 / 8100 / 9227 | flow server | HTTP API / ext-callback / extension WS |
34
+
35
+ ## What starts it
36
+ `start_hf.sh` (the container entrypoint) in order: restore profile from Postgres β†’ clean profile β†’
37
+ start monitor (3001) β†’ CDP proxy β†’ **start the 3 backend servers** (step 6a) β†’ launch Chrome with
38
+ the 3 extensions. Each server logs to `/home/chrome/{chatgpt,gemini,flow}.log`.
39
+
40
+ ## Components added on top of the base image
41
+ - `monitor/` β€” Go UI, now also the **reverse-proxy gateway** (`gatewayHandler`, `authOK`).
42
+ - `profilesync/` β€” Go tool, Chrome profile ⇄ Postgres snapshot.
43
+ - `chatgpt-free-api/`, `free-gemini-api/` (Go) + `flow-agent/` (Python/FastAPI) β€” the 3 servers,
44
+ built/installed into the image by the `Dockerfile`.
docs/deployment.md ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Deployment
2
+
3
+ ## Hugging Face (this repo == the Space)
4
+
5
+ 1. **Push** to `main` β†’ HF auto-rebuilds:
6
+ ```bash
7
+ git push origin main
8
+ ```
9
+ 2. **Set secrets** once (Settings β†’ Variables and secrets):
10
+ - `DATABASE_URL` β€” Neon Postgres (persistence). See [persistence.md](persistence.md).
11
+ - `API_KEY` β€” gateway auth. See [api-gateway.md](api-gateway.md).
12
+ 3. After build β†’ **log in** to ChatGPT/Gemini/Flow in the monitor UI once.
13
+
14
+ ### HF git auth (important)
15
+ The `origin` remote embeds a token: `https://<user>:<hf_token>@huggingface.co/spaces/<user>/<space>`.
16
+ - The token **must belong to the Space owner** (`akash1313`) with `repo.write`. A token from a
17
+ different account β†’ `pre-receive hook declined: You are not authorized to push`.
18
+ - Rotate/replace the token in the URL with:
19
+ `git remote set-url origin https://akash1313:<NEW_TOKEN>@huggingface.co/spaces/akash1313/selfapi`
20
+ - Local token files (`hf-token`, `neon-db`, `api-key`) are gitignored β€” never commit them.
21
+
22
+ ### Watch the build
23
+ ```bash
24
+ curl -s -H "Authorization: Bearer <hf_token>" \
25
+ https://huggingface.co/api/spaces/akash1313/selfapi/runtime
26
+ # stage: RUNNING_BUILDING β†’ RUNNING_APP_STARTING β†’ RUNNING (errors: BUILD_ERROR / RUNTIME_ERROR)
27
+ ```
28
+
29
+ ## Self-host Docker
30
+ ```bash
31
+ echo "API_KEY=$(openssl rand -hex 24)" > .env # gateway auth (DATABASE_URL not needed)
32
+ docker compose up --build -d
33
+ ```
34
+ Only the `chrome` service exists β€” it bakes in all 3 servers. Open `http://localhost:3001`.
35
+
36
+ ## Dockerfile build stages (what gets built)
37
+ | Stage | Image | Output |
38
+ |-------|-------|--------|
39
+ | `monitor-build` | golang:1.22 | `/monitor` (UI + gateway) |
40
+ | `profilesync-build` | golang:1.22 | `/profilesync` |
41
+ | `chatgpt-build` | golang:1.26 | `/agent` (+ `config.json`) |
42
+ | `gemini-build` | golang:1.26 | `/free-gemini-api` |
43
+ | final (on `akashyadav758/chrome`) | β€” | copies binaries, `pip install` flow deps, installs Chrome-for-Testing, perms |
44
+
45
+ > If you bump a server's `go.mod` Go version, bump its build-stage image too, or the build pulls a
46
+ > toolchain at build time.
docs/persistence.md ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Persistence β€” staying logged in
2
+
3
+ The Chrome profile (cookies/logins) lives in `/home/chrome/data`. How it survives a restart
4
+ depends on where you run.
5
+
6
+ ## Hugging Face β†’ Neon Postgres (required)
7
+
8
+ HF free `cpu-basic` Spaces have **no persistent disk** β€” the filesystem is wiped on every
9
+ restart/rebuild. So the profile is snapshotted to an external Postgres DB by the `profilesync` tool:
10
+
11
+ - **Boot:** `profilesync restore` pulls the last snapshot.
12
+ - **Every 5 min + on shutdown:** `profilesync backup` saves it.
13
+ - Stored as one row: `chrome_profile(id, updated_at, data bytea)` (auto-created).
14
+ - **Gated on `DATABASE_URL`.** Not set β†’ restore/backup skipped β†’ logins lost on restart.
15
+
16
+ ### Setup
17
+ 1. Free DB at [neon.tech](https://neon.tech) β†’ copy the connection string
18
+ (`postgresql://user:pass@host.neon.tech/db?sslmode=require`).
19
+ 2. HF Space β†’ Settings β†’ Variables and secrets β†’ secret **`DATABASE_URL`** = that string.
20
+ 3. Saving auto-restarts the Space. **Log in once** after that β†’ first backup within 5 min β†’ survives
21
+ all future restarts.
22
+
23
+ ### Verify a backup landed
24
+ ```sql
25
+ SELECT id, updated_at, octet_length(data) FROM chrome_profile;
26
+ ```
27
+ A row with non-zero size = persisted. (Profile stays small β€” junk/cache is stripped each boot;
28
+ typically 0.5–2 MB. Neon free = 512 MB, so it's ~0.1% used.)
29
+
30
+ ## Self-host Docker β†’ named volume (no DB needed)
31
+
32
+ `docker-compose.yml` mounts the `chrome-profile` named volume at `/home/chrome/data`, so logins
33
+ survive `docker compose down/up` and reboots automatically. **`DATABASE_URL` is not needed** for
34
+ Docker. To wipe the profile: `docker compose down -v`.
35
+
36
+ > Important: setting a new secret on HF forces a restart. If you log in *before* `DATABASE_URL` is
37
+ > set, that login is lost on the restart the secret triggers β€” log in again afterward.
docs/troubleshooting.md ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Troubleshooting β€” check here first
2
+
3
+ Every issue we actually hit, and the fix.
4
+
5
+ ## Deploy / build
6
+
7
+ | Symptom | Cause β†’ Fix |
8
+ |---------|-------------|
9
+ | `pre-receive hook declined: You are not authorized to push` | The token in the `origin` URL isn't the Space owner's. Use an `akash1313` token with `repo.write` (see [deployment.md](deployment.md)). |
10
+ | `Repository not found` on push | Remote points to a Space that doesn't exist. `git remote -v` and fix the name (we deploy to `akash1313/selfapi`). |
11
+ | Build `BUILD_ERROR` after bumping a server | `go.mod` Go version > build-stage image. Raise the `FROM golang:X` in the Dockerfile. |
12
+ | Python `externally-managed-environment` during pip | Debian 12 PEP-668. We use `pip3 install --break-system-packages` (already in Dockerfile). |
13
+ | Frequent restarts | Normal: **every `git push` and every secret change rebuilds.** Batch edits into one push. Not a CPU/RAM issue (cpu-basic = 2 vCPU / 16 GB; usage ~1–2 GB). |
14
+
15
+ ## API gateway
16
+
17
+ | Symptom | Cause β†’ Fix |
18
+ |---------|-------------|
19
+ | All `/gpt /gemini /flow` return `503` | `API_KEY` not set on the server. Set the secret (fail-closed by design). |
20
+ | `401` | Missing/wrong `Authorization: Bearer <key>`. |
21
+ | `502 backend unavailable` | That server is still booting or crashed. Check its log `/home/chrome/{chatgpt,gemini,flow}.log`. |
22
+ | `404` through the gateway | Path forwarded but wrong on the backend β€” check the route in [../HOWTOUSE.md](../HOWTOUSE.md). |
23
+
24
+ ## Runtime / browser
25
+
26
+ | Symptom | Cause β†’ Fix |
27
+ |---------|-------------|
28
+ | Login lost after restart | `DATABASE_URL` unset or DB unreachable (HF). Set the Neon secret; verify a row in `chrome_profile`. |
29
+ | ChatGPT Cloudflare "verify you are human" loops | UA/OS mismatch. The UA **must be Linux** (the Space runs Linux) β€” it's set in `start_hf.sh` and `chatgpt-free-api/cookies.go` (Chrome 145). If it still loops, it's the datacenter IP (HF=AWS) β†’ use a residential `--proxy-server`. |
30
+ | `extensionConnected:false` / `has_flow_key:false` on `/…/health` | The in-Chrome extension hasn't connected to its server yet. It connects when (a) Chrome has loaded the extension and (b) **you're logged in** to that service. Open the monitor UI, log in, wait. Extensions auto-retry (~5 s reconnect alarm). |
31
+ | `chrome://extensions/` empty, no error | Branded Chrome ignoring `--load-extension` β†’ must use Chrome for Testing (already in Dockerfile). |
32
+ | `Failed to connect to the bus` / `DidStartWorkerFail` in `chrome.log` | Harmless container warnings β€” not a crash. |
33
+ | "Restore pages?" popup | Handled by the `exit_type=Normal` Preferences injection in `start_hf.sh`. |
34
+
35
+ ## Self-host Docker
36
+
37
+ | Symptom | Cause β†’ Fix |
38
+ |---------|-------------|
39
+ | Port collision on 9225/8000/8101 | Don't add separate server containers β€” the `chrome` image already runs all 3. `docker-compose.yml` has only the `chrome` service by design. |
40
+ | APIs return `503` locally | Add `API_KEY=…` to `.env` (compose passes it to the chrome service). |
41
+ | Profile not persisting | Don't use `down -v` (that deletes the `chrome-profile` volume). |