Views
No views yet
1$ curl -s localhost:8000/predict -H 'content-type: application/json' -d '{
2 "features": {"URLLength": 31, "DomainLength": 25, "IsHTTPS": 1, "...": "all 49"}
3 }'
4{
5 "model": "nb_sklearn",
6 "label": 1,
7 "verdict": "legitimate",
8 "phishing_score": 0.0,
9 "n_provided": 33,
10 "n_imputed": 16,
11 "coverage_ratio": 0.6735,
12 "low_evidence": false
13}This is a coursework reimplementation, not a security product. It is trained on a static 2023–24 dataset, has no threat intelligence, no blocklist, and no knowledge of any campaign newer than its training data. Do not use it to decide whether a link is safe.
Gaussian Naive Bayes (scikit-learn) · Trained on PhiUSIIL · SMOTE · Feature Engineering| Route | Purpose |
|---|---|
POST /predict | one row → verdict, score, and how much of the row was real |
POST /predict/batch | up to 1000 rows |
GET /metadata | the feature contract, the demoted features, and this model's metrics |
GET /healthz | liveness |
GET /readyz | ready once the golden-row self-test has passed |
1make install # venv + pinned dependencies
2make selftest # prove the artifact reproduces its recorded prediction
3make serve # http://127.0.0.1:8000 (docs at /docs)model/), so a fresh clone can serve immediately.make docker-build && docker run -p 8000:8000 fetiai-v1-phiusiil-binclf-gnb-skl-202p:localnull is allowed and is the expected value for a feature the
caller could not determine — 12 of the 49 are permanently null, having failed the
extraction agreement gate in the parent project.1{
2 "features": { "URLLength": 31, "DomainLength": 25, "IsHTTPS": 1, /* ...46 more */ },
3 "url": "https://example.com/login", // optional
4 "domain": "example.com", // optional
5 "tld": "com", // optional
6 "title": "Sign in" // optional
7}GET /metadata returns the exact 49 names in order. Three of them carry typos that are
preserved on purpose — NoOfDegitsInURL, DegitRatioInURL, SpacialCharRatioInURL —
because those names are what the training data means.n_provided, n_imputed, coverage_ratio and low_evidence.
Without them a verdict drawn from six real values looks precisely as confident as one drawn
from all 49.url, domain, tld and title fields are worth sending when you have
them: 21 of the 49 features are derived from the URL string, and supplying it lets those be
recomputed rather than imputed.| Model | Phishing recall | Phishing precision | Accuracy |
|---|---|---|---|
| Gaussian Naive Bayes (scikit-learn) | 0.888 | 0.877 | 0.98191 |
fetiai-v1-phiusiil-binclf-gnb-scratch-198p.model/metrics.json also carries the legacy profile, flagged "leaky": true. It
reconstructs the original notebook's configuration, which standardised each split by its
own mean and standard deviation — information no deployed model can have, since there is no
batch to average over when a single row arrives. It is kept as evidence of what the leak
was worth and is never presented as this model's result.| Path | What it is |
|---|---|
model/nb_sklearn.joblib | the trained model (202 parameters) |
model/fitted_stats.json | not optional — the scaler, imputation values, clip bounds and mode tables |
model/manifest.json | sha256 of every file above, verified at load |
model/golden_row.json | one record with its expected vector and prediction |
phiusiil/ | the scoring path: schema, preprocessing, and this one model class |
server/ | loader, prediction, HTTP layer |
fitted_stats.json deserves the emphasis. The model alone cannot classify anything: it was
fitted on standardised inputs, and the numbers that produce that standardisation live in
that file. Publishing weights without it would be publishing something unusable.fit method attached, and the defect this whole pipeline exists to avoid is someone
calling it at serving time. Numbers that cannot be re-fitted cannot leak.The model file is a pickle.joblib.loadexecutes code, so treat it as you would any executable, and note that it was produced by scikit-learn 1.9.0 — loading it under a different version is unsupported. It holds a bare scikit-learn estimator rather than a wrapper class, so unpickling depends on scikit-learn alone and on nothing defined in this repository. If you want a model that loads without executing anything, the from-scratch counterpart infetiai-v1-phiusiil-binclf-gnb-scratch-198pis plain a JSON table of per-class means and standard deviations.
1make selftest # golden row, offline
2make test # golden row + HTTP contract + naming
3make namecheck # provenance hygieneorigin.json records where every copied file came from, including the parent bundle's own
hashes, so drift is detectable without the parent repository present.LICENSE.
![]() Thalita Zahra Sutejo 18222023 |
![]() Irfan Musthofa 18222056 |
![]() Eleanor Cordelia 18222059 |
![]() Muhammad Faiz Atharrahman 18222063 |