Instructions to use CaptchaKraken/Twilight-v1.2-FP8 with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use CaptchaKraken/Twilight-v1.2-FP8 with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("image-text-to-text", model="CaptchaKraken/Twilight-v1.2-FP8") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] pipe(text=messages)# Load model directly from transformers import AutoProcessor, AutoModelForMultimodalLM processor = AutoProcessor.from_pretrained("CaptchaKraken/Twilight-v1.2-FP8") model = AutoModelForMultimodalLM.from_pretrained("CaptchaKraken/Twilight-v1.2-FP8", device_map="auto") messages = [ { "role": "user", "content": [ {"type": "image", "url": "https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/p-blog/candy.JPG"}, {"type": "text", "text": "What animal is on the candy?"} ] }, ] inputs = processor.apply_chat_template( messages, add_generation_prompt=True, tokenize=True, return_dict=True, return_tensors="pt", ).to(model.device) outputs = model.generate(**inputs, max_new_tokens=40) print(processor.decode(outputs[0][inputs["input_ids"].shape[-1]:])) - Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- vLLM
How to use CaptchaKraken/Twilight-v1.2-FP8 with vLLM:
Install from pip and serve model
# Install vLLM from pip: pip install vllm # Start the vLLM server: vllm serve "CaptchaKraken/Twilight-v1.2-FP8" # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:8000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "CaptchaKraken/Twilight-v1.2-FP8", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker
docker model run hf.co/CaptchaKraken/Twilight-v1.2-FP8
- SGLang
How to use CaptchaKraken/Twilight-v1.2-FP8 with SGLang:
Install from pip and serve model
# Install SGLang from pip: pip install sglang # Start the SGLang server: python3 -m sglang.launch_server \ --model-path "CaptchaKraken/Twilight-v1.2-FP8" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "CaptchaKraken/Twilight-v1.2-FP8", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }'Use Docker images
docker run --gpus all \ --shm-size 32g \ -p 30000:30000 \ -v ~/.cache/huggingface:/root/.cache/huggingface \ --env "HF_TOKEN=<secret>" \ --ipc=host \ lmsysorg/sglang:latest \ python3 -m sglang.launch_server \ --model-path "CaptchaKraken/Twilight-v1.2-FP8" \ --host 0.0.0.0 \ --port 30000 # Call the server using curl (OpenAI-compatible API): curl -X POST "http://localhost:30000/v1/chat/completions" \ -H "Content-Type: application/json" \ --data '{ "model": "CaptchaKraken/Twilight-v1.2-FP8", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "Describe this image in one sentence." }, { "type": "image_url", "image_url": { "url": "https://cdn.britannica.com/61/93061-050-99147DCE/Statue-of-Liberty-Island-New-York-Bay.jpg" } } ] } ] }' - Docker Model Runner
How to use CaptchaKraken/Twilight-v1.2-FP8 with Docker Model Runner:
docker model run hf.co/CaptchaKraken/Twilight-v1.2-FP8
CaptchaKraken Twilight v1.2 (FP8)
A standalone captcha-solving model: the
CaptchaKraken-Lora-v1.2
adapter merged into Qwen/Qwen3.5-9B and quantized to FP8-dynamic. One
download, no adapter to wire up.
These are the weights our hosted API answers with.
Twilight is the stronger of two hardware tiers. Sunlight v1.2 is the same merge at AWQ 4-bit, ~5 GB smaller and lighter on VRAM.
- Weights: 13 GB (measured) · Min VRAM: ~22 GB
- Quantized: language-model linears at FP8 (channel-wise weights, per-token dynamic activations). The vision tower, the linear-attention projections and the multi-token-prediction head stay bf16 — the task is reading a small picture accurately, and quantizing the half that does the reading costs more than it saves. FP8-dynamic needs no calibration data.
What changed since v1.1
v1.1 solved reCAPTCHA and hCaptcha. v1.2 solves everything the generators cover — 44 puzzle types across 10 vendors, and it is the first generation to handle animated challenges and typed text captchas at all.
| v1.1 | v1.2 | |
|---|---|---|
| Vendors | reCAPTCHA, hCaptcha | + GeeTest, Yidun, BotDetect, MTCaptcha, Yandex, Tencent, Lemin, Prosopo |
| Animated / video challenges | ✗ | ✓ |
| Typed text captchas | ✗ | ✓ |
| Prompt generation | 1 | 2 |
Requires captchakraken >= 2.5.0
This model answers generation-2 prompts. Every v1.1 model is generation 1, and sending this one a generation-1 prompt does not error — it silently degrades on every puzzle. Clients before 2.5.0 hardcode generation-1 text and have no way to know otherwise.
pip install "captchakraken>=2.5.0" # or: npm install captchakraken@^2.5.0
Serving (vLLM)
vllm serve CaptchaKraken/Twilight-v1.2-FP8 \
--max-model-len 8192 --gpu-memory-utilization 0.85 --trust-remote-code --port 8000
export VLLM_BASE_URL=http://localhost:8000/v1
export CAPTCHA_KRAKEN_API_KEY=EMPTY
export CAPTCHA_LORA_NAME=CaptchaKraken/Twilight-v1.2-FP8 # must match the served name
No --enable-lora and no adapter flags — the adapter is already merged in.
Three things to get right, or it scores far below what it can
- Send the prompts it was trained on.
prompts.jsonin this repo carries them plus the puzzle-type → template mapping. A mismatched prompt does not error, it collapses accuracy. - Disable thinking —
chat_template_kwargs: {"enable_thinking": false}. With thinking on and a qwen3 reasoning parser, the answer goes toreasoningandcontentcomes back empty. - Serve it at a flat 720² pixel budget —
MIN_PIXELS=518400,MAX_PIXELS=518400. Qwen clamps each image's AREA into that band, and the band decides how many visual tokens the model reads a puzzle from. This one was measured, not guessed: see below.
Coordinates come back normalized 0–1000, top-left (0,0), bottom-right
(1000,1000) — not pixels. Grid screenshots must be sent with cell numbers
drawn on them; the model reads those labels and was never trained to invent a
numbering. The shipped client does all of this for you.
Evaluation
Scored with the project's soft-tolerance grader on the full 1458-sample held-out real eval — every hand-labelled real capture we hold, none of it trained on. Grid puzzles are exact tile-set match with per-error decay; click/drag receive partial credit by normalized distance, so these are graded scores, not "percent solved".
| Vendor | Puzzle types | Held-out samples | Score |
|---|---|---|---|
| reCAPTCHA | 2 | 629 | 0.600 |
| hCaptcha | 26 | 539 | 0.543 |
| GeeTest | 7 | 172 | 0.780 |
| NetEase Yidun | 3 | 37 | 0.775 |
| BotDetect | 1 | 28 | 0.929 |
| Tencent | 1 | 11 | 0.829 |
| Prosopo | 1 | 11 | 0.727 |
| Yandex | 1 | 11 | 0.364 |
| Lemin | 1 | 10 | 0.874 |
| MTCaptcha | 1 | 10 | 0.900 |
| Overall | 44 | 1458 | 0.6155 |
Training run 20260812-005302, verdict ready-to-deploy — passed all three
gates uncapped.
These figures are the unquantized adapter's. FP8 tracked the served base+adapter setup within noise at v1.1 (66.87% vs 66.30% on the eval current then), so the merge is not expected to cost anything here either — but the v1.2 quantization delta has not been measured on its own yet, and this note stays until it has.
v1.1's numbers are not comparable to these. They were taken on a 156-sample eval that predates the 2026-08-05 split fix, when part of the real capture set was still in training.
Why 720², and why not the ViT's native grid
Sweeping the serving floor over 448/576/640/704/720/736/768/896/1024² (full 1458-sample eval per arm, run-to-run noise ±0.001) put the plateau at 704–736²:
| floor | patch grid on a 400×580 capture | overall | 4×4 exact |
|---|---|---|---|
| 448² | 23×33 | 0.6115 | 0.390 |
| 640² | 33×48 | 0.6357 | 0.425 |
| 720² | 37×53 | 0.6412 | 0.406 |
| 768² | 39×57 | 0.6368 | 0.449 |
| 1024² | 53×77 | 0.6243 | 0.370 |
+3.0 points overall and reCAPTCHA 3×3 exact 0.648 → 0.715. num_position_embeddings: 2304
is 48×48 patches = 768² for a square image, but real captures are 400×580
portrait, so 768² of area already puts the long side at 57 patches. The area
that saturates the grid exactly is 640² — and it scores worse. Mild
position-embedding extrapolation plus real pixels beats staying inside the
grid; it falls apart past ~67 patches. Floor == ceiling, so every image arrives
at one size and the band cannot drift.
License
CaptchaKraken Source-Available License v1.1 — see LICENSE.
Use it, modify it, build commercially on it where captcha solving is an internal component of a product that delivers value beyond the solve — scrapers, anti-detection browsers, automation frameworks, QA and accessibility tooling.
You may not sell the solve: no reselling or offering for a fee a captcha solving service or API whose primary value is solving captchas, no thin wrappers exposing this model's solving capability, and no relaying its outputs through a paid or public captcha-solving API. Those require a separate written commercial agreement.
Copyright (c) 2026 CaptchaKraken LLC. All rights reserved.
- Downloads last month
- 5