captchakraken 2.0.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- captchakraken/__init__.py +61 -0
- captchakraken/action_types.py +56 -0
- captchakraken/cli.py +656 -0
- captchakraken/config.py +78 -0
- captchakraken/image_processor.py +244 -0
- captchakraken/overlay.py +520 -0
- captchakraken/planner.py +408 -0
- captchakraken/planner_types.py +74 -0
- captchakraken/server_manager.py +290 -0
- captchakraken/solver.py +434 -0
- captchakraken/timing.py +42 -0
- captchakraken/tool_calls/find_checkbox.py +72 -0
- captchakraken/tool_calls/find_grid.py +1762 -0
- captchakraken/tool_calls/move_indicator.py +431 -0
- captchakraken-2.0.0.dist-info/METADATA +102 -0
- captchakraken-2.0.0.dist-info/RECORD +18 -0
- captchakraken-2.0.0.dist-info/WHEEL +4 -0
- captchakraken-2.0.0.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""
|
|
2
|
+
CaptchaKraken — OpenCV grid detection + a fine-tuned Qwen3.5-9B vision LoRA
|
|
3
|
+
served on vLLM.
|
|
4
|
+
|
|
5
|
+
Usage:
|
|
6
|
+
from captchakraken import CaptchaSolver
|
|
7
|
+
solver = CaptchaSolver() # auto-starts / connects to a local vLLM server
|
|
8
|
+
actions = solver.solve("captcha.png")
|
|
9
|
+
|
|
10
|
+
Model/endpoint defaults live in `captchakraken.config` and are fully
|
|
11
|
+
env-overridable (VLLM_BASE_URL, CAPTCHA_LORA_ADAPTER, …); the solver itself is
|
|
12
|
+
model-agnostic. The legacy v1 stack (SAM3 grounding, multi-provider planner,
|
|
13
|
+
detect/segment/drag-refine) lives on the `v1-old-architecture` branch.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from pathlib import Path
|
|
17
|
+
|
|
18
|
+
try: # pragma: no cover
|
|
19
|
+
from dotenv import load_dotenv
|
|
20
|
+
|
|
21
|
+
project_root = Path(__file__).resolve().parent.parent
|
|
22
|
+
load_dotenv(project_root / ".env")
|
|
23
|
+
except Exception:
|
|
24
|
+
pass
|
|
25
|
+
|
|
26
|
+
from .action_types import (
|
|
27
|
+
CaptchaAction,
|
|
28
|
+
ClickAction,
|
|
29
|
+
DragAction,
|
|
30
|
+
TypeAction,
|
|
31
|
+
WaitAction,
|
|
32
|
+
)
|
|
33
|
+
from .image_processor import ImageProcessor
|
|
34
|
+
from .overlay import add_overlays_to_image
|
|
35
|
+
|
|
36
|
+
# The planner (requests) and solver (torch/vllm/transformers) pull in the heavy
|
|
37
|
+
# serving stack. Keep them optional so leaf modules — e.g. tool_calls.find_grid,
|
|
38
|
+
# which needs only cv2 + numpy + pillow — can be imported in a minimal env (CI's
|
|
39
|
+
# hermetic grid-detection test) without the full GPU dependency set installed.
|
|
40
|
+
try: # pragma: no cover - exercised only when the serving stack is installed
|
|
41
|
+
from .planner import ActionPlanner
|
|
42
|
+
from .solver import CaptchaSolver, solve_captcha
|
|
43
|
+
except ModuleNotFoundError:
|
|
44
|
+
ActionPlanner = None # type: ignore[assignment,misc]
|
|
45
|
+
CaptchaSolver = None # type: ignore[assignment,misc]
|
|
46
|
+
solve_captcha = None # type: ignore[assignment]
|
|
47
|
+
|
|
48
|
+
__all__ = [
|
|
49
|
+
"CaptchaSolver",
|
|
50
|
+
"solve_captcha",
|
|
51
|
+
"ActionPlanner",
|
|
52
|
+
"ImageProcessor",
|
|
53
|
+
"CaptchaAction",
|
|
54
|
+
"ClickAction",
|
|
55
|
+
"DragAction",
|
|
56
|
+
"TypeAction",
|
|
57
|
+
"WaitAction",
|
|
58
|
+
"add_overlays_to_image",
|
|
59
|
+
]
|
|
60
|
+
|
|
61
|
+
__version__ = "2.0.0"
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from typing import List, Literal, Optional, Union, Tuple
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, RootModel
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class BoundingBox(RootModel):
|
|
7
|
+
"""
|
|
8
|
+
Strongly typed bounding box: [x1, y1, x2, y2] in percentages (0.0 to 1.0).
|
|
9
|
+
Acts like a list for convenience but ensures exactly 4 float elements.
|
|
10
|
+
"""
|
|
11
|
+
root: Tuple[float, float, float, float]
|
|
12
|
+
|
|
13
|
+
def __iter__(self):
|
|
14
|
+
return iter(self.root)
|
|
15
|
+
|
|
16
|
+
def __getitem__(self, item):
|
|
17
|
+
return self.root[item]
|
|
18
|
+
|
|
19
|
+
def __len__(self):
|
|
20
|
+
return len(self.root)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class Action(BaseModel):
|
|
24
|
+
action: str
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ClickAction(Action):
|
|
28
|
+
action: Literal["click"]
|
|
29
|
+
target_bounding_boxes: List[BoundingBox] # List of [x1, y1, x2, y2] in percentages
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class DragAction(Action):
|
|
33
|
+
action: Literal["drag"]
|
|
34
|
+
source_bounding_box: BoundingBox = None # [x1, y1, x2, y2] in percentages
|
|
35
|
+
target_bounding_box: BoundingBox = None # [x1, y1, x2, y2] in percentages
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class TypeAction(Action):
|
|
39
|
+
"""Type text into an input."""
|
|
40
|
+
action: Literal["type"]
|
|
41
|
+
text: str
|
|
42
|
+
target_bounding_box: BoundingBox = None # [x1, y1, x2, y2] in percentages
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class WaitAction(Action):
|
|
46
|
+
"""Wait for a specified duration."""
|
|
47
|
+
action: Literal["wait"]
|
|
48
|
+
duration_ms: int
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class DoneAction(Action):
|
|
52
|
+
"""Signal that the captcha is solved or no further actions are needed."""
|
|
53
|
+
action: Literal["done"]
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
CaptchaAction = Union[ClickAction, DragAction, TypeAction, WaitAction, DoneAction]
|