Text Classification
Transformers
ONNX
Safetensors
modernbert
code
ai-detection
text-embeddings-inference
Instructions to use tiagozip/pancode with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use tiagozip/pancode with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="tiagozip/pancode")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForSequenceClassification tokenizer = AutoTokenizer.from_pretrained("tiagozip/pancode") model = AutoModelForSequenceClassification.from_pretrained("tiagozip/pancode", device_map="auto") - Notebooks
- Google Colab
- Kaggle
|
Download README.md from tiagozip/pancode: direct link, hf CLI and curl.
- Browser
- Download file 3.43 kB
-
https://huggingface.co/tiagozip/pancode/resolve/main/README.md
- Command line
-
hf download hf://tiagozip/pancode/README.md
-
curl -L -o README.md https://huggingface.co/tiagozip/pancode/resolve/main/README.md
3.43 kB
| license: apache-2.0 | |
| base_model: answerdotai/ModernBERT-large | |
| pipeline_tag: text-classification | |
| library_name: transformers | |
| tags: | |
| - code | |
| - ai-detection | |
| <img src="https://raw.githubusercontent.com/gist/tiagozip/a1e8d3c5fce271fefe15ecec70318c58/raw/44d1a919bd095e7aac3e1eb01ab6d1a2d0b9581d/pancode.svg" alt="banner"> | |
| # pancode | |
| pancode is an AI detector for code fine-tuned from ModernBERT-large to detect whether a code file was written by AI, and if so by which model. | |
| **try it in the [pancode space](https://huggingface.co/spaces/tiagozip/pancode).** | |
| ## training | |
| pancode was trained from hundreds of millions of lines of code and hundreds of thousands of files from GitHub, GitLab, Codeberg, synthetic data, and more, with a mix of human-written and AI-written code, with formatting and other preprocessing. | |
| positives are 2026 commits with a coding agent co-author trailer, such as `noreply@anthropic.com` or `noreply@openai.com`. negatives are code from 2022 to 2024, plus 2025 code by authors who never made an AI-trailered commit in that repo, from repos with no agent config files. | |
| ## results | |
| | | | | |
| | ----------------------------------------------- | ----- | | |
| | AUC against 2022 to 2024 code | 0.984 | | |
| | AI files caught at a 1% false positive rate | 82.5% | | |
| | AI files caught at a 5% false positive rate | 95.2% | | |
| | vendor right on the first guess | 80.5% | | |
| | exact model right on the first guess, out of 24 | 37.7% | | |
| | exact model in the top 3 guesses | 66.5% | | |
| vendor accuracy is 92% for Claude and 74% for OpenAI, and under 30% for DeepSeek, GLM, Grok, Qwen, and Kimi, since they're the ones with the least commits in the training set. inside a vendor, the model mostly confuses neighboring versions, like Claude Opus 5 and 5.5. | |
| ## usage | |
| the first two logits are human and AI. the rest are the 24 model classes listed in `config.pancode_heads`. `config.pancode_thresholds` has the 1% and 5% false positive thresholds, measured on validation 2022 to 2024 code. | |
| ```python | |
| import re | |
| from transformers import AutoModelForSequenceClassification, AutoTokenizer | |
| tokenizer = AutoTokenizer.from_pretrained("tiagozip/pancode") | |
| model = AutoModelForSequenceClassification.from_pretrained("tiagozip/pancode") | |
| code = re.sub(r"[ \t]+$", "", open("some_file.py").read(), flags=re.M) | |
| code = re.sub(r"(?<!\d)(19[89]\d|20[0-3]\d)(0[1-9]|1[0-2])([012]\d|3[01])(?!\d)", "YYYYMMDD", code) | |
| code = re.sub(r"(?<![\d.])(19[89]\d|20[0-3]\d)(?![\d.])", "YYYY", code) | |
| inputs = tokenizer(code[:6000], truncation=True, max_length=2048, return_tensors="pt") | |
| logits = model(**inputs).logits[0] | |
| ai_probability = logits[:2].softmax(-1)[1].item() | |
| closest_model = model.config.pancode_heads["models"][logits[2:].argmax()] | |
| threshold = model.config.pancode_thresholds["thr_1pct"] | |
| print(f"{ai_probability:.1%} AI, closest to {closest_model}") | |
| print("flagged" if ai_probability >= threshold else "not flagged") | |
| ``` | |
| for files over 6000 characters, score 6000-character chunks and average them by length. | |
| ## limits | |
| - pancode needs at least 200 characters and at maximum 6000 to work well | |
| - it only knows the 24 models it was trained on. code from other models still gets an AI score, but the model guess is one of the 24. | |
| - somebody editing AI code heavily or an agent prompted to imitate a style can push the score down. | |