Upload 75 files
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- .gitattributes +2 -0
- .github/workflows/docs.yml +51 -0
- .gitignore +7 -0
- CONTRIBUTING.md +67 -0
- DISCLAIMER.md +31 -0
- DISCLAIMER.zh-CN.md +31 -0
- Dockerfile.render +13 -0
- LICENSE +21 -0
- README.md +301 -8
- README.zh-CN.md +304 -0
- SECURITY.md +45 -0
- docs/acceptance.md +151 -0
- docs/api-reference.md +246 -0
- docs/assets/.gitkeep +0 -0
- docs/assets/ohmycaptcha-diagram.png +3 -0
- docs/assets/ohmycaptcha-hero.png +3 -0
- docs/deployment/huggingface.md +116 -0
- docs/deployment/local-model.md +155 -0
- docs/deployment/render.md +112 -0
- docs/faq.md +25 -0
- docs/getting-started.md +67 -0
- docs/index.md +126 -0
- docs/positioning.md +46 -0
- docs/skill.md +58 -0
- docs/stylesheets/extra.css +204 -0
- docs/usage/classification.md +163 -0
- docs/usage/hcaptcha.md +98 -0
- docs/usage/image-captcha.md +55 -0
- docs/usage/recaptcha-v2.md +126 -0
- docs/usage/recaptcha-v3.md +53 -0
- docs/usage/turnstile.md +108 -0
- docs/zh/acceptance.md +84 -0
- docs/zh/api-reference.md +180 -0
- docs/zh/deployment/huggingface.md +116 -0
- docs/zh/deployment/local-model.md +106 -0
- docs/zh/deployment/render.md +112 -0
- docs/zh/faq.md +25 -0
- docs/zh/getting-started.md +67 -0
- docs/zh/index.md +126 -0
- docs/zh/positioning.md +46 -0
- docs/zh/skill.md +58 -0
- docs/zh/usage/classification.md +70 -0
- docs/zh/usage/hcaptcha.md +74 -0
- docs/zh/usage/image-captcha.md +55 -0
- docs/zh/usage/recaptcha-v2.md +94 -0
- docs/zh/usage/recaptcha-v3.md +53 -0
- docs/zh/usage/turnstile.md +75 -0
- main.py +19 -0
- mkdocs.yml +134 -0
- pyrightconfig.json +15 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
docs/assets/ohmycaptcha-diagram.png filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
docs/assets/ohmycaptcha-hero.png filter=lfs diff=lfs merge=lfs -text
|
.github/workflows/docs.yml
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
name: Deploy Docs
|
| 2 |
+
|
| 3 |
+
on:
|
| 4 |
+
push:
|
| 5 |
+
branches: [main]
|
| 6 |
+
workflow_dispatch:
|
| 7 |
+
|
| 8 |
+
permissions:
|
| 9 |
+
contents: read
|
| 10 |
+
pages: write
|
| 11 |
+
id-token: write
|
| 12 |
+
|
| 13 |
+
concurrency:
|
| 14 |
+
group: pages
|
| 15 |
+
cancel-in-progress: true
|
| 16 |
+
|
| 17 |
+
jobs:
|
| 18 |
+
build:
|
| 19 |
+
runs-on: ubuntu-latest
|
| 20 |
+
steps:
|
| 21 |
+
- name: Checkout
|
| 22 |
+
uses: actions/checkout@v4
|
| 23 |
+
|
| 24 |
+
- name: Set up Python
|
| 25 |
+
uses: actions/setup-python@v5
|
| 26 |
+
with:
|
| 27 |
+
python-version: '3.11'
|
| 28 |
+
|
| 29 |
+
- name: Install docs dependencies
|
| 30 |
+
run: |
|
| 31 |
+
python -m pip install --upgrade pip
|
| 32 |
+
pip install mkdocs mkdocs-material mkdocs-redirects mkdocs-static-i18n pymdown-extensions
|
| 33 |
+
|
| 34 |
+
- name: Build docs
|
| 35 |
+
run: mkdocs build --strict
|
| 36 |
+
|
| 37 |
+
- name: Upload Pages artifact
|
| 38 |
+
uses: actions/upload-pages-artifact@v3
|
| 39 |
+
with:
|
| 40 |
+
path: site
|
| 41 |
+
|
| 42 |
+
deploy:
|
| 43 |
+
environment:
|
| 44 |
+
name: github-pages
|
| 45 |
+
url: ${{ steps.deployment.outputs.page_url }}
|
| 46 |
+
runs-on: ubuntu-latest
|
| 47 |
+
needs: build
|
| 48 |
+
steps:
|
| 49 |
+
- name: Deploy to GitHub Pages
|
| 50 |
+
id: deployment
|
| 51 |
+
uses: actions/deploy-pages@v4
|
.gitignore
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.venv/
|
| 2 |
+
__pycache__/
|
| 3 |
+
.pytest_cache/
|
| 4 |
+
site/
|
| 5 |
+
*.pyc
|
| 6 |
+
cache/
|
| 7 |
+
CLAUDE.md
|
CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Contributing
|
| 2 |
+
|
| 3 |
+
Thanks for contributing to OhMyCaptcha.
|
| 4 |
+
|
| 5 |
+
## Development setup
|
| 6 |
+
|
| 7 |
+
```bash
|
| 8 |
+
python -m venv .venv
|
| 9 |
+
source .venv/bin/activate
|
| 10 |
+
pip install -r requirements.txt
|
| 11 |
+
playwright install --with-deps chromium
|
| 12 |
+
```
|
| 13 |
+
|
| 14 |
+
## Run the project locally
|
| 15 |
+
|
| 16 |
+
```bash
|
| 17 |
+
python main.py
|
| 18 |
+
```
|
| 19 |
+
|
| 20 |
+
## Validate changes
|
| 21 |
+
|
| 22 |
+
Run tests:
|
| 23 |
+
|
| 24 |
+
```bash
|
| 25 |
+
pytest tests/
|
| 26 |
+
```
|
| 27 |
+
|
| 28 |
+
Run type checks:
|
| 29 |
+
|
| 30 |
+
```bash
|
| 31 |
+
npx pyright
|
| 32 |
+
```
|
| 33 |
+
|
| 34 |
+
Build docs:
|
| 35 |
+
|
| 36 |
+
```bash
|
| 37 |
+
mkdocs build --strict
|
| 38 |
+
```
|
| 39 |
+
|
| 40 |
+
## Contribution guidelines
|
| 41 |
+
|
| 42 |
+
- Keep changes aligned with the implemented task types and documented behavior.
|
| 43 |
+
- Do not add secret values, personal endpoints, or account-specific configuration to the repository.
|
| 44 |
+
- Prefer small, reviewable pull requests.
|
| 45 |
+
- Update docs when behavior changes.
|
| 46 |
+
- Keep examples copy-pasteable and placeholder-based.
|
| 47 |
+
- Avoid overstating compatibility or production guarantees.
|
| 48 |
+
|
| 49 |
+
## Pull requests
|
| 50 |
+
|
| 51 |
+
A good pull request usually includes:
|
| 52 |
+
|
| 53 |
+
- a concise summary of the change
|
| 54 |
+
- why the change is needed
|
| 55 |
+
- tests or validation notes
|
| 56 |
+
- documentation updates if relevant
|
| 57 |
+
|
| 58 |
+
## Documentation style
|
| 59 |
+
|
| 60 |
+
This repository aims for documentation that is:
|
| 61 |
+
|
| 62 |
+
- clear
|
| 63 |
+
- practical
|
| 64 |
+
- implementation-aware
|
| 65 |
+
- safe for public distribution
|
| 66 |
+
|
| 67 |
+
If you add deployment examples, use placeholders instead of real secrets or private URLs.
|
DISCLAIMER.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Disclaimer
|
| 2 |
+
|
| 3 |
+
**OhMyCaptcha is intended for legitimate research, security testing, and educational purposes only.**
|
| 4 |
+
|
| 5 |
+
## Intended use
|
| 6 |
+
|
| 7 |
+
This software is designed to help developers:
|
| 8 |
+
|
| 9 |
+
- Test and validate CAPTCHA integration in their own applications
|
| 10 |
+
- Research automated browser behavior and bot detection mechanisms
|
| 11 |
+
- Learn about multimodal AI applied to image recognition tasks
|
| 12 |
+
- Build compatible tooling for services that use YesCaptcha-style APIs under their own authorization
|
| 13 |
+
|
| 14 |
+
## Prohibited use
|
| 15 |
+
|
| 16 |
+
You **must not** use OhMyCaptcha to:
|
| 17 |
+
|
| 18 |
+
- Bypass CAPTCHAs on websites or services **without explicit written permission** from the site or service owner
|
| 19 |
+
- Conduct unauthorized automated access to third-party systems
|
| 20 |
+
- Circumvent security controls intended to prevent abuse or fraud
|
| 21 |
+
- Violate any website's Terms of Service
|
| 22 |
+
|
| 23 |
+
## Legal responsibility
|
| 24 |
+
|
| 25 |
+
- Unauthorized automated access to third-party services may violate their Terms of Service and could be illegal under applicable laws, including but not limited to the Computer Fraud and Abuse Act (CFAA), the EU General Data Protection Regulation (GDPR), or equivalent legislation in your jurisdiction.
|
| 26 |
+
- **The authors and contributors of OhMyCaptcha accept no liability** for any misuse, damages, legal consequences, or losses arising from the use or misuse of this software.
|
| 27 |
+
- By deploying or using this software, **you accept full responsibility** for ensuring that your usage complies with all applicable laws, regulations, and third-party terms of service.
|
| 28 |
+
|
| 29 |
+
## No warranty
|
| 30 |
+
|
| 31 |
+
This software is provided **"as is"**, without warranty of any kind. See [LICENSE](LICENSE) for the full MIT license terms.
|
DISCLAIMER.zh-CN.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 免责声明
|
| 2 |
+
|
| 3 |
+
**OhMyCaptcha 仅供合法的安全研究、渗透测试和技术学习使用。**
|
| 4 |
+
|
| 5 |
+
## 合法用途
|
| 6 |
+
|
| 7 |
+
本软件旨在帮助开发者:
|
| 8 |
+
|
| 9 |
+
- 在自己的应用中测试和验证 CAPTCHA 集成
|
| 10 |
+
- 研究自动化浏览器行为和机器人检测机制
|
| 11 |
+
- 学习多模态 AI 在图像识别任务中的应用
|
| 12 |
+
- 在获得授权的前提下,为使用 YesCaptcha 风格 API 的服务构建兼容工具
|
| 13 |
+
|
| 14 |
+
## 禁止用途
|
| 15 |
+
|
| 16 |
+
你**不得**将 OhMyCaptcha 用于:
|
| 17 |
+
|
| 18 |
+
- 在**未获得网站或服务所有者明确书面授权**的情况下,绕过其 CAPTCHA
|
| 19 |
+
- 对第三方系统进行未经授权的自动化访问
|
| 20 |
+
- 规避旨在防止滥用或欺诈的安全控制措施
|
| 21 |
+
- 违反任何网站的服务条款
|
| 22 |
+
|
| 23 |
+
## 法律责任
|
| 24 |
+
|
| 25 |
+
- 未经授权地对第三方服务进行自动化访问,可能违反其服务条款,并可能在相关法律管辖区(包括但不限于《计算机欺诈与滥用法》、欧盟《通用数据保护条例》(GDPR)或当地等效法规)下构成违法行为。
|
| 26 |
+
- **OhMyCaptcha 的作者和贡献者不承担任何因使用或滥用本软件而导致的损失、法律后果或责任。**
|
| 27 |
+
- 通过部署或使用本软件,**你完全同意并承担**确保其使用方式符合所有适用法律法规及第三方服务条款的责任。
|
| 28 |
+
|
| 29 |
+
## 无担保声明
|
| 30 |
+
|
| 31 |
+
本软件按**"原样"**提供,不附带任何形式的担保。完整 MIT 许可证条款请参阅 [LICENSE](LICENSE)。
|
Dockerfile.render
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM python:3.11-slim
|
| 2 |
+
|
| 3 |
+
WORKDIR /app
|
| 4 |
+
|
| 5 |
+
COPY requirements.txt .
|
| 6 |
+
RUN pip install --no-cache-dir --root-user-action=ignore -r requirements.txt
|
| 7 |
+
RUN playwright install --with-deps chromium
|
| 8 |
+
|
| 9 |
+
COPY . .
|
| 10 |
+
|
| 11 |
+
EXPOSE 8000
|
| 12 |
+
|
| 13 |
+
CMD ["python", "main.py"]
|
LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
MIT License
|
| 2 |
+
|
| 3 |
+
Copyright (c) 2026 shenhao-stu
|
| 4 |
+
|
| 5 |
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
| 6 |
+
of this software and associated documentation files (the "Software"), to deal
|
| 7 |
+
in the Software without restriction, including without limitation the rights
|
| 8 |
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
| 9 |
+
copies of the Software, and to permit persons to whom the Software is
|
| 10 |
+
furnished to do so, subject to the following conditions:
|
| 11 |
+
|
| 12 |
+
The above copyright notice and this permission notice shall be included in all
|
| 13 |
+
copies or substantial portions of the Software.
|
| 14 |
+
|
| 15 |
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
| 16 |
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
| 17 |
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
| 18 |
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
| 19 |
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
| 20 |
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
| 21 |
+
SOFTWARE.
|
README.md
CHANGED
|
@@ -1,11 +1,304 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
---
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
---
|
| 10 |
|
| 11 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<p align="center">
|
| 2 |
+
<img src="https://img.shields.io/badge/OhMyCaptcha-YesCaptcha--style%20API-2F6BFF?style=for-the-badge" alt="OhMyCaptcha">
|
| 3 |
+
<br/>
|
| 4 |
+
<img src="https://img.shields.io/badge/version-3.0-22C55E?style=flat-square" alt="Version">
|
| 5 |
+
<img src="https://img.shields.io/badge/license-MIT-2563EB?style=flat-square" alt="License">
|
| 6 |
+
<img src="https://img.shields.io/badge/task%20types-19-F59E0B?style=flat-square" alt="Task Types">
|
| 7 |
+
<img src="https://img.shields.io/badge/runtime-FastAPI%20%7C%20Playwright%20%7C%20OpenAI--compatible-7C3AED?style=flat-square" alt="Runtime">
|
| 8 |
+
<img src="https://img.shields.io/badge/deploy-Render%20%7C%20Hugging%20Face%20Spaces-0F172A?style=flat-square" alt="Deploy">
|
| 9 |
+
<img src="https://img.shields.io/badge/docs-bilingual-2563EB?style=flat-square" alt="Docs">
|
| 10 |
+
</p>
|
| 11 |
+
|
| 12 |
+
<h1 align="center">🧩 OhMyCaptcha</h1>
|
| 13 |
+
|
| 14 |
+
<p align="center">
|
| 15 |
+
<strong>Self-hostable YesCaptcha-style captcha solver for <a href="https://github.com/TheSmallHanCat/flow2api">flow2api</a> and similar integrations</strong>
|
| 16 |
+
<br/>
|
| 17 |
+
<em>19 task types · reCAPTCHA v2/v3 · hCaptcha · Cloudflare Turnstile · Image Classification</em>
|
| 18 |
+
</p>
|
| 19 |
+
|
| 20 |
+
<p align="center">
|
| 21 |
+
<a href="#-quick-start">Quick Start</a> •
|
| 22 |
+
<a href="#-architecture">Architecture</a> •
|
| 23 |
+
<a href="#-task-types">Task Types</a> •
|
| 24 |
+
<a href="#-deployment">Deployment</a> •
|
| 25 |
+
<a href="#-development">Development</a>
|
| 26 |
+
</p>
|
| 27 |
+
|
| 28 |
+
<p align="center">
|
| 29 |
+
<a href="README.zh-CN.md">中文说明</a> •
|
| 30 |
+
<a href="https://shenhao-stu.github.io/ohmycaptcha/">Documentation</a> •
|
| 31 |
+
<a href="https://shenhao-stu.github.io/ohmycaptcha/deployment/render/">Render Guide</a> •
|
| 32 |
+
<a href="https://shenhao-stu.github.io/ohmycaptcha/deployment/huggingface/">Hugging Face Guide</a>
|
| 33 |
+
</p>
|
| 34 |
+
|
| 35 |
+
<p align="center">
|
| 36 |
+
<img src="docs/assets/ohmycaptcha-hero.png" alt="OhMyCaptcha" width="680">
|
| 37 |
+
</p>
|
| 38 |
+
|
| 39 |
+
---
|
| 40 |
+
|
| 41 |
+
## ✨ What Is This?
|
| 42 |
+
|
| 43 |
+
**OhMyCaptcha** is a self-hosted captcha-solving service exposing a **YesCaptcha-style async API** with **19 supported task types**. Designed as a third-party captcha solver for **flow2api** and systems that expect `createTask` / `getTaskResult` semantics.
|
| 44 |
+
|
| 45 |
+
| Capability | Details |
|
| 46 |
+
|-----------|---------|
|
| 47 |
+
| **Browser automation** | Playwright + Chromium for reCAPTCHA v2/v3, hCaptcha, Cloudflare Turnstile |
|
| 48 |
+
| **Image recognition** | Local multimodal model (Qwen3.5-2B via SGLang) for image captcha analysis |
|
| 49 |
+
| **Image classification** | Local vision model for HCaptcha, reCAPTCHA v2, FunCaptcha, AWS grid classification |
|
| 50 |
+
| **API compatibility** | Full YesCaptcha `createTask`/`getTaskResult`/`getBalance` protocol |
|
| 51 |
+
| **Deployment** | Local, Render, Hugging Face Spaces with Docker support |
|
| 52 |
+
|
| 53 |
---
|
| 54 |
+
|
| 55 |
+
## 📦 Quick Start
|
| 56 |
+
|
| 57 |
+
```bash
|
| 58 |
+
python -m venv .venv && source .venv/bin/activate
|
| 59 |
+
pip install -r requirements.txt
|
| 60 |
+
playwright install --with-deps chromium
|
| 61 |
+
|
| 62 |
+
# Local model (self-hosted via SGLang)
|
| 63 |
+
export LOCAL_BASE_URL="http://localhost:30000/v1"
|
| 64 |
+
export LOCAL_MODEL="Qwen/Qwen3.5-2B"
|
| 65 |
+
|
| 66 |
+
# Cloud model (remote API)
|
| 67 |
+
export CLOUD_BASE_URL="https://your-openai-compatible-endpoint/v1"
|
| 68 |
+
export CLOUD_API_KEY="your-api-key"
|
| 69 |
+
export CLOUD_MODEL="gpt-5.4"
|
| 70 |
+
|
| 71 |
+
export CLIENT_KEY="your-client-key"
|
| 72 |
+
python main.py
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
Verify with:
|
| 76 |
+
|
| 77 |
+
```bash
|
| 78 |
+
curl http://localhost:8000/api/v1/health
|
| 79 |
+
```
|
| 80 |
+
|
| 81 |
---
|
| 82 |
|
| 83 |
+
## 🏗 Architecture
|
| 84 |
+
|
| 85 |
+
<p align="center">
|
| 86 |
+
<img src="docs/assets/ohmycaptcha-diagram.png" alt="OhMyCaptcha architecture" width="560">
|
| 87 |
+
</p>
|
| 88 |
+
|
| 89 |
+
**Core components:**
|
| 90 |
+
|
| 91 |
+
- **FastAPI** — HTTP API with YesCaptcha protocol
|
| 92 |
+
- **TaskManager** — async in-memory task queue with 10-min TTL
|
| 93 |
+
- **RecaptchaV3Solver** — Playwright-based reCAPTCHA v3/Enterprise token generation
|
| 94 |
+
- **RecaptchaV2Solver** — Playwright-based reCAPTCHA v2 checkbox solving
|
| 95 |
+
- **HCaptchaSolver** — Playwright-based hCaptcha solving
|
| 96 |
+
- **TurnstileSolver** — Playwright-based Cloudflare Turnstile solving
|
| 97 |
+
- **CaptchaRecognizer** — Argus-inspired multimodal image analysis
|
| 98 |
+
- **ClassificationSolver** — Vision model-based image classification
|
| 99 |
+
|
| 100 |
+
---
|
| 101 |
+
|
| 102 |
+
## 🧠 Task Types
|
| 103 |
+
|
| 104 |
+
### Browser-based solving (12 types)
|
| 105 |
+
|
| 106 |
+
| Category | Task Types | Solution Field |
|
| 107 |
+
|----------|-----------|----------------|
|
| 108 |
+
| reCAPTCHA v3 | `RecaptchaV3TaskProxyless`, `RecaptchaV3TaskProxylessM1`, `RecaptchaV3TaskProxylessM1S7`, `RecaptchaV3TaskProxylessM1S9` | `gRecaptchaResponse` |
|
| 109 |
+
| reCAPTCHA v3 Enterprise | `RecaptchaV3EnterpriseTask`, `RecaptchaV3EnterpriseTaskM1` | `gRecaptchaResponse` |
|
| 110 |
+
| reCAPTCHA v2 | `NoCaptchaTaskProxyless`, `RecaptchaV2TaskProxyless`, `RecaptchaV2EnterpriseTaskProxyless` | `gRecaptchaResponse` |
|
| 111 |
+
| hCaptcha | `HCaptchaTaskProxyless` | `gRecaptchaResponse` |
|
| 112 |
+
| Cloudflare Turnstile | `TurnstileTaskProxyless`, `TurnstileTaskProxylessM1` | `token` |
|
| 113 |
+
|
| 114 |
+
### Image recognition (3 types)
|
| 115 |
+
|
| 116 |
+
| Task Type | Solution Field |
|
| 117 |
+
|-----------|----------------|
|
| 118 |
+
| `ImageToTextTask` | `text` (structured JSON) |
|
| 119 |
+
| `ImageToTextTaskMuggle` | `text` |
|
| 120 |
+
| `ImageToTextTaskM1` | `text` |
|
| 121 |
+
|
| 122 |
+
### Image classification (4 types)
|
| 123 |
+
|
| 124 |
+
| Task Type | Solution Field |
|
| 125 |
+
|-----------|----------------|
|
| 126 |
+
| `HCaptchaClassification` | `objects` / `answer` |
|
| 127 |
+
| `ReCaptchaV2Classification` | `objects` |
|
| 128 |
+
| `FunCaptchaClassification` | `objects` |
|
| 129 |
+
| `AwsClassification` | `objects` |
|
| 130 |
+
|
| 131 |
+
---
|
| 132 |
+
|
| 133 |
+
## 🔌 API Surface
|
| 134 |
+
|
| 135 |
+
| Endpoint | Purpose |
|
| 136 |
+
|----------|---------|
|
| 137 |
+
| `POST /createTask` | Create an async captcha task |
|
| 138 |
+
| `POST /getTaskResult` | Poll task execution result |
|
| 139 |
+
| `POST /getBalance` | Return compatibility balance |
|
| 140 |
+
| `GET /api/v1/health` | Health and service status |
|
| 141 |
+
|
| 142 |
+
### Example: reCAPTCHA v3
|
| 143 |
+
|
| 144 |
+
```bash
|
| 145 |
+
curl -X POST http://localhost:8000/createTask \
|
| 146 |
+
-H "Content-Type: application/json" \
|
| 147 |
+
-d '{
|
| 148 |
+
"clientKey": "your-client-key",
|
| 149 |
+
"task": {
|
| 150 |
+
"type": "RecaptchaV3TaskProxyless",
|
| 151 |
+
"websiteURL": "https://antcpt.com/score_detector/",
|
| 152 |
+
"websiteKey": "6LcR_okUAAAAAPYrPe-HK_0RULO1aZM15ENyM-Mf",
|
| 153 |
+
"pageAction": "homepage"
|
| 154 |
+
}
|
| 155 |
+
}'
|
| 156 |
+
```
|
| 157 |
+
|
| 158 |
+
### Example: hCaptcha
|
| 159 |
+
|
| 160 |
+
```bash
|
| 161 |
+
curl -X POST http://localhost:8000/createTask \
|
| 162 |
+
-H "Content-Type: application/json" \
|
| 163 |
+
-d '{
|
| 164 |
+
"clientKey": "your-client-key",
|
| 165 |
+
"task": {
|
| 166 |
+
"type": "HCaptchaTaskProxyless",
|
| 167 |
+
"websiteURL": "https://example.com",
|
| 168 |
+
"websiteKey": "hcaptcha-site-key"
|
| 169 |
+
}
|
| 170 |
+
}'
|
| 171 |
+
```
|
| 172 |
+
|
| 173 |
+
### Example: Cloudflare Turnstile
|
| 174 |
+
|
| 175 |
+
```bash
|
| 176 |
+
curl -X POST http://localhost:8000/createTask \
|
| 177 |
+
-H "Content-Type: application/json" \
|
| 178 |
+
-d '{
|
| 179 |
+
"clientKey": "your-client-key",
|
| 180 |
+
"task": {
|
| 181 |
+
"type": "TurnstileTaskProxyless",
|
| 182 |
+
"websiteURL": "https://example.com",
|
| 183 |
+
"websiteKey": "turnstile-site-key"
|
| 184 |
+
}
|
| 185 |
+
}'
|
| 186 |
+
```
|
| 187 |
+
|
| 188 |
+
### Example: Image classification
|
| 189 |
+
|
| 190 |
+
```bash
|
| 191 |
+
curl -X POST http://localhost:8000/createTask \
|
| 192 |
+
-H "Content-Type: application/json" \
|
| 193 |
+
-d '{
|
| 194 |
+
"clientKey": "your-client-key",
|
| 195 |
+
"task": {
|
| 196 |
+
"type": "ReCaptchaV2Classification",
|
| 197 |
+
"image": "<base64-encoded-image>",
|
| 198 |
+
"question": "Select all images with traffic lights"
|
| 199 |
+
}
|
| 200 |
+
}'
|
| 201 |
+
```
|
| 202 |
+
|
| 203 |
+
### Poll result
|
| 204 |
+
|
| 205 |
+
```bash
|
| 206 |
+
curl -X POST http://localhost:8000/getTaskResult \
|
| 207 |
+
-H "Content-Type: application/json" \
|
| 208 |
+
-d '{"clientKey": "your-client-key", "taskId": "uuid-from-createTask"}'
|
| 209 |
+
```
|
| 210 |
+
|
| 211 |
+
---
|
| 212 |
+
|
| 213 |
+
## ⚙️ Configuration
|
| 214 |
+
|
| 215 |
+
### Model backends
|
| 216 |
+
|
| 217 |
+
OhMyCaptcha uses two model backends — a **local model** for image tasks and a **cloud model** for complex reasoning:
|
| 218 |
+
|
| 219 |
+
| Variable | Description | Default |
|
| 220 |
+
|----------|-------------|---------|
|
| 221 |
+
| `LOCAL_BASE_URL` | Local inference server (SGLang/vLLM) | `http://localhost:30000/v1` |
|
| 222 |
+
| `LOCAL_API_KEY` | Local server API key | `EMPTY` |
|
| 223 |
+
| `LOCAL_MODEL` | Local model name | `Qwen/Qwen3.5-2B` |
|
| 224 |
+
| `CLOUD_BASE_URL` | Cloud API base URL | External endpoint |
|
| 225 |
+
| `CLOUD_API_KEY` | Cloud API key | unset |
|
| 226 |
+
| `CLOUD_MODEL` | Cloud model name | `gpt-5.4` |
|
| 227 |
+
|
| 228 |
+
### General
|
| 229 |
+
|
| 230 |
+
| Variable | Description | Default |
|
| 231 |
+
|----------|-------------|---------|
|
| 232 |
+
| `CLIENT_KEY` | Client authentication key | unset |
|
| 233 |
+
| `CAPTCHA_RETRIES` | Retry count | `3` |
|
| 234 |
+
| `CAPTCHA_TIMEOUT` | Model timeout (seconds) | `30` |
|
| 235 |
+
| `BROWSER_HEADLESS` | Headless Chromium | `true` |
|
| 236 |
+
| `BROWSER_TIMEOUT` | Page load timeout (seconds) | `30` |
|
| 237 |
+
| `SERVER_HOST` | Bind host | `0.0.0.0` |
|
| 238 |
+
| `SERVER_PORT` | Bind port | `8000` |
|
| 239 |
+
|
| 240 |
+
> Legacy vars (`CAPTCHA_BASE_URL`, `CAPTCHA_API_KEY`, `CAPTCHA_MODEL`, `CAPTCHA_MULTIMODAL_MODEL`) are supported as fallbacks.
|
| 241 |
+
|
| 242 |
+
---
|
| 243 |
+
|
| 244 |
+
## 🚀 Deployment
|
| 245 |
+
|
| 246 |
+
- [Local model (SGLang)](https://shenhao-stu.github.io/ohmycaptcha/deployment/local-model/) — deploy Qwen3.5-2B locally
|
| 247 |
+
- [Render deployment](https://shenhao-stu.github.io/ohmycaptcha/deployment/render/)
|
| 248 |
+
- [Hugging Face Spaces deployment](https://shenhao-stu.github.io/ohmycaptcha/deployment/huggingface/)
|
| 249 |
+
- [Full documentation](https://shenhao-stu.github.io/ohmycaptcha/)
|
| 250 |
+
|
| 251 |
+
---
|
| 252 |
+
|
| 253 |
+
## ✅ Test Target
|
| 254 |
+
|
| 255 |
+
This service is validated against the public reCAPTCHA v3 score detector:
|
| 256 |
+
|
| 257 |
+
- URL: `https://antcpt.com/score_detector/`
|
| 258 |
+
- Site key: `6LcR_okUAAAAAPYrPe-HK_0RULO1aZM15ENyM-Mf`
|
| 259 |
+
|
| 260 |
+
---
|
| 261 |
+
|
| 262 |
+
## ⚠️ Limitations
|
| 263 |
+
|
| 264 |
+
- Tasks are stored **in memory** with a 10-minute TTL
|
| 265 |
+
- `minScore` is accepted for compatibility but not enforced
|
| 266 |
+
- Browser-based solving depends on environment, IP reputation, and target-site behavior
|
| 267 |
+
- Image classification quality depends on the vision model used
|
| 268 |
+
- Not all commercial captcha-service features are replicated
|
| 269 |
+
|
| 270 |
+
---
|
| 271 |
+
|
| 272 |
+
## 📢 Disclaimer
|
| 273 |
+
|
| 274 |
+
> **This project is intended for legitimate research, security testing, and educational purposes only.**
|
| 275 |
+
|
| 276 |
+
- OhMyCaptcha is a self-hostable tool. You are solely responsible for how you deploy and use it.
|
| 277 |
+
- CAPTCHA systems exist to protect services from abuse. **Do not use this tool to bypass CAPTCHAs on websites or services without explicit permission from the site owner.**
|
| 278 |
+
- Unauthorized automated access to third-party services may violate their Terms of Service, and may be illegal under applicable laws (e.g., the Computer Fraud and Abuse Act, GDPR, or equivalent legislation in your jurisdiction).
|
| 279 |
+
- The authors and contributors of this project **accept no liability** for any misuse, legal consequences, or damages arising from the use of this software.
|
| 280 |
+
- By using this software, you agree that you are solely responsible for ensuring your usage complies with all relevant laws and terms of service.
|
| 281 |
+
|
| 282 |
+
---
|
| 283 |
+
|
| 284 |
+
## 🔧 Development
|
| 285 |
+
|
| 286 |
+
```bash
|
| 287 |
+
pytest tests/
|
| 288 |
+
npx pyright
|
| 289 |
+
python -m mkdocs build --strict
|
| 290 |
+
```
|
| 291 |
+
|
| 292 |
+
---
|
| 293 |
+
|
| 294 |
+
## Star History
|
| 295 |
+
|
| 296 |
+
[](https://www.star-history.com/#shenhao-stu/ohmycaptcha&Date)
|
| 297 |
+
|
| 298 |
+
---
|
| 299 |
+
|
| 300 |
+
## 📄 License
|
| 301 |
+
|
| 302 |
+
[MIT](LICENSE) — use freely, modify openly, deploy carefully.
|
| 303 |
+
|
| 304 |
+
See [DISCLAIMER.md](DISCLAIMER.md) for full terms of use and liability limitations.
|
README.zh-CN.md
ADDED
|
@@ -0,0 +1,304 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<p align="center">
|
| 2 |
+
<img src="https://img.shields.io/badge/OhMyCaptcha-YesCaptcha--style%20API-2F6BFF?style=for-the-badge" alt="OhMyCaptcha">
|
| 3 |
+
<br/>
|
| 4 |
+
<img src="https://img.shields.io/badge/version-3.0-22C55E?style=flat-square" alt="Version">
|
| 5 |
+
<img src="https://img.shields.io/badge/license-MIT-2563EB?style=flat-square" alt="License">
|
| 6 |
+
<img src="https://img.shields.io/badge/task%20types-19-F59E0B?style=flat-square" alt="Task Types">
|
| 7 |
+
<img src="https://img.shields.io/badge/runtime-FastAPI%20%7C%20Playwright%20%7C%20OpenAI--compatible-7C3AED?style=flat-square" alt="Runtime">
|
| 8 |
+
<img src="https://img.shields.io/badge/deploy-Render%20%7C%20Hugging%20Face%20Spaces-0F172A?style=flat-square" alt="Deploy">
|
| 9 |
+
<img src="https://img.shields.io/badge/docs-bilingual-2563EB?style=flat-square" alt="Docs">
|
| 10 |
+
</p>
|
| 11 |
+
|
| 12 |
+
<h1 align="center">🧩 OhMyCaptcha</h1>
|
| 13 |
+
|
| 14 |
+
<p align="center">
|
| 15 |
+
<strong>面向 <a href="https://github.com/OpenClaw/openclaw">flow2api</a> 与类似集成场景的可自托管 YesCaptcha 风格验证码服务</strong>
|
| 16 |
+
<br/>
|
| 17 |
+
<em>19 种任务类型 · reCAPTCHA v2/v3 · hCaptcha · Cloudflare Turnstile · 图像分类</em>
|
| 18 |
+
</p>
|
| 19 |
+
|
| 20 |
+
<p align="center">
|
| 21 |
+
<a href="#-快速开始">快速开始</a> •
|
| 22 |
+
<a href="#-架构">架构</a> •
|
| 23 |
+
<a href="#-任务类型">任务类型</a> •
|
| 24 |
+
<a href="#-部署">部署</a> •
|
| 25 |
+
<a href="#-开发">开发</a>
|
| 26 |
+
</p>
|
| 27 |
+
|
| 28 |
+
<p align="center">
|
| 29 |
+
<a href="README.md">English README</a> •
|
| 30 |
+
<a href="https://shenhao-stu.github.io/ohmycaptcha/">在线文档</a> •
|
| 31 |
+
<a href="https://shenhao-stu.github.io/ohmycaptcha/zh/deployment/render/">Render 部署指南</a> •
|
| 32 |
+
<a href="https://shenhao-stu.github.io/ohmycaptcha/zh/deployment/huggingface/">Hugging Face Spaces 指南</a>
|
| 33 |
+
</p>
|
| 34 |
+
|
| 35 |
+
<p align="center">
|
| 36 |
+
<img src="docs/assets/ohmycaptcha-hero.png" alt="OhMyCaptcha" width="680">
|
| 37 |
+
</p>
|
| 38 |
+
|
| 39 |
+
---
|
| 40 |
+
|
| 41 |
+
## ✨ 这是什么?
|
| 42 |
+
|
| 43 |
+
**OhMyCaptcha** 是一个可直接部署的自托管验证码解决服务,提供 **YesCaptcha 风格异步 API**,支持 **19 种任务类型**。作为第三方打码工具,专为 **flow2api** 及依赖 `createTask` / `getTaskResult` 语义的系统设计。
|
| 44 |
+
|
| 45 |
+
| 能力 | 详情 |
|
| 46 |
+
|------|------|
|
| 47 |
+
| **浏览器自动化** | Playwright + Chromium 实现 reCAPTCHA v2/v3、hCaptcha、Cloudflare Turnstile 自动求解 |
|
| 48 |
+
| **图片识别** | 本地多模态模型(通过 SGLang 部署 Qwen3.5-2B)进行图片验证码分析 |
|
| 49 |
+
| **图像分类** | 本地视觉模型进行 HCaptcha、reCAPTCHA v2、FunCaptcha、AWS 网格分类 |
|
| 50 |
+
| **API 兼容** | 完整的 YesCaptcha `createTask`/`getTaskResult`/`getBalance` 协议 |
|
| 51 |
+
| **部署方式** | 支持本地、Render、Hugging Face Spaces 的 Docker 部署 |
|
| 52 |
+
|
| 53 |
+
---
|
| 54 |
+
|
| 55 |
+
## 📦 快速开始
|
| 56 |
+
|
| 57 |
+
```bash
|
| 58 |
+
python -m venv .venv && source .venv/bin/activate
|
| 59 |
+
pip install -r requirements.txt
|
| 60 |
+
playwright install --with-deps chromium
|
| 61 |
+
|
| 62 |
+
# 本地模型(通过 SGLang 自托管部署)
|
| 63 |
+
export LOCAL_BASE_URL="http://localhost:30000/v1"
|
| 64 |
+
export LOCAL_MODEL="Qwen/Qwen3.5-2B"
|
| 65 |
+
|
| 66 |
+
# 云端模型(远程 API)
|
| 67 |
+
export CLOUD_BASE_URL="https://your-openai-compatible-endpoint/v1"
|
| 68 |
+
export CLOUD_API_KEY="your-api-key"
|
| 69 |
+
export CLOUD_MODEL="gpt-5.4"
|
| 70 |
+
|
| 71 |
+
export CLIENT_KEY="your-client-key"
|
| 72 |
+
python main.py
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
验证服务:
|
| 76 |
+
|
| 77 |
+
```bash
|
| 78 |
+
curl http://localhost:8000/api/v1/health
|
| 79 |
+
```
|
| 80 |
+
|
| 81 |
+
---
|
| 82 |
+
|
| 83 |
+
## 🏗 架构
|
| 84 |
+
|
| 85 |
+
<p align="center">
|
| 86 |
+
<img src="docs/assets/ohmycaptcha-diagram.png" alt="OhMyCaptcha 架构图" width="560">
|
| 87 |
+
</p>
|
| 88 |
+
|
| 89 |
+
**核心组件:**
|
| 90 |
+
|
| 91 |
+
- **FastAPI** — 实现 YesCaptcha 协议的 HTTP API
|
| 92 |
+
- **TaskManager** — 异步内存任务队列,10 分钟 TTL
|
| 93 |
+
- **RecaptchaV3Solver** — 基于 Playwright 的 reCAPTCHA v3/Enterprise 令牌生成
|
| 94 |
+
- **RecaptchaV2Solver** — 基于 Playwright 的 reCAPTCHA v2 复选框求解
|
| 95 |
+
- **HCaptchaSolver** — 基于 Playwright 的 hCaptcha 求解
|
| 96 |
+
- **TurnstileSolver** — 基于 Playwright 的 Cloudflare Turnstile 求解
|
| 97 |
+
- **CaptchaRecognizer** — 受 Argus 启发的多模态图片分析
|
| 98 |
+
- **ClassificationSolver** — 基于视觉模型的图像分类
|
| 99 |
+
|
| 100 |
+
---
|
| 101 |
+
|
| 102 |
+
## 🧠 任务类型
|
| 103 |
+
|
| 104 |
+
### 浏览器自动化求解(12 种)
|
| 105 |
+
|
| 106 |
+
| 分类 | 任务类型 | 返回字段 |
|
| 107 |
+
|------|---------|---------|
|
| 108 |
+
| reCAPTCHA v3 | `RecaptchaV3TaskProxyless`, `RecaptchaV3TaskProxylessM1`, `RecaptchaV3TaskProxylessM1S7`, `RecaptchaV3TaskProxylessM1S9` | `gRecaptchaResponse` |
|
| 109 |
+
| reCAPTCHA v3 企业版 | `RecaptchaV3EnterpriseTask`, `RecaptchaV3EnterpriseTaskM1` | `gRecaptchaResponse` |
|
| 110 |
+
| reCAPTCHA v2 | `NoCaptchaTaskProxyless`, `RecaptchaV2TaskProxyless`, `RecaptchaV2EnterpriseTaskProxyless` | `gRecaptchaResponse` |
|
| 111 |
+
| hCaptcha | `HCaptchaTaskProxyless` | `gRecaptchaResponse` |
|
| 112 |
+
| Cloudflare Turnstile | `TurnstileTaskProxyless`, `TurnstileTaskProxylessM1` | `token` |
|
| 113 |
+
|
| 114 |
+
### 图片识别(3 种)
|
| 115 |
+
|
| 116 |
+
| 任务类型 | 返回字段 |
|
| 117 |
+
|---------|---------|
|
| 118 |
+
| `ImageToTextTask` | `text`(结构化 JSON) |
|
| 119 |
+
| `ImageToTextTaskMuggle` | `text` |
|
| 120 |
+
| `ImageToTextTaskM1` | `text` |
|
| 121 |
+
|
| 122 |
+
### 图像分类(4 种)
|
| 123 |
+
|
| 124 |
+
| 任务类型 | 返回字段 |
|
| 125 |
+
|---------|---------|
|
| 126 |
+
| `HCaptchaClassification` | `objects` / `answer` |
|
| 127 |
+
| `ReCaptchaV2Classification` | `objects` |
|
| 128 |
+
| `FunCaptchaClassification` | `objects` |
|
| 129 |
+
| `AwsClassification` | `objects` |
|
| 130 |
+
|
| 131 |
+
---
|
| 132 |
+
|
| 133 |
+
## 🔌 API 接口
|
| 134 |
+
|
| 135 |
+
| 接口 | 作用 |
|
| 136 |
+
|------|------|
|
| 137 |
+
| `POST /createTask` | 创建异步验证码任务 |
|
| 138 |
+
| `POST /getTaskResult` | 轮询任务执行结果 |
|
| 139 |
+
| `POST /getBalance` | 返回兼容性余额 |
|
| 140 |
+
| `GET /api/v1/health` | 健康状态检查 |
|
| 141 |
+
|
| 142 |
+
### 示例:reCAPTCHA v3
|
| 143 |
+
|
| 144 |
+
```bash
|
| 145 |
+
curl -X POST http://localhost:8000/createTask \
|
| 146 |
+
-H "Content-Type: application/json" \
|
| 147 |
+
-d '{
|
| 148 |
+
"clientKey": "your-client-key",
|
| 149 |
+
"task": {
|
| 150 |
+
"type": "RecaptchaV3TaskProxyless",
|
| 151 |
+
"websiteURL": "https://antcpt.com/score_detector/",
|
| 152 |
+
"websiteKey": "6LcR_okUAAAAAPYrPe-HK_0RULO1aZM15ENyM-Mf",
|
| 153 |
+
"pageAction": "homepage"
|
| 154 |
+
}
|
| 155 |
+
}'
|
| 156 |
+
```
|
| 157 |
+
|
| 158 |
+
### 示例:hCaptcha
|
| 159 |
+
|
| 160 |
+
```bash
|
| 161 |
+
curl -X POST http://localhost:8000/createTask \
|
| 162 |
+
-H "Content-Type: application/json" \
|
| 163 |
+
-d '{
|
| 164 |
+
"clientKey": "your-client-key",
|
| 165 |
+
"task": {
|
| 166 |
+
"type": "HCaptchaTaskProxyless",
|
| 167 |
+
"websiteURL": "https://example.com",
|
| 168 |
+
"websiteKey": "hcaptcha-site-key"
|
| 169 |
+
}
|
| 170 |
+
}'
|
| 171 |
+
```
|
| 172 |
+
|
| 173 |
+
### 示例:Cloudflare Turnstile
|
| 174 |
+
|
| 175 |
+
```bash
|
| 176 |
+
curl -X POST http://localhost:8000/createTask \
|
| 177 |
+
-H "Content-Type: application/json" \
|
| 178 |
+
-d '{
|
| 179 |
+
"clientKey": "your-client-key",
|
| 180 |
+
"task": {
|
| 181 |
+
"type": "TurnstileTaskProxyless",
|
| 182 |
+
"websiteURL": "https://example.com",
|
| 183 |
+
"websiteKey": "turnstile-site-key"
|
| 184 |
+
}
|
| 185 |
+
}'
|
| 186 |
+
```
|
| 187 |
+
|
| 188 |
+
### 示例:图像分类
|
| 189 |
+
|
| 190 |
+
```bash
|
| 191 |
+
curl -X POST http://localhost:8000/createTask \
|
| 192 |
+
-H "Content-Type: application/json" \
|
| 193 |
+
-d '{
|
| 194 |
+
"clientKey": "your-client-key",
|
| 195 |
+
"task": {
|
| 196 |
+
"type": "ReCaptchaV2Classification",
|
| 197 |
+
"image": "<base64-encoded-image>",
|
| 198 |
+
"question": "Select all images with traffic lights"
|
| 199 |
+
}
|
| 200 |
+
}'
|
| 201 |
+
```
|
| 202 |
+
|
| 203 |
+
### 轮询结果
|
| 204 |
+
|
| 205 |
+
```bash
|
| 206 |
+
curl -X POST http://localhost:8000/getTaskResult \
|
| 207 |
+
-H "Content-Type: application/json" \
|
| 208 |
+
-d '{"clientKey": "your-client-key", "taskId": "uuid-from-createTask"}'
|
| 209 |
+
```
|
| 210 |
+
|
| 211 |
+
---
|
| 212 |
+
|
| 213 |
+
## ⚙️ 配置项
|
| 214 |
+
|
| 215 |
+
### 模型后端
|
| 216 |
+
|
| 217 |
+
OhMyCaptcha 使用两种模型后端 —— **本地模型**处理图像任务,**云端模型**处理复杂推理:
|
| 218 |
+
|
| 219 |
+
| 变量 | 说明 | 默认值 |
|
| 220 |
+
|------|------|--------|
|
| 221 |
+
| `LOCAL_BASE_URL` | 本地推理服务地址(SGLang/vLLM) | `http://localhost:30000/v1` |
|
| 222 |
+
| `LOCAL_API_KEY` | 本地服务密钥 | `EMPTY` |
|
| 223 |
+
| `LOCAL_MODEL` | 本地模型名称 | `Qwen/Qwen3.5-2B` |
|
| 224 |
+
| `CLOUD_BASE_URL` | 云端 API 基地址 | 外部端点 |
|
| 225 |
+
| `CLOUD_API_KEY` | 云端 API 密钥 | 未设置 |
|
| 226 |
+
| `CLOUD_MODEL` | 云端模型名称 | `gpt-5.4` |
|
| 227 |
+
|
| 228 |
+
### 通用
|
| 229 |
+
|
| 230 |
+
| 变量 | 说明 | 默认值 |
|
| 231 |
+
|------|------|--------|
|
| 232 |
+
| `CLIENT_KEY` | 客户端认证密钥 | 未设置 |
|
| 233 |
+
| `CAPTCHA_RETRIES` | 重试次数 | `3` |
|
| 234 |
+
| `CAPTCHA_TIMEOUT` | 模型请求超时(秒) | `30` |
|
| 235 |
+
| `BROWSER_HEADLESS` | 无头浏览器 | `true` |
|
| 236 |
+
| `BROWSER_TIMEOUT` | 页面加载超时(秒) | `30` |
|
| 237 |
+
| `SERVER_HOST` | 监听地址 | `0.0.0.0` |
|
| 238 |
+
| `SERVER_PORT` | 监听端口 | `8000` |
|
| 239 |
+
|
| 240 |
+
> 旧版变量(`CAPTCHA_BASE_URL`、`CAPTCHA_API_KEY`、`CAPTCHA_MODEL`、`CAPTCHA_MULTIMODAL_MODEL`)仍支持作为回退。
|
| 241 |
+
|
| 242 |
+
---
|
| 243 |
+
|
| 244 |
+
## 🚀 部署
|
| 245 |
+
|
| 246 |
+
- [本地模型 (SGLang)](https://shenhao-stu.github.io/ohmycaptcha/zh/deployment/local-model/) — 本地部署 Qwen3.5-2B
|
| 247 |
+
- [Render 部署](https://shenhao-stu.github.io/ohmycaptcha/zh/deployment/render/)
|
| 248 |
+
- [Hugging Face Spaces 部署](https://shenhao-stu.github.io/ohmycaptcha/zh/deployment/huggingface/)
|
| 249 |
+
- [完整文档](https://shenhao-stu.github.io/ohmycaptcha/)
|
| 250 |
+
|
| 251 |
+
---
|
| 252 |
+
|
| 253 |
+
## ✅ 测试目标
|
| 254 |
+
|
| 255 |
+
本服务针对以下公开 reCAPTCHA v3 检测目标完成验证:
|
| 256 |
+
|
| 257 |
+
- URL:`https://antcpt.com/score_detector/`
|
| 258 |
+
- Site key:`6LcR_okUAAAAAPYrPe-HK_0RULO1aZM15ENyM-Mf`
|
| 259 |
+
|
| 260 |
+
---
|
| 261 |
+
|
| 262 |
+
## ⚠️ 限制说明
|
| 263 |
+
|
| 264 |
+
- 任务状态保存在**内存中**,TTL 为 10 分钟
|
| 265 |
+
- `minScore` 为兼容性字段,当前不做分数控制
|
| 266 |
+
- 浏览器自动化的稳定性取决于运行环境、IP 信誉和目标站行为
|
| 267 |
+
- 图像分类质量取决于所使用的视觉模型
|
| 268 |
+
- 并非所有商业打码平台功能均已复现
|
| 269 |
+
|
| 270 |
+
---
|
| 271 |
+
|
| 272 |
+
## 📢 免责声明
|
| 273 |
+
|
| 274 |
+
> **本项目仅供合法的安全研究、渗透测试和技术学习使用。**
|
| 275 |
+
|
| 276 |
+
- OhMyCaptcha 是一个可自托管的工具。你对自己的部署方式和使用行为负完全责任。
|
| 277 |
+
- CAPTCHA 系统的存在是为了保护服务免受滥用。**未经目标网站或服务所有者明确授权,请勿使用本工具绕过 CAPTCHA。**
|
| 278 |
+
- 未经授权地对第三方服务进行自动化访问,可能违反其服务条款,并可能在相关法律管辖区(如《计算机欺诈与滥用法》、GDPR 或当地等效法规)下构成违法行为。
|
| 279 |
+
- 本项目的作者和贡献者**不承担任何因使用本软件而导致的滥用行为、法律后果或损失的责任**。
|
| 280 |
+
- 使用本软件即表示你同意自行确保其使用方式符合所有相关法律法规及服务条款。
|
| 281 |
+
|
| 282 |
+
---
|
| 283 |
+
|
| 284 |
+
## 🔧 开发
|
| 285 |
+
|
| 286 |
+
```bash
|
| 287 |
+
pytest tests/
|
| 288 |
+
npx pyright
|
| 289 |
+
python -m mkdocs build --strict
|
| 290 |
+
```
|
| 291 |
+
|
| 292 |
+
---
|
| 293 |
+
|
| 294 |
+
## Star History
|
| 295 |
+
|
| 296 |
+
[](https://www.star-history.com/#shenhao-stu/ohmycaptcha&Date)
|
| 297 |
+
|
| 298 |
+
---
|
| 299 |
+
|
| 300 |
+
## 📄 License
|
| 301 |
+
|
| 302 |
+
[MIT](LICENSE) —— 自由使用,开放修改,谨慎部署。
|
| 303 |
+
|
| 304 |
+
完整使用条款与免责声明请参阅 [DISCLAIMER.zh-CN.md](DISCLAIMER.zh-CN.md)。
|
SECURITY.md
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Security Policy
|
| 2 |
+
|
| 3 |
+
## Supported Versions
|
| 4 |
+
|
| 5 |
+
OhMyCaptcha is currently maintained from the `main` branch. Security fixes will be applied there first.
|
| 6 |
+
|
| 7 |
+
## Reporting a Vulnerability
|
| 8 |
+
|
| 9 |
+
Please do **not** open public GitHub issues for sensitive security reports.
|
| 10 |
+
|
| 11 |
+
Instead:
|
| 12 |
+
|
| 13 |
+
1. Prepare a minimal reproduction or impact description.
|
| 14 |
+
2. Include the affected version, deployment mode, and whether the issue requires authentication.
|
| 15 |
+
3. Send the report privately through GitHub Security Advisories if available for the repository, or contact the maintainer through a private channel.
|
| 16 |
+
|
| 17 |
+
## What to include
|
| 18 |
+
|
| 19 |
+
Please include as much of the following as possible:
|
| 20 |
+
|
| 21 |
+
- affected endpoint or component
|
| 22 |
+
- reproduction steps
|
| 23 |
+
- expected vs actual behavior
|
| 24 |
+
- logs or screenshots with secrets removed
|
| 25 |
+
- whether the issue is exploitable remotely or only in a local/self-hosted setup
|
| 26 |
+
|
| 27 |
+
## Secret handling
|
| 28 |
+
|
| 29 |
+
This repository is designed for public use. Do not include any of the following in issues, pull requests, screenshots, or sample files:
|
| 30 |
+
|
| 31 |
+
- API keys
|
| 32 |
+
- access tokens
|
| 33 |
+
- cookies
|
| 34 |
+
- private model endpoints
|
| 35 |
+
- customer URLs
|
| 36 |
+
- personally identifying data
|
| 37 |
+
|
| 38 |
+
## Operational guidance
|
| 39 |
+
|
| 40 |
+
If you deploy OhMyCaptcha publicly:
|
| 41 |
+
|
| 42 |
+
- store secrets in environment variables or your hosting platform's secret manager
|
| 43 |
+
- avoid committing `.env` files
|
| 44 |
+
- rotate keys if they were ever exposed in logs or history
|
| 45 |
+
- consider placing the service behind your own authentication, rate limiting, and monitoring layers
|
docs/acceptance.md
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Acceptance
|
| 2 |
+
|
| 3 |
+
This page documents acceptance targets for each supported captcha type, including the test URLs, site keys, and observed outcomes during local validation runs.
|
| 4 |
+
|
| 5 |
+
## Summary
|
| 6 |
+
|
| 7 |
+
| Captcha type | Target | Status |
|
| 8 |
+
|-------------|--------|--------|
|
| 9 |
+
| reCAPTCHA v3 | `https://antcpt.com/score_detector/` | ✅ Token returned |
|
| 10 |
+
| Cloudflare Turnstile | `https://react-turnstile.vercel.app/basic` | ✅ Dummy token returned |
|
| 11 |
+
| reCAPTCHA v2 | `https://www.google.com/recaptcha/api2/demo` | ⚠️ Requires audio challenge (see notes) |
|
| 12 |
+
| hCaptcha | `https://accounts.hcaptcha.com/demo` | ⚠️ Challenge-dependent |
|
| 13 |
+
| Image-to-Text | Local base64 image | ✅ Text returned via vision model |
|
| 14 |
+
| Classification | Local base64 grid | ✅ Object indices returned via vision model |
|
| 15 |
+
|
| 16 |
+
---
|
| 17 |
+
|
| 18 |
+
## reCAPTCHA v3 — Primary acceptance target
|
| 19 |
+
|
| 20 |
+
**URL:** `https://antcpt.com/score_detector/`
|
| 21 |
+
**Site key:** `6LcR_okUAAAAAPYrPe-HK_0RULO1aZM15ENyM-Mf`
|
| 22 |
+
|
| 23 |
+
### Acceptance checklist
|
| 24 |
+
|
| 25 |
+
1. Install dependencies and Playwright Chromium.
|
| 26 |
+
2. Start the service: `python main.py`
|
| 27 |
+
3. Confirm `GET /api/v1/health` returns all 19 supported types.
|
| 28 |
+
4. Create a `RecaptchaV3TaskProxyless` task.
|
| 29 |
+
5. Poll `POST /getTaskResult` until `status=ready`.
|
| 30 |
+
6. Confirm a non-empty `solution.gRecaptchaResponse`.
|
| 31 |
+
|
| 32 |
+
### Curl example
|
| 33 |
+
|
| 34 |
+
```bash
|
| 35 |
+
TASK=$(curl -s -X POST http://localhost:8000/createTask \
|
| 36 |
+
-H "Content-Type: application/json" \
|
| 37 |
+
-d '{
|
| 38 |
+
"clientKey": "your-key",
|
| 39 |
+
"task": {
|
| 40 |
+
"type": "RecaptchaV3TaskProxyless",
|
| 41 |
+
"websiteURL": "https://antcpt.com/score_detector/",
|
| 42 |
+
"websiteKey": "6LcR_okUAAAAAPYrPe-HK_0RULO1aZM15ENyM-Mf",
|
| 43 |
+
"pageAction": "homepage"
|
| 44 |
+
}
|
| 45 |
+
}' | python -c "import sys,json; print(json.load(sys.stdin)['taskId'])")
|
| 46 |
+
|
| 47 |
+
curl -s -X POST http://localhost:8000/getTaskResult \
|
| 48 |
+
-H "Content-Type: application/json" \
|
| 49 |
+
-d '{"clientKey":"your-key","taskId":"'"$TASK"'"}'
|
| 50 |
+
```
|
| 51 |
+
|
| 52 |
+
### Verified outcome
|
| 53 |
+
|
| 54 |
+
- Service startup: ✅
|
| 55 |
+
- Health endpoint: ✅ (19 types registered)
|
| 56 |
+
- Task creation: ✅
|
| 57 |
+
- Token returned: ✅ (non-empty `gRecaptchaResponse`, length ~1060 chars)
|
| 58 |
+
|
| 59 |
+
---
|
| 60 |
+
|
| 61 |
+
## Cloudflare Turnstile
|
| 62 |
+
|
| 63 |
+
**URL:** `https://react-turnstile.vercel.app/basic`
|
| 64 |
+
**Site key:** `1x00000000000000000000AA` (Cloudflare official test key — always passes)
|
| 65 |
+
|
| 66 |
+
### Curl example
|
| 67 |
+
|
| 68 |
+
```bash
|
| 69 |
+
curl -s -X POST http://localhost:8000/createTask \
|
| 70 |
+
-H "Content-Type: application/json" \
|
| 71 |
+
-d '{
|
| 72 |
+
"clientKey": "your-key",
|
| 73 |
+
"task": {
|
| 74 |
+
"type": "TurnstileTaskProxyless",
|
| 75 |
+
"websiteURL": "https://react-turnstile.vercel.app/basic",
|
| 76 |
+
"websiteKey": "1x00000000000000000000AA"
|
| 77 |
+
}
|
| 78 |
+
}'
|
| 79 |
+
```
|
| 80 |
+
|
| 81 |
+
### Verified outcome
|
| 82 |
+
|
| 83 |
+
- Token returned: ✅ `XXXX.DUMMY.TOKEN.XXXX` (expected for Cloudflare test sitekeys)
|
| 84 |
+
|
| 85 |
+
---
|
| 86 |
+
|
| 87 |
+
## reCAPTCHA v2
|
| 88 |
+
|
| 89 |
+
**URL:** `https://www.google.com/recaptcha/api2/demo`
|
| 90 |
+
**Site key:** `6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-`
|
| 91 |
+
|
| 92 |
+
### Behavior with headless Chromium
|
| 93 |
+
|
| 94 |
+
Headless browsers are detected by Google's risk analysis engine. The checkbox click succeeds, but a visual image challenge is presented rather than issuing a token immediately.
|
| 95 |
+
|
| 96 |
+
**Implemented mitigation:** The solver falls back to the **audio challenge path** — clicking the audio button in the challenge dialog, downloading the MP3, transcribing via the configured model, and submitting the transcript.
|
| 97 |
+
|
| 98 |
+
!!! note "Audio challenge transcription"
|
| 99 |
+
The audio challenge requires a language model capable of processing audio or base64-encoded audio data. Accuracy depends on the model endpoint configured via `CAPTCHA_MODEL`.
|
| 100 |
+
|
| 101 |
+
### Curl example
|
| 102 |
+
|
| 103 |
+
```bash
|
| 104 |
+
curl -s -X POST http://localhost:8000/createTask \
|
| 105 |
+
-H "Content-Type: application/json" \
|
| 106 |
+
-d '{
|
| 107 |
+
"clientKey": "your-key",
|
| 108 |
+
"task": {
|
| 109 |
+
"type": "NoCaptchaTaskProxyless",
|
| 110 |
+
"websiteURL": "https://www.google.com/recaptcha/api2/demo",
|
| 111 |
+
"websiteKey": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
|
| 112 |
+
}
|
| 113 |
+
}'
|
| 114 |
+
```
|
| 115 |
+
|
| 116 |
+
### Status
|
| 117 |
+
|
| 118 |
+
⚠️ Functionally implemented with audio challenge fallback. Success rate depends on model audio capability and Google's current challenge difficulty.
|
| 119 |
+
|
| 120 |
+
---
|
| 121 |
+
|
| 122 |
+
## hCaptcha
|
| 123 |
+
|
| 124 |
+
**URL:** `https://accounts.hcaptcha.com/demo`
|
| 125 |
+
**Site key:** `10000000-ffff-ffff-ffff-000000000001` (hCaptcha official test key)
|
| 126 |
+
|
| 127 |
+
### Behavior
|
| 128 |
+
|
| 129 |
+
The hCaptcha test key (`10000000-ffff-ffff-ffff-000000000001`) is designed to always pass — but headless browsers detected as bots still receive an image challenge. The solver clicks the checkbox iframe and polls for a token for up to 30 seconds.
|
| 130 |
+
|
| 131 |
+
### Status
|
| 132 |
+
|
| 133 |
+
⚠️ Checkbox click succeeds. Token issuance depends on hCaptcha's bot detection score. For test environments, using the [HCaptchaClassification](usage/classification.md) task type (direct image classification) is the recommended integration path.
|
| 134 |
+
|
| 135 |
+
---
|
| 136 |
+
|
| 137 |
+
## Image-to-Text
|
| 138 |
+
|
| 139 |
+
Any base64-encoded image can be sent to `ImageToTextTask`. The vision model returns a structured description suitable for click/slide/drag_match captcha automation.
|
| 140 |
+
|
| 141 |
+
### Status
|
| 142 |
+
|
| 143 |
+
✅ Works with any OpenAI-compatible vision model endpoint. Accuracy depends on model capability.
|
| 144 |
+
|
| 145 |
+
---
|
| 146 |
+
|
| 147 |
+
## What these results mean
|
| 148 |
+
|
| 149 |
+
- ✅ **reCAPTCHA v3** and **Turnstile** are fully functional and pass in every local test run.
|
| 150 |
+
- ⚠️ **reCAPTCHA v2** and **hCaptcha** browser-based solving is limited by headless browser detection. These captcha types are primarily intended to be integrated with `HCaptchaClassification` / `ReCaptchaV2Classification` task types for image grid solving, or via audio challenge transcription.
|
| 151 |
+
- The service is designed as a **backend solver for flow2api** — in practice, real-world integrations extract the image challenge frames and send them to the classification endpoint, rather than relying on full browser automation to pass the widget.
|
docs/api-reference.md
ADDED
|
@@ -0,0 +1,246 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# API Reference
|
| 2 |
+
|
| 3 |
+
## Endpoints
|
| 4 |
+
|
| 5 |
+
- `POST /createTask`
|
| 6 |
+
- `POST /getTaskResult`
|
| 7 |
+
- `POST /getBalance`
|
| 8 |
+
- `GET /api/v1/health`
|
| 9 |
+
- `GET /`
|
| 10 |
+
|
| 11 |
+
All task endpoints are JSON-based and follow a YesCaptcha-style async task pattern.
|
| 12 |
+
|
| 13 |
+
## `POST /createTask`
|
| 14 |
+
|
| 15 |
+
### Request shape
|
| 16 |
+
|
| 17 |
+
```json
|
| 18 |
+
{
|
| 19 |
+
"clientKey": "your-client-key",
|
| 20 |
+
"task": {
|
| 21 |
+
"type": "RecaptchaV3TaskProxyless",
|
| 22 |
+
"websiteURL": "https://antcpt.com/score_detector/",
|
| 23 |
+
"websiteKey": "6LcR_okUAAAAAPYrPe-HK_0RULO1aZM15ENyM-Mf",
|
| 24 |
+
"pageAction": "homepage"
|
| 25 |
+
}
|
| 26 |
+
}
|
| 27 |
+
```
|
| 28 |
+
|
| 29 |
+
### Supported task types (19 total)
|
| 30 |
+
|
| 31 |
+
#### reCAPTCHA v3 (browser-based)
|
| 32 |
+
|
| 33 |
+
- `RecaptchaV3TaskProxyless`
|
| 34 |
+
- `RecaptchaV3TaskProxylessM1`
|
| 35 |
+
- `RecaptchaV3TaskProxylessM1S7`
|
| 36 |
+
- `RecaptchaV3TaskProxylessM1S9`
|
| 37 |
+
- `RecaptchaV3EnterpriseTask`
|
| 38 |
+
- `RecaptchaV3EnterpriseTaskM1`
|
| 39 |
+
|
| 40 |
+
Required fields: `websiteURL`, `websiteKey`. Optional: `pageAction`, `minScore`.
|
| 41 |
+
|
| 42 |
+
#### reCAPTCHA v2 (browser-based)
|
| 43 |
+
|
| 44 |
+
- `NoCaptchaTaskProxyless`
|
| 45 |
+
- `RecaptchaV2TaskProxyless`
|
| 46 |
+
- `RecaptchaV2EnterpriseTaskProxyless`
|
| 47 |
+
|
| 48 |
+
Required fields: `websiteURL`, `websiteKey`. Optional: `isInvisible`.
|
| 49 |
+
|
| 50 |
+
#### hCaptcha (browser-based)
|
| 51 |
+
|
| 52 |
+
- `HCaptchaTaskProxyless`
|
| 53 |
+
|
| 54 |
+
Required fields: `websiteURL`, `websiteKey`.
|
| 55 |
+
|
| 56 |
+
#### Cloudflare Turnstile (browser-based)
|
| 57 |
+
|
| 58 |
+
- `TurnstileTaskProxyless`
|
| 59 |
+
- `TurnstileTaskProxylessM1`
|
| 60 |
+
|
| 61 |
+
Required fields: `websiteURL`, `websiteKey`.
|
| 62 |
+
|
| 63 |
+
#### Image recognition
|
| 64 |
+
|
| 65 |
+
- `ImageToTextTask`
|
| 66 |
+
- `ImageToTextTaskMuggle`
|
| 67 |
+
- `ImageToTextTaskM1`
|
| 68 |
+
|
| 69 |
+
Required fields: `body` (base64-encoded image).
|
| 70 |
+
|
| 71 |
+
#### Image classification
|
| 72 |
+
|
| 73 |
+
- `HCaptchaClassification`
|
| 74 |
+
- `ReCaptchaV2Classification`
|
| 75 |
+
- `FunCaptchaClassification`
|
| 76 |
+
- `AwsClassification`
|
| 77 |
+
|
| 78 |
+
Required fields: `image` or `images` or `queries` (base64-encoded). Optional: `question`.
|
| 79 |
+
|
| 80 |
+
### Compatibility note on `minScore`
|
| 81 |
+
|
| 82 |
+
The request model accepts `minScore` for compatibility. The current solver implementation does **not** enforce score targeting based on this field.
|
| 83 |
+
|
| 84 |
+
### Success response
|
| 85 |
+
|
| 86 |
+
```json
|
| 87 |
+
{
|
| 88 |
+
"errorId": 0,
|
| 89 |
+
"taskId": "uuid-string"
|
| 90 |
+
}
|
| 91 |
+
```
|
| 92 |
+
|
| 93 |
+
### Common error responses
|
| 94 |
+
|
| 95 |
+
```json
|
| 96 |
+
{
|
| 97 |
+
"errorId": 1,
|
| 98 |
+
"errorCode": "ERROR_TASK_NOT_SUPPORTED",
|
| 99 |
+
"errorDescription": "Task type 'X' is not supported."
|
| 100 |
+
}
|
| 101 |
+
```
|
| 102 |
+
|
| 103 |
+
```json
|
| 104 |
+
{
|
| 105 |
+
"errorId": 1,
|
| 106 |
+
"errorCode": "ERROR_TASK_PROPERTY_EMPTY",
|
| 107 |
+
"errorDescription": "websiteURL and websiteKey are required"
|
| 108 |
+
}
|
| 109 |
+
```
|
| 110 |
+
|
| 111 |
+
## `POST /getTaskResult`
|
| 112 |
+
|
| 113 |
+
### Request
|
| 114 |
+
|
| 115 |
+
```json
|
| 116 |
+
{
|
| 117 |
+
"clientKey": "your-client-key",
|
| 118 |
+
"taskId": "uuid-from-createTask"
|
| 119 |
+
}
|
| 120 |
+
```
|
| 121 |
+
|
| 122 |
+
### Processing response
|
| 123 |
+
|
| 124 |
+
```json
|
| 125 |
+
{
|
| 126 |
+
"errorId": 0,
|
| 127 |
+
"status": "processing"
|
| 128 |
+
}
|
| 129 |
+
```
|
| 130 |
+
|
| 131 |
+
### Ready response for reCAPTCHA v2/v3
|
| 132 |
+
|
| 133 |
+
```json
|
| 134 |
+
{
|
| 135 |
+
"errorId": 0,
|
| 136 |
+
"status": "ready",
|
| 137 |
+
"solution": {
|
| 138 |
+
"gRecaptchaResponse": "token..."
|
| 139 |
+
}
|
| 140 |
+
}
|
| 141 |
+
```
|
| 142 |
+
|
| 143 |
+
### Ready response for Cloudflare Turnstile
|
| 144 |
+
|
| 145 |
+
```json
|
| 146 |
+
{
|
| 147 |
+
"errorId": 0,
|
| 148 |
+
"status": "ready",
|
| 149 |
+
"solution": {
|
| 150 |
+
"token": "cf-turnstile-token..."
|
| 151 |
+
}
|
| 152 |
+
}
|
| 153 |
+
```
|
| 154 |
+
|
| 155 |
+
### Ready response for `ImageToTextTask`
|
| 156 |
+
|
| 157 |
+
```json
|
| 158 |
+
{
|
| 159 |
+
"errorId": 0,
|
| 160 |
+
"status": "ready",
|
| 161 |
+
"solution": {
|
| 162 |
+
"text": "{\"captcha_type\":\"click\", ...}"
|
| 163 |
+
}
|
| 164 |
+
}
|
| 165 |
+
```
|
| 166 |
+
|
| 167 |
+
### Ready response for classification tasks
|
| 168 |
+
|
| 169 |
+
```json
|
| 170 |
+
{
|
| 171 |
+
"errorId": 0,
|
| 172 |
+
"status": "ready",
|
| 173 |
+
"solution": {
|
| 174 |
+
"objects": [0, 3, 6]
|
| 175 |
+
}
|
| 176 |
+
}
|
| 177 |
+
```
|
| 178 |
+
|
| 179 |
+
### Not found response
|
| 180 |
+
|
| 181 |
+
```json
|
| 182 |
+
{
|
| 183 |
+
"errorId": 1,
|
| 184 |
+
"errorCode": "ERROR_NO_SUCH_CAPCHA_ID",
|
| 185 |
+
"errorDescription": "Task not found"
|
| 186 |
+
}
|
| 187 |
+
```
|
| 188 |
+
|
| 189 |
+
## `POST /getBalance`
|
| 190 |
+
|
| 191 |
+
### Request
|
| 192 |
+
|
| 193 |
+
```json
|
| 194 |
+
{
|
| 195 |
+
"clientKey": "your-client-key"
|
| 196 |
+
}
|
| 197 |
+
```
|
| 198 |
+
|
| 199 |
+
### Response
|
| 200 |
+
|
| 201 |
+
```json
|
| 202 |
+
{
|
| 203 |
+
"errorId": 0,
|
| 204 |
+
"balance": 99999.0
|
| 205 |
+
}
|
| 206 |
+
```
|
| 207 |
+
|
| 208 |
+
This balance is currently a static compatibility response.
|
| 209 |
+
|
| 210 |
+
## `GET /api/v1/health`
|
| 211 |
+
|
| 212 |
+
Example response:
|
| 213 |
+
|
| 214 |
+
```json
|
| 215 |
+
{
|
| 216 |
+
"status": "ok",
|
| 217 |
+
"supported_task_types": [
|
| 218 |
+
"RecaptchaV3TaskProxyless",
|
| 219 |
+
"RecaptchaV3TaskProxylessM1",
|
| 220 |
+
"RecaptchaV3TaskProxylessM1S7",
|
| 221 |
+
"RecaptchaV3TaskProxylessM1S9",
|
| 222 |
+
"RecaptchaV3EnterpriseTask",
|
| 223 |
+
"RecaptchaV3EnterpriseTaskM1",
|
| 224 |
+
"NoCaptchaTaskProxyless",
|
| 225 |
+
"RecaptchaV2TaskProxyless",
|
| 226 |
+
"RecaptchaV2EnterpriseTaskProxyless",
|
| 227 |
+
"HCaptchaTaskProxyless",
|
| 228 |
+
"TurnstileTaskProxyless",
|
| 229 |
+
"TurnstileTaskProxylessM1",
|
| 230 |
+
"ImageToTextTask",
|
| 231 |
+
"ImageToTextTaskMuggle",
|
| 232 |
+
"ImageToTextTaskM1",
|
| 233 |
+
"HCaptchaClassification",
|
| 234 |
+
"ReCaptchaV2Classification",
|
| 235 |
+
"FunCaptchaClassification",
|
| 236 |
+
"AwsClassification"
|
| 237 |
+
],
|
| 238 |
+
"browser_headless": true,
|
| 239 |
+
"captcha_model": "gpt-5.4",
|
| 240 |
+
"captcha_multimodal_model": "qwen3.5-2b"
|
| 241 |
+
}
|
| 242 |
+
```
|
| 243 |
+
|
| 244 |
+
## `GET /`
|
| 245 |
+
|
| 246 |
+
The root endpoint returns a compact service description and the registered task types at runtime.
|
docs/assets/.gitkeep
ADDED
|
File without changes
|
docs/assets/ohmycaptcha-diagram.png
ADDED
|
Git LFS Details
|
docs/assets/ohmycaptcha-hero.png
ADDED
|
Git LFS Details
|
docs/deployment/huggingface.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Hugging Face Spaces Deployment
|
| 2 |
+
|
| 3 |
+
This guide shows how to deploy OhMyCaptcha on **Hugging Face Spaces** using a Docker-based Space.
|
| 4 |
+
|
| 5 |
+
## When to choose Hugging Face Spaces
|
| 6 |
+
|
| 7 |
+
Use Hugging Face Spaces when you want:
|
| 8 |
+
|
| 9 |
+
- a simple public or private demo deployment
|
| 10 |
+
- a UI-driven hosting workflow
|
| 11 |
+
- easy secret management inside the Space settings
|
| 12 |
+
- a Docker-based environment without managing a VPS yourself
|
| 13 |
+
|
| 14 |
+
## 1. Prepare the repository
|
| 15 |
+
|
| 16 |
+
Make sure your repository includes:
|
| 17 |
+
|
| 18 |
+
- `Dockerfile.render`
|
| 19 |
+
- `main.py`
|
| 20 |
+
- `requirements.txt`
|
| 21 |
+
- the `src/` application package
|
| 22 |
+
|
| 23 |
+
For Hugging Face Spaces, the current Dockerfile can be reused as a starting point because it already installs Python dependencies and Playwright Chromium.
|
| 24 |
+
|
| 25 |
+
## 2. Create a Docker Space
|
| 26 |
+
|
| 27 |
+
In Hugging Face:
|
| 28 |
+
|
| 29 |
+
1. Create a new **Space**.
|
| 30 |
+
2. Choose **Docker** as the SDK.
|
| 31 |
+
3. Select visibility according to your needs.
|
| 32 |
+
4. Connect the Space to this repository or upload the project files.
|
| 33 |
+
|
| 34 |
+
## 3. Configure secrets and variables
|
| 35 |
+
|
| 36 |
+
In the Space settings, add the following secrets:
|
| 37 |
+
|
| 38 |
+
- `CLIENT_KEY`
|
| 39 |
+
- `CAPTCHA_API_KEY`
|
| 40 |
+
|
| 41 |
+
Add or override variables as needed:
|
| 42 |
+
|
| 43 |
+
- `CAPTCHA_BASE_URL`
|
| 44 |
+
- `CAPTCHA_MODEL`
|
| 45 |
+
- `CAPTCHA_MULTIMODAL_MODEL`
|
| 46 |
+
- `BROWSER_HEADLESS=true`
|
| 47 |
+
- `BROWSER_TIMEOUT=30`
|
| 48 |
+
- `SERVER_PORT=7860`
|
| 49 |
+
|
| 50 |
+
Hugging Face Spaces typically expose applications on port `7860`, so set `SERVER_PORT=7860`.
|
| 51 |
+
|
| 52 |
+
## 4. Confirm the startup command
|
| 53 |
+
|
| 54 |
+
The container should start the app with:
|
| 55 |
+
|
| 56 |
+
```bash
|
| 57 |
+
python main.py
|
| 58 |
+
```
|
| 59 |
+
|
| 60 |
+
The entrypoint already respects environment-based port configuration.
|
| 61 |
+
|
| 62 |
+
## 5. Wait for the build to finish
|
| 63 |
+
|
| 64 |
+
After the Space starts building:
|
| 65 |
+
|
| 66 |
+
- watch the build logs
|
| 67 |
+
- confirm dependency installation finishes successfully
|
| 68 |
+
- confirm Playwright Chromium installs successfully
|
| 69 |
+
- wait for the app to enter the running state
|
| 70 |
+
|
| 71 |
+
## 6. Validate the deployment
|
| 72 |
+
|
| 73 |
+
Once the Space is live, verify:
|
| 74 |
+
|
| 75 |
+
### Root endpoint
|
| 76 |
+
|
| 77 |
+
```bash
|
| 78 |
+
curl https://<your-space-subdomain>.hf.space/
|
| 79 |
+
```
|
| 80 |
+
|
| 81 |
+
### Health endpoint
|
| 82 |
+
|
| 83 |
+
```bash
|
| 84 |
+
curl https://<your-space-subdomain>.hf.space/api/v1/health
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
### Create a detector task
|
| 88 |
+
|
| 89 |
+
```bash
|
| 90 |
+
curl -X POST https://<your-space-subdomain>.hf.space/createTask \
|
| 91 |
+
-H "Content-Type: application/json" \
|
| 92 |
+
-d '{
|
| 93 |
+
"clientKey": "your-client-key",
|
| 94 |
+
"task": {
|
| 95 |
+
"type": "RecaptchaV3TaskProxyless",
|
| 96 |
+
"websiteURL": "https://antcpt.com/score_detector/",
|
| 97 |
+
"websiteKey": "6LcR_okUAAAAAPYrPe-HK_0RULO1aZM15ENyM-Mf",
|
| 98 |
+
"pageAction": "homepage"
|
| 99 |
+
}
|
| 100 |
+
}'
|
| 101 |
+
```
|
| 102 |
+
|
| 103 |
+
## Operational notes
|
| 104 |
+
|
| 105 |
+
- Hugging Face Spaces are convenient, but cold starts and resource limits can affect Playwright-based workloads.
|
| 106 |
+
- Browser automation can be more sensitive to shared-hosting environments than standard API-only apps.
|
| 107 |
+
- If you need stricter runtime control, use Render or your own infrastructure.
|
| 108 |
+
|
| 109 |
+
## Recommended usage
|
| 110 |
+
|
| 111 |
+
Hugging Face Spaces is best suited for:
|
| 112 |
+
|
| 113 |
+
- evaluation
|
| 114 |
+
- demos
|
| 115 |
+
- low-volume internal usage
|
| 116 |
+
- fast public documentation-linked deployment
|
docs/deployment/local-model.md
ADDED
|
@@ -0,0 +1,155 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Local Model Deployment
|
| 2 |
+
|
| 3 |
+
OhMyCaptcha supports running image recognition and classification tasks on a **locally hosted model** served via [SGLang](https://github.com/sgl-project/sglang), [vLLM](https://github.com/vllm-project/vllm), or any OpenAI-compatible inference server.
|
| 4 |
+
|
| 5 |
+
This guide covers deploying [Qwen3.5-2B](https://modelscope.cn/models/Qwen/Qwen3.5-2B) locally with SGLang.
|
| 6 |
+
|
| 7 |
+
## Architecture: Local vs Cloud
|
| 8 |
+
|
| 9 |
+
OhMyCaptcha uses two model backends:
|
| 10 |
+
|
| 11 |
+
| Backend | Role | Env vars | Default |
|
| 12 |
+
|---------|------|----------|---------|
|
| 13 |
+
| **Local model** | Image recognition & classification (high-throughput, self-hosted) | `LOCAL_BASE_URL`, `LOCAL_API_KEY`, `LOCAL_MODEL` | `http://localhost:30000/v1`, `EMPTY`, `Qwen/Qwen3.5-2B` |
|
| 14 |
+
| **Cloud model** | Audio transcription & complex reasoning (powerful remote API) | `CLOUD_BASE_URL`, `CLOUD_API_KEY`, `CLOUD_MODEL` | External endpoint, your key, `gpt-5.4` |
|
| 15 |
+
|
| 16 |
+
```
|
| 17 |
+
┌────────────────────────────────────────────────────────────┐
|
| 18 |
+
│ OhMyCaptcha │
|
| 19 |
+
│ │
|
| 20 |
+
│ Browser tasks ──► Playwright (reCAPTCHA, Turnstile) │
|
| 21 |
+
│ │
|
| 22 |
+
│ Image tasks ───► Local Model (SGLang / vLLM) │
|
| 23 |
+
│ └─ Qwen3.5-2B on localhost:30000 │
|
| 24 |
+
│ │
|
| 25 |
+
│ Audio tasks ───► Cloud Model (remote API) │
|
| 26 |
+
│ └─ gpt-5.4 via external endpoint │
|
| 27 |
+
└────────────────────────────────────────────────────────────┘
|
| 28 |
+
```
|
| 29 |
+
|
| 30 |
+
## Prerequisites
|
| 31 |
+
|
| 32 |
+
- Python 3.10+
|
| 33 |
+
- NVIDIA GPU with CUDA support (recommended: 8GB+ VRAM for Qwen3.5-2B)
|
| 34 |
+
- `pip` package manager
|
| 35 |
+
|
| 36 |
+
## Step 1: Install SGLang
|
| 37 |
+
|
| 38 |
+
```bash
|
| 39 |
+
pip install "sglang[all]>=0.4.6.post1"
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
## Step 2: Launch the model server
|
| 43 |
+
|
| 44 |
+
### From Hugging Face
|
| 45 |
+
|
| 46 |
+
```bash
|
| 47 |
+
python -m sglang.launch_server \
|
| 48 |
+
--model-path Qwen/Qwen3.5-2B \
|
| 49 |
+
--host 0.0.0.0 \
|
| 50 |
+
--port 30000
|
| 51 |
+
```
|
| 52 |
+
|
| 53 |
+
### From ModelScope (recommended in China)
|
| 54 |
+
|
| 55 |
+
```bash
|
| 56 |
+
export SGLANG_USE_MODELSCOPE=true
|
| 57 |
+
python -m sglang.launch_server \
|
| 58 |
+
--model-path Qwen/Qwen3.5-2B \
|
| 59 |
+
--host 0.0.0.0 \
|
| 60 |
+
--port 30000
|
| 61 |
+
```
|
| 62 |
+
|
| 63 |
+
### With multiple GPUs
|
| 64 |
+
|
| 65 |
+
```bash
|
| 66 |
+
python -m sglang.launch_server \
|
| 67 |
+
--model-path Qwen/Qwen3.5-2B \
|
| 68 |
+
--host 0.0.0.0 \
|
| 69 |
+
--port 30000 \
|
| 70 |
+
--tensor-parallel-size 2
|
| 71 |
+
```
|
| 72 |
+
|
| 73 |
+
Once started, the server exposes an OpenAI-compatible API at `http://localhost:30000/v1`.
|
| 74 |
+
|
| 75 |
+
## Step 3: Verify the model server
|
| 76 |
+
|
| 77 |
+
```bash
|
| 78 |
+
curl http://localhost:30000/v1/chat/completions \
|
| 79 |
+
-H "Content-Type: application/json" \
|
| 80 |
+
-d '{
|
| 81 |
+
"model": "Qwen/Qwen3.5-2B",
|
| 82 |
+
"messages": [{"role": "user", "content": "Hello"}],
|
| 83 |
+
"max_tokens": 32
|
| 84 |
+
}'
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
You should receive a valid JSON response with model output.
|
| 88 |
+
|
| 89 |
+
## Step 4: Configure OhMyCaptcha
|
| 90 |
+
|
| 91 |
+
Set the local model env vars to point at your SGLang server:
|
| 92 |
+
|
| 93 |
+
```bash
|
| 94 |
+
# Local model (self-hosted via SGLang)
|
| 95 |
+
export LOCAL_BASE_URL="http://localhost:30000/v1"
|
| 96 |
+
export LOCAL_API_KEY="EMPTY"
|
| 97 |
+
export LOCAL_MODEL="Qwen/Qwen3.5-2B"
|
| 98 |
+
|
| 99 |
+
# Cloud model (remote API for audio transcription etc.)
|
| 100 |
+
export CLOUD_BASE_URL="https://your-api-endpoint/v1"
|
| 101 |
+
export CLOUD_API_KEY="sk-your-key"
|
| 102 |
+
export CLOUD_MODEL="gpt-5.4"
|
| 103 |
+
|
| 104 |
+
# Other config
|
| 105 |
+
export CLIENT_KEY="your-client-key"
|
| 106 |
+
export BROWSER_HEADLESS=true
|
| 107 |
+
```
|
| 108 |
+
|
| 109 |
+
## Step 5: Start OhMyCaptcha
|
| 110 |
+
|
| 111 |
+
```bash
|
| 112 |
+
python main.py
|
| 113 |
+
```
|
| 114 |
+
|
| 115 |
+
The health endpoint shows both model backends:
|
| 116 |
+
|
| 117 |
+
```bash
|
| 118 |
+
curl http://localhost:8000/api/v1/health
|
| 119 |
+
```
|
| 120 |
+
|
| 121 |
+
```json
|
| 122 |
+
{
|
| 123 |
+
"status": "ok",
|
| 124 |
+
"supported_task_types": ["RecaptchaV3TaskProxyless", "..."],
|
| 125 |
+
"browser_headless": true,
|
| 126 |
+
"cloud_model": "gpt-5.4",
|
| 127 |
+
"local_model": "Qwen/Qwen3.5-2B"
|
| 128 |
+
}
|
| 129 |
+
```
|
| 130 |
+
|
| 131 |
+
## Alternative: vLLM
|
| 132 |
+
|
| 133 |
+
vLLM can serve the same model with an identical API:
|
| 134 |
+
|
| 135 |
+
```bash
|
| 136 |
+
pip install vllm
|
| 137 |
+
python -m vllm.entrypoints.openai.api_server \
|
| 138 |
+
--model Qwen/Qwen3.5-2B \
|
| 139 |
+
--host 0.0.0.0 \
|
| 140 |
+
--port 30000
|
| 141 |
+
```
|
| 142 |
+
|
| 143 |
+
No changes to the OhMyCaptcha configuration are needed — both SGLang and vLLM expose `/v1/chat/completions`.
|
| 144 |
+
|
| 145 |
+
## Backward compatibility
|
| 146 |
+
|
| 147 |
+
The legacy environment variables (`CAPTCHA_BASE_URL`, `CAPTCHA_API_KEY`, `CAPTCHA_MODEL`, `CAPTCHA_MULTIMODAL_MODEL`) are still supported as fallbacks. If you set `CAPTCHA_BASE_URL` without setting `CLOUD_BASE_URL`, the old value will be used. The new `LOCAL_*` and `CLOUD_*` variables take precedence when set.
|
| 148 |
+
|
| 149 |
+
## Recommended models
|
| 150 |
+
|
| 151 |
+
| Model | Size | Use case | VRAM |
|
| 152 |
+
|-------|------|----------|------|
|
| 153 |
+
| `Qwen/Qwen3.5-2B` | 2B | Image recognition & classification | ~5 GB |
|
| 154 |
+
| `Qwen/Qwen3.5-7B` | 7B | Higher accuracy classification | ~15 GB |
|
| 155 |
+
| `Qwen/Qwen3.5-2B-FP8` | 2B (quantized) | Lower VRAM requirement | ~3 GB |
|
docs/deployment/render.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Render Deployment
|
| 2 |
+
|
| 3 |
+
This guide walks through a clean **Render** deployment for OhMyCaptcha using the Docker files already included in this repository.
|
| 4 |
+
|
| 5 |
+
## When to choose Render
|
| 6 |
+
|
| 7 |
+
Render is a good fit when you want:
|
| 8 |
+
|
| 9 |
+
- managed deployment with a stable public URL
|
| 10 |
+
- easy secret management
|
| 11 |
+
- a simple Docker-based workflow
|
| 12 |
+
- fewer runtime constraints than demo-oriented hosting platforms
|
| 13 |
+
|
| 14 |
+
## 1. Prepare the repository
|
| 15 |
+
|
| 16 |
+
This repository already includes the files Render needs:
|
| 17 |
+
|
| 18 |
+
- `Dockerfile.render`
|
| 19 |
+
- `render.yaml`
|
| 20 |
+
- `main.py`
|
| 21 |
+
- `requirements.txt`
|
| 22 |
+
- `src/`
|
| 23 |
+
|
| 24 |
+
The application listens on port `8000` and also respects the `PORT` environment variable injected by Render.
|
| 25 |
+
|
| 26 |
+
## 2. Create the Render service
|
| 27 |
+
|
| 28 |
+
In Render:
|
| 29 |
+
|
| 30 |
+
1. Create a new **Web Service**.
|
| 31 |
+
2. Connect your GitHub repository.
|
| 32 |
+
3. Choose **Docker** as the runtime.
|
| 33 |
+
4. Point Render at:
|
| 34 |
+
- Dockerfile: `Dockerfile.render`
|
| 35 |
+
- Context: repository root
|
| 36 |
+
|
| 37 |
+
You can also import the included `render.yaml` blueprint.
|
| 38 |
+
|
| 39 |
+
## 3. Configure environment variables
|
| 40 |
+
|
| 41 |
+
### Required secrets
|
| 42 |
+
|
| 43 |
+
Set these as protected environment variables in the Render dashboard:
|
| 44 |
+
|
| 45 |
+
- `CLIENT_KEY`
|
| 46 |
+
- `CAPTCHA_API_KEY`
|
| 47 |
+
|
| 48 |
+
### Recommended variables
|
| 49 |
+
|
| 50 |
+
- `CAPTCHA_BASE_URL=https://your-openai-compatible-endpoint/v1`
|
| 51 |
+
- `CAPTCHA_MODEL=gpt-5.4`
|
| 52 |
+
- `CAPTCHA_MULTIMODAL_MODEL=qwen3.5-2b`
|
| 53 |
+
- `CAPTCHA_RETRIES=3`
|
| 54 |
+
- `CAPTCHA_TIMEOUT=30`
|
| 55 |
+
- `BROWSER_HEADLESS=true`
|
| 56 |
+
- `BROWSER_TIMEOUT=30`
|
| 57 |
+
|
| 58 |
+
## 4. Trigger the first deploy
|
| 59 |
+
|
| 60 |
+
After saving the configuration:
|
| 61 |
+
|
| 62 |
+
- wait for the image build
|
| 63 |
+
- confirm Python dependencies install successfully
|
| 64 |
+
- confirm Playwright Chromium installation completes successfully
|
| 65 |
+
- wait until the service status becomes healthy
|
| 66 |
+
|
| 67 |
+
## 5. Validate the deployment
|
| 68 |
+
|
| 69 |
+
Once the Render URL is available, check:
|
| 70 |
+
|
| 71 |
+
### Root endpoint
|
| 72 |
+
|
| 73 |
+
```bash
|
| 74 |
+
curl https://<your-render-service>.onrender.com/
|
| 75 |
+
```
|
| 76 |
+
|
| 77 |
+
### Health endpoint
|
| 78 |
+
|
| 79 |
+
```bash
|
| 80 |
+
curl https://<your-render-service>.onrender.com/api/v1/health
|
| 81 |
+
```
|
| 82 |
+
|
| 83 |
+
### Create a detector task
|
| 84 |
+
|
| 85 |
+
```bash
|
| 86 |
+
curl -X POST https://<your-render-service>.onrender.com/createTask \
|
| 87 |
+
-H "Content-Type: application/json" \
|
| 88 |
+
-d '{
|
| 89 |
+
"clientKey": "your-client-key",
|
| 90 |
+
"task": {
|
| 91 |
+
"type": "RecaptchaV3TaskProxyless",
|
| 92 |
+
"websiteURL": "https://antcpt.com/score_detector/",
|
| 93 |
+
"websiteKey": "6LcR_okUAAAAAPYrPe-HK_0RULO1aZM15ENyM-Mf",
|
| 94 |
+
"pageAction": "homepage"
|
| 95 |
+
}
|
| 96 |
+
}'
|
| 97 |
+
```
|
| 98 |
+
|
| 99 |
+
## Operational notes
|
| 100 |
+
|
| 101 |
+
- Render is generally a better fit than lightweight demo platforms for browser automation.
|
| 102 |
+
- Browser-based solving can still be sensitive to cold starts, IP quality, and container resource limits.
|
| 103 |
+
- If you need stronger control over runtime behavior, move to your own infrastructure.
|
| 104 |
+
|
| 105 |
+
## Recommended usage
|
| 106 |
+
|
| 107 |
+
Render is a strong default choice for:
|
| 108 |
+
|
| 109 |
+
- persistent public deployments
|
| 110 |
+
- flow2api integration testing
|
| 111 |
+
- low-to-medium production traffic
|
| 112 |
+
- quick managed rollout without maintaining your own host
|
docs/faq.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# FAQ
|
| 2 |
+
|
| 3 |
+
## Does this fully replace YesCaptcha?
|
| 4 |
+
|
| 5 |
+
No. It implements a YesCaptcha-style API surface for the task types available in this repository. It should not be described as full vendor parity.
|
| 6 |
+
|
| 7 |
+
## Does `minScore` guarantee a target reCAPTCHA score?
|
| 8 |
+
|
| 9 |
+
No. The request model accepts `minScore` for compatibility, but the current solver does not enforce score targeting.
|
| 10 |
+
|
| 11 |
+
## Can I use local or self-hosted multimodal models?
|
| 12 |
+
|
| 13 |
+
Yes, if they expose an OpenAI-compatible API with image-capable chat completion behavior.
|
| 14 |
+
|
| 15 |
+
## Does `ImageToTextTask` return plain OCR text?
|
| 16 |
+
|
| 17 |
+
Not necessarily. The current implementation returns structured recognition output serialized into `solution.text`.
|
| 18 |
+
|
| 19 |
+
## Is task state persistent?
|
| 20 |
+
|
| 21 |
+
No. Task state is stored in memory and cleaned up after the configured TTL window.
|
| 22 |
+
|
| 23 |
+
## What affects reCAPTCHA v3 results?
|
| 24 |
+
|
| 25 |
+
Common factors include IP quality, browser fingerprint, target site behavior, page action correctness, and runtime environment.
|
docs/getting-started.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Getting Started
|
| 2 |
+
|
| 3 |
+
## Requirements
|
| 4 |
+
|
| 5 |
+
- Python 3.10+
|
| 6 |
+
- Chromium available through Playwright
|
| 7 |
+
- Network access to:
|
| 8 |
+
- target sites you want to solve against
|
| 9 |
+
- your configured OpenAI-compatible model endpoint
|
| 10 |
+
|
| 11 |
+
## Installation
|
| 12 |
+
|
| 13 |
+
```bash
|
| 14 |
+
python -m venv .venv
|
| 15 |
+
source .venv/bin/activate
|
| 16 |
+
pip install -r requirements.txt
|
| 17 |
+
playwright install --with-deps chromium
|
| 18 |
+
```
|
| 19 |
+
|
| 20 |
+
## Environment variables
|
| 21 |
+
|
| 22 |
+
| Variable | Description | Default |
|
| 23 |
+
| --- | --- | --- |
|
| 24 |
+
| `CLIENT_KEY` | Client auth key used as `clientKey` | unset |
|
| 25 |
+
| `CAPTCHA_BASE_URL` | OpenAI-compatible API base URL | `https://your-openai-compatible-endpoint/v1` |
|
| 26 |
+
| `CAPTCHA_API_KEY` | API key for your model provider | unset |
|
| 27 |
+
| `CAPTCHA_MODEL` | Strong text model | `gpt-5.4` |
|
| 28 |
+
| `CAPTCHA_MULTIMODAL_MODEL` | Multimodal model | `qwen3.5-2b` |
|
| 29 |
+
| `CAPTCHA_RETRIES` | Retry count | `3` |
|
| 30 |
+
| `CAPTCHA_TIMEOUT` | Model timeout in seconds | `30` |
|
| 31 |
+
| `BROWSER_HEADLESS` | Run Chromium headless | `true` |
|
| 32 |
+
| `BROWSER_TIMEOUT` | Browser timeout in seconds | `30` |
|
| 33 |
+
| `SERVER_HOST` | Bind host | `0.0.0.0` |
|
| 34 |
+
| `SERVER_PORT` | Bind port | `8000` |
|
| 35 |
+
|
| 36 |
+
## Start the service
|
| 37 |
+
|
| 38 |
+
```bash
|
| 39 |
+
export CLIENT_KEY="your-client-key"
|
| 40 |
+
export CAPTCHA_BASE_URL="https://your-openai-compatible-endpoint/v1"
|
| 41 |
+
export CAPTCHA_API_KEY="your-api-key"
|
| 42 |
+
export CAPTCHA_MODEL="gpt-5.4"
|
| 43 |
+
export CAPTCHA_MULTIMODAL_MODEL="qwen3.5-2b"
|
| 44 |
+
python main.py
|
| 45 |
+
```
|
| 46 |
+
|
| 47 |
+
## Verify startup
|
| 48 |
+
|
| 49 |
+
### Root endpoint
|
| 50 |
+
|
| 51 |
+
```bash
|
| 52 |
+
curl http://localhost:8000/
|
| 53 |
+
```
|
| 54 |
+
|
| 55 |
+
### Health endpoint
|
| 56 |
+
|
| 57 |
+
```bash
|
| 58 |
+
curl http://localhost:8000/api/v1/health
|
| 59 |
+
```
|
| 60 |
+
|
| 61 |
+
The health response should include the registered task types and current runtime model settings.
|
| 62 |
+
|
| 63 |
+
## Local and self-hosted model support
|
| 64 |
+
|
| 65 |
+
The image recognition path is built around **OpenAI-compatible APIs**. In practice, this means you can point `CAPTCHA_BASE_URL` at a hosted provider or a self-hosted/local multimodal gateway, as long as it exposes compatible chat-completions semantics and supports image input.
|
| 66 |
+
|
| 67 |
+
The project intentionally documents this in generic compatibility terms rather than claiming full validation for every provider stack.
|
docs/index.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# OhMyCaptcha
|
| 2 |
+
|
| 3 |
+
<div class="hero hero--light" markdown>
|
| 4 |
+
|
| 5 |
+
<div class="hero__visual">
|
| 6 |
+
<img src="assets/ohmycaptcha-hero.png" alt="OhMyCaptcha — self-hostable captcha solving service">
|
| 7 |
+
</div>
|
| 8 |
+
|
| 9 |
+
<div class="hero__copy" markdown>
|
| 10 |
+
|
| 11 |
+
## ⚡ Self-hostable captcha solving with a clean YesCaptcha-style API
|
| 12 |
+
|
| 13 |
+
OhMyCaptcha combines **FastAPI**, **Playwright**, and **OpenAI-compatible multimodal models** into a focused service for **flow2api** and similar integrations. Supports **19 task types** across reCAPTCHA, hCaptcha, Cloudflare Turnstile, and image classification.
|
| 14 |
+
|
| 15 |
+
<div class="hero__actions" markdown>
|
| 16 |
+
|
| 17 |
+
[Get started](getting-started.md){ .md-button .md-button--primary }
|
| 18 |
+
[API reference](api-reference.md){ .md-button }
|
| 19 |
+
[GitHub](https://github.com/shenhao-stu/ohmycaptcha){ .md-button }
|
| 20 |
+
|
| 21 |
+
</div>
|
| 22 |
+
|
| 23 |
+
</div>
|
| 24 |
+
|
| 25 |
+
</div>
|
| 26 |
+
|
| 27 |
+
## ✨ Highlights
|
| 28 |
+
|
| 29 |
+
<div class="grid cards feature-cards" markdown>
|
| 30 |
+
|
| 31 |
+
- :material-api: **YesCaptcha-style API**
|
| 32 |
+
|
| 33 |
+
---
|
| 34 |
+
|
| 35 |
+
Familiar async `createTask` / `getTaskResult` semantics covering reCAPTCHA v2/v3, hCaptcha, Turnstile, and image classification.
|
| 36 |
+
|
| 37 |
+
- :material-google-chrome: **Browser-based solving**
|
| 38 |
+
|
| 39 |
+
---
|
| 40 |
+
|
| 41 |
+
Playwright + Chromium automate token generation for reCAPTCHA v2/v3, hCaptcha, and Cloudflare Turnstile.
|
| 42 |
+
|
| 43 |
+
- :material-image-search: **Multimodal image recognition**
|
| 44 |
+
|
| 45 |
+
---
|
| 46 |
+
|
| 47 |
+
Route image captcha analysis through OpenAI-compatible vision models for HCaptcha, reCAPTCHA, FunCaptcha, and AWS classification.
|
| 48 |
+
|
| 49 |
+
- :material-cloud-outline: **Self-hosted deployment**
|
| 50 |
+
|
| 51 |
+
---
|
| 52 |
+
|
| 53 |
+
Run locally or follow the included Render and Hugging Face Spaces deployment guides.
|
| 54 |
+
|
| 55 |
+
</div>
|
| 56 |
+
|
| 57 |
+
## 🧠 Supported task types
|
| 58 |
+
|
| 59 |
+
### Browser-based solving (12 types)
|
| 60 |
+
|
| 61 |
+
| Category | Task Types |
|
| 62 |
+
|----------|-----------|
|
| 63 |
+
| **reCAPTCHA v3** | `RecaptchaV3TaskProxyless`, `RecaptchaV3TaskProxylessM1`, `RecaptchaV3TaskProxylessM1S7`, `RecaptchaV3TaskProxylessM1S9` |
|
| 64 |
+
| **reCAPTCHA v3 Enterprise** | `RecaptchaV3EnterpriseTask`, `RecaptchaV3EnterpriseTaskM1` |
|
| 65 |
+
| **reCAPTCHA v2** | `NoCaptchaTaskProxyless`, `RecaptchaV2TaskProxyless`, `RecaptchaV2EnterpriseTaskProxyless` |
|
| 66 |
+
| **hCaptcha** | `HCaptchaTaskProxyless` |
|
| 67 |
+
| **Cloudflare Turnstile** | `TurnstileTaskProxyless`, `TurnstileTaskProxylessM1` |
|
| 68 |
+
|
| 69 |
+
### Image recognition (3 types)
|
| 70 |
+
|
| 71 |
+
| Task Type | Description |
|
| 72 |
+
|-----------|-------------|
|
| 73 |
+
| `ImageToTextTask` | Argus-inspired multimodal recognition for click, slide, and drag captchas |
|
| 74 |
+
| `ImageToTextTaskMuggle` | Text/alphanumeric image recognition |
|
| 75 |
+
| `ImageToTextTaskM1` | Async image text recognition |
|
| 76 |
+
|
| 77 |
+
### Image classification (4 types)
|
| 78 |
+
|
| 79 |
+
| Task Type | Description |
|
| 80 |
+
|-----------|-------------|
|
| 81 |
+
| `HCaptchaClassification` | hCaptcha grid image classification |
|
| 82 |
+
| `ReCaptchaV2Classification` | reCAPTCHA v2 grid cell selection |
|
| 83 |
+
| `FunCaptchaClassification` | FunCaptcha image selection |
|
| 84 |
+
| `AwsClassification` | AWS CAPTCHA image classification |
|
| 85 |
+
|
| 86 |
+
## 🚀 Quick paths
|
| 87 |
+
|
| 88 |
+
<div class="grid cards feature-cards" markdown>
|
| 89 |
+
|
| 90 |
+
- :material-rocket-launch-outline: **Quick start**
|
| 91 |
+
|
| 92 |
+
---
|
| 93 |
+
|
| 94 |
+
Install dependencies, configure environment variables, and launch the service locally.
|
| 95 |
+
|
| 96 |
+
[Open quick start](getting-started.md)
|
| 97 |
+
|
| 98 |
+
- :material-file-document-outline: **API reference**
|
| 99 |
+
|
| 100 |
+
---
|
| 101 |
+
|
| 102 |
+
Review all 19 supported task types, endpoints, and request formats.
|
| 103 |
+
|
| 104 |
+
[Open API reference](api-reference.md)
|
| 105 |
+
|
| 106 |
+
- :material-play-box-outline: **Acceptance**
|
| 107 |
+
|
| 108 |
+
---
|
| 109 |
+
|
| 110 |
+
Validate detector-target behavior and confirm token generation flow.
|
| 111 |
+
|
| 112 |
+
[Open acceptance guide](acceptance.md)
|
| 113 |
+
|
| 114 |
+
- :material-server-outline: **Deployment**
|
| 115 |
+
|
| 116 |
+
---
|
| 117 |
+
|
| 118 |
+
Follow the Render or Hugging Face Spaces guides for a production-facing instance.
|
| 119 |
+
|
| 120 |
+
[Open deployment guide](deployment/render.md)
|
| 121 |
+
|
| 122 |
+
</div>
|
| 123 |
+
|
| 124 |
+
## 📌 Scope note
|
| 125 |
+
|
| 126 |
+
OhMyCaptcha implements a **YesCaptcha-style API surface covering 19 task types** across reCAPTCHA v2/v3, hCaptcha, Cloudflare Turnstile, and image classification. Browser-based tasks rely on Playwright automation and may require tuning for specific target sites. Image classification leverages multimodal vision models and accuracy depends on model quality.
|
docs/positioning.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Positioning
|
| 2 |
+
|
| 3 |
+
## What OhMyCaptcha is
|
| 4 |
+
|
| 5 |
+
OhMyCaptcha is a self-hostable captcha solving service with a YesCaptcha-style API for the task types implemented in this repository.
|
| 6 |
+
|
| 7 |
+
It is designed for users who want:
|
| 8 |
+
|
| 9 |
+
- a service they can run themselves
|
| 10 |
+
- compatibility with `createTask` / `getTaskResult` style workflows
|
| 11 |
+
- control over browser automation and model backends
|
| 12 |
+
- support for OpenAI-compatible multimodal providers, including local or self-hosted gateways
|
| 13 |
+
|
| 14 |
+
## Comparison with managed services such as YesCaptcha
|
| 15 |
+
|
| 16 |
+
Managed services such as YesCaptcha typically provide:
|
| 17 |
+
|
| 18 |
+
- a hosted platform
|
| 19 |
+
- a broad task catalog
|
| 20 |
+
- commercial SLAs and vendor-managed infrastructure
|
| 21 |
+
|
| 22 |
+
OhMyCaptcha instead focuses on:
|
| 23 |
+
|
| 24 |
+
- self-hosting
|
| 25 |
+
- transparent implementation
|
| 26 |
+
- prompt and browser customization
|
| 27 |
+
- backend flexibility for multimodal models
|
| 28 |
+
|
| 29 |
+
## Scope boundary
|
| 30 |
+
|
| 31 |
+
This repository should not be described as a full commercial-vendor replacement for every captcha family or task type.
|
| 32 |
+
|
| 33 |
+
A more accurate description is:
|
| 34 |
+
|
| 35 |
+
> a self-hostable service that provides a YesCaptcha-style API for the implemented task types and can be integrated into systems such as flow2api.
|
| 36 |
+
|
| 37 |
+
## Local and self-hosted model support
|
| 38 |
+
|
| 39 |
+
The project uses OpenAI-compatible APIs for multimodal recognition. This makes it possible to connect:
|
| 40 |
+
|
| 41 |
+
- hosted providers
|
| 42 |
+
- internal gateways
|
| 43 |
+
- self-hosted multimodal services
|
| 44 |
+
- local model-serving stacks that expose compatible semantics
|
| 45 |
+
|
| 46 |
+
The documentation intentionally keeps this phrasing generic. Compatibility depends on whether the backend supports image input and sufficiently consistent chat-completions behavior.
|
docs/skill.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Agent Skill
|
| 2 |
+
|
| 3 |
+
OhMyCaptcha ships with reusable skills under `skills/`.
|
| 4 |
+
|
| 5 |
+
## Available skills
|
| 6 |
+
|
| 7 |
+
- `skills/ohmycaptcha/` — operate, deploy, validate, and integrate the service
|
| 8 |
+
- `skills/ohmycaptcha-image/` — create public-safe visuals for README, docs, and launch assets
|
| 9 |
+
|
| 10 |
+
## For humans
|
| 11 |
+
|
| 12 |
+
If your tool can read a local skill folder directly, copy one or both of these directories into your local skills directory:
|
| 13 |
+
|
| 14 |
+
```text
|
| 15 |
+
skills/ohmycaptcha/
|
| 16 |
+
skills/ohmycaptcha-image/
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
Then restart your tool if it caches skill metadata.
|
| 20 |
+
|
| 21 |
+
## Let an LLM do it
|
| 22 |
+
|
| 23 |
+
Paste this into any capable agent environment:
|
| 24 |
+
|
| 25 |
+
```text
|
| 26 |
+
Install the OhMyCaptcha skills from this repository and make them available in my local skills directory. Then show me how to use the operational skill for deployment and the image skill for generating README or docs visuals.
|
| 27 |
+
```
|
| 28 |
+
|
| 29 |
+
## What the operational skill does
|
| 30 |
+
|
| 31 |
+
The `ohmycaptcha` skill helps with:
|
| 32 |
+
|
| 33 |
+
- local startup
|
| 34 |
+
- environment setup
|
| 35 |
+
- YesCaptcha-style API usage
|
| 36 |
+
- flow2api integration
|
| 37 |
+
- Render deployment
|
| 38 |
+
- Hugging Face Spaces deployment
|
| 39 |
+
- task validation and troubleshooting
|
| 40 |
+
|
| 41 |
+
## What the image skill does
|
| 42 |
+
|
| 43 |
+
The `ohmycaptcha-image` skill helps with:
|
| 44 |
+
|
| 45 |
+
- README hero image prompts
|
| 46 |
+
- docs illustrations
|
| 47 |
+
- public-safe technical visuals
|
| 48 |
+
- architecture-themed artwork
|
| 49 |
+
- reusable image-generation prompts for agent workflows
|
| 50 |
+
|
| 51 |
+
## Design guarantees
|
| 52 |
+
|
| 53 |
+
These skills are designed to:
|
| 54 |
+
|
| 55 |
+
- use placeholder credentials only
|
| 56 |
+
- stay aligned with the implemented task types
|
| 57 |
+
- keep current limitations explicit
|
| 58 |
+
- avoid embedding secrets, private endpoints, or customer data
|
docs/stylesheets/extra.css
ADDED
|
@@ -0,0 +1,204 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
:root {
|
| 2 |
+
--ohmycaptcha-radius: 18px;
|
| 3 |
+
--ohmycaptcha-shadow: 0 18px 44px rgba(37, 99, 235, 0.08);
|
| 4 |
+
}
|
| 5 |
+
|
| 6 |
+
[data-md-color-scheme="slate"] {
|
| 7 |
+
--ohmycaptcha-shadow: 0 18px 44px rgba(0, 0, 0, 0.3);
|
| 8 |
+
}
|
| 9 |
+
|
| 10 |
+
.md-header__option {
|
| 11 |
+
order: 20;
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
.md-header__option:last-of-type {
|
| 15 |
+
order: 99;
|
| 16 |
+
margin-inline-start: auto;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
.md-typeset .caption {
|
| 20 |
+
text-align: center;
|
| 21 |
+
color: var(--md-default-fg-color--light);
|
| 22 |
+
font-size: 0.8rem;
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
/* ── Hero section ── */
|
| 26 |
+
|
| 27 |
+
.md-typeset .hero {
|
| 28 |
+
position: relative;
|
| 29 |
+
margin: 0 0 2rem;
|
| 30 |
+
border-radius: 24px;
|
| 31 |
+
overflow: hidden;
|
| 32 |
+
border: 1px solid rgba(37, 99, 235, 0.12);
|
| 33 |
+
box-shadow: var(--ohmycaptcha-shadow);
|
| 34 |
+
background: #0f172a;
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
[data-md-color-scheme="slate"] .md-typeset .hero {
|
| 38 |
+
border-color: rgba(99, 102, 241, 0.2);
|
| 39 |
+
}
|
| 40 |
+
|
| 41 |
+
/* Full-width hero image strip */
|
| 42 |
+
.md-typeset .hero__visual {
|
| 43 |
+
display: block;
|
| 44 |
+
line-height: 0;
|
| 45 |
+
}
|
| 46 |
+
|
| 47 |
+
.md-typeset .hero__visual img {
|
| 48 |
+
width: 100%;
|
| 49 |
+
height: auto;
|
| 50 |
+
max-height: 340px;
|
| 51 |
+
object-fit: cover;
|
| 52 |
+
object-position: center top;
|
| 53 |
+
display: block;
|
| 54 |
+
border-radius: 0;
|
| 55 |
+
border: none;
|
| 56 |
+
background: transparent;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
/* Copy panel sits below the image */
|
| 60 |
+
.md-typeset .hero__copy {
|
| 61 |
+
padding: 1.6rem 2rem 1.8rem;
|
| 62 |
+
background: linear-gradient(135deg, #ffffff 0%, #f7faff 60%, #eef2ff 100%);
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
[data-md-color-scheme="slate"] .md-typeset .hero__copy {
|
| 66 |
+
background: linear-gradient(135deg, #0f172a 0%, #1e1b4b 60%, #1e293b 100%);
|
| 67 |
+
}
|
| 68 |
+
|
| 69 |
+
.md-typeset .hero--light h2 {
|
| 70 |
+
margin: 0 0 0.7rem;
|
| 71 |
+
color: #0f172a;
|
| 72 |
+
font-size: clamp(1.3rem, 3vw, 1.9rem);
|
| 73 |
+
line-height: 1.2;
|
| 74 |
+
letter-spacing: -0.025em;
|
| 75 |
+
font-weight: 700;
|
| 76 |
+
}
|
| 77 |
+
|
| 78 |
+
[data-md-color-scheme="slate"] .md-typeset .hero--light h2 {
|
| 79 |
+
color: #e2e8f0;
|
| 80 |
+
}
|
| 81 |
+
|
| 82 |
+
.md-typeset .hero--light p {
|
| 83 |
+
color: #475569;
|
| 84 |
+
margin: 0 0 0.5rem;
|
| 85 |
+
font-size: 0.95rem;
|
| 86 |
+
max-width: 68ch;
|
| 87 |
+
}
|
| 88 |
+
|
| 89 |
+
[data-md-color-scheme="slate"] .md-typeset .hero--light p {
|
| 90 |
+
color: #94a3b8;
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
.md-typeset .hero__copy > p {
|
| 94 |
+
margin: 0.6rem 0 0;
|
| 95 |
+
font-size: 0.95rem;
|
| 96 |
+
max-width: 68ch;
|
| 97 |
+
}
|
| 98 |
+
|
| 99 |
+
.md-typeset .hero__actions {
|
| 100 |
+
display: flex;
|
| 101 |
+
flex-wrap: wrap;
|
| 102 |
+
gap: 0.65rem;
|
| 103 |
+
margin-top: 1.1rem;
|
| 104 |
+
}
|
| 105 |
+
|
| 106 |
+
.md-typeset .hero__actions .md-button {
|
| 107 |
+
margin: 0;
|
| 108 |
+
border-radius: 999px;
|
| 109 |
+
font-size: 0.83rem;
|
| 110 |
+
padding: 0.4em 1.1em;
|
| 111 |
+
}
|
| 112 |
+
|
| 113 |
+
.md-typeset .hero__actions .md-button:not(.md-button--primary) {
|
| 114 |
+
color: #1d4ed8;
|
| 115 |
+
border-color: rgba(37, 99, 235, 0.28);
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
[data-md-color-scheme="slate"] .md-typeset .hero__actions .md-button:not(.md-button--primary) {
|
| 119 |
+
color: #818cf8;
|
| 120 |
+
border-color: rgba(129, 140, 248, 0.3);
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
/* ── Feature cards ── */
|
| 124 |
+
|
| 125 |
+
.md-typeset .feature-cards > ul {
|
| 126 |
+
display: grid;
|
| 127 |
+
grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
|
| 128 |
+
gap: 0.9rem;
|
| 129 |
+
padding: 0;
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
.md-typeset .feature-cards > ul > li {
|
| 133 |
+
list-style: none;
|
| 134 |
+
padding: 1.1rem;
|
| 135 |
+
border: 1px solid rgba(37, 99, 235, 0.12);
|
| 136 |
+
border-radius: var(--ohmycaptcha-radius);
|
| 137 |
+
background: #ffffff;
|
| 138 |
+
box-shadow: 0 10px 26px rgba(15, 23, 42, 0.04);
|
| 139 |
+
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
| 140 |
+
}
|
| 141 |
+
|
| 142 |
+
.md-typeset .feature-cards > ul > li:hover {
|
| 143 |
+
transform: translateY(-2px);
|
| 144 |
+
box-shadow: 0 14px 32px rgba(15, 23, 42, 0.08);
|
| 145 |
+
}
|
| 146 |
+
|
| 147 |
+
[data-md-color-scheme="slate"] .md-typeset .feature-cards > ul > li {
|
| 148 |
+
background: rgba(30, 30, 50, 0.6);
|
| 149 |
+
border-color: rgba(99, 102, 241, 0.15);
|
| 150 |
+
box-shadow: 0 10px 26px rgba(0, 0, 0, 0.2);
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
.md-typeset .feature-cards strong {
|
| 154 |
+
color: #0f172a;
|
| 155 |
+
}
|
| 156 |
+
|
| 157 |
+
[data-md-color-scheme="slate"] .md-typeset .feature-cards strong {
|
| 158 |
+
color: #e2e8f0;
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
.md-typeset .feature-cards p {
|
| 162 |
+
color: #475569;
|
| 163 |
+
}
|
| 164 |
+
|
| 165 |
+
[data-md-color-scheme="slate"] .md-typeset .feature-cards p {
|
| 166 |
+
color: #94a3b8;
|
| 167 |
+
}
|
| 168 |
+
|
| 169 |
+
.md-typeset .grid.cards > ul {
|
| 170 |
+
display: grid;
|
| 171 |
+
grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
|
| 172 |
+
gap: 0.8rem;
|
| 173 |
+
padding: 0;
|
| 174 |
+
}
|
| 175 |
+
|
| 176 |
+
.md-typeset .grid.cards > ul > li {
|
| 177 |
+
list-style: none;
|
| 178 |
+
border-radius: var(--ohmycaptcha-radius);
|
| 179 |
+
}
|
| 180 |
+
|
| 181 |
+
/* ── Task type tables ── */
|
| 182 |
+
|
| 183 |
+
.md-typeset table code {
|
| 184 |
+
font-size: 0.78rem;
|
| 185 |
+
padding: 0.1em 0.35em;
|
| 186 |
+
}
|
| 187 |
+
|
| 188 |
+
/* ── Responsive ── */
|
| 189 |
+
|
| 190 |
+
@media screen and (max-width: 76.1875em) {
|
| 191 |
+
.md-typeset .hero__copy {
|
| 192 |
+
padding: 1.2rem 1.2rem 1.4rem;
|
| 193 |
+
}
|
| 194 |
+
|
| 195 |
+
.md-typeset .hero__visual img {
|
| 196 |
+
max-height: 240px;
|
| 197 |
+
}
|
| 198 |
+
}
|
| 199 |
+
|
| 200 |
+
@media screen and (max-width: 44.9375em) {
|
| 201 |
+
.md-typeset .hero__visual img {
|
| 202 |
+
max-height: 180px;
|
| 203 |
+
}
|
| 204 |
+
}
|
docs/usage/classification.md
ADDED
|
@@ -0,0 +1,163 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Image Classification Usage
|
| 2 |
+
|
| 3 |
+
Image classification tasks send one or more captcha images to an OpenAI-compatible vision model and return the indices of matching cells or a boolean answer. No browser automation is involved — these are pure vision model API calls.
|
| 4 |
+
|
| 5 |
+
## Supported task types
|
| 6 |
+
|
| 7 |
+
| Task type | Description |
|
| 8 |
+
|-----------|-------------|
|
| 9 |
+
| `HCaptchaClassification` | hCaptcha 3x3 grid — returns matching cell indices |
|
| 10 |
+
| `ReCaptchaV2Classification` | reCAPTCHA v2 3x3 / 4x4 grid — returns matching cell indices |
|
| 11 |
+
| `FunCaptchaClassification` | FunCaptcha 2x3 grid — returns the correct cell index |
|
| 12 |
+
| `AwsClassification` | AWS CAPTCHA image selection |
|
| 13 |
+
|
| 14 |
+
## Solution fields
|
| 15 |
+
|
| 16 |
+
| Task type | Solution field | Example |
|
| 17 |
+
|-----------|---------------|---------|
|
| 18 |
+
| `HCaptchaClassification` | `objects` or `answer` | `[0, 2, 5]` or `true` |
|
| 19 |
+
| `ReCaptchaV2Classification` | `objects` | `[0, 3, 6]` |
|
| 20 |
+
| `FunCaptchaClassification` | `objects` | `[4]` |
|
| 21 |
+
| `AwsClassification` | `objects` | `[1]` |
|
| 22 |
+
|
| 23 |
+
## HCaptchaClassification
|
| 24 |
+
|
| 25 |
+
### Request shape
|
| 26 |
+
|
| 27 |
+
```json
|
| 28 |
+
{
|
| 29 |
+
"clientKey": "your-client-key",
|
| 30 |
+
"task": {
|
| 31 |
+
"type": "HCaptchaClassification",
|
| 32 |
+
"queries": ["<base64-image-1>", "<base64-image-2>", "<base64-image-3>"],
|
| 33 |
+
"question": "Please click each image containing a bicycle"
|
| 34 |
+
}
|
| 35 |
+
}
|
| 36 |
+
```
|
| 37 |
+
|
| 38 |
+
The `queries` field accepts a list of base64-encoded images (one per grid cell). The `question` field is the challenge prompt displayed to the user.
|
| 39 |
+
|
| 40 |
+
### Response
|
| 41 |
+
|
| 42 |
+
```json
|
| 43 |
+
{
|
| 44 |
+
"errorId": 0,
|
| 45 |
+
"status": "ready",
|
| 46 |
+
"solution": {
|
| 47 |
+
"objects": [1, 4]
|
| 48 |
+
}
|
| 49 |
+
}
|
| 50 |
+
```
|
| 51 |
+
|
| 52 |
+
## ReCaptchaV2Classification
|
| 53 |
+
|
| 54 |
+
### Request shape
|
| 55 |
+
|
| 56 |
+
```json
|
| 57 |
+
{
|
| 58 |
+
"clientKey": "your-client-key",
|
| 59 |
+
"task": {
|
| 60 |
+
"type": "ReCaptchaV2Classification",
|
| 61 |
+
"image": "<base64-encoded-grid-image>",
|
| 62 |
+
"question": "Select all images with traffic lights"
|
| 63 |
+
}
|
| 64 |
+
}
|
| 65 |
+
```
|
| 66 |
+
|
| 67 |
+
The `image` field is a single base64-encoded image of the full reCAPTCHA grid (3×3 = 9 cells or 4×4 = 16 cells). Cells are numbered 0–8 (or 0–15), left-to-right, top-to-bottom.
|
| 68 |
+
|
| 69 |
+
### Response
|
| 70 |
+
|
| 71 |
+
```json
|
| 72 |
+
{
|
| 73 |
+
"errorId": 0,
|
| 74 |
+
"status": "ready",
|
| 75 |
+
"solution": {
|
| 76 |
+
"objects": [0, 3, 6]
|
| 77 |
+
}
|
| 78 |
+
}
|
| 79 |
+
```
|
| 80 |
+
|
| 81 |
+
## FunCaptchaClassification
|
| 82 |
+
|
| 83 |
+
### Request shape
|
| 84 |
+
|
| 85 |
+
```json
|
| 86 |
+
{
|
| 87 |
+
"clientKey": "your-client-key",
|
| 88 |
+
"task": {
|
| 89 |
+
"type": "FunCaptchaClassification",
|
| 90 |
+
"image": "<base64-encoded-grid-image>",
|
| 91 |
+
"question": "Pick the image that shows a boat facing left"
|
| 92 |
+
}
|
| 93 |
+
}
|
| 94 |
+
```
|
| 95 |
+
|
| 96 |
+
The grid is typically 2×3 (6 cells). Usually one answer is expected.
|
| 97 |
+
|
| 98 |
+
### Response
|
| 99 |
+
|
| 100 |
+
```json
|
| 101 |
+
{
|
| 102 |
+
"errorId": 0,
|
| 103 |
+
"status": "ready",
|
| 104 |
+
"solution": {
|
| 105 |
+
"objects": [3]
|
| 106 |
+
}
|
| 107 |
+
}
|
| 108 |
+
```
|
| 109 |
+
|
| 110 |
+
## AwsClassification
|
| 111 |
+
|
| 112 |
+
### Request shape
|
| 113 |
+
|
| 114 |
+
```json
|
| 115 |
+
{
|
| 116 |
+
"clientKey": "your-client-key",
|
| 117 |
+
"task": {
|
| 118 |
+
"type": "AwsClassification",
|
| 119 |
+
"image": "<base64-encoded-image>",
|
| 120 |
+
"question": "Select the image that matches"
|
| 121 |
+
}
|
| 122 |
+
}
|
| 123 |
+
```
|
| 124 |
+
|
| 125 |
+
### Response
|
| 126 |
+
|
| 127 |
+
```json
|
| 128 |
+
{
|
| 129 |
+
"errorId": 0,
|
| 130 |
+
"status": "ready",
|
| 131 |
+
"solution": {
|
| 132 |
+
"objects": [1]
|
| 133 |
+
}
|
| 134 |
+
}
|
| 135 |
+
```
|
| 136 |
+
|
| 137 |
+
## Create and poll (generic example)
|
| 138 |
+
|
| 139 |
+
```bash
|
| 140 |
+
# Step 1: create task
|
| 141 |
+
TASK_ID=$(curl -s -X POST http://localhost:8000/createTask \
|
| 142 |
+
-H "Content-Type: application/json" \
|
| 143 |
+
-d '{
|
| 144 |
+
"clientKey": "your-client-key",
|
| 145 |
+
"task": {
|
| 146 |
+
"type": "ReCaptchaV2Classification",
|
| 147 |
+
"image": "'$(base64 -w0 captcha.png)'",
|
| 148 |
+
"question": "Select all images with traffic lights"
|
| 149 |
+
}
|
| 150 |
+
}' | python -c "import sys,json; print(json.load(sys.stdin)['taskId'])")
|
| 151 |
+
|
| 152 |
+
# Step 2: poll result
|
| 153 |
+
curl -s -X POST http://localhost:8000/getTaskResult \
|
| 154 |
+
-H "Content-Type: application/json" \
|
| 155 |
+
-d "{\"clientKey\":\"your-client-key\",\"taskId\":\"$TASK_ID\"}"
|
| 156 |
+
```
|
| 157 |
+
|
| 158 |
+
## Operational notes
|
| 159 |
+
|
| 160 |
+
- All classification tasks are **synchronous from the model's perspective** — the `asyncio.create_task` wrapper means the HTTP response is immediate, but the actual model call happens in the background.
|
| 161 |
+
- Model accuracy depends entirely on the vision model configured via `CAPTCHA_MULTIMODAL_MODEL` (default: `qwen3.5-2b`).
|
| 162 |
+
- For best results with classification, the `CAPTCHA_MODEL` (`gpt-5.4`) can be substituted by setting `CAPTCHA_MULTIMODAL_MODEL=gpt-5.4`.
|
| 163 |
+
- Images should not be pre-resized — the solver handles normalization internally.
|
docs/usage/hcaptcha.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# hCaptcha Usage
|
| 2 |
+
|
| 3 |
+
hCaptcha presents a CAPTCHA challenge via an iframe widget. The solver visits the target page with a Playwright-controlled Chromium browser, clicks the hCaptcha checkbox, waits for the challenge to resolve, and extracts the `h-captcha-response` token.
|
| 4 |
+
|
| 5 |
+
## Supported task type
|
| 6 |
+
|
| 7 |
+
| Task type | Description |
|
| 8 |
+
|-----------|-------------|
|
| 9 |
+
| `HCaptchaTaskProxyless` | Browser-based hCaptcha solving |
|
| 10 |
+
|
| 11 |
+
## Required fields
|
| 12 |
+
|
| 13 |
+
| Field | Type | Description |
|
| 14 |
+
|-------|------|-------------|
|
| 15 |
+
| `websiteURL` | string | Full URL of the page containing the captcha |
|
| 16 |
+
| `websiteKey` | string | The `data-sitekey` value from the page's HTML |
|
| 17 |
+
|
| 18 |
+
## Test targets
|
| 19 |
+
|
| 20 |
+
hCaptcha provides official test keys that produce predictable results:
|
| 21 |
+
|
| 22 |
+
| URL | Site key | Behavior |
|
| 23 |
+
|-----|----------|----------|
|
| 24 |
+
| `https://accounts.hcaptcha.com/demo` | `10000000-ffff-ffff-ffff-000000000001` | Always passes (test key) |
|
| 25 |
+
| `https://accounts.hcaptcha.com/demo` | `20000000-ffff-ffff-ffff-000000000002` | Enterprise safe-user test |
|
| 26 |
+
| `https://demo.hcaptcha.com/` | `10000000-ffff-ffff-ffff-000000000001` | Always passes (test key) |
|
| 27 |
+
|
| 28 |
+
## Create a task
|
| 29 |
+
|
| 30 |
+
```bash
|
| 31 |
+
curl -X POST http://localhost:8000/createTask \
|
| 32 |
+
-H "Content-Type: application/json" \
|
| 33 |
+
-d '{
|
| 34 |
+
"clientKey": "your-client-key",
|
| 35 |
+
"task": {
|
| 36 |
+
"type": "HCaptchaTaskProxyless",
|
| 37 |
+
"websiteURL": "https://accounts.hcaptcha.com/demo",
|
| 38 |
+
"websiteKey": "10000000-ffff-ffff-ffff-000000000001"
|
| 39 |
+
}
|
| 40 |
+
}'
|
| 41 |
+
```
|
| 42 |
+
|
| 43 |
+
Response:
|
| 44 |
+
|
| 45 |
+
```json
|
| 46 |
+
{
|
| 47 |
+
"errorId": 0,
|
| 48 |
+
"taskId": "uuid-string"
|
| 49 |
+
}
|
| 50 |
+
```
|
| 51 |
+
|
| 52 |
+
## Poll for result
|
| 53 |
+
|
| 54 |
+
```bash
|
| 55 |
+
curl -X POST http://localhost:8000/getTaskResult \
|
| 56 |
+
-H "Content-Type: application/json" \
|
| 57 |
+
-d '{
|
| 58 |
+
"clientKey": "your-client-key",
|
| 59 |
+
"taskId": "uuid-from-createTask"
|
| 60 |
+
}'
|
| 61 |
+
```
|
| 62 |
+
|
| 63 |
+
When ready:
|
| 64 |
+
|
| 65 |
+
```json
|
| 66 |
+
{
|
| 67 |
+
"errorId": 0,
|
| 68 |
+
"status": "ready",
|
| 69 |
+
"solution": {
|
| 70 |
+
"gRecaptchaResponse": "P1_eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9..."
|
| 71 |
+
}
|
| 72 |
+
}
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
!!! note "Response field name"
|
| 76 |
+
The token is returned in `solution.gRecaptchaResponse` for YesCaptcha API compatibility, even though hCaptcha natively uses the `h-captcha-response` field name.
|
| 77 |
+
|
| 78 |
+
## Acceptance status
|
| 79 |
+
|
| 80 |
+
| Target | Site key | Status | Notes |
|
| 81 |
+
|--------|----------|--------|-------|
|
| 82 |
+
| `https://accounts.hcaptcha.com/demo` | `10000000-ffff-ffff-ffff-000000000001` | ⚠️ Challenge-dependent | Headless browsers may still receive image challenges |
|
| 83 |
+
|
| 84 |
+
### Headless browser note
|
| 85 |
+
|
| 86 |
+
Even with the test site key (`10000000-ffff-ffff-ffff-000000000001`), hCaptcha may present an image challenge when the widget detects a headless browser. The solver clicks the checkbox and polls for a token for up to 30 seconds.
|
| 87 |
+
|
| 88 |
+
For headless environments, the recommended approach is to use the `HCaptchaClassification` task type to solve the image grid challenge, then inject the token. See [Image Classification](classification.md) for details.
|
| 89 |
+
|
| 90 |
+
## Image classification (HCaptchaClassification)
|
| 91 |
+
|
| 92 |
+
For programmatic grid classification without browser automation, see [Image Classification](classification.md).
|
| 93 |
+
|
| 94 |
+
## Operational notes
|
| 95 |
+
|
| 96 |
+
- hCaptcha challenges may require more time than reCAPTCHA v2 — the solver waits up to 5 seconds after clicking.
|
| 97 |
+
- Real-world sites with aggressive bot detection may require additional fingerprinting improvements.
|
| 98 |
+
- Test keys (`10000000-ffff-ffff-ffff-000000000001`) always pass and are useful for flow validation.
|
docs/usage/image-captcha.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Image CAPTCHA Usage
|
| 2 |
+
|
| 3 |
+
## Task type
|
| 4 |
+
|
| 5 |
+
- `ImageToTextTask`
|
| 6 |
+
|
| 7 |
+
## Request
|
| 8 |
+
|
| 9 |
+
```json
|
| 10 |
+
{
|
| 11 |
+
"clientKey": "your-client-key",
|
| 12 |
+
"task": {
|
| 13 |
+
"type": "ImageToTextTask",
|
| 14 |
+
"body": "<base64-encoded-image>"
|
| 15 |
+
}
|
| 16 |
+
}
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
## Implementation notes
|
| 20 |
+
|
| 21 |
+
The image solver is implemented in `src/services/recognition.py` and is inspired by Argus-style structured multimodal annotation.
|
| 22 |
+
|
| 23 |
+
Current behavior:
|
| 24 |
+
|
| 25 |
+
- image input is resized to **1440×900**
|
| 26 |
+
- the model is prompted to classify the captcha into structured action types
|
| 27 |
+
- the normalized coordinate space starts at `(0, 0)` in the top-left corner
|
| 28 |
+
|
| 29 |
+
Supported response styles in the prompt:
|
| 30 |
+
|
| 31 |
+
- `click`
|
| 32 |
+
- `slide`
|
| 33 |
+
- `drag_match`
|
| 34 |
+
|
| 35 |
+
## Result shape
|
| 36 |
+
|
| 37 |
+
The current API returns the structured model output serialized as a string in `solution.text`.
|
| 38 |
+
|
| 39 |
+
Example:
|
| 40 |
+
|
| 41 |
+
```json
|
| 42 |
+
{
|
| 43 |
+
"errorId": 0,
|
| 44 |
+
"status": "ready",
|
| 45 |
+
"solution": {
|
| 46 |
+
"text": "{\"captcha_type\":\"slide\",\"drag_distance\":270}"
|
| 47 |
+
}
|
| 48 |
+
}
|
| 49 |
+
```
|
| 50 |
+
|
| 51 |
+
## Backend compatibility
|
| 52 |
+
|
| 53 |
+
The multimodal path is designed for **OpenAI-compatible** APIs. This makes it suitable for hosted or self-hosted backends as long as they expose compatible image-capable chat completion behavior.
|
| 54 |
+
|
| 55 |
+
Accuracy depends heavily on the selected model and provider implementation.
|
docs/usage/recaptcha-v2.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# reCAPTCHA v2 Usage
|
| 2 |
+
|
| 3 |
+
reCAPTCHA v2 presents users with an "I'm not a robot" checkbox. The solver visits the target page with a real Chromium browser, clicks the checkbox, and extracts the resulting `gRecaptchaResponse` token.
|
| 4 |
+
|
| 5 |
+
## Supported task types
|
| 6 |
+
|
| 7 |
+
| Task type | Description |
|
| 8 |
+
|-----------|-------------|
|
| 9 |
+
| `NoCaptchaTaskProxyless` | Standard reCAPTCHA v2 checkbox |
|
| 10 |
+
| `RecaptchaV2TaskProxyless` | Same as above, alternate naming |
|
| 11 |
+
| `RecaptchaV2EnterpriseTaskProxyless` | reCAPTCHA v2 Enterprise variant |
|
| 12 |
+
|
| 13 |
+
## Required fields
|
| 14 |
+
|
| 15 |
+
| Field | Type | Description |
|
| 16 |
+
|-------|------|-------------|
|
| 17 |
+
| `websiteURL` | string | Full URL of the page containing the captcha |
|
| 18 |
+
| `websiteKey` | string | The `data-sitekey` value from the page's HTML |
|
| 19 |
+
| `isInvisible` | bool | Optional. Set `true` for invisible reCAPTCHA |
|
| 20 |
+
|
| 21 |
+
## Test target
|
| 22 |
+
|
| 23 |
+
The official Google demo page is suitable for acceptance validation:
|
| 24 |
+
|
| 25 |
+
- **URL:** `https://www.google.com/recaptcha/api2/demo`
|
| 26 |
+
- **Site key:** `6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-`
|
| 27 |
+
|
| 28 |
+
## Create a task
|
| 29 |
+
|
| 30 |
+
```bash
|
| 31 |
+
curl -X POST http://localhost:8000/createTask \
|
| 32 |
+
-H "Content-Type: application/json" \
|
| 33 |
+
-d '{
|
| 34 |
+
"clientKey": "your-client-key",
|
| 35 |
+
"task": {
|
| 36 |
+
"type": "NoCaptchaTaskProxyless",
|
| 37 |
+
"websiteURL": "https://www.google.com/recaptcha/api2/demo",
|
| 38 |
+
"websiteKey": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
|
| 39 |
+
}
|
| 40 |
+
}'
|
| 41 |
+
```
|
| 42 |
+
|
| 43 |
+
Response:
|
| 44 |
+
|
| 45 |
+
```json
|
| 46 |
+
{
|
| 47 |
+
"errorId": 0,
|
| 48 |
+
"taskId": "uuid-string"
|
| 49 |
+
}
|
| 50 |
+
```
|
| 51 |
+
|
| 52 |
+
## Poll for result
|
| 53 |
+
|
| 54 |
+
```bash
|
| 55 |
+
curl -X POST http://localhost:8000/getTaskResult \
|
| 56 |
+
-H "Content-Type: application/json" \
|
| 57 |
+
-d '{
|
| 58 |
+
"clientKey": "your-client-key",
|
| 59 |
+
"taskId": "uuid-from-createTask"
|
| 60 |
+
}'
|
| 61 |
+
```
|
| 62 |
+
|
| 63 |
+
When ready, you receive:
|
| 64 |
+
|
| 65 |
+
```json
|
| 66 |
+
{
|
| 67 |
+
"errorId": 0,
|
| 68 |
+
"status": "ready",
|
| 69 |
+
"solution": {
|
| 70 |
+
"gRecaptchaResponse": "03AGdBq24..."
|
| 71 |
+
}
|
| 72 |
+
}
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
## Invisible reCAPTCHA
|
| 76 |
+
|
| 77 |
+
For pages using invisible reCAPTCHA (no visible checkbox), add `"isInvisible": true`. The solver will call `grecaptcha.execute()` directly instead of clicking the checkbox:
|
| 78 |
+
|
| 79 |
+
```bash
|
| 80 |
+
curl -X POST http://localhost:8000/createTask \
|
| 81 |
+
-H "Content-Type: application/json" \
|
| 82 |
+
-d '{
|
| 83 |
+
"clientKey": "your-client-key",
|
| 84 |
+
"task": {
|
| 85 |
+
"type": "NoCaptchaTaskProxyless",
|
| 86 |
+
"websiteURL": "https://www.google.com/recaptcha/api2/demo",
|
| 87 |
+
"websiteKey": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-",
|
| 88 |
+
"isInvisible": true
|
| 89 |
+
}
|
| 90 |
+
}'
|
| 91 |
+
```
|
| 92 |
+
|
| 93 |
+
## Acceptance status
|
| 94 |
+
|
| 95 |
+
| Target | Status | Notes |
|
| 96 |
+
|--------|--------|-------|
|
| 97 |
+
| `https://www.google.com/recaptcha/api2/demo` | ⚠️ Audio challenge path | Google detects headless browsers |
|
| 98 |
+
|
| 99 |
+
### Headless browser detection
|
| 100 |
+
|
| 101 |
+
Google's risk analysis engine reliably detects headless Chromium and presents a visual image challenge rather than issuing a token directly. The solver implements an audio challenge fallback:
|
| 102 |
+
|
| 103 |
+
1. Click the checkbox — Google presents a challenge dialog.
|
| 104 |
+
2. Click the audio button in the challenge dialog.
|
| 105 |
+
3. Download the MP3 audio file.
|
| 106 |
+
4. Transcribe via the configured `CAPTCHA_MODEL` endpoint.
|
| 107 |
+
5. Submit the transcript to receive the token.
|
| 108 |
+
|
| 109 |
+
!!! warning "Audio transcription requirement"
|
| 110 |
+
The audio challenge path requires a model endpoint capable of processing audio. The standard `CAPTCHA_MODEL` must support audio/speech input. Accuracy and availability depend on the configured endpoint.
|
| 111 |
+
|
| 112 |
+
### Recommended integration path
|
| 113 |
+
|
| 114 |
+
For reliable reCAPTCHA v2 solving in production, consider using the **classification task** approach:
|
| 115 |
+
|
| 116 |
+
1. Extract the challenge image grid from the page using Playwright.
|
| 117 |
+
2. Send the grid image to `ReCaptchaV2Classification` with the challenge question.
|
| 118 |
+
3. Use the returned cell indices to programmatically click the matching tiles.
|
| 119 |
+
|
| 120 |
+
See [Image Classification](classification.md) for details.
|
| 121 |
+
|
| 122 |
+
## Operational notes
|
| 123 |
+
|
| 124 |
+
- Token validity is approximately 120 seconds; submit promptly.
|
| 125 |
+
- The `RecaptchaV2EnterpriseTaskProxyless` type uses the same browser path.
|
| 126 |
+
- On less aggressive sites (not Google's own demo), the checkbox click may succeed without triggering a challenge.
|
docs/usage/recaptcha-v3.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# reCAPTCHA v3 Usage
|
| 2 |
+
|
| 3 |
+
## Target used for acceptance
|
| 4 |
+
|
| 5 |
+
This repository was validated against:
|
| 6 |
+
|
| 7 |
+
- URL: `https://antcpt.com/score_detector/`
|
| 8 |
+
- site key: `6LcR_okUAAAAAPYrPe-HK_0RULO1aZM15ENyM-Mf`
|
| 9 |
+
|
| 10 |
+
## Create a task
|
| 11 |
+
|
| 12 |
+
```bash
|
| 13 |
+
curl -X POST http://localhost:8000/createTask \
|
| 14 |
+
-H "Content-Type: application/json" \
|
| 15 |
+
-d '{
|
| 16 |
+
"clientKey": "your-client-key",
|
| 17 |
+
"task": {
|
| 18 |
+
"type": "RecaptchaV3TaskProxyless",
|
| 19 |
+
"websiteURL": "https://antcpt.com/score_detector/",
|
| 20 |
+
"websiteKey": "6LcR_okUAAAAAPYrPe-HK_0RULO1aZM15ENyM-Mf",
|
| 21 |
+
"pageAction": "homepage"
|
| 22 |
+
}
|
| 23 |
+
}'
|
| 24 |
+
```
|
| 25 |
+
|
| 26 |
+
## Poll for result
|
| 27 |
+
|
| 28 |
+
```bash
|
| 29 |
+
curl -X POST http://localhost:8000/getTaskResult \
|
| 30 |
+
-H "Content-Type: application/json" \
|
| 31 |
+
-d '{
|
| 32 |
+
"clientKey": "your-client-key",
|
| 33 |
+
"taskId": "uuid-from-createTask"
|
| 34 |
+
}'
|
| 35 |
+
```
|
| 36 |
+
|
| 37 |
+
When the task is ready, you should receive `solution.gRecaptchaResponse`.
|
| 38 |
+
|
| 39 |
+
## Acceptance result for this codebase
|
| 40 |
+
|
| 41 |
+
A local acceptance run against the public detector target successfully:
|
| 42 |
+
|
| 43 |
+
- started the service
|
| 44 |
+
- created a task
|
| 45 |
+
- reached `ready`
|
| 46 |
+
- returned a non-empty token
|
| 47 |
+
|
| 48 |
+
## Operational caveats
|
| 49 |
+
|
| 50 |
+
- A returned token does not imply guaranteed score targeting.
|
| 51 |
+
- Site behavior may vary over time.
|
| 52 |
+
- IP quality and browser environment can affect outcomes.
|
| 53 |
+
- The repository currently uses the same internal solver path for all registered reCAPTCHA v3 task variants.
|
docs/usage/turnstile.md
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Cloudflare Turnstile Usage
|
| 2 |
+
|
| 3 |
+
Cloudflare Turnstile is an invisible or widget-based CAPTCHA alternative. The solver visits the target page with Chromium, interacts with the Turnstile widget, and extracts the resulting token from a hidden `cf-turnstile-response` input field.
|
| 4 |
+
|
| 5 |
+
## Supported task types
|
| 6 |
+
|
| 7 |
+
| Task type | Description |
|
| 8 |
+
|-----------|-------------|
|
| 9 |
+
| `TurnstileTaskProxyless` | Standard Turnstile solving |
|
| 10 |
+
| `TurnstileTaskProxylessM1` | Same path, alternate tier naming |
|
| 11 |
+
|
| 12 |
+
## Required fields
|
| 13 |
+
|
| 14 |
+
| Field | Type | Description |
|
| 15 |
+
|-------|------|-------------|
|
| 16 |
+
| `websiteURL` | string | Full URL of the page containing the Turnstile widget |
|
| 17 |
+
| `websiteKey` | string | The Turnstile `data-sitekey` value |
|
| 18 |
+
|
| 19 |
+
## Solution field
|
| 20 |
+
|
| 21 |
+
Unlike reCAPTCHA tasks, the result is returned in `solution.token` (not `solution.gRecaptchaResponse`):
|
| 22 |
+
|
| 23 |
+
```json
|
| 24 |
+
{
|
| 25 |
+
"errorId": 0,
|
| 26 |
+
"status": "ready",
|
| 27 |
+
"solution": {
|
| 28 |
+
"token": "0.ufq5RgSV..."
|
| 29 |
+
}
|
| 30 |
+
}
|
| 31 |
+
```
|
| 32 |
+
|
| 33 |
+
## Test targets
|
| 34 |
+
|
| 35 |
+
Cloudflare provides official dummy site keys for testing:
|
| 36 |
+
|
| 37 |
+
| Site key | Behavior | URL |
|
| 38 |
+
|----------|----------|-----|
|
| 39 |
+
| `1x00000000000000000000AA` | Always passes | Any domain |
|
| 40 |
+
| `2x00000000000000000000AB` | Always fails | Any domain |
|
| 41 |
+
| `3x00000000000000000000FF` | Forces interactive challenge | Any domain |
|
| 42 |
+
|
| 43 |
+
The React Turnstile demo is a good live test target:
|
| 44 |
+
|
| 45 |
+
- **URL:** `https://react-turnstile.vercel.app/basic`
|
| 46 |
+
- **Site key:** `1x00000000000000000000AA` (test key, always passes)
|
| 47 |
+
|
| 48 |
+
## Create a task
|
| 49 |
+
|
| 50 |
+
```bash
|
| 51 |
+
curl -X POST http://localhost:8000/createTask \
|
| 52 |
+
-H "Content-Type: application/json" \
|
| 53 |
+
-d '{
|
| 54 |
+
"clientKey": "your-client-key",
|
| 55 |
+
"task": {
|
| 56 |
+
"type": "TurnstileTaskProxyless",
|
| 57 |
+
"websiteURL": "https://react-turnstile.vercel.app/basic",
|
| 58 |
+
"websiteKey": "1x00000000000000000000AA"
|
| 59 |
+
}
|
| 60 |
+
}'
|
| 61 |
+
```
|
| 62 |
+
|
| 63 |
+
Response:
|
| 64 |
+
|
| 65 |
+
```json
|
| 66 |
+
{
|
| 67 |
+
"errorId": 0,
|
| 68 |
+
"taskId": "uuid-string"
|
| 69 |
+
}
|
| 70 |
+
```
|
| 71 |
+
|
| 72 |
+
## Poll for result
|
| 73 |
+
|
| 74 |
+
```bash
|
| 75 |
+
curl -X POST http://localhost:8000/getTaskResult \
|
| 76 |
+
-H "Content-Type: application/json" \
|
| 77 |
+
-d '{
|
| 78 |
+
"clientKey": "your-client-key",
|
| 79 |
+
"taskId": "uuid-from-createTask"
|
| 80 |
+
}'
|
| 81 |
+
```
|
| 82 |
+
|
| 83 |
+
When ready:
|
| 84 |
+
|
| 85 |
+
```json
|
| 86 |
+
{
|
| 87 |
+
"errorId": 0,
|
| 88 |
+
"status": "ready",
|
| 89 |
+
"solution": {
|
| 90 |
+
"token": "XXXX.DUMMY.TOKEN.XXXX"
|
| 91 |
+
}
|
| 92 |
+
}
|
| 93 |
+
```
|
| 94 |
+
|
| 95 |
+
!!! info "Dummy token"
|
| 96 |
+
Cloudflare test keys (`1x00000000000000000000AA`) return the dummy token `XXXX.DUMMY.TOKEN.XXXX`. This is the expected and correct behavior for test sitekeys — the token is accepted by Cloudflare's test infrastructure.
|
| 97 |
+
|
| 98 |
+
## Acceptance status
|
| 99 |
+
|
| 100 |
+
| Target | Site key | Status |
|
| 101 |
+
|--------|----------|--------|
|
| 102 |
+
| `https://react-turnstile.vercel.app/basic` | `1x00000000000000000000AA` | ✅ Dummy token returned |
|
| 103 |
+
|
| 104 |
+
## Operational notes
|
| 105 |
+
|
| 106 |
+
- Turnstile auto-solves most of the time without user interaction; the solver polls for the token after page load.
|
| 107 |
+
- Real production sitekeys will return a real token (not the dummy token).
|
| 108 |
+
- The `TurnstileTaskProxylessM1` type uses the same implementation path.
|
docs/zh/acceptance.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 验收测试
|
| 2 |
+
|
| 3 |
+
本页记录各支持验证码类型的验收目标、测试 URL、site key,以及本地验证运行的观察结果。
|
| 4 |
+
|
| 5 |
+
## 总览
|
| 6 |
+
|
| 7 |
+
| 验证码类型 | 目标 | 状态 |
|
| 8 |
+
|----------|------|------|
|
| 9 |
+
| reCAPTCHA v3 | `https://antcpt.com/score_detector/` | ✅ 已返回令牌 |
|
| 10 |
+
| Cloudflare Turnstile | `https://react-turnstile.vercel.app/basic` | ✅ 已返回 Dummy 令牌 |
|
| 11 |
+
| reCAPTCHA v2 | `https://www.google.com/recaptcha/api2/demo` | ⚠️ 需要音频挑战(见说明) |
|
| 12 |
+
| hCaptcha | `https://accounts.hcaptcha.com/demo` | ⚠️ 依赖挑战类型 |
|
| 13 |
+
| Image-to-Text | 本地 base64 图片 | ✅ 视觉模型返回文本 |
|
| 14 |
+
| 分类任务 | 本地 base64 网格 | ✅ 视觉模型返回对象索引 |
|
| 15 |
+
|
| 16 |
+
---
|
| 17 |
+
|
| 18 |
+
## reCAPTCHA v3 — 主要验收目标
|
| 19 |
+
|
| 20 |
+
**URL:** `https://antcpt.com/score_detector/`
|
| 21 |
+
**Site key:** `6LcR_okUAAAAAPYrPe-HK_0RULO1aZM15ENyM-Mf`
|
| 22 |
+
|
| 23 |
+
### 验收步骤
|
| 24 |
+
|
| 25 |
+
1. 安装依赖和 Playwright Chromium。
|
| 26 |
+
2. 启动服务:`python main.py`
|
| 27 |
+
3. 确认 `GET /api/v1/health` 返回全部 19 种任务类型。
|
| 28 |
+
4. 创建 `RecaptchaV3TaskProxyless` 任务。
|
| 29 |
+
5. 轮询 `POST /getTaskResult` 直至 `status=ready`。
|
| 30 |
+
6. 确认返回非空的 `solution.gRecaptchaResponse`。
|
| 31 |
+
|
| 32 |
+
### 已验证结果
|
| 33 |
+
|
| 34 |
+
- 服务启动:✅
|
| 35 |
+
- 健康检查端点:✅(19 种类型已注册)
|
| 36 |
+
- 任务创建:✅
|
| 37 |
+
- 令牌返回:✅(非空 `gRecaptchaResponse`,长度约 1060 字符)
|
| 38 |
+
|
| 39 |
+
---
|
| 40 |
+
|
| 41 |
+
## Cloudflare Turnstile
|
| 42 |
+
|
| 43 |
+
**URL:** `https://react-turnstile.vercel.app/basic`
|
| 44 |
+
**Site key:** `1x00000000000000000000AA`(Cloudflare 官方测试密钥——始终通过)
|
| 45 |
+
|
| 46 |
+
### 已验证结果
|
| 47 |
+
|
| 48 |
+
- 令牌返回:✅ `XXXX.DUMMY.TOKEN.XXXX`(Cloudflare 测试密钥的预期行为)
|
| 49 |
+
|
| 50 |
+
---
|
| 51 |
+
|
| 52 |
+
## reCAPTCHA v2
|
| 53 |
+
|
| 54 |
+
**URL:** `https://www.google.com/recaptcha/api2/demo`
|
| 55 |
+
**Site key:** `6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-`
|
| 56 |
+
|
| 57 |
+
### 无头浏览器行为
|
| 58 |
+
|
| 59 |
+
Google 风险分析引擎会检测无头浏览器。复选框点击成功,但会弹出图像挑战,而不是直接签发令牌。
|
| 60 |
+
|
| 61 |
+
**已实现的缓解措施:** 求解器回退到**音频挑战路径**——在挑战对话框中点击音频按钮,下载 MP3,通过配置的模型转录,并提交转录文本。
|
| 62 |
+
|
| 63 |
+
### 状态
|
| 64 |
+
|
| 65 |
+
⚠️ 已实现音频挑战回退。成功率取决于模型的音频处理能力和 Google 当前的挑战难度。
|
| 66 |
+
|
| 67 |
+
---
|
| 68 |
+
|
| 69 |
+
## hCaptcha
|
| 70 |
+
|
| 71 |
+
**URL:** `https://accounts.hcaptcha.com/demo`
|
| 72 |
+
**Site key:** `10000000-ffff-ffff-ffff-000000000001`(hCaptcha 官方测试密钥)
|
| 73 |
+
|
| 74 |
+
### 状态
|
| 75 |
+
|
| 76 |
+
⚠️ 复选框点击成功。令牌签发取决于 hCaptcha 的机器人检测评分。对于测试环境,推荐使用 [HCaptchaClassification](../usage/classification.md) 任务类型(直接图像分类)作为集成方案。
|
| 77 |
+
|
| 78 |
+
---
|
| 79 |
+
|
| 80 |
+
## 总结
|
| 81 |
+
|
| 82 |
+
- ✅ **reCAPTCHA v3** 和 **Turnstile** 完全可用,每次本地测试均通过。
|
| 83 |
+
- ⚠️ **reCAPTCHA v2** 和 **hCaptcha** 浏览器自动化求解受无头浏览器检测限制。这些类型主要通过 `HCaptchaClassification` / `ReCaptchaV2Classification` 分类任务进行图像网格求解集成。
|
| 84 |
+
- 本服务设计为 **flow2api 的后端打码工具**——实际集成中,通常提取图像挑战帧并发送到分类端点,而非完全依赖浏览器自动化通过组件。
|
docs/zh/api-reference.md
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# API 参考
|
| 2 |
+
|
| 3 |
+
## 接口列表
|
| 4 |
+
|
| 5 |
+
- `POST /createTask`
|
| 6 |
+
- `POST /getTaskResult`
|
| 7 |
+
- `POST /getBalance`
|
| 8 |
+
- `GET /api/v1/health`
|
| 9 |
+
- `GET /`
|
| 10 |
+
|
| 11 |
+
所有任务接口都基于 JSON,并遵循 YesCaptcha 风格的异步任务模式。
|
| 12 |
+
|
| 13 |
+
## `POST /createTask`
|
| 14 |
+
|
| 15 |
+
### 请求结构
|
| 16 |
+
|
| 17 |
+
```json
|
| 18 |
+
{
|
| 19 |
+
"clientKey": "your-client-key",
|
| 20 |
+
"task": {
|
| 21 |
+
"type": "RecaptchaV3TaskProxyless",
|
| 22 |
+
"websiteURL": "https://antcpt.com/score_detector/",
|
| 23 |
+
"websiteKey": "6LcR_okUAAAAAPYrPe-HK_0RULO1aZM15ENyM-Mf",
|
| 24 |
+
"pageAction": "homepage"
|
| 25 |
+
}
|
| 26 |
+
}
|
| 27 |
+
```
|
| 28 |
+
|
| 29 |
+
### 支持的任务类型
|
| 30 |
+
|
| 31 |
+
#### reCAPTCHA v3
|
| 32 |
+
|
| 33 |
+
- `RecaptchaV3TaskProxyless`
|
| 34 |
+
- `RecaptchaV3TaskProxylessM1`
|
| 35 |
+
- `RecaptchaV3TaskProxylessM1S7`
|
| 36 |
+
- `RecaptchaV3TaskProxylessM1S9`
|
| 37 |
+
|
| 38 |
+
必填字段:
|
| 39 |
+
|
| 40 |
+
- `websiteURL`
|
| 41 |
+
- `websiteKey`
|
| 42 |
+
- 推荐传入 `pageAction`,该字段会透传给 `grecaptcha.execute()`
|
| 43 |
+
|
| 44 |
+
#### 图片识别
|
| 45 |
+
|
| 46 |
+
- `ImageToTextTask`
|
| 47 |
+
|
| 48 |
+
必填字段:
|
| 49 |
+
|
| 50 |
+
- `body` — base64 编码后的图片
|
| 51 |
+
|
| 52 |
+
### `minScore` 兼容性说明
|
| 53 |
+
|
| 54 |
+
请求模型接受 `minScore` 字段用于兼容,但当前 solver **不会**根据该字段做分数控制。
|
| 55 |
+
|
| 56 |
+
### 成功响应
|
| 57 |
+
|
| 58 |
+
```json
|
| 59 |
+
{
|
| 60 |
+
"errorId": 0,
|
| 61 |
+
"taskId": "uuid-string"
|
| 62 |
+
}
|
| 63 |
+
```
|
| 64 |
+
|
| 65 |
+
### 常见错误响应
|
| 66 |
+
|
| 67 |
+
```json
|
| 68 |
+
{
|
| 69 |
+
"errorId": 1,
|
| 70 |
+
"errorCode": "ERROR_TASK_NOT_SUPPORTED",
|
| 71 |
+
"errorDescription": "Task type 'X' is not supported."
|
| 72 |
+
}
|
| 73 |
+
```
|
| 74 |
+
|
| 75 |
+
```json
|
| 76 |
+
{
|
| 77 |
+
"errorId": 1,
|
| 78 |
+
"errorCode": "ERROR_TASK_PROPERTY_EMPTY",
|
| 79 |
+
"errorDescription": "websiteURL and websiteKey are required"
|
| 80 |
+
}
|
| 81 |
+
```
|
| 82 |
+
|
| 83 |
+
## `POST /getTaskResult`
|
| 84 |
+
|
| 85 |
+
### 请求
|
| 86 |
+
|
| 87 |
+
```json
|
| 88 |
+
{
|
| 89 |
+
"clientKey": "your-client-key",
|
| 90 |
+
"taskId": "uuid-from-createTask"
|
| 91 |
+
}
|
| 92 |
+
```
|
| 93 |
+
|
| 94 |
+
### 处理中响应
|
| 95 |
+
|
| 96 |
+
```json
|
| 97 |
+
{
|
| 98 |
+
"errorId": 0,
|
| 99 |
+
"status": "processing"
|
| 100 |
+
}
|
| 101 |
+
```
|
| 102 |
+
|
| 103 |
+
### reCAPTCHA v3 完成响应
|
| 104 |
+
|
| 105 |
+
```json
|
| 106 |
+
{
|
| 107 |
+
"errorId": 0,
|
| 108 |
+
"status": "ready",
|
| 109 |
+
"solution": {
|
| 110 |
+
"gRecaptchaResponse": "token..."
|
| 111 |
+
}
|
| 112 |
+
}
|
| 113 |
+
```
|
| 114 |
+
|
| 115 |
+
### `ImageToTextTask` 完成响应
|
| 116 |
+
|
| 117 |
+
```json
|
| 118 |
+
{
|
| 119 |
+
"errorId": 0,
|
| 120 |
+
"status": "ready",
|
| 121 |
+
"solution": {
|
| 122 |
+
"text": "{\"captcha_type\":\"click\", ...}"
|
| 123 |
+
}
|
| 124 |
+
}
|
| 125 |
+
```
|
| 126 |
+
|
| 127 |
+
### 未找到任务响应
|
| 128 |
+
|
| 129 |
+
```json
|
| 130 |
+
{
|
| 131 |
+
"errorId": 1,
|
| 132 |
+
"errorCode": "ERROR_NO_SUCH_CAPCHA_ID",
|
| 133 |
+
"errorDescription": "Task not found"
|
| 134 |
+
}
|
| 135 |
+
```
|
| 136 |
+
|
| 137 |
+
## `POST /getBalance`
|
| 138 |
+
|
| 139 |
+
### 请求
|
| 140 |
+
|
| 141 |
+
```json
|
| 142 |
+
{
|
| 143 |
+
"clientKey": "your-client-key"
|
| 144 |
+
}
|
| 145 |
+
```
|
| 146 |
+
|
| 147 |
+
### 响应
|
| 148 |
+
|
| 149 |
+
```json
|
| 150 |
+
{
|
| 151 |
+
"errorId": 0,
|
| 152 |
+
"balance": 99999.0
|
| 153 |
+
}
|
| 154 |
+
```
|
| 155 |
+
|
| 156 |
+
当前余额为静态兼容性响应。
|
| 157 |
+
|
| 158 |
+
## `GET /api/v1/health`
|
| 159 |
+
|
| 160 |
+
示例响应:
|
| 161 |
+
|
| 162 |
+
```json
|
| 163 |
+
{
|
| 164 |
+
"status": "ok",
|
| 165 |
+
"supported_task_types": [
|
| 166 |
+
"RecaptchaV3TaskProxyless",
|
| 167 |
+
"RecaptchaV3TaskProxylessM1",
|
| 168 |
+
"RecaptchaV3TaskProxylessM1S7",
|
| 169 |
+
"RecaptchaV3TaskProxylessM1S9",
|
| 170 |
+
"ImageToTextTask"
|
| 171 |
+
],
|
| 172 |
+
"browser_headless": true,
|
| 173 |
+
"captcha_model": "gpt-5.4",
|
| 174 |
+
"captcha_multimodal_model": "qwen3.5-2b"
|
| 175 |
+
}
|
| 176 |
+
```
|
| 177 |
+
|
| 178 |
+
## `GET /`
|
| 179 |
+
|
| 180 |
+
根接口会返回服务简述以及运行时已注册的任务类型。
|
docs/zh/deployment/huggingface.md
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Hugging Face Spaces 部署
|
| 2 |
+
|
| 3 |
+
本指南说明如何使用 **Hugging Face Spaces** 的 Docker Space 来部署 OhMyCaptcha。
|
| 4 |
+
|
| 5 |
+
## 什么时候适合用 Hugging Face Spaces
|
| 6 |
+
|
| 7 |
+
当你有以下需求时,Hugging Face Spaces 会比较合适:
|
| 8 |
+
|
| 9 |
+
- 希望快速部署一个公开或私有演示环境
|
| 10 |
+
- 希望使用图形界面的托管流程
|
| 11 |
+
- 希望在 Space 设置里直接管理密钥
|
| 12 |
+
- 不想自己维护 VPS,但又需要 Docker 部署环境
|
| 13 |
+
|
| 14 |
+
## 1. 准备仓库
|
| 15 |
+
|
| 16 |
+
请确认仓库中已经包含:
|
| 17 |
+
|
| 18 |
+
- `Dockerfile.render`
|
| 19 |
+
- `main.py`
|
| 20 |
+
- `requirements.txt`
|
| 21 |
+
- `src/` 应用目录
|
| 22 |
+
|
| 23 |
+
对于 Hugging Face Spaces,当前 Dockerfile 可以直接作为起点,因为它已经包含 Python 依赖安装和 Playwright Chromium 安装步骤。
|
| 24 |
+
|
| 25 |
+
## 2. 创建 Docker Space
|
| 26 |
+
|
| 27 |
+
在 Hugging Face 中:
|
| 28 |
+
|
| 29 |
+
1. 创建新的 **Space**。
|
| 30 |
+
2. SDK 选择 **Docker**。
|
| 31 |
+
3. 根据需要选择公开或私有。
|
| 32 |
+
4. 将 Space 连接到本仓库,或上传项目文件。
|
| 33 |
+
|
| 34 |
+
## 3. 配置密钥和变量
|
| 35 |
+
|
| 36 |
+
在 Space 设置中添加以下 secrets:
|
| 37 |
+
|
| 38 |
+
- `CLIENT_KEY`
|
| 39 |
+
- `CAPTCHA_API_KEY`
|
| 40 |
+
|
| 41 |
+
按需添加或覆盖变量:
|
| 42 |
+
|
| 43 |
+
- `CAPTCHA_BASE_URL`
|
| 44 |
+
- `CAPTCHA_MODEL`
|
| 45 |
+
- `CAPTCHA_MULTIMODAL_MODEL`
|
| 46 |
+
- `BROWSER_HEADLESS=true`
|
| 47 |
+
- `BROWSER_TIMEOUT=30`
|
| 48 |
+
- `SERVER_PORT=7860`
|
| 49 |
+
|
| 50 |
+
Hugging Face Spaces 通常对外暴露 `7860` 端口,因此建议设置 `SERVER_PORT=7860`。
|
| 51 |
+
|
| 52 |
+
## 4. 确认启动命令
|
| 53 |
+
|
| 54 |
+
容器应通过以下命令启动应用:
|
| 55 |
+
|
| 56 |
+
```bash
|
| 57 |
+
python main.py
|
| 58 |
+
```
|
| 59 |
+
|
| 60 |
+
当前入口已经支持通过环境变量读取端口。
|
| 61 |
+
|
| 62 |
+
## 5. 等待构建完成
|
| 63 |
+
|
| 64 |
+
当 Space 开始构建后:
|
| 65 |
+
|
| 66 |
+
- 观察构建日志
|
| 67 |
+
- 确认依赖安装成功
|
| 68 |
+
- 确认 Playwright Chromium 安装成功
|
| 69 |
+
- 等待应用进入运行状态
|
| 70 |
+
|
| 71 |
+
## 6. 验证部署结果
|
| 72 |
+
|
| 73 |
+
当 Space 可访问后,先验证:
|
| 74 |
+
|
| 75 |
+
### 根接口
|
| 76 |
+
|
| 77 |
+
```bash
|
| 78 |
+
curl https://<your-space-subdomain>.hf.space/
|
| 79 |
+
```
|
| 80 |
+
|
| 81 |
+
### 健康检查
|
| 82 |
+
|
| 83 |
+
```bash
|
| 84 |
+
curl https://<your-space-subdomain>.hf.space/api/v1/health
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
### 创建 detector 任务
|
| 88 |
+
|
| 89 |
+
```bash
|
| 90 |
+
curl -X POST https://<your-space-subdomain>.hf.space/createTask \
|
| 91 |
+
-H "Content-Type: application/json" \
|
| 92 |
+
-d '{
|
| 93 |
+
"clientKey": "your-client-key",
|
| 94 |
+
"task": {
|
| 95 |
+
"type": "RecaptchaV3TaskProxyless",
|
| 96 |
+
"websiteURL": "https://antcpt.com/score_detector/",
|
| 97 |
+
"websiteKey": "6LcR_okUAAAAAPYrPe-HK_0RULO1aZM15ENyM-Mf",
|
| 98 |
+
"pageAction": "homepage"
|
| 99 |
+
}
|
| 100 |
+
}'
|
| 101 |
+
```
|
| 102 |
+
|
| 103 |
+
## 运行说明
|
| 104 |
+
|
| 105 |
+
- Hugging Face Spaces 部署方便,但冷启动和资源限制会影响 Playwright 这类浏览器自动化负载。
|
| 106 |
+
- 相比纯 API 服务,浏览器自动化对共享托管环境更敏感。
|
| 107 |
+
- 如果你需要更强的运行时控制,建议使用 Render 或自有基础设施。
|
| 108 |
+
|
| 109 |
+
## 推荐用途
|
| 110 |
+
|
| 111 |
+
Hugging Face Spaces 更适合:
|
| 112 |
+
|
| 113 |
+
- 验证
|
| 114 |
+
- 演示
|
| 115 |
+
- 低流量内部使用
|
| 116 |
+
- 作为文档中可直接访问的公开部署示例
|
docs/zh/deployment/local-model.md
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 本地模型部署
|
| 2 |
+
|
| 3 |
+
OhMyCaptcha 支持使用 [SGLang](https://github.com/sgl-project/sglang)、[vLLM](https://github.com/vllm-project/vllm) 或任何 OpenAI 兼容推理服务在本地部署图像识别和分类模型。
|
| 4 |
+
|
| 5 |
+
本指南以 [Qwen3.5-2B](https://modelscope.cn/models/Qwen/Qwen3.5-2B) + SGLang 为例。
|
| 6 |
+
|
| 7 |
+
## 架构:本地模型 vs 云端模型
|
| 8 |
+
|
| 9 |
+
OhMyCaptcha 使用两种模型后端:
|
| 10 |
+
|
| 11 |
+
| 后端 | 角色 | 环境变量 | 默认值 |
|
| 12 |
+
|------|------|---------|-------|
|
| 13 |
+
| **本地模型** | 图像识别与分类(高吞吐,自托管) | `LOCAL_BASE_URL`, `LOCAL_API_KEY`, `LOCAL_MODEL` | `http://localhost:30000/v1`, `EMPTY`, `Qwen/Qwen3.5-2B` |
|
| 14 |
+
| **云端模型** | 音频转录与复杂推理(强大远程 API) | `CLOUD_BASE_URL`, `CLOUD_API_KEY`, `CLOUD_MODEL` | 外部端点, 你的密钥, `gpt-5.4` |
|
| 15 |
+
|
| 16 |
+
## 前置要求
|
| 17 |
+
|
| 18 |
+
- Python 3.10+
|
| 19 |
+
- NVIDIA GPU + CUDA(推荐 8GB+ 显存用于 Qwen3.5-2B)
|
| 20 |
+
|
| 21 |
+
## 第一步:安装 SGLang
|
| 22 |
+
|
| 23 |
+
```bash
|
| 24 |
+
pip install "sglang[all]>=0.4.6.post1"
|
| 25 |
+
```
|
| 26 |
+
|
| 27 |
+
## 第二步:启动模型服务
|
| 28 |
+
|
| 29 |
+
### 从 ModelScope 下载(国内推荐)
|
| 30 |
+
|
| 31 |
+
```bash
|
| 32 |
+
export SGLANG_USE_MODELSCOPE=true
|
| 33 |
+
python -m sglang.launch_server \
|
| 34 |
+
--model-path Qwen/Qwen3.5-2B \
|
| 35 |
+
--host 0.0.0.0 \
|
| 36 |
+
--port 30000
|
| 37 |
+
```
|
| 38 |
+
|
| 39 |
+
### 从 Hugging Face 下载
|
| 40 |
+
|
| 41 |
+
```bash
|
| 42 |
+
python -m sglang.launch_server \
|
| 43 |
+
--model-path Qwen/Qwen3.5-2B \
|
| 44 |
+
--host 0.0.0.0 \
|
| 45 |
+
--port 30000
|
| 46 |
+
```
|
| 47 |
+
|
| 48 |
+
### 多 GPU 部署
|
| 49 |
+
|
| 50 |
+
```bash
|
| 51 |
+
python -m sglang.launch_server \
|
| 52 |
+
--model-path Qwen/Qwen3.5-2B \
|
| 53 |
+
--host 0.0.0.0 \
|
| 54 |
+
--port 30000 \
|
| 55 |
+
--tensor-parallel-size 2
|
| 56 |
+
```
|
| 57 |
+
|
| 58 |
+
启动后,服务在 `http://localhost:30000/v1` 提供 OpenAI 兼容 API。
|
| 59 |
+
|
| 60 |
+
## 第三步:验证模型服务
|
| 61 |
+
|
| 62 |
+
```bash
|
| 63 |
+
curl http://localhost:30000/v1/chat/completions \
|
| 64 |
+
-H "Content-Type: application/json" \
|
| 65 |
+
-d '{
|
| 66 |
+
"model": "Qwen/Qwen3.5-2B",
|
| 67 |
+
"messages": [{"role": "user", "content": "Hello"}],
|
| 68 |
+
"max_tokens": 32
|
| 69 |
+
}'
|
| 70 |
+
```
|
| 71 |
+
|
| 72 |
+
## 第四步:配置 OhMyCaptcha
|
| 73 |
+
|
| 74 |
+
```bash
|
| 75 |
+
# 本地模型(SGLang 自托管)
|
| 76 |
+
export LOCAL_BASE_URL="http://localhost:30000/v1"
|
| 77 |
+
export LOCAL_API_KEY="EMPTY"
|
| 78 |
+
export LOCAL_MODEL="Qwen/Qwen3.5-2B"
|
| 79 |
+
|
| 80 |
+
# 云端模型(远程 API,用于音频转录等)
|
| 81 |
+
export CLOUD_BASE_URL="https://your-api-endpoint/v1"
|
| 82 |
+
export CLOUD_API_KEY="sk-your-key"
|
| 83 |
+
export CLOUD_MODEL="gpt-5.4"
|
| 84 |
+
|
| 85 |
+
# 其他配置
|
| 86 |
+
export CLIENT_KEY="your-client-key"
|
| 87 |
+
export BROWSER_HEADLESS=true
|
| 88 |
+
```
|
| 89 |
+
|
| 90 |
+
## 第五步:启动 OhMyCaptcha
|
| 91 |
+
|
| 92 |
+
```bash
|
| 93 |
+
python main.py
|
| 94 |
+
```
|
| 95 |
+
|
| 96 |
+
## 向后兼容
|
| 97 |
+
|
| 98 |
+
旧版环境变量(`CAPTCHA_BASE_URL`、`CAPTCHA_API_KEY`、`CAPTCHA_MODEL`、`CAPTCHA_MULTIMODAL_MODEL`)仍然支持。新的 `LOCAL_*` 和 `CLOUD_*` 变量优先生效。
|
| 99 |
+
|
| 100 |
+
## 推荐模型
|
| 101 |
+
|
| 102 |
+
| 模型 | 大小 | 用途 | 显存 |
|
| 103 |
+
|------|------|------|------|
|
| 104 |
+
| `Qwen/Qwen3.5-2B` | 2B | 图像识别与分类 | ~5 GB |
|
| 105 |
+
| `Qwen/Qwen3.5-7B` | 7B | 更高精度分类 | ~15 GB |
|
| 106 |
+
| `Qwen/Qwen3.5-2B-FP8` | 2B(量化) | 低显存需求 | ~3 GB |
|
docs/zh/deployment/render.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Render 部署
|
| 2 |
+
|
| 3 |
+
本指南说明如何使用仓库中已经提供的 Docker 文件,把 OhMyCaptcha 部署到 **Render**。
|
| 4 |
+
|
| 5 |
+
## 什么时候适合用 Render
|
| 6 |
+
|
| 7 |
+
当你有以下需求时,Render 是一个很合适的选择:
|
| 8 |
+
|
| 9 |
+
- 希望获得稳定的公网地址
|
| 10 |
+
- 希望方便地管理密钥和环境变量
|
| 11 |
+
- 希望使用简单的 Docker 部署流程
|
| 12 |
+
- 希望比演示型托管平台拥有更稳定的运行环境
|
| 13 |
+
|
| 14 |
+
## 1. 准备仓库
|
| 15 |
+
|
| 16 |
+
当前仓库已经包含 Render 所需文件:
|
| 17 |
+
|
| 18 |
+
- `Dockerfile.render`
|
| 19 |
+
- `render.yaml`
|
| 20 |
+
- `main.py`
|
| 21 |
+
- `requirements.txt`
|
| 22 |
+
- `src/`
|
| 23 |
+
|
| 24 |
+
应用默认监听 `8000` 端口,同时也兼容 Render 注入的 `PORT` 环境变量。
|
| 25 |
+
|
| 26 |
+
## 2. 创建 Render 服务
|
| 27 |
+
|
| 28 |
+
在 Render 中:
|
| 29 |
+
|
| 30 |
+
1. 创建新的 **Web Service**。
|
| 31 |
+
2. 连接你的 GitHub 仓库。
|
| 32 |
+
3. Runtime 选择 **Docker**。
|
| 33 |
+
4. 指向以下配置:
|
| 34 |
+
- Dockerfile:`Dockerfile.render`
|
| 35 |
+
- Context:仓库根目录
|
| 36 |
+
|
| 37 |
+
你也可以直接导入仓库中的 `render.yaml` blueprint。
|
| 38 |
+
|
| 39 |
+
## 3. 配置环境变量
|
| 40 |
+
|
| 41 |
+
### 必需密钥
|
| 42 |
+
|
| 43 |
+
请在 Render 控制台中配置以下受保护变量:
|
| 44 |
+
|
| 45 |
+
- `CLIENT_KEY`
|
| 46 |
+
- `CAPTCHA_API_KEY`
|
| 47 |
+
|
| 48 |
+
### 建议变量
|
| 49 |
+
|
| 50 |
+
- `CAPTCHA_BASE_URL=https://your-openai-compatible-endpoint/v1`
|
| 51 |
+
- `CAPTCHA_MODEL=gpt-5.4`
|
| 52 |
+
- `CAPTCHA_MULTIMODAL_MODEL=qwen3.5-2b`
|
| 53 |
+
- `CAPTCHA_RETRIES=3`
|
| 54 |
+
- `CAPTCHA_TIMEOUT=30`
|
| 55 |
+
- `BROWSER_HEADLESS=true`
|
| 56 |
+
- `BROWSER_TIMEOUT=30`
|
| 57 |
+
|
| 58 |
+
## 4. 触发首次部署
|
| 59 |
+
|
| 60 |
+
保存配置后:
|
| 61 |
+
|
| 62 |
+
- 等待镜像构建完成
|
| 63 |
+
- 确认 Python 依赖安装成功
|
| 64 |
+
- 确认 Playwright Chromium 安装成功
|
| 65 |
+
- 等待服务进入 healthy 状态
|
| 66 |
+
|
| 67 |
+
## 5. 验证部署结果
|
| 68 |
+
|
| 69 |
+
当 Render 提供 URL 后,先检查:
|
| 70 |
+
|
| 71 |
+
### 根接口
|
| 72 |
+
|
| 73 |
+
```bash
|
| 74 |
+
curl https://<your-render-service>.onrender.com/
|
| 75 |
+
```
|
| 76 |
+
|
| 77 |
+
### 健康检查
|
| 78 |
+
|
| 79 |
+
```bash
|
| 80 |
+
curl https://<your-render-service>.onrender.com/api/v1/health
|
| 81 |
+
```
|
| 82 |
+
|
| 83 |
+
### 创建 detector 任务
|
| 84 |
+
|
| 85 |
+
```bash
|
| 86 |
+
curl -X POST https://<your-render-service>.onrender.com/createTask \
|
| 87 |
+
-H "Content-Type: application/json" \
|
| 88 |
+
-d '{
|
| 89 |
+
"clientKey": "your-client-key",
|
| 90 |
+
"task": {
|
| 91 |
+
"type": "RecaptchaV3TaskProxyless",
|
| 92 |
+
"websiteURL": "https://antcpt.com/score_detector/",
|
| 93 |
+
"websiteKey": "6LcR_okUAAAAAPYrPe-HK_0RULO1aZM15ENyM-Mf",
|
| 94 |
+
"pageAction": "homepage"
|
| 95 |
+
}
|
| 96 |
+
}'
|
| 97 |
+
```
|
| 98 |
+
|
| 99 |
+
## 运行说明
|
| 100 |
+
|
| 101 |
+
- 相比轻量演示型托管平台,Render 更适合浏览器自动化类服务。
|
| 102 |
+
- 但浏览器求解依然会受到冷启动、IP 质量和容器资源限制的影响。
|
| 103 |
+
- 如果你需要更强的运行时控制,建议迁移到自有基础设施。
|
| 104 |
+
|
| 105 |
+
## 推荐用途
|
| 106 |
+
|
| 107 |
+
Render 很适合作为以下场景的默认部署方案:
|
| 108 |
+
|
| 109 |
+
- 持续在线的公网服务
|
| 110 |
+
- flow2api 联调
|
| 111 |
+
- 低到中等流量的生产环境
|
| 112 |
+
- 不想自己维护服务器时的快速上线
|
docs/zh/faq.md
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 常见问题
|
| 2 |
+
|
| 3 |
+
## 这能完全替代 YesCaptcha 吗?
|
| 4 |
+
|
| 5 |
+
不能。它实现的是本仓库所支持任务类型对应的 YesCaptcha 风格 API,而不是对所有商业平台功能的完整覆盖。
|
| 6 |
+
|
| 7 |
+
## `minScore` 能保证目标 reCAPTCHA 分数吗?
|
| 8 |
+
|
| 9 |
+
不能。请求模型里保留了 `minScore` 字段用于兼容,但当前 solver 不会根据它做分数控制。
|
| 10 |
+
|
| 11 |
+
## 可以使用本地或自托管多模态模型吗?
|
| 12 |
+
|
| 13 |
+
可以,前提是它们提供支持图像输入的 OpenAI-compatible API。
|
| 14 |
+
|
| 15 |
+
## `ImageToTextTask` 返回的是纯 OCR 文本吗?
|
| 16 |
+
|
| 17 |
+
不一定。当前实现会把结构化识别结果序列化后放入 `solution.text`。
|
| 18 |
+
|
| 19 |
+
## 任务状态会持久化吗?
|
| 20 |
+
|
| 21 |
+
不会。任务状态保存在内存中,并会在 TTL 到期后清理。
|
| 22 |
+
|
| 23 |
+
## 哪些因素会影响 reCAPTCHA v3 结果?
|
| 24 |
+
|
| 25 |
+
常见因素包括 IP 质量、浏览器指纹、目标站行为、`pageAction` 是否正确,以及运行环境本身。
|
docs/zh/getting-started.md
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 快速开始
|
| 2 |
+
|
| 3 |
+
## 环境要求
|
| 4 |
+
|
| 5 |
+
- Python 3.10+
|
| 6 |
+
- 通过 Playwright 安装 Chromium
|
| 7 |
+
- 具备访问以下资源的网络能力:
|
| 8 |
+
- 目标网站
|
| 9 |
+
- 你配置的 OpenAI-compatible 模型接口
|
| 10 |
+
|
| 11 |
+
## 安装
|
| 12 |
+
|
| 13 |
+
```bash
|
| 14 |
+
python -m venv .venv
|
| 15 |
+
source .venv/bin/activate
|
| 16 |
+
pip install -r requirements.txt
|
| 17 |
+
playwright install --with-deps chromium
|
| 18 |
+
```
|
| 19 |
+
|
| 20 |
+
## 环境变量
|
| 21 |
+
|
| 22 |
+
| 变量 | 说明 | 默认值 |
|
| 23 |
+
| --- | --- | --- |
|
| 24 |
+
| `CLIENT_KEY` | 客户端鉴权密钥 | 未设置 |
|
| 25 |
+
| `CAPTCHA_BASE_URL` | OpenAI-compatible API 地址 | `https://your-openai-compatible-endpoint/v1` |
|
| 26 |
+
| `CAPTCHA_API_KEY` | 模型接口密钥 | 未设置 |
|
| 27 |
+
| `CAPTCHA_MODEL` | 强文本模型 | `gpt-5.4` |
|
| 28 |
+
| `CAPTCHA_MULTIMODAL_MODEL` | 多模态模型 | `qwen3.5-2b` |
|
| 29 |
+
| `CAPTCHA_RETRIES` | 重试次数 | `3` |
|
| 30 |
+
| `CAPTCHA_TIMEOUT` | 模型超时(秒) | `30` |
|
| 31 |
+
| `BROWSER_HEADLESS` | 是否无头运行 Chromium | `true` |
|
| 32 |
+
| `BROWSER_TIMEOUT` | 浏览器超时(秒) | `30` |
|
| 33 |
+
| `SERVER_HOST` | 监听地址 | `0.0.0.0` |
|
| 34 |
+
| `SERVER_PORT` | 监听端口 | `8000` |
|
| 35 |
+
|
| 36 |
+
## 启动服务
|
| 37 |
+
|
| 38 |
+
```bash
|
| 39 |
+
export CLIENT_KEY="your-client-key"
|
| 40 |
+
export CAPTCHA_BASE_URL="https://your-openai-compatible-endpoint/v1"
|
| 41 |
+
export CAPTCHA_API_KEY="your-api-key"
|
| 42 |
+
export CAPTCHA_MODEL="gpt-5.4"
|
| 43 |
+
export CAPTCHA_MULTIMODAL_MODEL="qwen3.5-2b"
|
| 44 |
+
python main.py
|
| 45 |
+
```
|
| 46 |
+
|
| 47 |
+
## 验证启动
|
| 48 |
+
|
| 49 |
+
### 根接口
|
| 50 |
+
|
| 51 |
+
```bash
|
| 52 |
+
curl http://localhost:8000/
|
| 53 |
+
```
|
| 54 |
+
|
| 55 |
+
### 健康检查
|
| 56 |
+
|
| 57 |
+
```bash
|
| 58 |
+
curl http://localhost:8000/api/v1/health
|
| 59 |
+
```
|
| 60 |
+
|
| 61 |
+
健康检查响应中应包含已注册任务类型以及当前运行时模型配置。
|
| 62 |
+
|
| 63 |
+
## 本地 / 自托管模型支持
|
| 64 |
+
|
| 65 |
+
图片识别路径基于 **OpenAI-compatible API** 设计。因此,只要你的后端具备兼容的 chat-completions 语义并支持图像输入,就可以把 `CAPTCHA_BASE_URL` 指向托管服务、内部网关或本地/自托管多模态网关。
|
| 66 |
+
|
| 67 |
+
文档采用通用兼容性表述,而不是对每一种模型服务栈做完整验证承诺。
|
docs/zh/index.md
ADDED
|
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# OhMyCaptcha
|
| 2 |
+
|
| 3 |
+
<div class="hero hero--light" markdown>
|
| 4 |
+
|
| 5 |
+
<div class="hero__visual">
|
| 6 |
+
<img src="../assets/ohmycaptcha-hero.png" alt="OhMyCaptcha — 自托管验证码求解服务">
|
| 7 |
+
</div>
|
| 8 |
+
|
| 9 |
+
<div class="hero__copy" markdown>
|
| 10 |
+
|
| 11 |
+
## ⚡ 面向自托管场景的 YesCaptcha 风格验证码服务
|
| 12 |
+
|
| 13 |
+
OhMyCaptcha 将 **FastAPI**、**Playwright** 与 **OpenAI-compatible 多模态模型** 组合为一个全面的验证码求解服务,支持 **19 种任务类型**,适用于 **flow2api** 与类似集成场景。
|
| 14 |
+
|
| 15 |
+
<div class="hero__actions" markdown>
|
| 16 |
+
|
| 17 |
+
[快速开始](getting-started.md){ .md-button .md-button--primary }
|
| 18 |
+
[API 参考](api-reference.md){ .md-button }
|
| 19 |
+
[GitHub](https://github.com/shenhao-stu/ohmycaptcha){ .md-button }
|
| 20 |
+
|
| 21 |
+
</div>
|
| 22 |
+
|
| 23 |
+
</div>
|
| 24 |
+
|
| 25 |
+
</div>
|
| 26 |
+
|
| 27 |
+
## ✨ 项目亮点
|
| 28 |
+
|
| 29 |
+
<div class="grid cards feature-cards" markdown>
|
| 30 |
+
|
| 31 |
+
- :material-api: **YesCaptcha 风格 API**
|
| 32 |
+
|
| 33 |
+
---
|
| 34 |
+
|
| 35 |
+
覆盖 reCAPTCHA v2/v3、hCaptcha、Turnstile 和图像分类的异步 `createTask` / `getTaskResult` 语义。
|
| 36 |
+
|
| 37 |
+
- :material-google-chrome: **浏览器自动化求解**
|
| 38 |
+
|
| 39 |
+
---
|
| 40 |
+
|
| 41 |
+
Playwright + Chromium 为 reCAPTCHA v2/v3、hCaptcha 和 Cloudflare Turnstile 生成令牌。
|
| 42 |
+
|
| 43 |
+
- :material-image-search: **多模态图片识别**
|
| 44 |
+
|
| 45 |
+
---
|
| 46 |
+
|
| 47 |
+
通过 OpenAI-compatible 视觉模型进行 HCaptcha、reCAPTCHA、FunCaptcha、AWS 图像分类。
|
| 48 |
+
|
| 49 |
+
- :material-cloud-outline: **自托管部署**
|
| 50 |
+
|
| 51 |
+
---
|
| 52 |
+
|
| 53 |
+
支持本地运行,配合 Render 和 Hugging Face Spaces 指南完成生产部署。
|
| 54 |
+
|
| 55 |
+
</div>
|
| 56 |
+
|
| 57 |
+
## 🧠 支持的任务类型
|
| 58 |
+
|
| 59 |
+
### 浏览器自动化求解(12 种)
|
| 60 |
+
|
| 61 |
+
| 分类 | 任务类型 |
|
| 62 |
+
|------|---------|
|
| 63 |
+
| **reCAPTCHA v3** | `RecaptchaV3TaskProxyless`, `RecaptchaV3TaskProxylessM1`, `RecaptchaV3TaskProxylessM1S7`, `RecaptchaV3TaskProxylessM1S9` |
|
| 64 |
+
| **reCAPTCHA v3 企业版** | `RecaptchaV3EnterpriseTask`, `RecaptchaV3EnterpriseTaskM1` |
|
| 65 |
+
| **reCAPTCHA v2** | `NoCaptchaTaskProxyless`, `RecaptchaV2TaskProxyless`, `RecaptchaV2EnterpriseTaskProxyless` |
|
| 66 |
+
| **hCaptcha** | `HCaptchaTaskProxyless` |
|
| 67 |
+
| **Cloudflare Turnstile** | `TurnstileTaskProxyless`, `TurnstileTaskProxylessM1` |
|
| 68 |
+
|
| 69 |
+
### 图片识别(3 种)
|
| 70 |
+
|
| 71 |
+
| 任务类型 | 说明 |
|
| 72 |
+
|---------|------|
|
| 73 |
+
| `ImageToTextTask` | 受 Argus 启发的多模态识别 |
|
| 74 |
+
| `ImageToTextTaskMuggle` | 文本/字母数字识别 |
|
| 75 |
+
| `ImageToTextTaskM1` | 异步图片文本识别 |
|
| 76 |
+
|
| 77 |
+
### 图像分类(4 种)
|
| 78 |
+
|
| 79 |
+
| 任务类型 | 说明 |
|
| 80 |
+
|---------|------|
|
| 81 |
+
| `HCaptchaClassification` | hCaptcha 网格图像分类 |
|
| 82 |
+
| `ReCaptchaV2Classification` | reCAPTCHA v2 网格选择 |
|
| 83 |
+
| `FunCaptchaClassification` | FunCaptcha 图像选择 |
|
| 84 |
+
| `AwsClassification` | AWS 验证码图像分类 |
|
| 85 |
+
|
| 86 |
+
## 🚀 快速入口
|
| 87 |
+
|
| 88 |
+
<div class="grid cards feature-cards" markdown>
|
| 89 |
+
|
| 90 |
+
- :material-rocket-launch-outline: **快速开始**
|
| 91 |
+
|
| 92 |
+
---
|
| 93 |
+
|
| 94 |
+
安装依赖、配置环境变量,并在本地启动服务。
|
| 95 |
+
|
| 96 |
+
[打开快速开始](getting-started.md)
|
| 97 |
+
|
| 98 |
+
- :material-file-document-outline: **API 参考**
|
| 99 |
+
|
| 100 |
+
---
|
| 101 |
+
|
| 102 |
+
查看全部 19 种任务类型、接口和请求格式。
|
| 103 |
+
|
| 104 |
+
[打开 API 参考](api-reference.md)
|
| 105 |
+
|
| 106 |
+
- :material-play-box-outline: **验收说明**
|
| 107 |
+
|
| 108 |
+
---
|
| 109 |
+
|
| 110 |
+
验证 detector 目标流程,并确认 token 返回行为。
|
| 111 |
+
|
| 112 |
+
[打开验收指南](acceptance.md)
|
| 113 |
+
|
| 114 |
+
- :material-server-outline: **部署指南**
|
| 115 |
+
|
| 116 |
+
---
|
| 117 |
+
|
| 118 |
+
按 Render 或 Hugging Face Spaces 路径部署你的服务实例。
|
| 119 |
+
|
| 120 |
+
[打开部署指南](deployment/render.md)
|
| 121 |
+
|
| 122 |
+
</div>
|
| 123 |
+
|
| 124 |
+
## 📌 范围说明
|
| 125 |
+
|
| 126 |
+
OhMyCaptcha 实现了**覆盖 19 种任务类型的 YesCaptcha 风格 API**,涵盖 reCAPTCHA v2/v3、hCaptcha、Cloudflare Turnstile 和图像分类。浏览器自动化任务依赖 Playwright,可能需要针对特定目标站点调优。图像分类利用多模态视觉模型,准确性取决于模型质量。
|
docs/zh/positioning.md
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 项目定位
|
| 2 |
+
|
| 3 |
+
## OhMyCaptcha 是什么
|
| 4 |
+
|
| 5 |
+
OhMyCaptcha 是一个可自托管的验证码解决服务,为本仓库已经实现的任务类型提供 YesCaptcha 风格的 API。
|
| 6 |
+
|
| 7 |
+
它适合以下场景:
|
| 8 |
+
|
| 9 |
+
- 希望自托管验证码服务
|
| 10 |
+
- 希望兼容 `createTask` / `getTaskResult` 风格工作流
|
| 11 |
+
- 希望可控地管理浏览器自动化和模型后端
|
| 12 |
+
- 希望支持 OpenAI-compatible 多模态提供方,包括本地或自托管网关
|
| 13 |
+
|
| 14 |
+
## 与 YesCaptcha 等托管服务的对比
|
| 15 |
+
|
| 16 |
+
YesCaptcha 等托管服务通常提供:
|
| 17 |
+
|
| 18 |
+
- 托管平台
|
| 19 |
+
- 更广泛的任务类型目录
|
| 20 |
+
- 商业 SLA 与供应商托管基础设施
|
| 21 |
+
|
| 22 |
+
OhMyCaptcha 更关注:
|
| 23 |
+
|
| 24 |
+
- 自托管
|
| 25 |
+
- 实现透明
|
| 26 |
+
- 提示词和浏览器逻辑可自定义
|
| 27 |
+
- 多模态模型后端灵活可替换
|
| 28 |
+
|
| 29 |
+
## 范围边界
|
| 30 |
+
|
| 31 |
+
本仓库不应被描述为对商业平台所有验证码家族与任务类型的完整替代。
|
| 32 |
+
|
| 33 |
+
更准确的表述是:
|
| 34 |
+
|
| 35 |
+
> 一个针对已实现任务类型提供 YesCaptcha 风格 API 的自托管服务,可集成到 flow2api 等系统中。
|
| 36 |
+
|
| 37 |
+
## 本地 / 自托管模型支持
|
| 38 |
+
|
| 39 |
+
项目在多模态识别路径上采用 OpenAI-compatible API,因此可以连接:
|
| 40 |
+
|
| 41 |
+
- 托管服务
|
| 42 |
+
- 内部网关
|
| 43 |
+
- 自托管多模态服务
|
| 44 |
+
- 语义兼容的本地模型服务栈
|
| 45 |
+
|
| 46 |
+
文档刻意保持通用兼容性表述。实际兼容性仍取决于后端是否支持图像输入,以及 chat-completions 行为是否足够兼容。
|
docs/zh/skill.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Agent Skill
|
| 2 |
+
|
| 3 |
+
OhMyCaptcha 在 `skills/` 目录下附带了可复用的 skills。
|
| 4 |
+
|
| 5 |
+
## 可用 skills
|
| 6 |
+
|
| 7 |
+
- `skills/ohmycaptcha/` — 用于部署、验证、集成和运维服务
|
| 8 |
+
- `skills/ohmycaptcha-image/` — 用于生成 README、文档和发布素材所需的公开安全图片
|
| 9 |
+
|
| 10 |
+
## For humans
|
| 11 |
+
|
| 12 |
+
如果你的工具支持直接读取本地 skill 目录,可以把下面这些目录复制到你的本地 skills 目录中:
|
| 13 |
+
|
| 14 |
+
```text
|
| 15 |
+
skills/ohmycaptcha/
|
| 16 |
+
skills/ohmycaptcha-image/
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
如果你的工具会缓存 skill 元信息,请复制后重启。
|
| 20 |
+
|
| 21 |
+
## Let an LLM do it
|
| 22 |
+
|
| 23 |
+
你也可以把下面这段话直接贴给支持工具调用的 LLM agent:
|
| 24 |
+
|
| 25 |
+
```text
|
| 26 |
+
Install the OhMyCaptcha skills from this repository and make them available in my local skills directory. Then show me how to use the operational skill for deployment and the image skill for generating README or docs visuals.
|
| 27 |
+
```
|
| 28 |
+
|
| 29 |
+
## 运维 skill 的作用
|
| 30 |
+
|
| 31 |
+
`ohmycaptcha` skill 主要覆盖:
|
| 32 |
+
|
| 33 |
+
- 本地启动
|
| 34 |
+
- 环境变量配置
|
| 35 |
+
- YesCaptcha 风格 API 使用
|
| 36 |
+
- flow2api 集成
|
| 37 |
+
- Render 部署
|
| 38 |
+
- Hugging Face Spaces 部署
|
| 39 |
+
- 任务验收与排障
|
| 40 |
+
|
| 41 |
+
## 图片 skill 的作用
|
| 42 |
+
|
| 43 |
+
`ohmycaptcha-image` skill 主要覆盖:
|
| 44 |
+
|
| 45 |
+
- README Hero 图 prompt
|
| 46 |
+
- 文档插图
|
| 47 |
+
- 面向公开仓库的安全技术视觉素材
|
| 48 |
+
- 架构风格图片
|
| 49 |
+
- 面向 agent 工作流的可复用图像生成 prompt
|
| 50 |
+
|
| 51 |
+
## 设计保证
|
| 52 |
+
|
| 53 |
+
这些 skill 的设计目标包括:
|
| 54 |
+
|
| 55 |
+
- 只使用占位符密钥
|
| 56 |
+
- 与当前已实现任务类型保持一致
|
| 57 |
+
- 明确说明当前限制
|
| 58 |
+
- 避免嵌入 secrets、私有接口地址或客户数据
|
docs/zh/usage/classification.md
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 图像分类使用指南
|
| 2 |
+
|
| 3 |
+
图像分类任务将一张或多张验证码图片发送给 OpenAI-compatible 视觉模型,返回匹配格子的索引或布尔值答案。无需浏览器自动化,这些均为纯视觉模型 API 调用。
|
| 4 |
+
|
| 5 |
+
## 支持的任务类型
|
| 6 |
+
|
| 7 |
+
| 任务类型 | 说明 |
|
| 8 |
+
|---------|------|
|
| 9 |
+
| `HCaptchaClassification` | hCaptcha 3×3 网格——返回匹配格子索引 |
|
| 10 |
+
| `ReCaptchaV2Classification` | reCAPTCHA v2 3×3/4×4 网格——返回匹配格子索引 |
|
| 11 |
+
| `FunCaptchaClassification` | FunCaptcha 2×3 网格——返回正确格子索引 |
|
| 12 |
+
| `AwsClassification` | AWS 验证码图像选择 |
|
| 13 |
+
|
| 14 |
+
## 返回字段
|
| 15 |
+
|
| 16 |
+
| 任务类型 | 返回字段 | 示例 |
|
| 17 |
+
|---------|---------|------|
|
| 18 |
+
| `HCaptchaClassification` | `objects` 或 `answer` | `[0, 2, 5]` 或 `true` |
|
| 19 |
+
| `ReCaptchaV2Classification` | `objects` | `[0, 3, 6]` |
|
| 20 |
+
| `FunCaptchaClassification` | `objects` | `[4]` |
|
| 21 |
+
| `AwsClassification` | `objects` | `[1]` |
|
| 22 |
+
|
| 23 |
+
## HCaptchaClassification 示例
|
| 24 |
+
|
| 25 |
+
```json
|
| 26 |
+
{
|
| 27 |
+
"clientKey": "your-client-key",
|
| 28 |
+
"task": {
|
| 29 |
+
"type": "HCaptchaClassification",
|
| 30 |
+
"queries": ["<base64-image-1>", "<base64-image-2>", "<base64-image-3>"],
|
| 31 |
+
"question": "Please click each image containing a bicycle"
|
| 32 |
+
}
|
| 33 |
+
}
|
| 34 |
+
```
|
| 35 |
+
|
| 36 |
+
`queries` 字段接受 base64 编码的图片列表(每个格子一张)。
|
| 37 |
+
|
| 38 |
+
## ReCaptchaV2Classification 示例
|
| 39 |
+
|
| 40 |
+
```json
|
| 41 |
+
{
|
| 42 |
+
"clientKey": "your-client-key",
|
| 43 |
+
"task": {
|
| 44 |
+
"type": "ReCaptchaV2Classification",
|
| 45 |
+
"image": "<base64-encoded-grid-image>",
|
| 46 |
+
"question": "Select all images with traffic lights"
|
| 47 |
+
}
|
| 48 |
+
}
|
| 49 |
+
```
|
| 50 |
+
|
| 51 |
+
`image` 字段为完整的 reCAPTCHA 网格图片(3×3 = 9 格,或 4×4 = 16 格)。格子编号从 0 开始,从左到右、从上到下。
|
| 52 |
+
|
| 53 |
+
## FunCaptchaClassification 示例
|
| 54 |
+
|
| 55 |
+
```json
|
| 56 |
+
{
|
| 57 |
+
"clientKey": "your-client-key",
|
| 58 |
+
"task": {
|
| 59 |
+
"type": "FunCaptchaClassification",
|
| 60 |
+
"image": "<base64-encoded-grid-image>",
|
| 61 |
+
"question": "Pick the image that shows a boat facing left"
|
| 62 |
+
}
|
| 63 |
+
}
|
| 64 |
+
```
|
| 65 |
+
|
| 66 |
+
## 注意事项
|
| 67 |
+
|
| 68 |
+
- 所有分类任务均通过 `CAPTCHA_MULTIMODAL_MODEL`(默认:`qwen3.5-2b`)指定的视觉模型处理。
|
| 69 |
+
- 模型准确性取决于所配置的视觉模型质量。
|
| 70 |
+
- 图片无需预先缩放,求解器内部会处理归一化。
|
docs/zh/usage/hcaptcha.md
ADDED
|
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# hCaptcha 使用指南
|
| 2 |
+
|
| 3 |
+
hCaptcha 通过 iframe 组件展示验证码挑战。求解器使用 Playwright 控制的 Chromium 访问目标页面,点击 hCaptcha 复选框,等待挑战完成,提取响应令牌。
|
| 4 |
+
|
| 5 |
+
## 支持的任务类型
|
| 6 |
+
|
| 7 |
+
| 任务类型 | 说明 |
|
| 8 |
+
|---------|------|
|
| 9 |
+
| `HCaptchaTaskProxyless` | 基于浏览器的 hCaptcha 求解 |
|
| 10 |
+
|
| 11 |
+
## 必填字段
|
| 12 |
+
|
| 13 |
+
| 字段 | 类型 | 说明 |
|
| 14 |
+
|------|------|------|
|
| 15 |
+
| `websiteURL` | string | 包含验证码的页面完整 URL |
|
| 16 |
+
| `websiteKey` | string | 页面 HTML 中的 `data-sitekey` 值 |
|
| 17 |
+
|
| 18 |
+
## 测试目标
|
| 19 |
+
|
| 20 |
+
hCaptcha 提供官方测试密钥:
|
| 21 |
+
|
| 22 |
+
| URL | Site key | 行为 |
|
| 23 |
+
|-----|----------|------|
|
| 24 |
+
| `https://accounts.hcaptcha.com/demo` | `10000000-ffff-ffff-ffff-000000000001` | 始终通过(测试密钥) |
|
| 25 |
+
| `https://demo.hcaptcha.com/` | `10000000-ffff-ffff-ffff-000000000001` | 始终通过(测试密钥) |
|
| 26 |
+
|
| 27 |
+
## 创建任务
|
| 28 |
+
|
| 29 |
+
```bash
|
| 30 |
+
curl -X POST http://localhost:8000/createTask \
|
| 31 |
+
-H "Content-Type: application/json" \
|
| 32 |
+
-d '{
|
| 33 |
+
"clientKey": "your-client-key",
|
| 34 |
+
"task": {
|
| 35 |
+
"type": "HCaptchaTaskProxyless",
|
| 36 |
+
"websiteURL": "https://accounts.hcaptcha.com/demo",
|
| 37 |
+
"websiteKey": "10000000-ffff-ffff-ffff-000000000001"
|
| 38 |
+
}
|
| 39 |
+
}'
|
| 40 |
+
```
|
| 41 |
+
|
| 42 |
+
## 轮询结果
|
| 43 |
+
|
| 44 |
+
就绪时返回:
|
| 45 |
+
|
| 46 |
+
```json
|
| 47 |
+
{
|
| 48 |
+
"errorId": 0,
|
| 49 |
+
"status": "ready",
|
| 50 |
+
"solution": {
|
| 51 |
+
"gRecaptchaResponse": "P1_eyJ0eXAiOiJKV1QiLC..."
|
| 52 |
+
}
|
| 53 |
+
}
|
| 54 |
+
```
|
| 55 |
+
|
| 56 |
+
!!! note "字段命名"
|
| 57 |
+
令牌以 `solution.gRecaptchaResponse` 返回,保持与 YesCaptcha API 的兼容性。
|
| 58 |
+
|
| 59 |
+
## 验收状态
|
| 60 |
+
|
| 61 |
+
| 目标 | Site key | 状态 | 说明 |
|
| 62 |
+
|------|----------|------|------|
|
| 63 |
+
| `https://accounts.hcaptcha.com/demo` | `10000000-ffff-ffff-ffff-000000000001` | ⚠️ 依赖挑战类型 | 无头浏览器可能仍会收到图像挑战 |
|
| 64 |
+
|
| 65 |
+
### 无头浏览器说明
|
| 66 |
+
|
| 67 |
+
即使使用测试密钥(`10000000-ffff-ffff-ffff-000000000001`),hCaptcha 在检测到无头浏览器时仍可能弹出图像挑战。求解器在点击复选框后最多等待 30 秒以获取令牌。
|
| 68 |
+
|
| 69 |
+
对于无头环境,推荐使用 `HCaptchaClassification` 任务类型求解图像网格挑战,然后注入令牌。
|
| 70 |
+
|
| 71 |
+
## 注意事项
|
| 72 |
+
|
| 73 |
+
- hCaptcha 挑战通常比 reCAPTCHA v2 需要更多时间,求解器点击后最多等待 30 秒。
|
| 74 |
+
- 测试密钥(`10000000-ffff-ffff-ffff-000000000001`)在低风险环境下会立即通过。
|
docs/zh/usage/image-captcha.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# 图片验证码使用指南
|
| 2 |
+
|
| 3 |
+
## 任务类型
|
| 4 |
+
|
| 5 |
+
- `ImageToTextTask`
|
| 6 |
+
|
| 7 |
+
## 请求示例
|
| 8 |
+
|
| 9 |
+
```json
|
| 10 |
+
{
|
| 11 |
+
"clientKey": "your-client-key",
|
| 12 |
+
"task": {
|
| 13 |
+
"type": "ImageToTextTask",
|
| 14 |
+
"body": "<base64-encoded-image>"
|
| 15 |
+
}
|
| 16 |
+
}
|
| 17 |
+
```
|
| 18 |
+
|
| 19 |
+
## 实现说明
|
| 20 |
+
|
| 21 |
+
图片 solver 位于 `src/services/recognition.py`,采用受 Argus 启发的结构化多模态标注思路。
|
| 22 |
+
|
| 23 |
+
当前行为:
|
| 24 |
+
|
| 25 |
+
- 输入图片会被缩放到 **1440×900**
|
| 26 |
+
- 模型会被提示识别验证码类型并输出结构化结果
|
| 27 |
+
- 归一化坐标空间以左上角 `(0, 0)` 为原点
|
| 28 |
+
|
| 29 |
+
提示词当前支持的结构化类型包括:
|
| 30 |
+
|
| 31 |
+
- `click`
|
| 32 |
+
- `slide`
|
| 33 |
+
- `drag_match`
|
| 34 |
+
|
| 35 |
+
## 返回结构
|
| 36 |
+
|
| 37 |
+
当前 API 会把模型输出的结构化 JSON 序列化后放在 `solution.text` 中返回。
|
| 38 |
+
|
| 39 |
+
示例:
|
| 40 |
+
|
| 41 |
+
```json
|
| 42 |
+
{
|
| 43 |
+
"errorId": 0,
|
| 44 |
+
"status": "ready",
|
| 45 |
+
"solution": {
|
| 46 |
+
"text": "{\"captcha_type\":\"slide\",\"drag_distance\":270}"
|
| 47 |
+
}
|
| 48 |
+
}
|
| 49 |
+
```
|
| 50 |
+
|
| 51 |
+
## 后端兼容性
|
| 52 |
+
|
| 53 |
+
多模态路径面向 **OpenAI-compatible** 接口设计,因此只要后端支持图像输入并具备兼容的 chat completion 行为,就可以接托管或自托管服务。
|
| 54 |
+
|
| 55 |
+
实际准确率会强烈依赖所选模型与供应商实现质量。
|
docs/zh/usage/recaptcha-v2.md
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# reCAPTCHA v2 使用指南
|
| 2 |
+
|
| 3 |
+
reCAPTCHA v2 向用户展示"我不是机器人"复选框。求解器使用真实 Chromium 浏览器访问目标页面,点击复选框,并提取生成的 `gRecaptchaResponse` 令牌。
|
| 4 |
+
|
| 5 |
+
## 支持的任务类型
|
| 6 |
+
|
| 7 |
+
| 任务类型 | 说明 |
|
| 8 |
+
|---------|------|
|
| 9 |
+
| `NoCaptchaTaskProxyless` | 标准 reCAPTCHA v2 复选框 |
|
| 10 |
+
| `RecaptchaV2TaskProxyless` | 同上,备用命名 |
|
| 11 |
+
| `RecaptchaV2EnterpriseTaskProxyless` | reCAPTCHA v2 企业版 |
|
| 12 |
+
|
| 13 |
+
## 必填字段
|
| 14 |
+
|
| 15 |
+
| 字段 | 类型 | 说明 |
|
| 16 |
+
|------|------|------|
|
| 17 |
+
| `websiteURL` | string | 包含验证码的页面完整 URL |
|
| 18 |
+
| `websiteKey` | string | 页面 HTML 中的 `data-sitekey` 值 |
|
| 19 |
+
| `isInvisible` | bool | 可选。不可见 reCAPTCHA 设为 `true` |
|
| 20 |
+
|
| 21 |
+
## 测试目标
|
| 22 |
+
|
| 23 |
+
Google 官方 Demo 页面适合验收测试:
|
| 24 |
+
|
| 25 |
+
- **URL:** `https://www.google.com/recaptcha/api2/demo`
|
| 26 |
+
- **Site key:** `6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-`
|
| 27 |
+
|
| 28 |
+
## 创建任务
|
| 29 |
+
|
| 30 |
+
```bash
|
| 31 |
+
curl -X POST http://localhost:8000/createTask \
|
| 32 |
+
-H "Content-Type: application/json" \
|
| 33 |
+
-d '{
|
| 34 |
+
"clientKey": "your-client-key",
|
| 35 |
+
"task": {
|
| 36 |
+
"type": "NoCaptchaTaskProxyless",
|
| 37 |
+
"websiteURL": "https://www.google.com/recaptcha/api2/demo",
|
| 38 |
+
"websiteKey": "6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-"
|
| 39 |
+
}
|
| 40 |
+
}'
|
| 41 |
+
```
|
| 42 |
+
|
| 43 |
+
## 轮询结果
|
| 44 |
+
|
| 45 |
+
```bash
|
| 46 |
+
curl -X POST http://localhost:8000/getTaskResult \
|
| 47 |
+
-H "Content-Type: application/json" \
|
| 48 |
+
-d '{
|
| 49 |
+
"clientKey": "your-client-key",
|
| 50 |
+
"taskId": "uuid-from-createTask"
|
| 51 |
+
}'
|
| 52 |
+
```
|
| 53 |
+
|
| 54 |
+
就绪时返回:
|
| 55 |
+
|
| 56 |
+
```json
|
| 57 |
+
{
|
| 58 |
+
"errorId": 0,
|
| 59 |
+
"status": "ready",
|
| 60 |
+
"solution": {
|
| 61 |
+
"gRecaptchaResponse": "03AGdBq24..."
|
| 62 |
+
}
|
| 63 |
+
}
|
| 64 |
+
```
|
| 65 |
+
|
| 66 |
+
## 验收状态
|
| 67 |
+
|
| 68 |
+
| 目标 | 状态 | 说明 |
|
| 69 |
+
|------|------|------|
|
| 70 |
+
| `https://www.google.com/recaptcha/api2/demo` | ⚠️ 音频挑战路径 | Google 检测到无头浏览器 |
|
| 71 |
+
|
| 72 |
+
### 无头浏览器检测
|
| 73 |
+
|
| 74 |
+
Google 的风险分析引擎可靠地检测到无头 Chromium,会弹出图像挑战而非直接签发令牌。求解器实现了音频挑战回退方案:
|
| 75 |
+
|
| 76 |
+
1. 点击复选框——Google 弹出挑战对话框。
|
| 77 |
+
2. 在挑战对话框中点击音频按钮。
|
| 78 |
+
3. 下载 MP3 音频文件。
|
| 79 |
+
4. 通过配置的 `CAPTCHA_MODEL` 端点进行转录。
|
| 80 |
+
5. 提交转录文本以获得令牌。
|
| 81 |
+
|
| 82 |
+
### 推荐的集成方案
|
| 83 |
+
|
| 84 |
+
对于生产环境中可靠的 reCAPTCHA v2 求解,建议使用**分类任务**方案:
|
| 85 |
+
|
| 86 |
+
1. 使用 Playwright 从页面提取挑战图像网格。
|
| 87 |
+
2. 将网格图片发送给 `ReCaptchaV2Classification`,附上挑战问题。
|
| 88 |
+
3. 使用返回的格子索引以编程方式点击匹配的格子。
|
| 89 |
+
|
| 90 |
+
## 注意事项
|
| 91 |
+
|
| 92 |
+
- 令牌有效期约 120 秒,请尽快提交。
|
| 93 |
+
- `RecaptchaV2EnterpriseTaskProxyless` 类型使用相同的浏览器路径。
|
| 94 |
+
- 在侵入性较低的网站(非 Google 自己的 Demo),复选框点击可能直接成功而无需挑战。
|
docs/zh/usage/recaptcha-v3.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# reCAPTCHA v3 使用指南
|
| 2 |
+
|
| 3 |
+
## 验收目标
|
| 4 |
+
|
| 5 |
+
本仓库使用以下目标完成了验证:
|
| 6 |
+
|
| 7 |
+
- URL:`https://antcpt.com/score_detector/`
|
| 8 |
+
- site key:`6LcR_okUAAAAAPYrPe-HK_0RULO1aZM15ENyM-Mf`
|
| 9 |
+
|
| 10 |
+
## 创建任务
|
| 11 |
+
|
| 12 |
+
```bash
|
| 13 |
+
curl -X POST http://localhost:8000/createTask \
|
| 14 |
+
-H "Content-Type: application/json" \
|
| 15 |
+
-d '{
|
| 16 |
+
"clientKey": "your-client-key",
|
| 17 |
+
"task": {
|
| 18 |
+
"type": "RecaptchaV3TaskProxyless",
|
| 19 |
+
"websiteURL": "https://antcpt.com/score_detector/",
|
| 20 |
+
"websiteKey": "6LcR_okUAAAAAPYrPe-HK_0RULO1aZM15ENyM-Mf",
|
| 21 |
+
"pageAction": "homepage"
|
| 22 |
+
}
|
| 23 |
+
}'
|
| 24 |
+
```
|
| 25 |
+
|
| 26 |
+
## 轮询结果
|
| 27 |
+
|
| 28 |
+
```bash
|
| 29 |
+
curl -X POST http://localhost:8000/getTaskResult \
|
| 30 |
+
-H "Content-Type: application/json" \
|
| 31 |
+
-d '{
|
| 32 |
+
"clientKey": "your-client-key",
|
| 33 |
+
"taskId": "uuid-from-createTask"
|
| 34 |
+
}'
|
| 35 |
+
```
|
| 36 |
+
|
| 37 |
+
当任务完成时,你会收到 `solution.gRecaptchaResponse`。
|
| 38 |
+
|
| 39 |
+
## 当前代码库的验收结果
|
| 40 |
+
|
| 41 |
+
一次本地验收已经成功完成以下流程:
|
| 42 |
+
|
| 43 |
+
- 启动服务
|
| 44 |
+
- 创建任务
|
| 45 |
+
- 轮询到 `ready`
|
| 46 |
+
- 返回非空 token
|
| 47 |
+
|
| 48 |
+
## 运行注意事项
|
| 49 |
+
|
| 50 |
+
- 返回 token 不代表可以保证指定 score。
|
| 51 |
+
- 目标站行为可能随时间变化。
|
| 52 |
+
- IP 质量与浏览器环境会影响结果。
|
| 53 |
+
- 当前仓库中,所有已注册的 reCAPTCHA v3 变体共享同一套内部 solver 路径。
|
docs/zh/usage/turnstile.md
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Cloudflare Turnstile 使用指南
|
| 2 |
+
|
| 3 |
+
Cloudflare Turnstile 是一种无感或组件式验证码替代方案。求解器使用 Chromium 访问目标页面,与 Turnstile 组件交互,并从隐藏的 `cf-turnstile-response` 输入字段中提取令牌。
|
| 4 |
+
|
| 5 |
+
## 支持的任务类型
|
| 6 |
+
|
| 7 |
+
| 任务类型 | 说明 |
|
| 8 |
+
|---------|------|
|
| 9 |
+
| `TurnstileTaskProxyless` | 标准 Turnstile 求解 |
|
| 10 |
+
| `TurnstileTaskProxylessM1` | 同上,备用命名 |
|
| 11 |
+
|
| 12 |
+
## 必填字段
|
| 13 |
+
|
| 14 |
+
| 字段 | 类型 | 说明 |
|
| 15 |
+
|------|------|------|
|
| 16 |
+
| `websiteURL` | string | 包含 Turnstile 组件的页面完整 URL |
|
| 17 |
+
| `websiteKey` | string | Turnstile `data-sitekey` 值 |
|
| 18 |
+
|
| 19 |
+
## 返回字段
|
| 20 |
+
|
| 21 |
+
结果在 `solution.token`(而非 `solution.gRecaptchaResponse`)中返回:
|
| 22 |
+
|
| 23 |
+
```json
|
| 24 |
+
{
|
| 25 |
+
"errorId": 0,
|
| 26 |
+
"status": "ready",
|
| 27 |
+
"solution": {
|
| 28 |
+
"token": "XXXX.DUMMY.TOKEN.XXXX"
|
| 29 |
+
}
|
| 30 |
+
}
|
| 31 |
+
```
|
| 32 |
+
|
| 33 |
+
## 测试目标
|
| 34 |
+
|
| 35 |
+
Cloudflare 提供官方测试密钥:
|
| 36 |
+
|
| 37 |
+
| Site key | 行为 |
|
| 38 |
+
|----------|------|
|
| 39 |
+
| `1x00000000000000000000AA` | 始终通过(可见组件) |
|
| 40 |
+
| `2x00000000000000000000AB` | 始终失败 |
|
| 41 |
+
| `3x00000000000000000000FF` | 强制交互式挑战 |
|
| 42 |
+
|
| 43 |
+
推荐测试页面:
|
| 44 |
+
|
| 45 |
+
- **URL:** `https://react-turnstile.vercel.app/basic`
|
| 46 |
+
- **Site key:** `1x00000000000000000000AA`(测试密钥,始终通过)
|
| 47 |
+
|
| 48 |
+
## 创建任务
|
| 49 |
+
|
| 50 |
+
```bash
|
| 51 |
+
curl -X POST http://localhost:8000/createTask \
|
| 52 |
+
-H "Content-Type: application/json" \
|
| 53 |
+
-d '{
|
| 54 |
+
"clientKey": "your-client-key",
|
| 55 |
+
"task": {
|
| 56 |
+
"type": "TurnstileTaskProxyless",
|
| 57 |
+
"websiteURL": "https://react-turnstile.vercel.app/basic",
|
| 58 |
+
"websiteKey": "1x00000000000000000000AA"
|
| 59 |
+
}
|
| 60 |
+
}'
|
| 61 |
+
```
|
| 62 |
+
|
| 63 |
+
## 验收状态
|
| 64 |
+
|
| 65 |
+
| 目标 | Site key | 状态 |
|
| 66 |
+
|------|----------|------|
|
| 67 |
+
| `https://react-turnstile.vercel.app/basic` | `1x00000000000000000000AA` | ✅ 已返回令牌 |
|
| 68 |
+
|
| 69 |
+
!!! info "Dummy token 说明"
|
| 70 |
+
Cloudflare 测试密钥返回 `XXXX.DUMMY.TOKEN.XXXX`,这是预期行为,表明组件已正常识别。
|
| 71 |
+
|
| 72 |
+
## 注意事项
|
| 73 |
+
|
| 74 |
+
- Turnstile 大多数情况下自动完成,无需用户交互。
|
| 75 |
+
- 生产环境的真实密钥将返回真实令牌(非 dummy)。
|
main.py
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Service entrypoint compatible with Render-style deployment."""
|
| 2 |
+
|
| 3 |
+
import os
|
| 4 |
+
|
| 5 |
+
import uvicorn
|
| 6 |
+
|
| 7 |
+
from src.main import app
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
if __name__ == "__main__":
|
| 11 |
+
from src.core.config import config
|
| 12 |
+
|
| 13 |
+
port = int(os.environ.get("PORT", config.server_port))
|
| 14 |
+
uvicorn.run(
|
| 15 |
+
"src.main:app",
|
| 16 |
+
host=config.server_host,
|
| 17 |
+
port=port,
|
| 18 |
+
reload=False,
|
| 19 |
+
)
|
mkdocs.yml
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
site_name: OhMyCaptcha
|
| 2 |
+
site_description: Self-hostable YesCaptcha-compatible captcha solver built with FastAPI, Playwright, and OpenAI-compatible multimodal models.
|
| 3 |
+
site_url: https://shenhao-stu.github.io/ohmycaptcha/
|
| 4 |
+
repo_url: https://github.com/shenhao-stu/ohmycaptcha
|
| 5 |
+
repo_name: shenhao-stu/ohmycaptcha
|
| 6 |
+
edit_uri: edit/main/docs/
|
| 7 |
+
|
| 8 |
+
extra:
|
| 9 |
+
social:
|
| 10 |
+
- icon: fontawesome/brands/github
|
| 11 |
+
link: https://github.com/shenhao-stu/ohmycaptcha
|
| 12 |
+
|
| 13 |
+
extra_css:
|
| 14 |
+
- stylesheets/extra.css
|
| 15 |
+
|
| 16 |
+
theme:
|
| 17 |
+
name: material
|
| 18 |
+
language: en
|
| 19 |
+
icon:
|
| 20 |
+
repo: fontawesome/brands/github
|
| 21 |
+
palette:
|
| 22 |
+
- media: "(prefers-color-scheme: light)"
|
| 23 |
+
scheme: default
|
| 24 |
+
primary: white
|
| 25 |
+
accent: indigo
|
| 26 |
+
toggle:
|
| 27 |
+
icon: material/weather-night
|
| 28 |
+
name: Switch to dark mode
|
| 29 |
+
- media: "(prefers-color-scheme: dark)"
|
| 30 |
+
scheme: slate
|
| 31 |
+
primary: black
|
| 32 |
+
accent: indigo
|
| 33 |
+
toggle:
|
| 34 |
+
icon: material/weather-sunny
|
| 35 |
+
name: Switch to light mode
|
| 36 |
+
features:
|
| 37 |
+
- navigation.sections
|
| 38 |
+
- navigation.expand
|
| 39 |
+
- navigation.top
|
| 40 |
+
- toc.follow
|
| 41 |
+
- content.code.copy
|
| 42 |
+
- content.action.edit
|
| 43 |
+
- search.suggest
|
| 44 |
+
- search.highlight
|
| 45 |
+
|
| 46 |
+
plugins:
|
| 47 |
+
- search
|
| 48 |
+
- i18n:
|
| 49 |
+
docs_structure: folder
|
| 50 |
+
fallback_to_default: true
|
| 51 |
+
reconfigure_material: true
|
| 52 |
+
reconfigure_search: true
|
| 53 |
+
languages:
|
| 54 |
+
- locale: en
|
| 55 |
+
name: English
|
| 56 |
+
default: true
|
| 57 |
+
build: true
|
| 58 |
+
nav_translations:
|
| 59 |
+
Home: Home
|
| 60 |
+
Getting Started: Getting Started
|
| 61 |
+
API Reference: API Reference
|
| 62 |
+
Usage: Usage
|
| 63 |
+
reCAPTCHA v3: reCAPTCHA v3
|
| 64 |
+
reCAPTCHA v2: reCAPTCHA v2
|
| 65 |
+
hCaptcha: hCaptcha
|
| 66 |
+
Cloudflare Turnstile: Cloudflare Turnstile
|
| 67 |
+
Image Classification: Image Classification
|
| 68 |
+
Image CAPTCHA: Image CAPTCHA
|
| 69 |
+
Positioning: Positioning
|
| 70 |
+
Deployment: Deployment
|
| 71 |
+
Local Model (SGLang): Local Model (SGLang)
|
| 72 |
+
Render: Render
|
| 73 |
+
Hugging Face Spaces: Hugging Face Spaces
|
| 74 |
+
Agent Skill: Agent Skill
|
| 75 |
+
Acceptance: Acceptance
|
| 76 |
+
FAQ: FAQ
|
| 77 |
+
- locale: zh
|
| 78 |
+
name: 简体中文
|
| 79 |
+
build: true
|
| 80 |
+
site_name: OhMyCaptcha
|
| 81 |
+
nav_translations:
|
| 82 |
+
Home: 首页
|
| 83 |
+
Getting Started: 快速开始
|
| 84 |
+
API Reference: API 参考
|
| 85 |
+
Usage: 使用指南
|
| 86 |
+
reCAPTCHA v3: reCAPTCHA v3
|
| 87 |
+
reCAPTCHA v2: reCAPTCHA v2
|
| 88 |
+
hCaptcha: hCaptcha
|
| 89 |
+
Cloudflare Turnstile: Cloudflare Turnstile
|
| 90 |
+
Image Classification: 图像分类
|
| 91 |
+
Image CAPTCHA: 图片验证码
|
| 92 |
+
Positioning: 项目定位
|
| 93 |
+
Deployment: 部署
|
| 94 |
+
Local Model (SGLang): 本地模型 (SGLang)
|
| 95 |
+
Render: Render
|
| 96 |
+
Hugging Face Spaces: Hugging Face Spaces
|
| 97 |
+
Agent Skill: Agent Skill
|
| 98 |
+
Acceptance: 验收
|
| 99 |
+
FAQ: 常见问题
|
| 100 |
+
- redirects
|
| 101 |
+
|
| 102 |
+
markdown_extensions:
|
| 103 |
+
- admonition
|
| 104 |
+
- attr_list
|
| 105 |
+
- md_in_html
|
| 106 |
+
- tables
|
| 107 |
+
- toc:
|
| 108 |
+
permalink: true
|
| 109 |
+
- pymdownx.highlight
|
| 110 |
+
- pymdownx.superfences
|
| 111 |
+
- pymdownx.inlinehilite
|
| 112 |
+
- pymdownx.details
|
| 113 |
+
- pymdownx.tabbed:
|
| 114 |
+
alternate_style: true
|
| 115 |
+
|
| 116 |
+
nav:
|
| 117 |
+
- Home: index.md
|
| 118 |
+
- Getting Started: getting-started.md
|
| 119 |
+
- API Reference: api-reference.md
|
| 120 |
+
- Usage:
|
| 121 |
+
- reCAPTCHA v3: usage/recaptcha-v3.md
|
| 122 |
+
- reCAPTCHA v2: usage/recaptcha-v2.md
|
| 123 |
+
- hCaptcha: usage/hcaptcha.md
|
| 124 |
+
- Cloudflare Turnstile: usage/turnstile.md
|
| 125 |
+
- Image Classification: usage/classification.md
|
| 126 |
+
- Image CAPTCHA: usage/image-captcha.md
|
| 127 |
+
- Positioning: positioning.md
|
| 128 |
+
- Deployment:
|
| 129 |
+
- Local Model (SGLang): deployment/local-model.md
|
| 130 |
+
- Render: deployment/render.md
|
| 131 |
+
- Hugging Face Spaces: deployment/huggingface.md
|
| 132 |
+
- Agent Skill: skill.md
|
| 133 |
+
- Acceptance: acceptance.md
|
| 134 |
+
- FAQ: faq.md
|
pyrightconfig.json
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"include": [
|
| 3 |
+
"main.py",
|
| 4 |
+
"src",
|
| 5 |
+
"tests"
|
| 6 |
+
],
|
| 7 |
+
"extraPaths": [
|
| 8 |
+
".",
|
| 9 |
+
"/home/shenhao/recaptcha"
|
| 10 |
+
],
|
| 11 |
+
"stubPath": "typings",
|
| 12 |
+
"venvPath": ".",
|
| 13 |
+
"venv": ".venv",
|
| 14 |
+
"typeCheckingMode": "standard"
|
| 15 |
+
}
|