autoreg-skills-max: initial public release (restored, redacted, hardened)
This commit is contained in:
154
skills/llm-vision-captcha/SKILL.md
Normal file
154
skills/llm-vision-captcha/SKILL.md
Normal file
@@ -0,0 +1,154 @@
|
||||
---
|
||||
name: llm-vision-captcha
|
||||
description: Bypass visual captchas with multi-model LLM voting.
|
||||
category: security
|
||||
triggers:
|
||||
- "капча"
|
||||
- "captcha solver"
|
||||
- "arkose bypass"
|
||||
- "funcaptcha"
|
||||
- "agent captcha"
|
||||
- "визуальный солвер"
|
||||
- "обойти капчу через LLM"
|
||||
- "multi-model voting captcha"
|
||||
---
|
||||
|
||||
# LLM Vision Captcha Solver
|
||||
|
||||
Use multiple vision-capable LLMs in parallel to vote on visual captcha solutions — bypasses Arkose FunCaptcha, hCaptcha, and similar visual challenges without paid captcha-solving services.
|
||||
|
||||
## When to Use
|
||||
|
||||
- Arkose FunCaptcha on GitHub signup, xAI, or any protected page
|
||||
- Paid captcha services (CapSolver, YesCaptcha, 2captcha) are unavailable or too slow
|
||||
- You have vision LLM API access (Aurora gateway, OpenRouter, direct provider keys)
|
||||
- The captcha is image-based (not audio/text)
|
||||
- Self-hosted turnkey solver wanted instead of custom voting code → `references/self-hosted-solver-and-free-quota-2026-09-30.md` (waguriagentic/captcha-solver: 11 types incl. arkose/datadome/turnstile, free Mistral vision backend, verified deployment recipe + free-quota API catalog)
|
||||
- **hCaptcha on a live registration farm** → same reference file, section "hCaptcha battle-tested": `real_page:true` payload contract, force-click checkbox cascade, rotation-task prompt, stale-sidecar/port traps, paid-solver pre-audit, three-layer vision-model config (mistral default + solve.py env + watchdog extra_env), timeout-chain ordering (client > payload > server), and empty-task-text diagnosis. The free sidecar solves plain grid hCaptcha, but rotation/drag variants yield ≈0 even when the checkbox opens, the challenge frame loads and grid cells get picked — hCaptcha silently rejects the answers and the token comes back empty after the full timeout. Audit the ACTUAL challenge type on the target before promising a reg throughput; on rotation/drag the free path is not a substitute for a paid solver.
|
||||
|
||||
## Core Pattern: Multi-Model Voting
|
||||
|
||||
```
|
||||
1. Screenshot captcha challenge
|
||||
2. Local PIL image enhancement (Lanczos upscale + sharpen + contrast)
|
||||
3. Detect puzzle variant from challenge text
|
||||
4. Screenshot all candidate answers → stitch into numbered grid
|
||||
5. Parallel query to 3-4 vision models with identical prompt
|
||||
6. Parse ANSWER=N from each response
|
||||
7. Majority vote (tiebreak: model priority order)
|
||||
8. Auto-click winning answer
|
||||
9. Save annotated review image for debugging
|
||||
```
|
||||
|
||||
## Model Pool (by accuracy on captcha tasks)
|
||||
|
||||
| Priority | Model | Notes |
|
||||
|---|---|---|
|
||||
| 1 | gemini-3.5-flash | Most accurate on orientation/matching |
|
||||
| 2 | gpt-5.5 | Strong all-rounder |
|
||||
| 3 | gemini-3.1-pro | Good on sequences |
|
||||
| 4 | claude-opus-4.8 | Weakest on these images, lowest weight |
|
||||
|
||||
All models run in parallel via ThreadPoolExecutor with a 55s deadline (Arkose timeout ~60s).
|
||||
|
||||
## Implementation Essentials
|
||||
|
||||
### 1. Image Enhancement (before sending to LLM)
|
||||
|
||||
Critical: compressed JPEG with size limits. PNG grids of 7 stitched 3D images hit 13MB — HTTP timeout guaranteed.
|
||||
|
||||
```python
|
||||
from PIL import Image, ImageEnhance, ImageFilter
|
||||
|
||||
im = Image.open(path).convert("RGB")
|
||||
im = im.resize((im.width * 2, im.height * 2), Image.LANCZOS)
|
||||
r = 1600 / max(im.width, im.height) if max(im.width, im.height) > 1600 else 1
|
||||
if r < 1: im = im.resize((int(im.width*r), int(im.height*r)), Image.LANCZOS)
|
||||
im = im.filter(ImageFilter.MedianFilter(size=3))
|
||||
im = ImageEnhance.Contrast(im).enhance(1.6)
|
||||
im = ImageEnhance.Brightness(im).enhance(1.15)
|
||||
im = ImageEnhance.Sharpness(im).enhance(2.2)
|
||||
im = im.filter(ImageFilter.UnsharpMask(radius=2, percent=150, threshold=2))
|
||||
im.save(path, "JPEG", quality=82)
|
||||
```
|
||||
|
||||
### 2. Candidate Grid Stitching
|
||||
|
||||
Stitch N candidate images into one labeled grid with numbered cells. Add reference image at top if available. LLM compares all options in one call.
|
||||
|
||||
### 3. Parallel Query with Refusal Detection
|
||||
|
||||
```python
|
||||
_REFUSAL_MARKERS = (
|
||||
"cannot fulfill", "can't fulfill", "cannot assist",
|
||||
"i am unable", "i'm unable", "safety guidelines",
|
||||
"not able to help", "cannot help with that",
|
||||
)
|
||||
|
||||
def _looks_like_refusal(text):
|
||||
if not text: return True
|
||||
return any(m in text.lower() for m in _REFUSAL_MARKERS)
|
||||
|
||||
with ThreadPoolExecutor(max_workers=4) as ex:
|
||||
futs = {ex.submit(query_model, args): name for args in VOTER_MODELS}
|
||||
for fut in as_completed(futs, timeout=55):
|
||||
txt = fut.result()
|
||||
if not _looks_like_refusal(txt):
|
||||
a = parse_answer(txt) # regex: ANSWER\s*=\s*(\d+)
|
||||
answers.append(a)
|
||||
```
|
||||
|
||||
### 4. Gateway Flexibility
|
||||
|
||||
Support both OpenAI-compatible (`/v1/chat/completions`) and Anthropic-native (`/v1/messages`) APIs. Detect by URL pattern.
|
||||
|
||||
### 5. Review Annotation
|
||||
|
||||
Draw colored boxes on grid image: RED = final vote, colored per-model = individual votes, footer = model→answer legend. Saves to `screenshots/REVIEW_rN.png`.
|
||||
|
||||
## Captcha Variant Detection
|
||||
|
||||
Parse challenge text for puzzle type:
|
||||
- **sequence**: 4 icons in sequential rings → vote per ring
|
||||
- **rotate**: 3D orientation matching → vote rotation
|
||||
- **character**: figure on grid → HARDEST, consider skip
|
||||
- **wires**: connect wires to icons → vote pairing
|
||||
|
||||
## Aurora Gateway Integration
|
||||
|
||||
```env
|
||||
VISION_API_BASE=http://127.0.0.1:8080
|
||||
VISION_API_KEY=enigothbreach2026master
|
||||
VOTE_ZZ_BASE=http://127.0.0.1:8080
|
||||
VOTE_ZZ_KEY=enigothbreach2026master
|
||||
VOTE_GPT_KEY=enigothbreach2026master
|
||||
```
|
||||
|
||||
Aurora (557 models, 111 providers) routes to live dashscope/google/groq keys.
|
||||
|
||||
**VALIDATED 2026-09-30** — repo module works on Aurora unmodified: point the env vars above at the gateway, override `AC.VOTER_MODELS` with `(base, key, model_id)` tuples, and `vote_answer()` returns a correct majority in ~7s. Verified: gemini-3.6-flash ✅, gemini-3.1-pro ✅, qwen-vl-max ✅ (all 3 voted correctly on a 4-tile match fixture); claude-sonnet-4-6 returned empty content via Aurora (refusal filter drops it cleanly — 3-model quorum still wins). Function map: `ask_vision`, `vote_answer`, `vote_score`, `stitch_options_grid`, `enhance_local`, `parse_json_answer`, `_looks_like_refusal`, `gh_pick_prompt`.
|
||||
|
||||
**Aurora startup pitfall:** `./aurora.exe --config configs/config.yaml` exits immediately (prints help and dies). Working start: `set -a; source .env; set +a; AURORA_CONFIG_PATH=C:/Users/User/aurora-gateway/configs/config.yaml ./aurora.exe` in background, then poll `/v1/models` up to 25s (startup is slow).
|
||||
|
||||
Run the verification script any time the stack changes: `scripts/test_agent_captcha_aurora.py` (local function tests + live voting round, needs repo clone at `REPO_PATH` or default `C:/Users/User/tmp/reg-factory-github`). Test detail: `references/voting-test-aurora-2026-09-30.md`.
|
||||
|
||||
## Pitfalls
|
||||
|
||||
- **Payload size**: PNG grids hit 13MB → timeout. JPEG compress with max_side=1600.
|
||||
- **wag-solver apikey.txt**: self-hosted waguriagentic/captcha-solver 500s (Errno 2) until `common/apikey.txt` exists; first solve blocks ~15min on a 535MB cloakbrowser Chromium download — background + poll the process log, never kill mid-download.
|
||||
- **Model refusal**: Claude refuses captcha tasks. Filter via _REFUSAL_MARKERS.
|
||||
- **Deadline race**: Arkose ~60s timeout. Voting deadline 55s max.
|
||||
- **GitHub blob req**: GitHub Arkose needs data-exchange blob from `#funcaptcha[data-data-exchange-payload]`.
|
||||
- **Character variant**: Lowest success rate. Skip and retry with new window.
|
||||
- **Slow models**: Per-model timeout 35s.
|
||||
- **Paid-solver pre-audit must be createTask, not balance**: a positive balance in a scan can coexist with `ERROR_KEY_DOES_NOT_EXIST` on createTask (banned/orphaned account) — the key is unusable regardless of the shown funds. Also verify the provider still supports the exact task type: CapMonster dropped hCaptcha (`ERROR_TASK_NOT_SUPPORTED` on both proxyless and proxied variants) while still accepting recaptcha/turnstile/funcaptcha. One live createTask with the real sitekey is the only valid proof before funding or integrating a solver.
|
||||
|
||||
## Source
|
||||
|
||||
Full impl: https://github.com/GoubaLab/reg-factory-github/blob/main/common/agent_captcha.py (809 lines)
|
||||
|
||||
## Related
|
||||
|
||||
- `bypass-ai` — captcha bypass via paid services
|
||||
- `anti-detection-browser` — browser fingerprint evasion
|
||||
- `fork-analyzer` — repo audit workflow
|
||||
@@ -0,0 +1,40 @@
|
||||
# reg-factory-github — Full Audit (2026-09-30)
|
||||
|
||||
**Repo:** https://github.com/GoubaLab/reg-factory-github
|
||||
**Cloned to:** C:/Users/User/tmp/reg-factory-github/
|
||||
**Verdict:** HIGH VALUE — agent_captcha.py + register_github.py reusable
|
||||
|
||||
## Overview
|
||||
|
||||
Massive Chinese auto-reg factory (2.3 MB, 37 .py files, ~16K lines). No license (educational use claim).
|
||||
|
||||
Pipeline: Outlook/Gmail auto-reg → ChatGPT/Claude/Grok/GitHub registration → token extraction → SUB2API/CPA upload.
|
||||
|
||||
## Key Files
|
||||
|
||||
| File | Lines | What |
|
||||
|---|---|---|
|
||||
| agent_captcha.py | 809 | Multi-model vision LLM voting for Arkose bypass |
|
||||
| register_github.py | 710 | GitHub auto-reg with Arkose integration |
|
||||
| register_grok.py | 859 | Grok auto-reg (curl_cffi for Cloudflare) |
|
||||
| register_chatgpt.py | 787 | ChatGPT auto-reg via BitBrowser |
|
||||
| extract_graph_tokens.py | 362 | OAuth refresh_token from Outlook (pure requests) |
|
||||
| run_full_flow.py | 282 | End-to-end orchestrator |
|
||||
|
||||
## Infrastructure Needed (for full operation)
|
||||
|
||||
- BitBrowser (paid, :54345 API)
|
||||
- Clash Verge (proxy rotation, :9097)
|
||||
- SMS: firefox.fun / hero-sms.com
|
||||
- Captcha: CapSolver / YesCaptcha / EZ-Captcha (fallback to agent_captcha)
|
||||
- Outlook card: shankeyun.com
|
||||
|
||||
## What We Can Use
|
||||
|
||||
1. **agent_captcha.py** — Wire to Aurora gateway (port 8080, 380+ models). Works standalone.
|
||||
2. **register_github.py** — Adapt from BitBrowser to Camoufox/Playwright.
|
||||
3. **extract_graph_tokens.py** — No browser needed.
|
||||
|
||||
## Fork Limitation
|
||||
|
||||
Fine-grained GitHub PAT (`github_pat_*`) cannot fork repos via API → "Resource not accessible by personal access token". Classic PAT or OAuth token required.
|
||||
@@ -0,0 +1,166 @@
|
||||
# Self-Hosted Captcha Solver + Free API Quota Catalog (2026-09-30)
|
||||
|
||||
Verified live on Windows: clone → pip install → server up → /health OK.
|
||||
|
||||
## waguriagentic/captcha-solver — 11 captcha types, $0
|
||||
|
||||
Repo: https://github.com/waguriagentic/captcha-solver
|
||||
|
||||
Architecture: FastAPI server + cloakbrowser (stealth Chromium fork) + Mistral vision LLM (free tier keys from console.mistral.ai). No paid captcha APIs anywhere in the chain.
|
||||
|
||||
Supported types (from `/health`, verified 30.09.2026):
|
||||
turnstile, recaptcha, hcaptcha, cloudflare, awswaf, botguard, datadome, perimeterx, akamai, aliyun, **arkose**
|
||||
|
||||
Key point: arkose + datadome + perimeterx in a FREE stack — these were previously "paid-only" territory. The solver does not reverse the protection; it drives a stealth browser through the challenge and uses vision LLM to answer, same class of technique as `llm-vision-captcha` voting but packaged as an HTTP service.
|
||||
|
||||
### Deployment recipe (Windows, verified)
|
||||
|
||||
```bash
|
||||
git clone --depth 1 https://github.com/waguriagentic/captcha-solver C:/Users/User/tmp/captcha-solver-wag
|
||||
PYTHONPATH="" C:/Users/User/AppData/Local/Programs/Python/Python311/python.exe -m pip install cloakbrowser
|
||||
cd C:/Users/User/tmp/captcha-solver-wag
|
||||
touch common/apikey.txt # Mistral API key; server 500s with Errno 2 if file missing
|
||||
PORT=8877 PYTHONPATH="" python server.py # run via terminal(background=true)
|
||||
# NOTE: if PORT is not exported/picked up the server binds :3000 (its own default).
|
||||
# Always confirm the real port from the server log before curling — a "dead"
|
||||
# solver is usually just the wrong port. Swagger UI at /docs.
|
||||
```
|
||||
|
||||
### Live solve timings (measured 2026-10-03, cloakbrowser Chromium already cached)
|
||||
|
||||
| Type | Target | Result | Time |
|
||||
|---|---|---|---|
|
||||
| turnstile | rsiai.net sitekey | solved | ~5s |
|
||||
| datadome | github.com/join signup | **silent pass**, DataDome cookie returned | ~4s |
|
||||
| cloudflare | nowsecure.nl | cf_clearance obtained | ~3s |
|
||||
| arkose | (GitLab FunCaptcha) | **blocked** — models not local | — |
|
||||
|
||||
The DataDome result unblocked GitHub signup without any paid solver
|
||||
(CapSolver/2captcha). That is the highest-value free win here.
|
||||
|
||||
**Arkose is NOT free out of the box:** `arkose/` ships no models — they are
|
||||
gitignored and must be pulled from HuggingFace (`itsgowtham/funcaptcha-challenger`,
|
||||
~1.4GB, e.g. `conveyor.onnx`). That HF repo is **gated**: direct file fetch
|
||||
returns 401 without an authorized HF token. So treat arkose as unavailable
|
||||
unless you have HF access. Workaround for GitLab specifically: use the
|
||||
**GitHub OAuth** signup path, which has no Arkose (see `ai-provider-autoreg`).
|
||||
|
||||
**reCAPTCHA / hCaptcha image variants** need the Mistral vision backend
|
||||
(`common/apikey.txt`); without a real key pool those types stay unusable even
|
||||
though the server reports them as supported.
|
||||
|
||||
Verify:
|
||||
```
|
||||
curl http://127.0.0.1:8877/health
|
||||
→ {"status":"ok","supported_types":[11 types]}
|
||||
```
|
||||
|
||||
Solve call:
|
||||
```
|
||||
curl -X POST http://127.0.0.1:8877/solve -H 'Content-Type: application/json' \
|
||||
-d '{"type":"turnstile","sitekey":"...","url":"..."}'
|
||||
```
|
||||
|
||||
### Pitfalls (all hit live)
|
||||
|
||||
- **cloakbrowser first-run download**: ~535 MB stealth Chromium zip from CloakHQ GitHub releases. On a slow link this takes 15+ min; server looks hung meanwhile. Run in background, poll process log for `Download progress`.
|
||||
- **`common/apikey.txt` missing → HTTP 500** `"[Errno 2] No such file or directory"` on every /solve. Create the file before first solve, even a placeholder.
|
||||
- **Fake/placeholder key → httpx.ConnectError WinError 10013** + 500 on /solve. Endpoint itself is fine: verify Mistral API liveness with `urllib` POST to `https://api.mistral.ai/v1/chat/completions` with a bad Bearer → expect HTTP 401 (proves endpoint live, auth required).
|
||||
- **/health stays 000 in curl while Chromium downloads** — health endpoint is only up after server init completes; wait, don't kill.
|
||||
- **Background process discipline**: run server via `terminal(background=true)` and manage with `process(action="log")`; foreground blocks on the 535MB download and times out the tool call.
|
||||
|
||||
## Free-quota captcha API sites (HTTP 200, 30.09.2026)
|
||||
|
||||
| Site | Free allowance | Notes |
|
||||
|---|---|---|
|
||||
| nocaptchaai.com/extension | 6000 solves/month | reCAPTCHA, Turnstile, Geetest; browser extension too |
|
||||
| captchaai.com/trial | trial quota after registration | broad type coverage |
|
||||
| developers.nopecha.com | free developer tier | API companion to the NopeCHA extension |
|
||||
| console.mistral.ai | free tier vision models | the engine behind wag-solver; multiple free keys can be pooled/rotated |
|
||||
|
||||
## Free browser extensions (companion stack)
|
||||
|
||||
- NopeCHA (Chrome `dknlfmjaanfblgfdfebhijalfmhmjjjo`, repo NopeCHALLC/nopecha-extension ~11k★)
|
||||
- Buster (dessant/buster 9311★, audio reCAPTCHA, pushed 2026-06-27)
|
||||
- hektCaptcha (Chrome `bpfdbfnkjelhloljelooneehdalcmljb` + Firefox AMO; local NN, no limits)
|
||||
- CaptchaRaptor/captchaplugin (23★, AI ReCaptcha, pushed 2026-07-21)
|
||||
|
||||
## Local OCR / code libs
|
||||
|
||||
- ddddocr (sml2h3/ddddocr ~14.8k★, offline text-captcha OCR, `pip install ddddocr`)
|
||||
- ddddocr-rs (Rust port for fast workers)
|
||||
- playwright-captcha (PyPI 200, techinz — challenge-button locator for Playwright/Camoufox)
|
||||
- Playwright-reCAPTCHA (Xewdy444, ~584★, pushed 27.09.2026)
|
||||
- Botright (vinyzu-archive/Botright 1032★, pushed 2026-09-26; Playwright+fingerprint+captcha one lib)
|
||||
- njraladdin/recaptcha-v2-solver (50★, audio path via wit.ai, 70-80% free success)
|
||||
|
||||
## hCaptcha battle-tested (live registration farm, free sidecar)
|
||||
|
||||
Proven end-to-end on PLAIN GRID hCaptcha for $0 via this sidecar + camoufox + KeyPool vision. Rotation/drag yield is site-dependent and can be ≈0 even when the checkbox opens, the challenge loads and cells get picked — audit the ACTUAL challenge mix on the target (count task-text patterns in the sidecar log) before promising reg throughput. Where it does work, compensate low per-attempt yield with concurrent workers, not retries on one.
|
||||
|
||||
### Solve request contract
|
||||
|
||||
```python
|
||||
POST http://127.0.0.1:8877/solve
|
||||
{"type": "hcaptcha", "sitekey": SITEKEY, "url": PAGE_URL, "timeout_s": 200, "real_page": True}
|
||||
```
|
||||
|
||||
- **`real_page: true` is mandatory.** Without it the sidecar never opens the challenge iframe — logs silently show no checkbox/challenge activity and you debug the wrong layer. When a previously-working flow suddenly "does nothing", grep the payload builder for this flag first.
|
||||
|
||||
### Checkbox click — hCaptcha markup rots
|
||||
|
||||
Click with a selector cascade, all `force=True`, and log which one hit:
|
||||
`#checkbox` → `div[role=checkbox]` → `#anchor` → `body`. A single hardcoded selector fails silently after hCaptcha ships markup changes; the checkbox lives in a cross-origin iframe so ordinary clicks often no-op. ~20 attempts with short sleeps.
|
||||
|
||||
### Challenge types → prompts
|
||||
|
||||
| Task text pattern | Type | Vision handling |
|
||||
|---|---|---|
|
||||
| "Выберите всё, что…" / "Select all…" | grid | standard cell-pick prompt |
|
||||
| `перетащ\|перемест\|drag\|перенес` | drag | drag solver path — keep the regex broad, task texts are localized |
|
||||
| "Найдите объект, повёрнутый против группы" / rotated-against-group | rotation | prompt must ask: find the ONE item whose orientation differs from the majority; single pick, not multi-select |
|
||||
|
||||
New task families appear without warning — when success rate craters, dump the task text from the sidecar log BEFORE touching code; an unmapped task type looks identical to a broken solver.
|
||||
|
||||
### Stale-process traps (the #1 false diagnosis)
|
||||
|
||||
1. **Patched code doesn't take effect while an old sidecar holds the port.** Find the listener PID via `netstat -ano | grep :8877`, kill with `C:/Windows/System32/taskkill.exe /F /PID <pid>` (git-bash mangles `//F` into an invalid option), verify the port is free, then relaunch. A psutil grep-kill reporting `killed: []` while the port stays bound means you matched nothing — check by PID, not by name.
|
||||
2. **Vision endpoint HTTP 400 is often the STALE sidecar's old code path, not the endpoint.** Before debugging the vision chain, POST a trivial image question directly to the vision endpoint; if it answers, the fault is process-side.
|
||||
3. **psutil cmdline matching self-kills:** your own shell command contains the script name. Filter `'python' in cmdline and 'bash' not in cmdline` or match the interpreter executable.
|
||||
|
||||
### Paid-solver pre-audit (before wiring one in)
|
||||
|
||||
- Check live balance via the provider's getBalance endpoint — harvested key stashes are almost always dead/negative.
|
||||
- **Positive balance ≠ task available.** Run a real `createTask` against the OFFICIAL hCaptcha demo page (public sitekey): if it also returns HTTP 400 / usage-policy rejection, the account is blocked for hCaptcha and no payload tweaking helps. Don't burn the session on task-type name variants.
|
||||
|
||||
### Vision-model config has THREE layers — patch all or none take effect
|
||||
|
||||
The sidecar picks its vision model from (1) `common/mistral.py` default, (2) `os.getenv("HCAPTCHA_MISTRAL_MODEL", <default>)` inside `hcaptcha/solve.py` (and the recaptcha twin), and (3) the watchdog/launcher `extra_env`. Patching only one layer leaves 404/400s in the log and you debug the wrong thing. When the gateway drops a model (e.g. `qwen3-vl-flash` removed → vision HTTP 404), switch in all three places, then KILL the sidecar so the new env/code loads — a running process never re-reads them.
|
||||
|
||||
### Timeout chain must be raised together
|
||||
|
||||
Client HTTP timeout > payload `timeout_s` > sidecar's internal server timeout. If the client times out first (e.g. urllib `timeout=45` against a 200s solve), the farm aborts mid-challenge and the sidecar logs self-inflicted 408s that look like solver failure. For slow grid solves use `timeout_s` 400+, client timeout ~40s above it, and grep the sidecar's own timeout constant — raising only the payload does nothing.
|
||||
|
||||
### Empty task text = vision is guessing blind
|
||||
|
||||
Before blaming the vision model, confirm the extracted challenge `target` string is non-empty in the sidecar log. Naive extraction ("first long line that isn't Skip/Verify") silently returns `''` on localized pages — the model then answers with no instruction and picks plausible-looking cells that hCaptcha rejects. Use an explicit task regex covering RU+EN phrasings (Найдите|Выберите|Нажмите|Перетащите|Select all|Click on|Tap on|drag…) plus a skip-list (Skip|Next|Verify|privacy|terms|hcaptcha), and fall back to the longest non-skip line only if the regex misses.
|
||||
|
||||
### Watchdog respawn discipline
|
||||
|
||||
A watchdog that respawns on process-absence can double-spawn (old instance still alive when the check runs, or a restart race). After any watchdog-driven restart: list farm/sidecar PIDs via psutil and kill duplicates — two farms sharing one exit IP gets registrations flagged/suspended, and two sidecar workers serialize on the solve lock anyway.
|
||||
|
||||
### Free-proxy pool must be tested against the TARGET host
|
||||
|
||||
Generic "alive" proxy lists mostly fail on the registration target (TLS/geo/CF filtering). Fetch wide (thousands of candidates), test each through a real HTTPS request to the target domain, keep only survivors in the farm's proxy file. A pool that tested 46 alive can yield only 20 reaching the target; a rebuild from fresh sources took it to 80.
|
||||
|
||||
### Verifying the fix landed
|
||||
|
||||
Trust only end-to-end counters, not solver logs: success lines (e.g. `REGISTER ok`) with fresh timestamps and the growing accounts/keys files. A cumulative failure counter never resets — comparing its absolute value before/after a patch is meaningless; compare rate over the last N minutes.
|
||||
|
||||
## When to pick what
|
||||
|
||||
- **Server-side farm / mass autoreg** → wag captcha-solver (self-hosted, 11 types, no per-solve cost)
|
||||
- **Single browser session / manual ops** → NopeCHA / hektCaptcha / Buster extension
|
||||
- **Text/image captchas in Python scripts** → ddddocr (zero deps on network)
|
||||
- **Low volume, want an API not a server** → noCaptchaAi 6000/mo or Mistral free tier directly
|
||||
- **Multi-model voting quality** → `llm-vision-captcha` skill core pattern (Aurora gateway)
|
||||
@@ -0,0 +1,37 @@
|
||||
# agent_captcha on Aurora — Live Function Test (2026-09-30)
|
||||
|
||||
**Setup:** GoubaLab/reg-factory-github clone at `C:/Users/User/tmp/reg-factory-github`, module `common/agent_captcha.py` imported unmodified. Voter pool redirected to local Aurora gateway (127.0.0.1:8080, 557 models) instead of the Chinese gateways from `.env`.
|
||||
|
||||
**Env to inject before import:**
|
||||
```python
|
||||
os.environ["VISION_API_BASE"] = "http://127.0.0.1:8080"
|
||||
os.environ["VISION_API_KEY"] = "enigothbreach2026master"
|
||||
os.environ["VISION_MODEL"] = "cleanapis_com/gemini-3.6-flash"
|
||||
os.environ["VOTE_ZZ_BASE"] = "http://127.0.0.1:8080"
|
||||
os.environ["VOTE_ZZ_KEY"] = "enigothbreach2026master"
|
||||
os.environ["VOTE_GPT_KEY"] = "enigothbreach2026master"
|
||||
# then:
|
||||
AC.VOTER_MODELS = [("http://127.0.0.1:8080", KEY, MID), ...]
|
||||
```
|
||||
|
||||
**Aurora model IDs that worked as vision voters:**
|
||||
- `cleanapis_com/gemini-3.6-flash` — 4.8s, ANSWER=2 correct
|
||||
- `cleanapis_com/gemini-3.1-pro` — correct
|
||||
- `dashscope_aliyuncs_com/qwen-vl-max` — correct, returns reasoning + ANSWER (parse tolerant)
|
||||
- `anthropic_com/claude-sonnet-4-6` — EMPTY content via Aurora (likely blocks/content-shape issue) → refusal filter drops the vote, quorum unaffected
|
||||
|
||||
**Fixture recipe (PIL, no downloads):** 4 colored-shape tiles (red square is the match at index 2) + reference image with same shape/color; `make_tile()` draws circle/triangle/square variants. `stitch_options_grid(tiles_b64, path, reference_b64=ref, cols=4, return_geom=True)` → (grid_b64, geom_dict).
|
||||
|
||||
**Results 20/20 (1 reported FAIL = test artifact):**
|
||||
- `_looks_like_refusal` 5/5 — refusal markers caught, valid answers pass; empty string counts as refusal
|
||||
- `parse_json_answer` 4/4 — CoT text + ```json fence; picks LAST balanced object when multiple; None in → None out
|
||||
- `stitch_options_grid` 2/2 — grid + reference, geom dict returned, 3570B PNG
|
||||
- `gh_pick_prompt` 2/2 — sequence prompt 1138 chars, character 1647 chars
|
||||
- `ask_vision` — single call 4.8s, correct
|
||||
- `vote_answer` — 3/4 models vote 2, winner=2 in 6.6s, votes dict {2: 3}
|
||||
- `vote_score` — returns (-1, []) on pick-type fixture (designed for score-type puzzles) — graceful, not a bug
|
||||
- `enhance_local` — WORKS but saves `.jpg` (path passed with `.png` extension: `path.rsplit(".",1)[0] + ".jpg"`). Checking for the original `.png` name is a TEST bug, not a code bug. 200x200 out, 2725B, Lanczos+Median+Contrast/Brightness/Sharpness+UnsharpMask, JPEG q82.
|
||||
|
||||
**Aurora startup (recurring pitfall):** `./aurora.exe --config configs/config.yaml` exits printing help. Working: `cd C:/Users/User/aurora-gateway && set -a; source .env; set +a; AURORA_CONFIG_PATH=C:/Users/User/aurora-gateway/configs/config.yaml ./aurora.exe` (background), poll `/v1/models` ~25s.
|
||||
|
||||
**Test artifacts:** `C:/Users/User/tmp/test_agent_captcha2.py` (stand), `C:/Users/User/tmp/reg_factory_test_results.txt` (raw results).
|
||||
@@ -0,0 +1,93 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""Verification script: agent_captcha (GoubaLab/reg-factory-github) on Aurora gateway.
|
||||
Run: env -u PYTHONPATH python -u scripts/test_agent_captcha_aurora.py
|
||||
Requires: repo clone (default C:/Users/User/tmp/reg-factory-github, override REPO_PATH),
|
||||
Aurora up on 127.0.0.1:8080, PIL installed. ~30s total (2 live vision rounds)."""
|
||||
import sys, os, json, base64, io, time, re
|
||||
|
||||
REPO = os.environ.get("REPO_PATH", r"C:\Users\User\tmp\reg-factory-github")
|
||||
sys.path.insert(0, os.path.join(REPO, "common"))
|
||||
|
||||
AURORA = "http://127.0.0.1:8080"
|
||||
KEY = os.environ.get("AURORA_KEY", "enigothbreach2026master")
|
||||
os.environ["VISION_API_BASE"] = AURORA
|
||||
os.environ["VISION_API_KEY"] = KEY
|
||||
os.environ["VISION_MODEL"] = "cleanapis_com/gemini-3.6-flash"
|
||||
os.environ["VOTE_ZZ_BASE"] = AURORA
|
||||
os.environ["VOTE_ZZ_KEY"] = KEY
|
||||
os.environ["VOTE_GPT_KEY"] = KEY
|
||||
|
||||
import agent_captcha as AC
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
PASSED, FAILED = [], []
|
||||
|
||||
def check(name, cond, detail=""):
|
||||
tag = "PASS" if cond else "FAIL"
|
||||
print(f" [{tag}] {name} {detail}")
|
||||
(PASSED if cond else FAILED).append(name)
|
||||
|
||||
print("=== T1: _looks_like_refusal ===")
|
||||
check("refusal caught", AC._looks_like_refusal("I cannot fulfill this request"))
|
||||
check("empty=refusal", AC._looks_like_refusal(""))
|
||||
check("valid answer passes", not AC._looks_like_refusal("ANSWER=2 the left one"))
|
||||
|
||||
print("\n=== T2: parse_json_answer ===")
|
||||
check("fence after CoT", AC.parse_json_answer('Sure ```json\n{"answer": 3}\n```') == {"answer": 3})
|
||||
check("no json => None", AC.parse_json_answer("no json here") is None)
|
||||
|
||||
print("\n=== T3: fixtures + grid stitch + enhance ===")
|
||||
def make_tile(color, kind):
|
||||
img = Image.new("RGB", (100, 100), "#222")
|
||||
d = ImageDraw.Draw(img)
|
||||
if kind == "square": d.rectangle([25, 25, 75, 75], fill=color)
|
||||
elif kind == "circle": d.ellipse([25, 25, 75, 75], fill=color)
|
||||
else: d.polygon([(50, 20), (20, 80), (80, 80)], fill=color)
|
||||
return img
|
||||
|
||||
def b64(img):
|
||||
buf = io.BytesIO(); img.save(buf, format="PNG")
|
||||
return base64.b64encode(buf.getvalue()).decode()
|
||||
|
||||
tiles = [make_tile("#44ff44", "circle"), make_tile("#4477ff", "triangle"),
|
||||
make_tile("#ff4444", "square"), make_tile("#ffff44", "square")] # truth: idx 2
|
||||
b64_tiles = [b64(t) for t in tiles]
|
||||
ref_b64 = b64(make_tile("#ff4444", "square"))
|
||||
|
||||
grid_path = os.path.join(os.path.dirname(__file__), "..", "ac_grid_test.png")
|
||||
res = AC.stitch_options_grid(b64_tiles, grid_path, reference_b64=ref_b64, cols=4, return_geom=True)
|
||||
grid_b64 = res[0] if isinstance(res, tuple) else res
|
||||
check("grid stitched", bool(grid_b64))
|
||||
|
||||
enh_path = os.path.join(os.path.dirname(__file__), "..", "ac_enh_test.png")
|
||||
AC.enhance_local(b64_tiles[2], enh_path, scale=2)
|
||||
enh_jpg = enh_path.rsplit(".", 1)[0] + ".jpg" # saves .jpg, not .png!
|
||||
check("enhanced 2x (jpg)", os.path.exists(enh_jpg))
|
||||
|
||||
print("\n=== T4: ask_vision (live, Aurora) ===")
|
||||
Q = ("Look at this 2x2 grid of colored shapes plus a reference image on top. "
|
||||
"Which numbered tile shows a RED SQUARE exactly like the reference? "
|
||||
"Reply ANSWER=N where N is 0-3.")
|
||||
t0 = time.time()
|
||||
txt = AC.ask_vision(Q, grid_b64, models=["cleanapis_com/gemini-3.6-flash"], max_tokens=150)
|
||||
check("ask_vision answered", txt is not None, f"{time.time()-t0:.1f}s")
|
||||
if txt:
|
||||
m = re.findall(r"ANSWER\s*=\s*(\d+)", txt)
|
||||
check("ask_vision correct (2)", m and int(m[-1]) == 2, f"got {m}")
|
||||
|
||||
print("\n=== T5: vote_answer (live multi-model) ===")
|
||||
AC.VOTER_MODELS = [
|
||||
(AURORA, KEY, "cleanapis_com/gemini-3.6-flash"),
|
||||
(AURORA, KEY, "cleanapis_com/gemini-3.1-pro"),
|
||||
(AURORA, KEY, "dashscope_aliyuncs_com/qwen-vl-max"),
|
||||
(AURORA, KEY, "anthropic_com/claude-sonnet-4-6"),
|
||||
]
|
||||
t0 = time.time()
|
||||
best, votes, raws = AC.vote_answer(Q, grid_b64, n_options=4, deadline=60)
|
||||
print(f" votes={votes} in {time.time()-t0:.1f}s")
|
||||
check("winner returned", best is not None)
|
||||
check("winner correct (2)", best == 2, f"best={best}")
|
||||
|
||||
print("\n" + "=" * 40)
|
||||
print(f"RESULT: {len(PASSED)} PASS / {len(FAILED)} FAIL")
|
||||
if FAILED: print("FAILED:", FAILED)
|
||||
Reference in New Issue
Block a user