Upload folder using huggingface_hub
Browse files- .gitattributes +8 -0
- README.md +214 -0
- multilingual/infer.py +154 -0
- multilingual/model.bin +3 -0
- multilingual/train.py +12 -0
- multilingual/train.txt +3 -0
- multilingual/val.txt +3 -0
- quality/__pycache__/infer.cpython-312.pyc +0 -0
- quality/infer.py +153 -0
- quality/model.bin +3 -0
- quality/train.py +11 -0
- quality/train.txt +3 -0
- quality/val.txt +3 -0
- research_novelty/bins.json +28 -0
- research_novelty/infer.py +156 -0
- research_novelty/model.bin +3 -0
- research_novelty/train.py +12 -0
- research_novelty/train.txt +3 -0
- research_novelty/val.txt +3 -0
- tags/infer.py +174 -0
- tags/model.bin +3 -0
- tags/tag_vocab.json +855 -0
- tags/train.py +12 -0
- tags/train.txt +3 -0
- tags/val.txt +3 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,11 @@ 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 |
+
multilingual/train.txt filter=lfs diff=lfs merge=lfs -text
|
| 37 |
+
multilingual/val.txt filter=lfs diff=lfs merge=lfs -text
|
| 38 |
+
quality/train.txt filter=lfs diff=lfs merge=lfs -text
|
| 39 |
+
quality/val.txt filter=lfs diff=lfs merge=lfs -text
|
| 40 |
+
research_novelty/train.txt filter=lfs diff=lfs merge=lfs -text
|
| 41 |
+
research_novelty/val.txt filter=lfs diff=lfs merge=lfs -text
|
| 42 |
+
tags/train.txt filter=lfs diff=lfs merge=lfs -text
|
| 43 |
+
tags/val.txt filter=lfs diff=lfs merge=lfs -text
|
README.md
ADDED
|
@@ -0,0 +1,214 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# PR quality/multilingual/tags fastText classifiers
|
| 2 |
+
|
| 3 |
+
Four fastText classifiers that score or tag a GitHub PR from its diff + touched-file
|
| 4 |
+
content, distilled from Jev (`typesafe/jev-1.13`) annotations on mined GitHub Archive
|
| 5 |
+
PRs. Each subfolder is self-contained: `model.bin` (weights), `train.txt`/`val.txt`
|
| 6 |
+
(the exact fastText training data), `train.py` (the exact training call — rerun in
|
| 7 |
+
place to reproduce `model.bin` from `train.txt`), and `infer.py` (standalone scoring
|
| 8 |
+
script — fetches a live PR via the GitHub API and classifies it, no dependency on the
|
| 9 |
+
original mining pipeline).
|
| 10 |
+
|
| 11 |
+
## Usage
|
| 12 |
+
|
| 13 |
+
```bash
|
| 14 |
+
pip install fasttext==0.9.3 "numpy<2" requests # numpy<2 is required -- see note below
|
| 15 |
+
export GITHUB_PAT=... # any GitHub token (read-only is fine)
|
| 16 |
+
python quality/infer.py https://github.com/owner/repo/pull/123
|
| 17 |
+
python multilingual/infer.py https://github.com/owner/repo/pull/123
|
| 18 |
+
python research_novelty/infer.py https://github.com/owner/repo/pull/123
|
| 19 |
+
python tags/infer.py https://github.com/owner/repo/pull/123 # multi-label
|
| 20 |
+
python tags/infer.py --threshold 0.3 https://github.com/owner/repo/pull/123
|
| 21 |
+
```
|
| 22 |
+
|
| 23 |
+
To retrain a model from its own `train.txt` in place: `cd <subfolder> && python train.py`.
|
| 24 |
+
|
| 25 |
+
`quality`/`multilingual`/`research_novelty` each print a `soft` score (probability-
|
| 26 |
+
weighted expected value, the better-correlating of the two — use this) and a `hard`
|
| 27 |
+
score (argmax level), both on a 0-10 scale. `tags` instead prints every tag (of 424)
|
| 28 |
+
whose predicted probability clears `--threshold` (default 0.5), sorted by confidence —
|
| 29 |
+
see its own section below for why it's one multi-label model, not 424 separate ones.
|
| 30 |
+
|
| 31 |
+
**Note on fastText + NumPy 2.x:** the prebuilt `fasttext-wheel` can silently corrupt
|
| 32 |
+
batch-`predict()` probabilities under NumPy 2.x, and even a from-source build's Python
|
| 33 |
+
wrapper crashes outright on `np.array(..., copy=False)`. Pin `numpy<2`.
|
| 34 |
+
|
| 35 |
+
## `quality/` — Jev's strict 0-10 quality rubric
|
| 36 |
+
|
| 37 |
+
Rates the PR's diff on a strict, sensibility-gated 0-10 scale: 0-5 is gated on whether
|
| 38 |
+
the codebase/diff is coherent and credible (a simple-but-clean change tops out at 5); 6+
|
| 39 |
+
requires genuine engineering or conceptual complexity on top of that. See
|
| 40 |
+
`annotate_pr_quality.py`'s `QUALITY_LEVELS` for the full rubric text.
|
| 41 |
+
|
| 42 |
+
- **Hyperparameters**: dim=64, epoch=10, lr=0.3, wordNgrams=2, minCount=3, bucket=2,000,000
|
| 43 |
+
- **Train**: 254,143 PRs (`train.txt`)
|
| 44 |
+
- **Val**: 28,238 PRs, 1,766 at level≥6 (`val.txt`)
|
| 45 |
+
|
| 46 |
+
**This is the plain dim64/epoch10 baseline** — every variant tried (2-4x capacity, class-
|
| 47 |
+
rebalanced train sets, a ~1.55x-larger combined corpus with a separately-mined
|
| 48 |
+
higher-credibility PR pool) came out flat or slightly worse on a held-out 10,000-PR
|
| 49 |
+
tracking set (685 at quality≥6). More data/capacity does not fix this classifier;
|
| 50 |
+
treat it as a known ceiling, not a bug to chase.
|
| 51 |
+
|
| 52 |
+
**Metrics** (10,000-PR tracking holdout, rule = `quality >= 6`):
|
| 53 |
+
|
| 54 |
+
| metric | value |
|
| 55 |
+
|---|---|
|
| 56 |
+
| rule accuracy | 93.73% |
|
| 57 |
+
| precision | 74.17% |
|
| 58 |
+
| **recall** | **12.99%** |
|
| 59 |
+
| exact-level accuracy | 78.01% |
|
| 60 |
+
| MAE | 0.531 |
|
| 61 |
+
| soft Pearson / Spearman | 0.7252 / 0.6339 |
|
| 62 |
+
|
| 63 |
+
**Read this before using it as a filter**: it misses ~87% of genuinely good PRs
|
| 64 |
+
(quality≥6) to keep false positives to 0.33% of negatives, and its own predictions never
|
| 65 |
+
exceed ~6.8-7 on any PR we've tested — it is a high-precision, very-low-recall filter,
|
| 66 |
+
not a general-purpose quality scorer. It also gave near-identical predictions (4.4-5.3)
|
| 67 |
+
to real, high-quality ML/research PRs (e.g. lucidrains' `x-transformers`, `imagen-pytorch`)
|
| 68 |
+
as to trivial personal-repo PRs — it is not sensitive to genuine technical depth. Lowering
|
| 69 |
+
the decision threshold to `>=5` makes this *worse*, not better (accuracy drops to 37%,
|
| 70 |
+
since ~80% of real PRs are already `>=5` and the model's own predicted mass sits below
|
| 71 |
+
that line).
|
| 72 |
+
|
| 73 |
+
## `multilingual/` — non-English comment/string content
|
| 74 |
+
|
| 75 |
+
Purely descriptive 0-10 scale: how much non-English natural-language text (comments,
|
| 76 |
+
docstrings, string literals) appears in the diff and touched files, independent of the
|
| 77 |
+
programming language itself. See `annotate_pr_quality.py`'s `MULTILINGUAL_LEVELS`.
|
| 78 |
+
|
| 79 |
+
- **Hyperparameters**: dim=128, epoch=25, lr=0.3, wordNgrams=2, minCount=3, bucket=2,000,000
|
| 80 |
+
(best of a capacity sweep vs dim64/epoch10 baseline and dim256/epoch25 — dim128 won on
|
| 81 |
+
every axis, dim256 added nothing further for 2x the model size)
|
| 82 |
+
- **Train**: 254,143 PRs (`train.txt`)
|
| 83 |
+
- **Val**: 28,238 PRs (`val.txt`)
|
| 84 |
+
|
| 85 |
+
**Metrics** (100-PR live holdout, 79 true positives, rule = `multilingual <= 1`):
|
| 86 |
+
|
| 87 |
+
| metric | value |
|
| 88 |
+
|---|---|
|
| 89 |
+
| rule accuracy | 96.00% |
|
| 90 |
+
| precision | 96.30% |
|
| 91 |
+
| **recall** | **98.73%** |
|
| 92 |
+
| MAE | 0.586 |
|
| 93 |
+
| Pearson / Spearman | 0.906 / 0.721 |
|
| 94 |
+
|
| 95 |
+
This one is genuinely reliable as a pre-filter — high recall *and* precision. If you only
|
| 96 |
+
trust one of these two classifiers for a filtering decision, trust this one.
|
| 97 |
+
|
| 98 |
+
## `research_novelty/` — research/IP content (⚠️ still recall≈0 at the `>=6` rule)
|
| 99 |
+
|
| 100 |
+
0-10 scale rating the extent to which the PR implements technical algorithms, ideas from
|
| 101 |
+
research papers, or original design/IP, as opposed to routine engineering — independent
|
| 102 |
+
of how difficult or high-quality the engineering itself is. See `annotate_pr_quality.py`'s
|
| 103 |
+
`RESEARCH_NOVELTY_LEVELS`.
|
| 104 |
+
|
| 105 |
+
- **Hyperparameters**: dim=64, epoch=10 (same baseline as `quality`/`multilingual`)
|
| 106 |
+
- **Train**: 96,634 PRs, 297 at level≥6 (`train.txt`)
|
| 107 |
+
- **Val**: 10,772 PRs, 35 at level≥6 (`val.txt`)
|
| 108 |
+
- **Same train/val PR ids as `tags/`** (both come from the same annotation batch; see
|
| 109 |
+
Provenance) — comparable across the two.
|
| 110 |
+
|
| 111 |
+
**Updated 2026-09-30**: retrained on a new 107,406-PR annotation batch (up from the
|
| 112 |
+
original 39,081-PR/98-positive pass), joined back to `quality`/`multilingual`'s existing
|
| 113 |
+
`text` field so the same 254K+-PR pool's diff/file content is reused rather than
|
| 114 |
+
re-mined. Labels use the field's own fixed 0-10 scale (int truncation), same as
|
| 115 |
+
`quality`/`multilingual` — not sample quantiles.
|
| 116 |
+
|
| 117 |
+
**Metrics** (own val.txt, 10,772 PRs):
|
| 118 |
+
|
| 119 |
+
| metric | value |
|
| 120 |
+
|---|---|
|
| 121 |
+
| exact-level accuracy | 82.45% |
|
| 122 |
+
| within-1-level accuracy | 94.06% |
|
| 123 |
+
| MAE | 0.2745 |
|
| 124 |
+
| hard Pearson / Spearman | 0.5679 / 0.5069 |
|
| 125 |
+
| soft Pearson / Spearman | 0.6662 / 0.5470 |
|
| 126 |
+
| rule (`>=6`) accuracy | 99.68% |
|
| 127 |
+
| rule (`>=6`) precision | undefined (0 predicted positive) |
|
| 128 |
+
| **rule (`>=6`) recall** | **0.00%** (0/35) |
|
| 129 |
+
|
| 130 |
+
**Read this before using it as a filter**: correlation improved modestly over the old
|
| 131 |
+
diagnostic pass (soft Pearson 0.60→0.67) and the accuracy/MAE numbers look good, but that's
|
| 132 |
+
almost entirely the near-100%-easy "correctly predict low novelty" majority class — at the
|
| 133 |
+
actual decision boundary that matters (`>=6`), it now has enough val data to say
|
| 134 |
+
confidently (35 true positives, not 2) that it **misses every single one**, the same
|
| 135 |
+
recall-collapse pattern as `quality`. Its own predictions rarely if ever clear ~6-7 (see
|
| 136 |
+
the Megatron-LM spot-check below). Treat it as a continuous novelty *signal* (the soft
|
| 137 |
+
score correlates reasonably, 0.67) rather than a working `>=6` binary classifier.
|
| 138 |
+
|
| 139 |
+
**Spot-check**: `NVIDIA/Megatron-LM#7762` (an Engram/CUDA synchronization change) scores
|
| 140 |
+
soft=2.46, hard=1 — plausible as "some genuine ML-systems depth but not paper-derived,"
|
| 141 |
+
though still likely underrating it given the classifier's known insensitivity to real
|
| 142 |
+
technical depth (see `quality`'s note above; the same failure mode shows up here).
|
| 143 |
+
|
| 144 |
+
## `tags/` — multi-label topic tagging (424 tags)
|
| 145 |
+
|
| 146 |
+
Multi-label classification over the topic vocabulary in `/ansh/harbor-tags.txt` (424
|
| 147 |
+
distinct tags after dedup — e.g. `python`, `machine-learning`, `web-security`,
|
| 148 |
+
`gpu`, `formal methods`) — any number of tags can apply to one PR, independently.
|
| 149 |
+
Each tag is an independent Jev "noul" (boolean-probability) claim ("this PR's diff or
|
| 150 |
+
touched files involve code/content related to topic X"), bundled into one Jev call per
|
| 151 |
+
PR alongside `research_novelty` (see `annotate_tags_research.py`).
|
| 152 |
+
|
| 153 |
+
**One joint multi-label model, not 424 separate binary classifiers.** fastText's native
|
| 154 |
+
multi-label mode (`loss="ova"`, one-vs-all) shares a single embedding/vocabulary across
|
| 155 |
+
all 424 tags and trains in one pass — dramatically cheaper than 424x the training
|
| 156 |
+
time/storage for what is fundamentally the same text signal, at the cost of slightly
|
| 157 |
+
less per-tag threshold flexibility (mitigated by tuning `--threshold` in `infer.py`
|
| 158 |
+
per use case; default 0.5).
|
| 159 |
+
|
| 160 |
+
- **Hyperparameters**: dim=64, epoch=10, lr=0.3, wordNgrams=2, minCount=3,
|
| 161 |
+
bucket=2,000,000, **loss=ova**
|
| 162 |
+
- **Train**: 96,604 PRs (`train.txt`) / **Val**: 10,769 PRs (`val.txt`) — same PR ids as
|
| 163 |
+
`research_novelty/`'s updated split (both from the same annotation batch)
|
| 164 |
+
- 33 PRs with zero tags above threshold were dropped (fastText needs ≥1 label/line)
|
| 165 |
+
|
| 166 |
+
**Metrics** (10,769-PR val set, pooled across all 10,769×424 PR-tag pairs, threshold=0.5):
|
| 167 |
+
|
| 168 |
+
| metric | value |
|
| 169 |
+
|---|---|
|
| 170 |
+
| **precision** | **81.95%** |
|
| 171 |
+
| **recall** | **57.17%** |
|
| 172 |
+
| f1 | 67.35% |
|
| 173 |
+
| pooled Pearson r (vs. Jev's raw `tag_probs`) | **0.8055** |
|
| 174 |
+
| pooled Spearman ρ | **0.7145** |
|
| 175 |
+
|
| 176 |
+
Precision stays high across common tags (0.79-0.99) with recall degrading gracefully as
|
| 177 |
+
per-tag support drops — normal multi-label behavior, not a red flag. This is the
|
| 178 |
+
best-behaved of the four classifiers relative to its task difficulty (a 424-way
|
| 179 |
+
multi-label problem vs. a single 0-10 scale).
|
| 180 |
+
|
| 181 |
+
**Known data-hygiene issue**: `harbor-tags.txt` has a couple of near-duplicate tag pairs
|
| 182 |
+
that survived as distinct labels (`data processing`/`data-processing`, `data
|
| 183 |
+
engineering`/`data_engineering` — the latter pair also collided post-slugification and
|
| 184 |
+
one was suffixed `_dup` in `tag_vocab.json` to disambiguate). Worth deduping the source
|
| 185 |
+
file; not fixed here since it would invalidate the current label vocabulary/model.
|
| 186 |
+
|
| 187 |
+
**Spot-check**: `vercel/next.js#99499` (a tag-revalidation fix) → 30 tags incl.
|
| 188 |
+
`typescript`, `react`, `nextjs`, `frontend`, `routing`, `concurrency`, `web-server`.
|
| 189 |
+
`NVIDIA/Megatron-LM#7762` → 36 tags incl. `machine-learning`, `pytorch`, `cuda`, `gpu`,
|
| 190 |
+
`distributed-systems`, `performance-optimization`, `deeply-technical-ip`. Both match
|
| 191 |
+
what a human skim of the PRs would tag.
|
| 192 |
+
|
| 193 |
+
## Provenance
|
| 194 |
+
|
| 195 |
+
- Distilled from `typesafe/jev-1.13` (via OpenRouter) on GitHub Archive-mined PRs.
|
| 196 |
+
- Full annotation/training pipeline: `/ansh/prism-datagen/annotate_pr_quality.py`
|
| 197 |
+
(rubric + Jev calls, incl. `HARBOR_TAGS`/`TAG_CLAIMS`), `/ansh/fasttext-stuff/run.py`/
|
| 198 |
+
`train_sweep.py` (quality/multilingual training — each subfolder's `train.py` is the
|
| 199 |
+
relevant one of these, trimmed to a single model), `/ansh/fasttext-stuff/evaluate.py`/
|
| 200 |
+
`evaluate_sweep.py`/`compare_pre_post.py` (eval).
|
| 201 |
+
- `quality`'s known ceiling was diagnosed, not guessed: a dim/epoch capacity sweep
|
| 202 |
+
(64→128→256), a class-rebalancing ablation (10%/15% minority oversampling), and a
|
| 203 |
+
~1.55x larger combined training corpus (adding a separately GitHub-credibility-filtered
|
| 204 |
+
PR pool skewed toward higher quality) were all tried and none moved recall past ~14%.
|
| 205 |
+
- `research_novelty`/`tags` come from a separate, lighter-weight annotation pass:
|
| 206 |
+
`/ansh/prism-datagen/annotate_tags_research.py` re-streams the same S3 source
|
| 207 |
+
`quality`/`multilingual` were mined from, filtered to PR ids already in that
|
| 208 |
+
254K+-PR corpus, and asks Jev only for `research_novelty` + the 424 tag claims
|
| 209 |
+
(bundled into one call per PR, not 424 separate calls) — reusing that corpus's
|
| 210 |
+
existing `text` field rather than re-annotating everything from scratch. Dataset
|
| 211 |
+
build: `/ansh/fasttext-stuff/build_research_novelty_v2_dataset.py` and
|
| 212 |
+
`build_tags_dataset.py` (both replicate `quality`/`multilingual`'s exact train/val
|
| 213 |
+
split — same seed, same 10%, same PR ids — for cross-classifier comparability).
|
| 214 |
+
Training/eval: each subfolder's own `train.py`/`evaluate.py`.
|
multilingual/infer.py
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Standalone inference: fetch a live GitHub PR and score it with this multilingual
|
| 2 |
+
classifier (0-10: how much non-English comment/doc/string text appears in the diff and
|
| 3 |
+
touched files -- purely descriptive, not a quality judgment). Self-contained -- only
|
| 4 |
+
needs `requests` and `fasttext` installed (see /ansh/fasttext-stuff/requirements.txt:
|
| 5 |
+
fasttext==0.9.3, numpy<2, scipy<1.14 if you also want the correlation-metric scripts;
|
| 6 |
+
numpy<2 alone is required for fasttext's batch predict() to work at all).
|
| 7 |
+
|
| 8 |
+
Usage:
|
| 9 |
+
export GITHUB_PAT=... # a GitHub personal access token (read-only is fine)
|
| 10 |
+
python infer.py https://github.com/owner/repo/pull/123 [more PR urls...]
|
| 11 |
+
|
| 12 |
+
The text fed to the model is built EXACTLY the way training data was: the same
|
| 13 |
+
render_document() + fasttext_preprocess() pipeline as annotate_pr_quality.py, so a
|
| 14 |
+
score here is directly comparable to what's in train.txt/val.txt.
|
| 15 |
+
"""
|
| 16 |
+
import base64
|
| 17 |
+
import os
|
| 18 |
+
import re
|
| 19 |
+
import sys
|
| 20 |
+
|
| 21 |
+
import fasttext
|
| 22 |
+
import requests
|
| 23 |
+
|
| 24 |
+
HERE = os.path.dirname(os.path.abspath(__file__))
|
| 25 |
+
MODEL_PATH = os.path.join(HERE, "model.bin")
|
| 26 |
+
|
| 27 |
+
MAX_FILES = 10
|
| 28 |
+
MAX_FILE_CHARS = 4_000
|
| 29 |
+
MAX_DIFF_CHARS = 12_000
|
| 30 |
+
MAX_FASTTEXT_TOKENS = 4_096
|
| 31 |
+
NON_CODE_EXTS = {"json", "xml"}
|
| 32 |
+
TOKEN_PATTERN = re.compile(r"\w+(?:['’]\w+)*|[^\w\s]", re.UNICODE)
|
| 33 |
+
|
| 34 |
+
TOKEN = os.environ["GITHUB_PAT"]
|
| 35 |
+
HEADERS = {"Authorization": f"token {TOKEN}", "Accept": "application/vnd.github+json"}
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
def truncate(text, limit):
|
| 39 |
+
if text is None:
|
| 40 |
+
return None
|
| 41 |
+
if len(text) <= limit:
|
| 42 |
+
return text
|
| 43 |
+
return text[:limit] + f"\n...[truncated, {len(text) - limit} more chars]"
|
| 44 |
+
|
| 45 |
+
|
| 46 |
+
def fasttext_preprocess(text):
|
| 47 |
+
tokens = []
|
| 48 |
+
for match in TOKEN_PATTERN.finditer(text.casefold()):
|
| 49 |
+
if len(tokens) == MAX_FASTTEXT_TOKENS:
|
| 50 |
+
break
|
| 51 |
+
token = match.group()
|
| 52 |
+
if token.startswith("__label__"):
|
| 53 |
+
token = "literal_" + token
|
| 54 |
+
tokens.append(token)
|
| 55 |
+
return " ".join(tokens)
|
| 56 |
+
|
| 57 |
+
|
| 58 |
+
def render_document(state):
|
| 59 |
+
lines = [f"repo : {state['repo']['full_name']}"]
|
| 60 |
+
if state["repo"]["description"]:
|
| 61 |
+
lines.append(f"description : {state['repo']['description']}")
|
| 62 |
+
lines.append(f"stars : {state['repo']['stars']}")
|
| 63 |
+
if state["repo"]["license"]:
|
| 64 |
+
lines.append(f"license : {state['repo']['license']}")
|
| 65 |
+
if state["pull_request_title"]:
|
| 66 |
+
lines.append(f"title : {state['pull_request_title']}")
|
| 67 |
+
lines.append("touched files : " + ", ".join(state["all_touched_files"]))
|
| 68 |
+
for f in state["files"]:
|
| 69 |
+
lines.append(f"--- {f['path']} (pre-change) ---")
|
| 70 |
+
lines.append(f["pre_change_content"] or "[new file]")
|
| 71 |
+
lines.append("--- diff ---")
|
| 72 |
+
lines.append(state["diff"] or "")
|
| 73 |
+
return "\n".join(lines)
|
| 74 |
+
|
| 75 |
+
|
| 76 |
+
def get(url, headers=None, **kw):
|
| 77 |
+
resp = requests.get(url, headers=headers or HEADERS, timeout=20, **kw)
|
| 78 |
+
resp.raise_for_status()
|
| 79 |
+
return resp
|
| 80 |
+
|
| 81 |
+
|
| 82 |
+
def parse_pr_url(url):
|
| 83 |
+
m = re.search(r"github\.com/([^/]+)/([^/]+)/pull/(\d+)", url)
|
| 84 |
+
return m.group(1), m.group(2), int(m.group(3))
|
| 85 |
+
|
| 86 |
+
|
| 87 |
+
def fetch_state(pr_url):
|
| 88 |
+
owner, repo, number = parse_pr_url(pr_url)
|
| 89 |
+
repo_full = f"{owner}/{repo}"
|
| 90 |
+
|
| 91 |
+
repo_info = get(f"https://api.github.com/repos/{repo_full}").json()
|
| 92 |
+
pr_info = get(f"https://api.github.com/repos/{repo_full}/pulls/{number}").json()
|
| 93 |
+
files_info = get(f"https://api.github.com/repos/{repo_full}/pulls/{number}/files",
|
| 94 |
+
params={"per_page": 100}).json()
|
| 95 |
+
diff = get(f"https://api.github.com/repos/{repo_full}/pulls/{number}",
|
| 96 |
+
headers={**HEADERS, "Accept": "application/vnd.github.v3.diff"}).text
|
| 97 |
+
|
| 98 |
+
base_sha = pr_info["base"]["sha"]
|
| 99 |
+
all_touched_files = [f["filename"] for f in files_info]
|
| 100 |
+
|
| 101 |
+
picked = []
|
| 102 |
+
for f in files_info:
|
| 103 |
+
path = f["filename"]
|
| 104 |
+
ext = path.rsplit(".", 1)[-1].lower() if "." in path else ""
|
| 105 |
+
if ext in NON_CODE_EXTS:
|
| 106 |
+
continue
|
| 107 |
+
content = None
|
| 108 |
+
if f["status"] != "added":
|
| 109 |
+
try:
|
| 110 |
+
c = get(f"https://api.github.com/repos/{repo_full}/contents/{path}",
|
| 111 |
+
params={"ref": base_sha}).json()
|
| 112 |
+
if c.get("encoding") == "base64":
|
| 113 |
+
content = base64.b64decode(c["content"]).decode("utf-8", errors="replace")
|
| 114 |
+
except requests.HTTPError:
|
| 115 |
+
content = None
|
| 116 |
+
picked.append({"path": path, "pre_change_content": truncate(content, MAX_FILE_CHARS)})
|
| 117 |
+
if len(picked) == MAX_FILES:
|
| 118 |
+
break
|
| 119 |
+
|
| 120 |
+
license_ = repo_info.get("license") or {}
|
| 121 |
+
return {
|
| 122 |
+
"repo": {
|
| 123 |
+
"full_name": repo_full,
|
| 124 |
+
"description": repo_info.get("description"),
|
| 125 |
+
"stars": repo_info.get("stargazers_count"),
|
| 126 |
+
"license": license_.get("spdx_id") or license_.get("name"),
|
| 127 |
+
},
|
| 128 |
+
"pull_request_title": pr_info.get("title"),
|
| 129 |
+
"all_touched_files": all_touched_files,
|
| 130 |
+
"files": picked,
|
| 131 |
+
"diff": truncate(diff, MAX_DIFF_CHARS),
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
|
| 135 |
+
def predict(model, text):
|
| 136 |
+
n_labels = len(model.get_labels())
|
| 137 |
+
labels, probs = model.predict(text, k=n_labels)
|
| 138 |
+
soft = sum(p * int(l.rsplit("_", 1)[1]) for l, p in zip(labels, probs))
|
| 139 |
+
hard = int(labels[0].rsplit("_", 1)[1])
|
| 140 |
+
return soft, hard
|
| 141 |
+
|
| 142 |
+
|
| 143 |
+
if __name__ == "__main__":
|
| 144 |
+
if len(sys.argv) < 2:
|
| 145 |
+
raise SystemExit("usage: python infer.py <github PR url> [more PR urls...]")
|
| 146 |
+
|
| 147 |
+
model = fasttext.load_model(MODEL_PATH)
|
| 148 |
+
for pr_url in sys.argv[1:]:
|
| 149 |
+
state = fetch_state(pr_url)
|
| 150 |
+
text = fasttext_preprocess(render_document(state))
|
| 151 |
+
soft, hard = predict(model, text)
|
| 152 |
+
print(f"{pr_url}")
|
| 153 |
+
print(f" repo: {state['repo']['full_name']} stars: {state['repo']['stars']}")
|
| 154 |
+
print(f" predicted multilingual score: soft={soft:.2f} hard_level={hard}\n")
|
multilingual/model.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:13e27ed9bfe7f186579f95c6e58345e1a7f9061fc207b60f8e1b95617d6bd3bf
|
| 3 |
+
size 2545727308
|
multilingual/train.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Exact training call used for this model. Run from inside this directory:
|
| 2 |
+
python train.py
|
| 3 |
+
Retrains model.bin from train.txt in place (dim=128/epoch=25 -- the winner of a capacity
|
| 4 |
+
sweep against dim=64/epoch=10 and dim=256/epoch=25; dim256 added nothing further, see
|
| 5 |
+
README.md)."""
|
| 6 |
+
import fasttext
|
| 7 |
+
|
| 8 |
+
HPARAMS = dict(dim=128, epoch=25, lr=0.3, wordNgrams=2, minCount=3, bucket=2_000_000)
|
| 9 |
+
|
| 10 |
+
model = fasttext.train_supervised(input="train.txt", **HPARAMS)
|
| 11 |
+
model.save_model("model.bin")
|
| 12 |
+
print("saved model.bin")
|
multilingual/train.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:3ec67e1e15a3844f1f914f55882fbc97024c51ed9a39a555d6901da13c069768
|
| 3 |
+
size 2802807438
|
multilingual/val.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:b26041cdb01d61d1d3fc91bbbbecc8b43e3ecfb987055da93b8c4cda1f660061
|
| 3 |
+
size 309577373
|
quality/__pycache__/infer.cpython-312.pyc
ADDED
|
Binary file (8.79 kB). View file
|
|
|
quality/infer.py
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Standalone inference: fetch a live GitHub PR and score it with this quality
|
| 2 |
+
classifier. Self-contained -- only needs `requests` and `fasttext` installed
|
| 3 |
+
(see /ansh/fasttext-stuff/requirements.txt: fasttext==0.9.3, numpy<2, scipy<1.14
|
| 4 |
+
if you also want the correlation-metric scripts; numpy<2 alone is required for
|
| 5 |
+
fasttext's batch predict() to work at all).
|
| 6 |
+
|
| 7 |
+
Usage:
|
| 8 |
+
export GITHUB_PAT=... # a GitHub personal access token (read-only is fine)
|
| 9 |
+
python infer.py https://github.com/owner/repo/pull/123 [more PR urls...]
|
| 10 |
+
|
| 11 |
+
The text fed to the model is built EXACTLY the way training data was: the same
|
| 12 |
+
render_document() + fasttext_preprocess() pipeline as annotate_pr_quality.py, so a
|
| 13 |
+
score here is directly comparable to what's in train.txt/val.txt.
|
| 14 |
+
"""
|
| 15 |
+
import base64
|
| 16 |
+
import os
|
| 17 |
+
import re
|
| 18 |
+
import sys
|
| 19 |
+
|
| 20 |
+
import fasttext
|
| 21 |
+
import requests
|
| 22 |
+
|
| 23 |
+
HERE = os.path.dirname(os.path.abspath(__file__))
|
| 24 |
+
MODEL_PATH = os.path.join(HERE, "model.bin")
|
| 25 |
+
|
| 26 |
+
MAX_FILES = 10
|
| 27 |
+
MAX_FILE_CHARS = 4_000
|
| 28 |
+
MAX_DIFF_CHARS = 12_000
|
| 29 |
+
MAX_FASTTEXT_TOKENS = 4_096
|
| 30 |
+
NON_CODE_EXTS = {"json", "xml"}
|
| 31 |
+
TOKEN_PATTERN = re.compile(r"\w+(?:['’]\w+)*|[^\w\s]", re.UNICODE)
|
| 32 |
+
|
| 33 |
+
TOKEN = os.environ["GITHUB_PAT"]
|
| 34 |
+
HEADERS = {"Authorization": f"token {TOKEN}", "Accept": "application/vnd.github+json"}
|
| 35 |
+
|
| 36 |
+
|
| 37 |
+
def truncate(text, limit):
|
| 38 |
+
if text is None:
|
| 39 |
+
return None
|
| 40 |
+
if len(text) <= limit:
|
| 41 |
+
return text
|
| 42 |
+
return text[:limit] + f"\n...[truncated, {len(text) - limit} more chars]"
|
| 43 |
+
|
| 44 |
+
|
| 45 |
+
def fasttext_preprocess(text):
|
| 46 |
+
tokens = []
|
| 47 |
+
for match in TOKEN_PATTERN.finditer(text.casefold()):
|
| 48 |
+
if len(tokens) == MAX_FASTTEXT_TOKENS:
|
| 49 |
+
break
|
| 50 |
+
token = match.group()
|
| 51 |
+
if token.startswith("__label__"):
|
| 52 |
+
token = "literal_" + token
|
| 53 |
+
tokens.append(token)
|
| 54 |
+
return " ".join(tokens)
|
| 55 |
+
|
| 56 |
+
|
| 57 |
+
def render_document(state):
|
| 58 |
+
lines = [f"repo : {state['repo']['full_name']}"]
|
| 59 |
+
if state["repo"]["description"]:
|
| 60 |
+
lines.append(f"description : {state['repo']['description']}")
|
| 61 |
+
lines.append(f"stars : {state['repo']['stars']}")
|
| 62 |
+
if state["repo"]["license"]:
|
| 63 |
+
lines.append(f"license : {state['repo']['license']}")
|
| 64 |
+
if state["pull_request_title"]:
|
| 65 |
+
lines.append(f"title : {state['pull_request_title']}")
|
| 66 |
+
lines.append("touched files : " + ", ".join(state["all_touched_files"]))
|
| 67 |
+
for f in state["files"]:
|
| 68 |
+
lines.append(f"--- {f['path']} (pre-change) ---")
|
| 69 |
+
lines.append(f["pre_change_content"] or "[new file]")
|
| 70 |
+
lines.append("--- diff ---")
|
| 71 |
+
lines.append(state["diff"] or "")
|
| 72 |
+
return "\n".join(lines)
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
def get(url, headers=None, **kw):
|
| 76 |
+
resp = requests.get(url, headers=headers or HEADERS, timeout=20, **kw)
|
| 77 |
+
resp.raise_for_status()
|
| 78 |
+
return resp
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
def parse_pr_url(url):
|
| 82 |
+
m = re.search(r"github\.com/([^/]+)/([^/]+)/pull/(\d+)", url)
|
| 83 |
+
return m.group(1), m.group(2), int(m.group(3))
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def fetch_state(pr_url):
|
| 87 |
+
owner, repo, number = parse_pr_url(pr_url)
|
| 88 |
+
repo_full = f"{owner}/{repo}"
|
| 89 |
+
|
| 90 |
+
repo_info = get(f"https://api.github.com/repos/{repo_full}").json()
|
| 91 |
+
pr_info = get(f"https://api.github.com/repos/{repo_full}/pulls/{number}").json()
|
| 92 |
+
files_info = get(f"https://api.github.com/repos/{repo_full}/pulls/{number}/files",
|
| 93 |
+
params={"per_page": 100}).json()
|
| 94 |
+
diff = get(f"https://api.github.com/repos/{repo_full}/pulls/{number}",
|
| 95 |
+
headers={**HEADERS, "Accept": "application/vnd.github.v3.diff"}).text
|
| 96 |
+
|
| 97 |
+
base_sha = pr_info["base"]["sha"]
|
| 98 |
+
all_touched_files = [f["filename"] for f in files_info]
|
| 99 |
+
|
| 100 |
+
picked = []
|
| 101 |
+
for f in files_info:
|
| 102 |
+
path = f["filename"]
|
| 103 |
+
ext = path.rsplit(".", 1)[-1].lower() if "." in path else ""
|
| 104 |
+
if ext in NON_CODE_EXTS:
|
| 105 |
+
continue
|
| 106 |
+
content = None
|
| 107 |
+
if f["status"] != "added":
|
| 108 |
+
try:
|
| 109 |
+
c = get(f"https://api.github.com/repos/{repo_full}/contents/{path}",
|
| 110 |
+
params={"ref": base_sha}).json()
|
| 111 |
+
if c.get("encoding") == "base64":
|
| 112 |
+
content = base64.b64decode(c["content"]).decode("utf-8", errors="replace")
|
| 113 |
+
except requests.HTTPError:
|
| 114 |
+
content = None
|
| 115 |
+
picked.append({"path": path, "pre_change_content": truncate(content, MAX_FILE_CHARS)})
|
| 116 |
+
if len(picked) == MAX_FILES:
|
| 117 |
+
break
|
| 118 |
+
|
| 119 |
+
license_ = repo_info.get("license") or {}
|
| 120 |
+
return {
|
| 121 |
+
"repo": {
|
| 122 |
+
"full_name": repo_full,
|
| 123 |
+
"description": repo_info.get("description"),
|
| 124 |
+
"stars": repo_info.get("stargazers_count"),
|
| 125 |
+
"license": license_.get("spdx_id") or license_.get("name"),
|
| 126 |
+
},
|
| 127 |
+
"pull_request_title": pr_info.get("title"),
|
| 128 |
+
"all_touched_files": all_touched_files,
|
| 129 |
+
"files": picked,
|
| 130 |
+
"diff": truncate(diff, MAX_DIFF_CHARS),
|
| 131 |
+
}
|
| 132 |
+
|
| 133 |
+
|
| 134 |
+
def predict(model, text):
|
| 135 |
+
n_labels = len(model.get_labels())
|
| 136 |
+
labels, probs = model.predict(text, k=n_labels)
|
| 137 |
+
soft = sum(p * int(l.rsplit("_", 1)[1]) for l, p in zip(labels, probs))
|
| 138 |
+
hard = int(labels[0].rsplit("_", 1)[1])
|
| 139 |
+
return soft, hard
|
| 140 |
+
|
| 141 |
+
|
| 142 |
+
if __name__ == "__main__":
|
| 143 |
+
if len(sys.argv) < 2:
|
| 144 |
+
raise SystemExit("usage: python infer.py <github PR url> [more PR urls...]")
|
| 145 |
+
|
| 146 |
+
model = fasttext.load_model(MODEL_PATH)
|
| 147 |
+
for pr_url in sys.argv[1:]:
|
| 148 |
+
state = fetch_state(pr_url)
|
| 149 |
+
text = fasttext_preprocess(render_document(state))
|
| 150 |
+
soft, hard = predict(model, text)
|
| 151 |
+
print(f"{pr_url}")
|
| 152 |
+
print(f" repo: {state['repo']['full_name']} stars: {state['repo']['stars']}")
|
| 153 |
+
print(f" predicted score: soft={soft:.2f} hard_level={hard}\n")
|
quality/model.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:2037f469a40e1baada22d185d549a22f36ac8fce8f6a752e51e357b43e1279d0
|
| 3 |
+
size 1306555670
|
quality/train.py
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Exact training call used for this model. Run from inside this directory:
|
| 2 |
+
python train.py
|
| 3 |
+
Retrains model.bin from train.txt in place (dim=64/epoch=10 baseline -- see README.md
|
| 4 |
+
for why higher capacity/rebalancing/more data were all tried and didn't help recall)."""
|
| 5 |
+
import fasttext
|
| 6 |
+
|
| 7 |
+
HPARAMS = dict(dim=64, epoch=10, lr=0.3, wordNgrams=2, minCount=3, bucket=2_000_000)
|
| 8 |
+
|
| 9 |
+
model = fasttext.train_supervised(input="train.txt", **HPARAMS)
|
| 10 |
+
model.save_model("model.bin")
|
| 11 |
+
print("saved model.bin")
|
quality/train.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:190483bf69835756e28e282a2e3de1152046199c00ee6821efb0eb649781b90a
|
| 3 |
+
size 2802807438
|
quality/val.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f244d446eff36e234c5c8a3ccfc3d2d3f22defdd52f86f7a84b0bc2861faf61c
|
| 3 |
+
size 309577373
|
research_novelty/bins.json
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"counts": [
|
| 3 |
+
87150,
|
| 4 |
+
11209,
|
| 5 |
+
4607,
|
| 6 |
+
2167,
|
| 7 |
+
1298,
|
| 8 |
+
645,
|
| 9 |
+
271,
|
| 10 |
+
57,
|
| 11 |
+
2,
|
| 12 |
+
0,
|
| 13 |
+
0
|
| 14 |
+
],
|
| 15 |
+
"bin_means": [
|
| 16 |
+
0.23606701090074586,
|
| 17 |
+
1.4044954946917656,
|
| 18 |
+
2.425053179943564,
|
| 19 |
+
3.457143516382095,
|
| 20 |
+
4.4452234206471495,
|
| 21 |
+
5.416713178294574,
|
| 22 |
+
6.39959409594096,
|
| 23 |
+
7.317368421052632,
|
| 24 |
+
8.32,
|
| 25 |
+
null,
|
| 26 |
+
null
|
| 27 |
+
]
|
| 28 |
+
}
|
research_novelty/infer.py
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Standalone inference: fetch a live GitHub PR and score it with this research/IP-
|
| 2 |
+
novelty classifier (0-10: the extent to which the PR implements technical algorithms,
|
| 3 |
+
paper-derived ideas, or original design, vs routine engineering -- see README.md for
|
| 4 |
+
the SEVERE data-scarcity caveat, this model should not be trusted much yet).
|
| 5 |
+
Self-contained -- only needs `requests` and `fasttext` installed (see
|
| 6 |
+
/ansh/fasttext-stuff/requirements.txt: fasttext==0.9.3, numpy<2, scipy<1.14 if you also
|
| 7 |
+
want the correlation-metric scripts; numpy<2 alone is required for fasttext's batch
|
| 8 |
+
predict() to work at all).
|
| 9 |
+
|
| 10 |
+
Usage:
|
| 11 |
+
export GITHUB_PAT=... # a GitHub personal access token (read-only is fine)
|
| 12 |
+
python infer.py https://github.com/owner/repo/pull/123 [more PR urls...]
|
| 13 |
+
|
| 14 |
+
The text fed to the model is built EXACTLY the way training data was: the same
|
| 15 |
+
render_document() + fasttext_preprocess() pipeline as annotate_pr_quality.py, so a
|
| 16 |
+
score here is directly comparable to what's in train.txt/val.txt.
|
| 17 |
+
"""
|
| 18 |
+
import base64
|
| 19 |
+
import os
|
| 20 |
+
import re
|
| 21 |
+
import sys
|
| 22 |
+
|
| 23 |
+
import fasttext
|
| 24 |
+
import requests
|
| 25 |
+
|
| 26 |
+
HERE = os.path.dirname(os.path.abspath(__file__))
|
| 27 |
+
MODEL_PATH = os.path.join(HERE, "model.bin")
|
| 28 |
+
|
| 29 |
+
MAX_FILES = 10
|
| 30 |
+
MAX_FILE_CHARS = 4_000
|
| 31 |
+
MAX_DIFF_CHARS = 12_000
|
| 32 |
+
MAX_FASTTEXT_TOKENS = 4_096
|
| 33 |
+
NON_CODE_EXTS = {"json", "xml"}
|
| 34 |
+
TOKEN_PATTERN = re.compile(r"\w+(?:['’]\w+)*|[^\w\s]", re.UNICODE)
|
| 35 |
+
|
| 36 |
+
TOKEN = os.environ["GITHUB_PAT"]
|
| 37 |
+
HEADERS = {"Authorization": f"token {TOKEN}", "Accept": "application/vnd.github+json"}
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
def truncate(text, limit):
|
| 41 |
+
if text is None:
|
| 42 |
+
return None
|
| 43 |
+
if len(text) <= limit:
|
| 44 |
+
return text
|
| 45 |
+
return text[:limit] + f"\n...[truncated, {len(text) - limit} more chars]"
|
| 46 |
+
|
| 47 |
+
|
| 48 |
+
def fasttext_preprocess(text):
|
| 49 |
+
tokens = []
|
| 50 |
+
for match in TOKEN_PATTERN.finditer(text.casefold()):
|
| 51 |
+
if len(tokens) == MAX_FASTTEXT_TOKENS:
|
| 52 |
+
break
|
| 53 |
+
token = match.group()
|
| 54 |
+
if token.startswith("__label__"):
|
| 55 |
+
token = "literal_" + token
|
| 56 |
+
tokens.append(token)
|
| 57 |
+
return " ".join(tokens)
|
| 58 |
+
|
| 59 |
+
|
| 60 |
+
def render_document(state):
|
| 61 |
+
lines = [f"repo : {state['repo']['full_name']}"]
|
| 62 |
+
if state["repo"]["description"]:
|
| 63 |
+
lines.append(f"description : {state['repo']['description']}")
|
| 64 |
+
lines.append(f"stars : {state['repo']['stars']}")
|
| 65 |
+
if state["repo"]["license"]:
|
| 66 |
+
lines.append(f"license : {state['repo']['license']}")
|
| 67 |
+
if state["pull_request_title"]:
|
| 68 |
+
lines.append(f"title : {state['pull_request_title']}")
|
| 69 |
+
lines.append("touched files : " + ", ".join(state["all_touched_files"]))
|
| 70 |
+
for f in state["files"]:
|
| 71 |
+
lines.append(f"--- {f['path']} (pre-change) ---")
|
| 72 |
+
lines.append(f["pre_change_content"] or "[new file]")
|
| 73 |
+
lines.append("--- diff ---")
|
| 74 |
+
lines.append(state["diff"] or "")
|
| 75 |
+
return "\n".join(lines)
|
| 76 |
+
|
| 77 |
+
|
| 78 |
+
def get(url, headers=None, **kw):
|
| 79 |
+
resp = requests.get(url, headers=headers or HEADERS, timeout=20, **kw)
|
| 80 |
+
resp.raise_for_status()
|
| 81 |
+
return resp
|
| 82 |
+
|
| 83 |
+
|
| 84 |
+
def parse_pr_url(url):
|
| 85 |
+
m = re.search(r"github\.com/([^/]+)/([^/]+)/pull/(\d+)", url)
|
| 86 |
+
return m.group(1), m.group(2), int(m.group(3))
|
| 87 |
+
|
| 88 |
+
|
| 89 |
+
def fetch_state(pr_url):
|
| 90 |
+
owner, repo, number = parse_pr_url(pr_url)
|
| 91 |
+
repo_full = f"{owner}/{repo}"
|
| 92 |
+
|
| 93 |
+
repo_info = get(f"https://api.github.com/repos/{repo_full}").json()
|
| 94 |
+
pr_info = get(f"https://api.github.com/repos/{repo_full}/pulls/{number}").json()
|
| 95 |
+
files_info = get(f"https://api.github.com/repos/{repo_full}/pulls/{number}/files",
|
| 96 |
+
params={"per_page": 100}).json()
|
| 97 |
+
diff = get(f"https://api.github.com/repos/{repo_full}/pulls/{number}",
|
| 98 |
+
headers={**HEADERS, "Accept": "application/vnd.github.v3.diff"}).text
|
| 99 |
+
|
| 100 |
+
base_sha = pr_info["base"]["sha"]
|
| 101 |
+
all_touched_files = [f["filename"] for f in files_info]
|
| 102 |
+
|
| 103 |
+
picked = []
|
| 104 |
+
for f in files_info:
|
| 105 |
+
path = f["filename"]
|
| 106 |
+
ext = path.rsplit(".", 1)[-1].lower() if "." in path else ""
|
| 107 |
+
if ext in NON_CODE_EXTS:
|
| 108 |
+
continue
|
| 109 |
+
content = None
|
| 110 |
+
if f["status"] != "added":
|
| 111 |
+
try:
|
| 112 |
+
c = get(f"https://api.github.com/repos/{repo_full}/contents/{path}",
|
| 113 |
+
params={"ref": base_sha}).json()
|
| 114 |
+
if c.get("encoding") == "base64":
|
| 115 |
+
content = base64.b64decode(c["content"]).decode("utf-8", errors="replace")
|
| 116 |
+
except requests.HTTPError:
|
| 117 |
+
content = None
|
| 118 |
+
picked.append({"path": path, "pre_change_content": truncate(content, MAX_FILE_CHARS)})
|
| 119 |
+
if len(picked) == MAX_FILES:
|
| 120 |
+
break
|
| 121 |
+
|
| 122 |
+
license_ = repo_info.get("license") or {}
|
| 123 |
+
return {
|
| 124 |
+
"repo": {
|
| 125 |
+
"full_name": repo_full,
|
| 126 |
+
"description": repo_info.get("description"),
|
| 127 |
+
"stars": repo_info.get("stargazers_count"),
|
| 128 |
+
"license": license_.get("spdx_id") or license_.get("name"),
|
| 129 |
+
},
|
| 130 |
+
"pull_request_title": pr_info.get("title"),
|
| 131 |
+
"all_touched_files": all_touched_files,
|
| 132 |
+
"files": picked,
|
| 133 |
+
"diff": truncate(diff, MAX_DIFF_CHARS),
|
| 134 |
+
}
|
| 135 |
+
|
| 136 |
+
|
| 137 |
+
def predict(model, text):
|
| 138 |
+
n_labels = len(model.get_labels())
|
| 139 |
+
labels, probs = model.predict(text, k=n_labels)
|
| 140 |
+
soft = sum(p * int(l.rsplit("_", 1)[1]) for l, p in zip(labels, probs))
|
| 141 |
+
hard = int(labels[0].rsplit("_", 1)[1])
|
| 142 |
+
return soft, hard
|
| 143 |
+
|
| 144 |
+
|
| 145 |
+
if __name__ == "__main__":
|
| 146 |
+
if len(sys.argv) < 2:
|
| 147 |
+
raise SystemExit("usage: python infer.py <github PR url> [more PR urls...]")
|
| 148 |
+
|
| 149 |
+
model = fasttext.load_model(MODEL_PATH)
|
| 150 |
+
for pr_url in sys.argv[1:]:
|
| 151 |
+
state = fetch_state(pr_url)
|
| 152 |
+
text = fasttext_preprocess(render_document(state))
|
| 153 |
+
soft, hard = predict(model, text)
|
| 154 |
+
print(f"{pr_url}")
|
| 155 |
+
print(f" repo: {state['repo']['full_name']} stars: {state['repo']['stars']}")
|
| 156 |
+
print(f" predicted research_novelty score: soft={soft:.2f} hard_level={hard}\n")
|
research_novelty/model.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ee241bd0d406b50af9dd3a2b51570e41a17a173065fd5fff3d5b04ddb9d238f5
|
| 3 |
+
size 881045797
|
research_novelty/train.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Exact training call used for this model. Run from inside this directory:
|
| 2 |
+
python train.py
|
| 3 |
+
Same dim64/epoch10 baseline hyperparams as quality/. Trained on the expanded
|
| 4 |
+
107,406-PR research_novelty annotation batch (330 at level>=6, up from the original
|
| 5 |
+
39,081-PR/98-positive pass) -- see README.md for current stats and caveats."""
|
| 6 |
+
import fasttext
|
| 7 |
+
|
| 8 |
+
HPARAMS = dict(dim=64, epoch=10, lr=0.3, wordNgrams=2, minCount=3, bucket=2_000_000)
|
| 9 |
+
|
| 10 |
+
model = fasttext.train_supervised(input="train.txt", **HPARAMS)
|
| 11 |
+
model.save_model("model.bin")
|
| 12 |
+
print("saved model.bin")
|
research_novelty/train.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:ec4190a66eb1dcf212ed1f015f0cac0464bca7667daa74655cb52a9fc0e58d24
|
| 3 |
+
size 1065555987
|
research_novelty/val.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:a821e6e2daba9bc2575e2ccc984e159a08f858675864ae5bf64e73fdb077cb9f
|
| 3 |
+
size 119036497
|
tags/infer.py
ADDED
|
@@ -0,0 +1,174 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Standalone inference: fetch a live GitHub PR and tag it with this multi-label
|
| 2 |
+
classifier (424 topics from harbor-tags.txt -- any number can apply to one PR).
|
| 3 |
+
Self-contained -- only needs `requests` and `fasttext` installed (see
|
| 4 |
+
/ansh/fasttext-stuff/requirements.txt: fasttext==0.9.3, numpy<2, scipy<1.14 if you also
|
| 5 |
+
want the correlation-metric scripts; numpy<2 alone is required for fasttext's batch
|
| 6 |
+
predict() to work at all).
|
| 7 |
+
|
| 8 |
+
Usage:
|
| 9 |
+
export GITHUB_PAT=... # a GitHub personal access token (read-only is fine)
|
| 10 |
+
python infer.py https://github.com/owner/repo/pull/123 [more PR urls...]
|
| 11 |
+
python infer.py --threshold 0.3 https://github.com/owner/repo/pull/123
|
| 12 |
+
|
| 13 |
+
The text fed to the model is built EXACTLY the way training data was: the same
|
| 14 |
+
render_document() + fasttext_preprocess() pipeline as annotate_pr_quality.py, so a
|
| 15 |
+
prediction here is directly comparable to what's in train.txt/val.txt.
|
| 16 |
+
"""
|
| 17 |
+
import base64
|
| 18 |
+
import json
|
| 19 |
+
import os
|
| 20 |
+
import re
|
| 21 |
+
import sys
|
| 22 |
+
|
| 23 |
+
import fasttext
|
| 24 |
+
import requests
|
| 25 |
+
|
| 26 |
+
HERE = os.path.dirname(os.path.abspath(__file__))
|
| 27 |
+
MODEL_PATH = os.path.join(HERE, "model.bin")
|
| 28 |
+
VOCAB_PATH = os.path.join(HERE, "tag_vocab.json")
|
| 29 |
+
|
| 30 |
+
MAX_FILES = 10
|
| 31 |
+
MAX_FILE_CHARS = 4_000
|
| 32 |
+
MAX_DIFF_CHARS = 12_000
|
| 33 |
+
MAX_FASTTEXT_TOKENS = 4_096
|
| 34 |
+
NON_CODE_EXTS = {"json", "xml"}
|
| 35 |
+
TOKEN_PATTERN = re.compile(r"\w+(?:['’]\w+)*|[^\w\s]", re.UNICODE)
|
| 36 |
+
DEFAULT_THRESHOLD = 0.5
|
| 37 |
+
|
| 38 |
+
TOKEN = os.environ["GITHUB_PAT"]
|
| 39 |
+
HEADERS = {"Authorization": f"token {TOKEN}", "Accept": "application/vnd.github+json"}
|
| 40 |
+
|
| 41 |
+
|
| 42 |
+
def truncate(text, limit):
|
| 43 |
+
if text is None:
|
| 44 |
+
return None
|
| 45 |
+
if len(text) <= limit:
|
| 46 |
+
return text
|
| 47 |
+
return text[:limit] + f"\n...[truncated, {len(text) - limit} more chars]"
|
| 48 |
+
|
| 49 |
+
|
| 50 |
+
def fasttext_preprocess(text):
|
| 51 |
+
tokens = []
|
| 52 |
+
for match in TOKEN_PATTERN.finditer(text.casefold()):
|
| 53 |
+
if len(tokens) == MAX_FASTTEXT_TOKENS:
|
| 54 |
+
break
|
| 55 |
+
token = match.group()
|
| 56 |
+
if token.startswith("__label__"):
|
| 57 |
+
token = "literal_" + token
|
| 58 |
+
tokens.append(token)
|
| 59 |
+
return " ".join(tokens)
|
| 60 |
+
|
| 61 |
+
|
| 62 |
+
def render_document(state):
|
| 63 |
+
lines = [f"repo : {state['repo']['full_name']}"]
|
| 64 |
+
if state["repo"]["description"]:
|
| 65 |
+
lines.append(f"description : {state['repo']['description']}")
|
| 66 |
+
lines.append(f"stars : {state['repo']['stars']}")
|
| 67 |
+
if state["repo"]["license"]:
|
| 68 |
+
lines.append(f"license : {state['repo']['license']}")
|
| 69 |
+
if state["pull_request_title"]:
|
| 70 |
+
lines.append(f"title : {state['pull_request_title']}")
|
| 71 |
+
lines.append("touched files : " + ", ".join(state["all_touched_files"]))
|
| 72 |
+
for f in state["files"]:
|
| 73 |
+
lines.append(f"--- {f['path']} (pre-change) ---")
|
| 74 |
+
lines.append(f["pre_change_content"] or "[new file]")
|
| 75 |
+
lines.append("--- diff ---")
|
| 76 |
+
lines.append(state["diff"] or "")
|
| 77 |
+
return "\n".join(lines)
|
| 78 |
+
|
| 79 |
+
|
| 80 |
+
def get(url, headers=None, **kw):
|
| 81 |
+
resp = requests.get(url, headers=headers or HEADERS, timeout=20, **kw)
|
| 82 |
+
resp.raise_for_status()
|
| 83 |
+
return resp
|
| 84 |
+
|
| 85 |
+
|
| 86 |
+
def parse_pr_url(url):
|
| 87 |
+
m = re.search(r"github\.com/([^/]+)/([^/]+)/pull/(\d+)", url)
|
| 88 |
+
return m.group(1), m.group(2), int(m.group(3))
|
| 89 |
+
|
| 90 |
+
|
| 91 |
+
def fetch_state(pr_url):
|
| 92 |
+
owner, repo, number = parse_pr_url(pr_url)
|
| 93 |
+
repo_full = f"{owner}/{repo}"
|
| 94 |
+
|
| 95 |
+
repo_info = get(f"https://api.github.com/repos/{repo_full}").json()
|
| 96 |
+
pr_info = get(f"https://api.github.com/repos/{repo_full}/pulls/{number}").json()
|
| 97 |
+
files_info = get(f"https://api.github.com/repos/{repo_full}/pulls/{number}/files",
|
| 98 |
+
params={"per_page": 100}).json()
|
| 99 |
+
diff = get(f"https://api.github.com/repos/{repo_full}/pulls/{number}",
|
| 100 |
+
headers={**HEADERS, "Accept": "application/vnd.github.v3.diff"}).text
|
| 101 |
+
|
| 102 |
+
base_sha = pr_info["base"]["sha"]
|
| 103 |
+
all_touched_files = [f["filename"] for f in files_info]
|
| 104 |
+
|
| 105 |
+
picked = []
|
| 106 |
+
for f in files_info:
|
| 107 |
+
path = f["filename"]
|
| 108 |
+
ext = path.rsplit(".", 1)[-1].lower() if "." in path else ""
|
| 109 |
+
if ext in NON_CODE_EXTS:
|
| 110 |
+
continue
|
| 111 |
+
content = None
|
| 112 |
+
if f["status"] != "added":
|
| 113 |
+
try:
|
| 114 |
+
c = get(f"https://api.github.com/repos/{repo_full}/contents/{path}",
|
| 115 |
+
params={"ref": base_sha}).json()
|
| 116 |
+
if c.get("encoding") == "base64":
|
| 117 |
+
content = base64.b64decode(c["content"]).decode("utf-8", errors="replace")
|
| 118 |
+
except requests.HTTPError:
|
| 119 |
+
content = None
|
| 120 |
+
picked.append({"path": path, "pre_change_content": truncate(content, MAX_FILE_CHARS)})
|
| 121 |
+
if len(picked) == MAX_FILES:
|
| 122 |
+
break
|
| 123 |
+
|
| 124 |
+
license_ = repo_info.get("license") or {}
|
| 125 |
+
return {
|
| 126 |
+
"repo": {
|
| 127 |
+
"full_name": repo_full,
|
| 128 |
+
"description": repo_info.get("description"),
|
| 129 |
+
"stars": repo_info.get("stargazers_count"),
|
| 130 |
+
"license": license_.get("spdx_id") or license_.get("name"),
|
| 131 |
+
},
|
| 132 |
+
"pull_request_title": pr_info.get("title"),
|
| 133 |
+
"all_touched_files": all_touched_files,
|
| 134 |
+
"files": picked,
|
| 135 |
+
"diff": truncate(diff, MAX_DIFF_CHARS),
|
| 136 |
+
}
|
| 137 |
+
|
| 138 |
+
|
| 139 |
+
def predict(model, tag_of_slug, text, threshold):
|
| 140 |
+
n_labels = len(model.get_labels())
|
| 141 |
+
labels, probs = model.predict(text, k=n_labels)
|
| 142 |
+
tagged = []
|
| 143 |
+
for label, prob in zip(labels, probs):
|
| 144 |
+
slug = label[len("__label__"):]
|
| 145 |
+
tag = tag_of_slug.get(slug, slug)
|
| 146 |
+
if prob >= threshold:
|
| 147 |
+
tagged.append((tag, float(prob)))
|
| 148 |
+
tagged.sort(key=lambda x: -x[1])
|
| 149 |
+
return tagged
|
| 150 |
+
|
| 151 |
+
|
| 152 |
+
if __name__ == "__main__":
|
| 153 |
+
args = sys.argv[1:]
|
| 154 |
+
threshold = DEFAULT_THRESHOLD
|
| 155 |
+
if args and args[0] == "--threshold":
|
| 156 |
+
threshold = float(args[1])
|
| 157 |
+
args = args[2:]
|
| 158 |
+
if not args:
|
| 159 |
+
raise SystemExit("usage: python infer.py [--threshold 0.5] <github PR url> [more PR urls...]")
|
| 160 |
+
|
| 161 |
+
vocab = json.loads(open(VOCAB_PATH).read())
|
| 162 |
+
tag_of_slug = {v: k for k, v in vocab["slug_of"].items()}
|
| 163 |
+
|
| 164 |
+
model = fasttext.load_model(MODEL_PATH)
|
| 165 |
+
for pr_url in args:
|
| 166 |
+
state = fetch_state(pr_url)
|
| 167 |
+
text = fasttext_preprocess(render_document(state))
|
| 168 |
+
tagged = predict(model, tag_of_slug, text, threshold)
|
| 169 |
+
print(f"{pr_url}")
|
| 170 |
+
print(f" repo: {state['repo']['full_name']} stars: {state['repo']['stars']}")
|
| 171 |
+
print(f" {len(tagged)} tags (threshold={threshold}):")
|
| 172 |
+
for tag, prob in tagged:
|
| 173 |
+
print(f" {tag}: {prob:.3f}")
|
| 174 |
+
print()
|
tags/model.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:9b67d07e2442cc73f3303fe182738500821fe30afe41019a1b430176f69e98b9
|
| 3 |
+
size 881160000
|
tags/tag_vocab.json
ADDED
|
@@ -0,0 +1,855 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
{
|
| 2 |
+
"tags": [
|
| 3 |
+
"3d-modeling",
|
| 4 |
+
"AMT",
|
| 5 |
+
"Bayesian-inference",
|
| 6 |
+
"C",
|
| 7 |
+
"ERP",
|
| 8 |
+
"GSEA",
|
| 9 |
+
"MES",
|
| 10 |
+
"MusicXML",
|
| 11 |
+
"R",
|
| 12 |
+
"SATB",
|
| 13 |
+
"TMT",
|
| 14 |
+
"WMS",
|
| 15 |
+
"adaptive-rejection-sampling",
|
| 16 |
+
"administrative-data",
|
| 17 |
+
"advertising",
|
| 18 |
+
"after-sales",
|
| 19 |
+
"aggregation",
|
| 20 |
+
"algorithms",
|
| 21 |
+
"analysis",
|
| 22 |
+
"anonymization",
|
| 23 |
+
"api",
|
| 24 |
+
"applied-microeconomics",
|
| 25 |
+
"applied-statistics",
|
| 26 |
+
"asset-lineage",
|
| 27 |
+
"async",
|
| 28 |
+
"audio-transcription",
|
| 29 |
+
"audit-provenance",
|
| 30 |
+
"autokey-cipher",
|
| 31 |
+
"aviation",
|
| 32 |
+
"bash",
|
| 33 |
+
"batching",
|
| 34 |
+
"bayesian-network",
|
| 35 |
+
"bayesian-statistics",
|
| 36 |
+
"bcbs-279",
|
| 37 |
+
"benchmark-construction",
|
| 38 |
+
"bessel-functions",
|
| 39 |
+
"binlog",
|
| 40 |
+
"bioinformatics",
|
| 41 |
+
"biology",
|
| 42 |
+
"black-box-parity",
|
| 43 |
+
"bootkit",
|
| 44 |
+
"browser",
|
| 45 |
+
"build-tools",
|
| 46 |
+
"bun",
|
| 47 |
+
"c",
|
| 48 |
+
"c-programming",
|
| 49 |
+
"cad",
|
| 50 |
+
"caffe",
|
| 51 |
+
"calendar",
|
| 52 |
+
"cdc",
|
| 53 |
+
"checkpoint-conversion",
|
| 54 |
+
"cheminformatics",
|
| 55 |
+
"chemistry",
|
| 56 |
+
"chorale",
|
| 57 |
+
"cli",
|
| 58 |
+
"climate-science",
|
| 59 |
+
"cloning",
|
| 60 |
+
"cnn",
|
| 61 |
+
"code-vulnerability",
|
| 62 |
+
"coding",
|
| 63 |
+
"cold-start",
|
| 64 |
+
"combinatorial-optimization",
|
| 65 |
+
"combinatorics",
|
| 66 |
+
"common-weakness-enumeration",
|
| 67 |
+
"compaction",
|
| 68 |
+
"compilation",
|
| 69 |
+
"compiled-extensions",
|
| 70 |
+
"compilers",
|
| 71 |
+
"compliance",
|
| 72 |
+
"compression",
|
| 73 |
+
"computer-use",
|
| 74 |
+
"computer-vision",
|
| 75 |
+
"concurrency",
|
| 76 |
+
"config-generation",
|
| 77 |
+
"config-management",
|
| 78 |
+
"conflict-resolution",
|
| 79 |
+
"connected_components",
|
| 80 |
+
"constraint",
|
| 81 |
+
"constraint-satisfaction",
|
| 82 |
+
"contact-dynamics",
|
| 83 |
+
"coq",
|
| 84 |
+
"corewars",
|
| 85 |
+
"counterparty-credit-risk",
|
| 86 |
+
"cpp",
|
| 87 |
+
"cpu",
|
| 88 |
+
"crm",
|
| 89 |
+
"cross-referencing",
|
| 90 |
+
"cryptanalysis",
|
| 91 |
+
"cryptography",
|
| 92 |
+
"crystallography",
|
| 93 |
+
"csv",
|
| 94 |
+
"cuda",
|
| 95 |
+
"custom-protocol",
|
| 96 |
+
"cybersecurity",
|
| 97 |
+
"cybersecurity-vulnerability-resolution",
|
| 98 |
+
"dangerous-goods",
|
| 99 |
+
"data",
|
| 100 |
+
"data engineering",
|
| 101 |
+
"data processing",
|
| 102 |
+
"data-analysis",
|
| 103 |
+
"data-integration",
|
| 104 |
+
"data-linkage",
|
| 105 |
+
"data-pipeline",
|
| 106 |
+
"data-processing",
|
| 107 |
+
"data-science",
|
| 108 |
+
"data_engineering",
|
| 109 |
+
"database",
|
| 110 |
+
"databases",
|
| 111 |
+
"datasets",
|
| 112 |
+
"debian",
|
| 113 |
+
"debugging",
|
| 114 |
+
"decrypt",
|
| 115 |
+
"deduplication",
|
| 116 |
+
"deeply-technical-ip",
|
| 117 |
+
"deepseek-r1",
|
| 118 |
+
"dependency",
|
| 119 |
+
"devops",
|
| 120 |
+
"differential-expression",
|
| 121 |
+
"digital-design",
|
| 122 |
+
"dispatch",
|
| 123 |
+
"distributed-systems",
|
| 124 |
+
"distributed-training",
|
| 125 |
+
"distributed_systems",
|
| 126 |
+
"document-processing",
|
| 127 |
+
"document-verification",
|
| 128 |
+
"domain-reasoning",
|
| 129 |
+
"drawing",
|
| 130 |
+
"drift-detection",
|
| 131 |
+
"driver-hours",
|
| 132 |
+
"editable-layout",
|
| 133 |
+
"email-server",
|
| 134 |
+
"embedded-systems",
|
| 135 |
+
"encryption",
|
| 136 |
+
"ensembl-vep",
|
| 137 |
+
"entity-resolution",
|
| 138 |
+
"erp",
|
| 139 |
+
"etl",
|
| 140 |
+
"evaluation",
|
| 141 |
+
"event-time",
|
| 142 |
+
"excel",
|
| 143 |
+
"exploration-exploitation",
|
| 144 |
+
"fastapi",
|
| 145 |
+
"fdtd",
|
| 146 |
+
"feature-interpretation",
|
| 147 |
+
"file-operations",
|
| 148 |
+
"financial",
|
| 149 |
+
"firmware",
|
| 150 |
+
"fitting",
|
| 151 |
+
"flight-planning",
|
| 152 |
+
"forensics",
|
| 153 |
+
"formal methods",
|
| 154 |
+
"formal-mathematics",
|
| 155 |
+
"formal-verification",
|
| 156 |
+
"forms",
|
| 157 |
+
"fp8",
|
| 158 |
+
"fraud-detection",
|
| 159 |
+
"freecad",
|
| 160 |
+
"frontend",
|
| 161 |
+
"fuel-planning",
|
| 162 |
+
"gaming",
|
| 163 |
+
"gaussian-process",
|
| 164 |
+
"genomics",
|
| 165 |
+
"geometry",
|
| 166 |
+
"german-compliance",
|
| 167 |
+
"git",
|
| 168 |
+
"glycomics",
|
| 169 |
+
"gpu",
|
| 170 |
+
"gpu-parallelisms",
|
| 171 |
+
"grader",
|
| 172 |
+
"graph-algorithms",
|
| 173 |
+
"graphic-design",
|
| 174 |
+
"graphics",
|
| 175 |
+
"h100",
|
| 176 |
+
"hardware",
|
| 177 |
+
"hardware-kernels",
|
| 178 |
+
"hardware-modeling",
|
| 179 |
+
"harmony",
|
| 180 |
+
"heat-pumps",
|
| 181 |
+
"hgvs",
|
| 182 |
+
"histopathology",
|
| 183 |
+
"historical-linguistics",
|
| 184 |
+
"household-consumption",
|
| 185 |
+
"hpc",
|
| 186 |
+
"html-sanitization",
|
| 187 |
+
"huggingface",
|
| 188 |
+
"hydrogen-bonding",
|
| 189 |
+
"ics-parsing",
|
| 190 |
+
"image-processing",
|
| 191 |
+
"images",
|
| 192 |
+
"imo",
|
| 193 |
+
"impeller",
|
| 194 |
+
"incident-response",
|
| 195 |
+
"inference",
|
| 196 |
+
"information-retrieval",
|
| 197 |
+
"infrastructure-configuration",
|
| 198 |
+
"interpenetration",
|
| 199 |
+
"intrastat",
|
| 200 |
+
"inverse-design",
|
| 201 |
+
"inverse-problem",
|
| 202 |
+
"jax",
|
| 203 |
+
"kafka",
|
| 204 |
+
"kernel-optimization",
|
| 205 |
+
"knowledge-graph",
|
| 206 |
+
"knowledge-graphs",
|
| 207 |
+
"kuramoto-sivashinsky",
|
| 208 |
+
"large-scale-text-manipulation",
|
| 209 |
+
"latency",
|
| 210 |
+
"latex",
|
| 211 |
+
"layout-analysis",
|
| 212 |
+
"layout-reconstruction",
|
| 213 |
+
"layout-shift",
|
| 214 |
+
"lean4",
|
| 215 |
+
"legacy-gui",
|
| 216 |
+
"legacy-modernization",
|
| 217 |
+
"legacy-software",
|
| 218 |
+
"linux",
|
| 219 |
+
"liquid_scintillation_counting",
|
| 220 |
+
"list-decoding",
|
| 221 |
+
"litdata",
|
| 222 |
+
"live-surgery",
|
| 223 |
+
"live-system",
|
| 224 |
+
"llm",
|
| 225 |
+
"llm-eval",
|
| 226 |
+
"log-analysis",
|
| 227 |
+
"logistics",
|
| 228 |
+
"lsh",
|
| 229 |
+
"lsm",
|
| 230 |
+
"machine-learning",
|
| 231 |
+
"mailing-list",
|
| 232 |
+
"manufacturing",
|
| 233 |
+
"mass-spectrometry",
|
| 234 |
+
"mathematics",
|
| 235 |
+
"mcmc",
|
| 236 |
+
"mechanical-engineering",
|
| 237 |
+
"medical-billing",
|
| 238 |
+
"meep",
|
| 239 |
+
"megatron",
|
| 240 |
+
"memory-management",
|
| 241 |
+
"meter-data",
|
| 242 |
+
"migration",
|
| 243 |
+
"minhash",
|
| 244 |
+
"mixture-of-experts",
|
| 245 |
+
"ml-monitoring",
|
| 246 |
+
"ml-platform",
|
| 247 |
+
"mlops",
|
| 248 |
+
"model-risk",
|
| 249 |
+
"model-training",
|
| 250 |
+
"mteb",
|
| 251 |
+
"mujoco",
|
| 252 |
+
"multi-container",
|
| 253 |
+
"multi-modal",
|
| 254 |
+
"multi-service",
|
| 255 |
+
"music",
|
| 256 |
+
"mvcc",
|
| 257 |
+
"mysql",
|
| 258 |
+
"network",
|
| 259 |
+
"network-analysis",
|
| 260 |
+
"networking",
|
| 261 |
+
"next.js",
|
| 262 |
+
"nextjs",
|
| 263 |
+
"no-verified-solution",
|
| 264 |
+
"numerical-analysis",
|
| 265 |
+
"numerical-approximation",
|
| 266 |
+
"numerical-optimization",
|
| 267 |
+
"numpy",
|
| 268 |
+
"ocr",
|
| 269 |
+
"offline-evaluation",
|
| 270 |
+
"operating-systems",
|
| 271 |
+
"optimization",
|
| 272 |
+
"owl",
|
| 273 |
+
"pandas",
|
| 274 |
+
"panel-construction",
|
| 275 |
+
"parametric",
|
| 276 |
+
"parquet",
|
| 277 |
+
"pathfinding",
|
| 278 |
+
"pde",
|
| 279 |
+
"penetration-testing",
|
| 280 |
+
"performance",
|
| 281 |
+
"performance-engineering",
|
| 282 |
+
"performance-optimization",
|
| 283 |
+
"phonology",
|
| 284 |
+
"photonics",
|
| 285 |
+
"physical-chemistry",
|
| 286 |
+
"physics",
|
| 287 |
+
"pipeline-parallelism",
|
| 288 |
+
"pixel-matching",
|
| 289 |
+
"planning",
|
| 290 |
+
"playwright",
|
| 291 |
+
"pmars",
|
| 292 |
+
"postgresql",
|
| 293 |
+
"pretraining",
|
| 294 |
+
"privacy",
|
| 295 |
+
"process-modeling",
|
| 296 |
+
"production planning",
|
| 297 |
+
"proofs",
|
| 298 |
+
"protein-structure",
|
| 299 |
+
"proteins",
|
| 300 |
+
"proteomics",
|
| 301 |
+
"ptrace",
|
| 302 |
+
"pydrake",
|
| 303 |
+
"pystan",
|
| 304 |
+
"python",
|
| 305 |
+
"python-extension",
|
| 306 |
+
"python-migration",
|
| 307 |
+
"pytorch",
|
| 308 |
+
"qemu",
|
| 309 |
+
"query-optimization",
|
| 310 |
+
"qwen3-coder",
|
| 311 |
+
"radiochemistry",
|
| 312 |
+
"ray-tracing",
|
| 313 |
+
"rdf",
|
| 314 |
+
"react",
|
| 315 |
+
"reasoning",
|
| 316 |
+
"reasoning-model",
|
| 317 |
+
"recovery",
|
| 318 |
+
"reed-solomon",
|
| 319 |
+
"regex",
|
| 320 |
+
"reimplementation",
|
| 321 |
+
"release-security",
|
| 322 |
+
"report-generation",
|
| 323 |
+
"research",
|
| 324 |
+
"retrieval",
|
| 325 |
+
"retro-computing",
|
| 326 |
+
"retro-console",
|
| 327 |
+
"reverse-engineering",
|
| 328 |
+
"rocksdb",
|
| 329 |
+
"routing",
|
| 330 |
+
"rstan",
|
| 331 |
+
"rtl",
|
| 332 |
+
"rule-induction",
|
| 333 |
+
"sa-ccr",
|
| 334 |
+
"satb",
|
| 335 |
+
"scala",
|
| 336 |
+
"scheduling",
|
| 337 |
+
"schema-mapping",
|
| 338 |
+
"scientific-computing",
|
| 339 |
+
"scipy",
|
| 340 |
+
"security",
|
| 341 |
+
"session-windows",
|
| 342 |
+
"sglang",
|
| 343 |
+
"simulation",
|
| 344 |
+
"software-engineering",
|
| 345 |
+
"software-installation",
|
| 346 |
+
"source-maps",
|
| 347 |
+
"spark",
|
| 348 |
+
"sparql",
|
| 349 |
+
"sparql-query",
|
| 350 |
+
"spatial-reasoning",
|
| 351 |
+
"spcas9",
|
| 352 |
+
"spectral-methods",
|
| 353 |
+
"spectroscopy",
|
| 354 |
+
"speculative-decoding",
|
| 355 |
+
"spring_clip",
|
| 356 |
+
"sql",
|
| 357 |
+
"sql-query",
|
| 358 |
+
"sqlite",
|
| 359 |
+
"stan",
|
| 360 |
+
"state",
|
| 361 |
+
"stateful-cli",
|
| 362 |
+
"statistical-filing",
|
| 363 |
+
"statistics",
|
| 364 |
+
"stats",
|
| 365 |
+
"storage-engine",
|
| 366 |
+
"stream-processing",
|
| 367 |
+
"streaming",
|
| 368 |
+
"string-parsing",
|
| 369 |
+
"string-rewriting",
|
| 370 |
+
"structural-elucidation",
|
| 371 |
+
"supramolecular-chemistry",
|
| 372 |
+
"symbolic-math",
|
| 373 |
+
"sympy",
|
| 374 |
+
"sys-admin",
|
| 375 |
+
"system",
|
| 376 |
+
"system-on-chip",
|
| 377 |
+
"tandem-ms",
|
| 378 |
+
"tariffs",
|
| 379 |
+
"template-matching",
|
| 380 |
+
"temporal-reasoning",
|
| 381 |
+
"tensor-parallelism",
|
| 382 |
+
"tensorflow",
|
| 383 |
+
"terminal",
|
| 384 |
+
"text-editing",
|
| 385 |
+
"theorem-proving",
|
| 386 |
+
"time-series",
|
| 387 |
+
"tokenization",
|
| 388 |
+
"tool-calling",
|
| 389 |
+
"topology",
|
| 390 |
+
"topology-optimization",
|
| 391 |
+
"trajectory-optimization",
|
| 392 |
+
"transformer",
|
| 393 |
+
"troubleshooting",
|
| 394 |
+
"typescript",
|
| 395 |
+
"typography",
|
| 396 |
+
"uefi",
|
| 397 |
+
"userform",
|
| 398 |
+
"utility-billing",
|
| 399 |
+
"validation",
|
| 400 |
+
"vba",
|
| 401 |
+
"vector-graphics",
|
| 402 |
+
"verilog",
|
| 403 |
+
"version-control",
|
| 404 |
+
"video-processing",
|
| 405 |
+
"vigenere",
|
| 406 |
+
"vim",
|
| 407 |
+
"vim-macros",
|
| 408 |
+
"virtual-machine",
|
| 409 |
+
"virtualization",
|
| 410 |
+
"vision",
|
| 411 |
+
"vllm",
|
| 412 |
+
"vnc",
|
| 413 |
+
"voice-leading",
|
| 414 |
+
"wal",
|
| 415 |
+
"warranty",
|
| 416 |
+
"watermarks",
|
| 417 |
+
"wdm",
|
| 418 |
+
"web",
|
| 419 |
+
"web-security",
|
| 420 |
+
"web-server",
|
| 421 |
+
"weight-balance",
|
| 422 |
+
"windows-3.11",
|
| 423 |
+
"workflow",
|
| 424 |
+
"x86_64",
|
| 425 |
+
"xss",
|
| 426 |
+
"zero-downtime"
|
| 427 |
+
],
|
| 428 |
+
"slug_of": {
|
| 429 |
+
"3d-modeling": "3d-modeling",
|
| 430 |
+
"AMT": "AMT",
|
| 431 |
+
"Bayesian-inference": "Bayesian-inference",
|
| 432 |
+
"C": "C",
|
| 433 |
+
"ERP": "ERP",
|
| 434 |
+
"GSEA": "GSEA",
|
| 435 |
+
"MES": "MES",
|
| 436 |
+
"MusicXML": "MusicXML",
|
| 437 |
+
"R": "R",
|
| 438 |
+
"SATB": "SATB",
|
| 439 |
+
"TMT": "TMT",
|
| 440 |
+
"WMS": "WMS",
|
| 441 |
+
"adaptive-rejection-sampling": "adaptive-rejection-sampling",
|
| 442 |
+
"administrative-data": "administrative-data",
|
| 443 |
+
"advertising": "advertising",
|
| 444 |
+
"after-sales": "after-sales",
|
| 445 |
+
"aggregation": "aggregation",
|
| 446 |
+
"algorithms": "algorithms",
|
| 447 |
+
"analysis": "analysis",
|
| 448 |
+
"anonymization": "anonymization",
|
| 449 |
+
"api": "api",
|
| 450 |
+
"applied-microeconomics": "applied-microeconomics",
|
| 451 |
+
"applied-statistics": "applied-statistics",
|
| 452 |
+
"asset-lineage": "asset-lineage",
|
| 453 |
+
"async": "async",
|
| 454 |
+
"audio-transcription": "audio-transcription",
|
| 455 |
+
"audit-provenance": "audit-provenance",
|
| 456 |
+
"autokey-cipher": "autokey-cipher",
|
| 457 |
+
"aviation": "aviation",
|
| 458 |
+
"bash": "bash",
|
| 459 |
+
"batching": "batching",
|
| 460 |
+
"bayesian-network": "bayesian-network",
|
| 461 |
+
"bayesian-statistics": "bayesian-statistics",
|
| 462 |
+
"bcbs-279": "bcbs-279",
|
| 463 |
+
"benchmark-construction": "benchmark-construction",
|
| 464 |
+
"bessel-functions": "bessel-functions",
|
| 465 |
+
"binlog": "binlog",
|
| 466 |
+
"bioinformatics": "bioinformatics",
|
| 467 |
+
"biology": "biology",
|
| 468 |
+
"black-box-parity": "black-box-parity",
|
| 469 |
+
"bootkit": "bootkit",
|
| 470 |
+
"browser": "browser",
|
| 471 |
+
"build-tools": "build-tools",
|
| 472 |
+
"bun": "bun",
|
| 473 |
+
"c": "c",
|
| 474 |
+
"c-programming": "c-programming",
|
| 475 |
+
"cad": "cad",
|
| 476 |
+
"caffe": "caffe",
|
| 477 |
+
"calendar": "calendar",
|
| 478 |
+
"cdc": "cdc",
|
| 479 |
+
"checkpoint-conversion": "checkpoint-conversion",
|
| 480 |
+
"cheminformatics": "cheminformatics",
|
| 481 |
+
"chemistry": "chemistry",
|
| 482 |
+
"chorale": "chorale",
|
| 483 |
+
"cli": "cli",
|
| 484 |
+
"climate-science": "climate-science",
|
| 485 |
+
"cloning": "cloning",
|
| 486 |
+
"cnn": "cnn",
|
| 487 |
+
"code-vulnerability": "code-vulnerability",
|
| 488 |
+
"coding": "coding",
|
| 489 |
+
"cold-start": "cold-start",
|
| 490 |
+
"combinatorial-optimization": "combinatorial-optimization",
|
| 491 |
+
"combinatorics": "combinatorics",
|
| 492 |
+
"common-weakness-enumeration": "common-weakness-enumeration",
|
| 493 |
+
"compaction": "compaction",
|
| 494 |
+
"compilation": "compilation",
|
| 495 |
+
"compiled-extensions": "compiled-extensions",
|
| 496 |
+
"compilers": "compilers",
|
| 497 |
+
"compliance": "compliance",
|
| 498 |
+
"compression": "compression",
|
| 499 |
+
"computer-use": "computer-use",
|
| 500 |
+
"computer-vision": "computer-vision",
|
| 501 |
+
"concurrency": "concurrency",
|
| 502 |
+
"config-generation": "config-generation",
|
| 503 |
+
"config-management": "config-management",
|
| 504 |
+
"conflict-resolution": "conflict-resolution",
|
| 505 |
+
"connected_components": "connected_components",
|
| 506 |
+
"constraint": "constraint",
|
| 507 |
+
"constraint-satisfaction": "constraint-satisfaction",
|
| 508 |
+
"contact-dynamics": "contact-dynamics",
|
| 509 |
+
"coq": "coq",
|
| 510 |
+
"corewars": "corewars",
|
| 511 |
+
"counterparty-credit-risk": "counterparty-credit-risk",
|
| 512 |
+
"cpp": "cpp",
|
| 513 |
+
"cpu": "cpu",
|
| 514 |
+
"crm": "crm",
|
| 515 |
+
"cross-referencing": "cross-referencing",
|
| 516 |
+
"cryptanalysis": "cryptanalysis",
|
| 517 |
+
"cryptography": "cryptography",
|
| 518 |
+
"crystallography": "crystallography",
|
| 519 |
+
"csv": "csv",
|
| 520 |
+
"cuda": "cuda",
|
| 521 |
+
"custom-protocol": "custom-protocol",
|
| 522 |
+
"cybersecurity": "cybersecurity",
|
| 523 |
+
"cybersecurity-vulnerability-resolution": "cybersecurity-vulnerability-resolution",
|
| 524 |
+
"dangerous-goods": "dangerous-goods",
|
| 525 |
+
"data": "data",
|
| 526 |
+
"data engineering": "data_engineering",
|
| 527 |
+
"data processing": "data_processing",
|
| 528 |
+
"data-analysis": "data-analysis",
|
| 529 |
+
"data-integration": "data-integration",
|
| 530 |
+
"data-linkage": "data-linkage",
|
| 531 |
+
"data-pipeline": "data-pipeline",
|
| 532 |
+
"data-processing": "data-processing",
|
| 533 |
+
"data-science": "data-science",
|
| 534 |
+
"data_engineering": "data_engineering_dup",
|
| 535 |
+
"database": "database",
|
| 536 |
+
"databases": "databases",
|
| 537 |
+
"datasets": "datasets",
|
| 538 |
+
"debian": "debian",
|
| 539 |
+
"debugging": "debugging",
|
| 540 |
+
"decrypt": "decrypt",
|
| 541 |
+
"deduplication": "deduplication",
|
| 542 |
+
"deeply-technical-ip": "deeply-technical-ip",
|
| 543 |
+
"deepseek-r1": "deepseek-r1",
|
| 544 |
+
"dependency": "dependency",
|
| 545 |
+
"devops": "devops",
|
| 546 |
+
"differential-expression": "differential-expression",
|
| 547 |
+
"digital-design": "digital-design",
|
| 548 |
+
"dispatch": "dispatch",
|
| 549 |
+
"distributed-systems": "distributed-systems",
|
| 550 |
+
"distributed-training": "distributed-training",
|
| 551 |
+
"distributed_systems": "distributed_systems",
|
| 552 |
+
"document-processing": "document-processing",
|
| 553 |
+
"document-verification": "document-verification",
|
| 554 |
+
"domain-reasoning": "domain-reasoning",
|
| 555 |
+
"drawing": "drawing",
|
| 556 |
+
"drift-detection": "drift-detection",
|
| 557 |
+
"driver-hours": "driver-hours",
|
| 558 |
+
"editable-layout": "editable-layout",
|
| 559 |
+
"email-server": "email-server",
|
| 560 |
+
"embedded-systems": "embedded-systems",
|
| 561 |
+
"encryption": "encryption",
|
| 562 |
+
"ensembl-vep": "ensembl-vep",
|
| 563 |
+
"entity-resolution": "entity-resolution",
|
| 564 |
+
"erp": "erp",
|
| 565 |
+
"etl": "etl",
|
| 566 |
+
"evaluation": "evaluation",
|
| 567 |
+
"event-time": "event-time",
|
| 568 |
+
"excel": "excel",
|
| 569 |
+
"exploration-exploitation": "exploration-exploitation",
|
| 570 |
+
"fastapi": "fastapi",
|
| 571 |
+
"fdtd": "fdtd",
|
| 572 |
+
"feature-interpretation": "feature-interpretation",
|
| 573 |
+
"file-operations": "file-operations",
|
| 574 |
+
"financial": "financial",
|
| 575 |
+
"firmware": "firmware",
|
| 576 |
+
"fitting": "fitting",
|
| 577 |
+
"flight-planning": "flight-planning",
|
| 578 |
+
"forensics": "forensics",
|
| 579 |
+
"formal methods": "formal_methods",
|
| 580 |
+
"formal-mathematics": "formal-mathematics",
|
| 581 |
+
"formal-verification": "formal-verification",
|
| 582 |
+
"forms": "forms",
|
| 583 |
+
"fp8": "fp8",
|
| 584 |
+
"fraud-detection": "fraud-detection",
|
| 585 |
+
"freecad": "freecad",
|
| 586 |
+
"frontend": "frontend",
|
| 587 |
+
"fuel-planning": "fuel-planning",
|
| 588 |
+
"gaming": "gaming",
|
| 589 |
+
"gaussian-process": "gaussian-process",
|
| 590 |
+
"genomics": "genomics",
|
| 591 |
+
"geometry": "geometry",
|
| 592 |
+
"german-compliance": "german-compliance",
|
| 593 |
+
"git": "git",
|
| 594 |
+
"glycomics": "glycomics",
|
| 595 |
+
"gpu": "gpu",
|
| 596 |
+
"gpu-parallelisms": "gpu-parallelisms",
|
| 597 |
+
"grader": "grader",
|
| 598 |
+
"graph-algorithms": "graph-algorithms",
|
| 599 |
+
"graphic-design": "graphic-design",
|
| 600 |
+
"graphics": "graphics",
|
| 601 |
+
"h100": "h100",
|
| 602 |
+
"hardware": "hardware",
|
| 603 |
+
"hardware-kernels": "hardware-kernels",
|
| 604 |
+
"hardware-modeling": "hardware-modeling",
|
| 605 |
+
"harmony": "harmony",
|
| 606 |
+
"heat-pumps": "heat-pumps",
|
| 607 |
+
"hgvs": "hgvs",
|
| 608 |
+
"histopathology": "histopathology",
|
| 609 |
+
"historical-linguistics": "historical-linguistics",
|
| 610 |
+
"household-consumption": "household-consumption",
|
| 611 |
+
"hpc": "hpc",
|
| 612 |
+
"html-sanitization": "html-sanitization",
|
| 613 |
+
"huggingface": "huggingface",
|
| 614 |
+
"hydrogen-bonding": "hydrogen-bonding",
|
| 615 |
+
"ics-parsing": "ics-parsing",
|
| 616 |
+
"image-processing": "image-processing",
|
| 617 |
+
"images": "images",
|
| 618 |
+
"imo": "imo",
|
| 619 |
+
"impeller": "impeller",
|
| 620 |
+
"incident-response": "incident-response",
|
| 621 |
+
"inference": "inference",
|
| 622 |
+
"information-retrieval": "information-retrieval",
|
| 623 |
+
"infrastructure-configuration": "infrastructure-configuration",
|
| 624 |
+
"interpenetration": "interpenetration",
|
| 625 |
+
"intrastat": "intrastat",
|
| 626 |
+
"inverse-design": "inverse-design",
|
| 627 |
+
"inverse-problem": "inverse-problem",
|
| 628 |
+
"jax": "jax",
|
| 629 |
+
"kafka": "kafka",
|
| 630 |
+
"kernel-optimization": "kernel-optimization",
|
| 631 |
+
"knowledge-graph": "knowledge-graph",
|
| 632 |
+
"knowledge-graphs": "knowledge-graphs",
|
| 633 |
+
"kuramoto-sivashinsky": "kuramoto-sivashinsky",
|
| 634 |
+
"large-scale-text-manipulation": "large-scale-text-manipulation",
|
| 635 |
+
"latency": "latency",
|
| 636 |
+
"latex": "latex",
|
| 637 |
+
"layout-analysis": "layout-analysis",
|
| 638 |
+
"layout-reconstruction": "layout-reconstruction",
|
| 639 |
+
"layout-shift": "layout-shift",
|
| 640 |
+
"lean4": "lean4",
|
| 641 |
+
"legacy-gui": "legacy-gui",
|
| 642 |
+
"legacy-modernization": "legacy-modernization",
|
| 643 |
+
"legacy-software": "legacy-software",
|
| 644 |
+
"linux": "linux",
|
| 645 |
+
"liquid_scintillation_counting": "liquid_scintillation_counting",
|
| 646 |
+
"list-decoding": "list-decoding",
|
| 647 |
+
"litdata": "litdata",
|
| 648 |
+
"live-surgery": "live-surgery",
|
| 649 |
+
"live-system": "live-system",
|
| 650 |
+
"llm": "llm",
|
| 651 |
+
"llm-eval": "llm-eval",
|
| 652 |
+
"log-analysis": "log-analysis",
|
| 653 |
+
"logistics": "logistics",
|
| 654 |
+
"lsh": "lsh",
|
| 655 |
+
"lsm": "lsm",
|
| 656 |
+
"machine-learning": "machine-learning",
|
| 657 |
+
"mailing-list": "mailing-list",
|
| 658 |
+
"manufacturing": "manufacturing",
|
| 659 |
+
"mass-spectrometry": "mass-spectrometry",
|
| 660 |
+
"mathematics": "mathematics",
|
| 661 |
+
"mcmc": "mcmc",
|
| 662 |
+
"mechanical-engineering": "mechanical-engineering",
|
| 663 |
+
"medical-billing": "medical-billing",
|
| 664 |
+
"meep": "meep",
|
| 665 |
+
"megatron": "megatron",
|
| 666 |
+
"memory-management": "memory-management",
|
| 667 |
+
"meter-data": "meter-data",
|
| 668 |
+
"migration": "migration",
|
| 669 |
+
"minhash": "minhash",
|
| 670 |
+
"mixture-of-experts": "mixture-of-experts",
|
| 671 |
+
"ml-monitoring": "ml-monitoring",
|
| 672 |
+
"ml-platform": "ml-platform",
|
| 673 |
+
"mlops": "mlops",
|
| 674 |
+
"model-risk": "model-risk",
|
| 675 |
+
"model-training": "model-training",
|
| 676 |
+
"mteb": "mteb",
|
| 677 |
+
"mujoco": "mujoco",
|
| 678 |
+
"multi-container": "multi-container",
|
| 679 |
+
"multi-modal": "multi-modal",
|
| 680 |
+
"multi-service": "multi-service",
|
| 681 |
+
"music": "music",
|
| 682 |
+
"mvcc": "mvcc",
|
| 683 |
+
"mysql": "mysql",
|
| 684 |
+
"network": "network",
|
| 685 |
+
"network-analysis": "network-analysis",
|
| 686 |
+
"networking": "networking",
|
| 687 |
+
"next.js": "next.js",
|
| 688 |
+
"nextjs": "nextjs",
|
| 689 |
+
"no-verified-solution": "no-verified-solution",
|
| 690 |
+
"numerical-analysis": "numerical-analysis",
|
| 691 |
+
"numerical-approximation": "numerical-approximation",
|
| 692 |
+
"numerical-optimization": "numerical-optimization",
|
| 693 |
+
"numpy": "numpy",
|
| 694 |
+
"ocr": "ocr",
|
| 695 |
+
"offline-evaluation": "offline-evaluation",
|
| 696 |
+
"operating-systems": "operating-systems",
|
| 697 |
+
"optimization": "optimization",
|
| 698 |
+
"owl": "owl",
|
| 699 |
+
"pandas": "pandas",
|
| 700 |
+
"panel-construction": "panel-construction",
|
| 701 |
+
"parametric": "parametric",
|
| 702 |
+
"parquet": "parquet",
|
| 703 |
+
"pathfinding": "pathfinding",
|
| 704 |
+
"pde": "pde",
|
| 705 |
+
"penetration-testing": "penetration-testing",
|
| 706 |
+
"performance": "performance",
|
| 707 |
+
"performance-engineering": "performance-engineering",
|
| 708 |
+
"performance-optimization": "performance-optimization",
|
| 709 |
+
"phonology": "phonology",
|
| 710 |
+
"photonics": "photonics",
|
| 711 |
+
"physical-chemistry": "physical-chemistry",
|
| 712 |
+
"physics": "physics",
|
| 713 |
+
"pipeline-parallelism": "pipeline-parallelism",
|
| 714 |
+
"pixel-matching": "pixel-matching",
|
| 715 |
+
"planning": "planning",
|
| 716 |
+
"playwright": "playwright",
|
| 717 |
+
"pmars": "pmars",
|
| 718 |
+
"postgresql": "postgresql",
|
| 719 |
+
"pretraining": "pretraining",
|
| 720 |
+
"privacy": "privacy",
|
| 721 |
+
"process-modeling": "process-modeling",
|
| 722 |
+
"production planning": "production_planning",
|
| 723 |
+
"proofs": "proofs",
|
| 724 |
+
"protein-structure": "protein-structure",
|
| 725 |
+
"proteins": "proteins",
|
| 726 |
+
"proteomics": "proteomics",
|
| 727 |
+
"ptrace": "ptrace",
|
| 728 |
+
"pydrake": "pydrake",
|
| 729 |
+
"pystan": "pystan",
|
| 730 |
+
"python": "python",
|
| 731 |
+
"python-extension": "python-extension",
|
| 732 |
+
"python-migration": "python-migration",
|
| 733 |
+
"pytorch": "pytorch",
|
| 734 |
+
"qemu": "qemu",
|
| 735 |
+
"query-optimization": "query-optimization",
|
| 736 |
+
"qwen3-coder": "qwen3-coder",
|
| 737 |
+
"radiochemistry": "radiochemistry",
|
| 738 |
+
"ray-tracing": "ray-tracing",
|
| 739 |
+
"rdf": "rdf",
|
| 740 |
+
"react": "react",
|
| 741 |
+
"reasoning": "reasoning",
|
| 742 |
+
"reasoning-model": "reasoning-model",
|
| 743 |
+
"recovery": "recovery",
|
| 744 |
+
"reed-solomon": "reed-solomon",
|
| 745 |
+
"regex": "regex",
|
| 746 |
+
"reimplementation": "reimplementation",
|
| 747 |
+
"release-security": "release-security",
|
| 748 |
+
"report-generation": "report-generation",
|
| 749 |
+
"research": "research",
|
| 750 |
+
"retrieval": "retrieval",
|
| 751 |
+
"retro-computing": "retro-computing",
|
| 752 |
+
"retro-console": "retro-console",
|
| 753 |
+
"reverse-engineering": "reverse-engineering",
|
| 754 |
+
"rocksdb": "rocksdb",
|
| 755 |
+
"routing": "routing",
|
| 756 |
+
"rstan": "rstan",
|
| 757 |
+
"rtl": "rtl",
|
| 758 |
+
"rule-induction": "rule-induction",
|
| 759 |
+
"sa-ccr": "sa-ccr",
|
| 760 |
+
"satb": "satb",
|
| 761 |
+
"scala": "scala",
|
| 762 |
+
"scheduling": "scheduling",
|
| 763 |
+
"schema-mapping": "schema-mapping",
|
| 764 |
+
"scientific-computing": "scientific-computing",
|
| 765 |
+
"scipy": "scipy",
|
| 766 |
+
"security": "security",
|
| 767 |
+
"session-windows": "session-windows",
|
| 768 |
+
"sglang": "sglang",
|
| 769 |
+
"simulation": "simulation",
|
| 770 |
+
"software-engineering": "software-engineering",
|
| 771 |
+
"software-installation": "software-installation",
|
| 772 |
+
"source-maps": "source-maps",
|
| 773 |
+
"spark": "spark",
|
| 774 |
+
"sparql": "sparql",
|
| 775 |
+
"sparql-query": "sparql-query",
|
| 776 |
+
"spatial-reasoning": "spatial-reasoning",
|
| 777 |
+
"spcas9": "spcas9",
|
| 778 |
+
"spectral-methods": "spectral-methods",
|
| 779 |
+
"spectroscopy": "spectroscopy",
|
| 780 |
+
"speculative-decoding": "speculative-decoding",
|
| 781 |
+
"spring_clip": "spring_clip",
|
| 782 |
+
"sql": "sql",
|
| 783 |
+
"sql-query": "sql-query",
|
| 784 |
+
"sqlite": "sqlite",
|
| 785 |
+
"stan": "stan",
|
| 786 |
+
"state": "state",
|
| 787 |
+
"stateful-cli": "stateful-cli",
|
| 788 |
+
"statistical-filing": "statistical-filing",
|
| 789 |
+
"statistics": "statistics",
|
| 790 |
+
"stats": "stats",
|
| 791 |
+
"storage-engine": "storage-engine",
|
| 792 |
+
"stream-processing": "stream-processing",
|
| 793 |
+
"streaming": "streaming",
|
| 794 |
+
"string-parsing": "string-parsing",
|
| 795 |
+
"string-rewriting": "string-rewriting",
|
| 796 |
+
"structural-elucidation": "structural-elucidation",
|
| 797 |
+
"supramolecular-chemistry": "supramolecular-chemistry",
|
| 798 |
+
"symbolic-math": "symbolic-math",
|
| 799 |
+
"sympy": "sympy",
|
| 800 |
+
"sys-admin": "sys-admin",
|
| 801 |
+
"system": "system",
|
| 802 |
+
"system-on-chip": "system-on-chip",
|
| 803 |
+
"tandem-ms": "tandem-ms",
|
| 804 |
+
"tariffs": "tariffs",
|
| 805 |
+
"template-matching": "template-matching",
|
| 806 |
+
"temporal-reasoning": "temporal-reasoning",
|
| 807 |
+
"tensor-parallelism": "tensor-parallelism",
|
| 808 |
+
"tensorflow": "tensorflow",
|
| 809 |
+
"terminal": "terminal",
|
| 810 |
+
"text-editing": "text-editing",
|
| 811 |
+
"theorem-proving": "theorem-proving",
|
| 812 |
+
"time-series": "time-series",
|
| 813 |
+
"tokenization": "tokenization",
|
| 814 |
+
"tool-calling": "tool-calling",
|
| 815 |
+
"topology": "topology",
|
| 816 |
+
"topology-optimization": "topology-optimization",
|
| 817 |
+
"trajectory-optimization": "trajectory-optimization",
|
| 818 |
+
"transformer": "transformer",
|
| 819 |
+
"troubleshooting": "troubleshooting",
|
| 820 |
+
"typescript": "typescript",
|
| 821 |
+
"typography": "typography",
|
| 822 |
+
"uefi": "uefi",
|
| 823 |
+
"userform": "userform",
|
| 824 |
+
"utility-billing": "utility-billing",
|
| 825 |
+
"validation": "validation",
|
| 826 |
+
"vba": "vba",
|
| 827 |
+
"vector-graphics": "vector-graphics",
|
| 828 |
+
"verilog": "verilog",
|
| 829 |
+
"version-control": "version-control",
|
| 830 |
+
"video-processing": "video-processing",
|
| 831 |
+
"vigenere": "vigenere",
|
| 832 |
+
"vim": "vim",
|
| 833 |
+
"vim-macros": "vim-macros",
|
| 834 |
+
"virtual-machine": "virtual-machine",
|
| 835 |
+
"virtualization": "virtualization",
|
| 836 |
+
"vision": "vision",
|
| 837 |
+
"vllm": "vllm",
|
| 838 |
+
"vnc": "vnc",
|
| 839 |
+
"voice-leading": "voice-leading",
|
| 840 |
+
"wal": "wal",
|
| 841 |
+
"warranty": "warranty",
|
| 842 |
+
"watermarks": "watermarks",
|
| 843 |
+
"wdm": "wdm",
|
| 844 |
+
"web": "web",
|
| 845 |
+
"web-security": "web-security",
|
| 846 |
+
"web-server": "web-server",
|
| 847 |
+
"weight-balance": "weight-balance",
|
| 848 |
+
"windows-3.11": "windows-3.11",
|
| 849 |
+
"workflow": "workflow",
|
| 850 |
+
"x86_64": "x86_64",
|
| 851 |
+
"xss": "xss",
|
| 852 |
+
"zero-downtime": "zero-downtime"
|
| 853 |
+
},
|
| 854 |
+
"n_tags": 424
|
| 855 |
+
}
|
tags/train.py
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""Exact training call used for this model. Run from inside this directory:
|
| 2 |
+
python train.py
|
| 3 |
+
Same dim64/epoch10 baseline hyperparams as quality/multilingual, plus loss="ova"
|
| 4 |
+
(fastText's native multi-label mode): one shared model/vocabulary across all 424 tags,
|
| 5 |
+
trained jointly, rather than 424 separate binary classifiers -- see README.md."""
|
| 6 |
+
import fasttext
|
| 7 |
+
|
| 8 |
+
HPARAMS = dict(dim=64, epoch=10, lr=0.3, wordNgrams=2, minCount=3, bucket=2_000_000, loss="ova")
|
| 9 |
+
|
| 10 |
+
model = fasttext.train_supervised(input="train.txt", **HPARAMS)
|
| 11 |
+
model.save_model("model.bin")
|
| 12 |
+
print("saved model.bin")
|
tags/train.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:deafd9750d4d82b7209ee453381cc1bacf5dcae49bd125cdbf702f3136ec19af
|
| 3 |
+
size 1114536579
|
tags/val.txt
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:19ae51807b1c1d42981ec8d41907bddfa095358e301e59a7e689d6e01348f666
|
| 3 |
+
size 124512325
|