Instructions to use FlowRank/mailSort with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use FlowRank/mailSort with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("text-classification", model="FlowRank/mailSort")# pip install -U transformers accelerate # Load model directly from transformers import AutoModel model = AutoModel.from_pretrained("FlowRank/mailSort", device_map="auto") - Notebooks
- Google Colab
- Kaggle
Commit ·
8d69eed
1
Parent(s): be4db4a
feat(training): support dataset revision for enrichment branch
Browse filesAjoute --dataset-revision à train et eval pour charger
FlowRank/labeled_emails@enrichment (20 labels).
Co-authored-by: Hilarion Lefuneste <hilarionlefuneste@tutamail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
- .gitignore +1 -0
- src/mailsort/eval.py +9 -1
- src/mailsort/train.py +11 -3
.gitignore
CHANGED
|
@@ -5,6 +5,7 @@ __pycache__/
|
|
| 5 |
|
| 6 |
# training outputs (local only)
|
| 7 |
outputs/
|
|
|
|
| 8 |
outputs_smoke/
|
| 9 |
|
| 10 |
# HF caches
|
|
|
|
| 5 |
|
| 6 |
# training outputs (local only)
|
| 7 |
outputs/
|
| 8 |
+
outputs-enrichment/
|
| 9 |
outputs_smoke/
|
| 10 |
|
| 11 |
# HF caches
|
src/mailsort/eval.py
CHANGED
|
@@ -11,6 +11,7 @@ from transformers import AutoModelForSequenceClassification, AutoTokenizer, pipe
|
|
| 11 |
@dataclass(frozen=True)
|
| 12 |
class Config:
|
| 13 |
dataset_id: str
|
|
|
|
| 14 |
model_id_or_path: str
|
| 15 |
subfolder: str | None
|
| 16 |
split: str
|
|
@@ -28,6 +29,11 @@ def _build_text(subject: str, body: str) -> str:
|
|
| 28 |
def _parse_args() -> Config:
|
| 29 |
p = argparse.ArgumentParser(description="Evaluate a model (local or Hub) against a HF dataset split.")
|
| 30 |
p.add_argument("--dataset-id", default="FlowRank/labeled_emails")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
p.add_argument("--model", default="outputs", help="Local path OR Hugging Face repo id (e.g. FlowRank/mailSort).")
|
| 32 |
p.add_argument("--subfolder", default=None, help="Optional subfolder (e.g. model).")
|
| 33 |
p.add_argument("--split", default="test", help="Which split to evaluate (e.g. test).")
|
|
@@ -35,6 +41,7 @@ def _parse_args() -> Config:
|
|
| 35 |
a = p.parse_args()
|
| 36 |
return Config(
|
| 37 |
dataset_id=a.dataset_id,
|
|
|
|
| 38 |
model_id_or_path=a.model,
|
| 39 |
subfolder=a.subfolder,
|
| 40 |
split=a.split,
|
|
@@ -45,7 +52,8 @@ def _parse_args() -> Config:
|
|
| 45 |
def main() -> int:
|
| 46 |
cfg = _parse_args()
|
| 47 |
|
| 48 |
-
|
|
|
|
| 49 |
if cfg.split not in ds:
|
| 50 |
raise SystemExit(f"Split '{cfg.split}' not found. Available: {list(ds.keys())}")
|
| 51 |
|
|
|
|
| 11 |
@dataclass(frozen=True)
|
| 12 |
class Config:
|
| 13 |
dataset_id: str
|
| 14 |
+
dataset_revision: str | None
|
| 15 |
model_id_or_path: str
|
| 16 |
subfolder: str | None
|
| 17 |
split: str
|
|
|
|
| 29 |
def _parse_args() -> Config:
|
| 30 |
p = argparse.ArgumentParser(description="Evaluate a model (local or Hub) against a HF dataset split.")
|
| 31 |
p.add_argument("--dataset-id", default="FlowRank/labeled_emails")
|
| 32 |
+
p.add_argument(
|
| 33 |
+
"--dataset-revision",
|
| 34 |
+
default=None,
|
| 35 |
+
help="Git revision of the dataset repo (branch, tag, or commit).",
|
| 36 |
+
)
|
| 37 |
p.add_argument("--model", default="outputs", help="Local path OR Hugging Face repo id (e.g. FlowRank/mailSort).")
|
| 38 |
p.add_argument("--subfolder", default=None, help="Optional subfolder (e.g. model).")
|
| 39 |
p.add_argument("--split", default="test", help="Which split to evaluate (e.g. test).")
|
|
|
|
| 41 |
a = p.parse_args()
|
| 42 |
return Config(
|
| 43 |
dataset_id=a.dataset_id,
|
| 44 |
+
dataset_revision=a.dataset_revision,
|
| 45 |
model_id_or_path=a.model,
|
| 46 |
subfolder=a.subfolder,
|
| 47 |
split=a.split,
|
|
|
|
| 52 |
def main() -> int:
|
| 53 |
cfg = _parse_args()
|
| 54 |
|
| 55 |
+
kwargs = {"revision": cfg.dataset_revision} if cfg.dataset_revision else {}
|
| 56 |
+
ds = load_dataset(cfg.dataset_id, **kwargs)
|
| 57 |
if cfg.split not in ds:
|
| 58 |
raise SystemExit(f"Split '{cfg.split}' not found. Available: {list(ds.keys())}")
|
| 59 |
|
src/mailsort/train.py
CHANGED
|
@@ -18,6 +18,7 @@ from transformers import (
|
|
| 18 |
@dataclass(frozen=True)
|
| 19 |
class Config:
|
| 20 |
dataset_id: str
|
|
|
|
| 21 |
model_name: str
|
| 22 |
hub_model_id: str
|
| 23 |
output_dir: str
|
|
@@ -41,6 +42,11 @@ def _build_text(subject: str, body: str) -> str:
|
|
| 41 |
def _parse_args() -> Config:
|
| 42 |
p = argparse.ArgumentParser(description="Train & push email classifier to Hugging Face Hub.")
|
| 43 |
p.add_argument("--dataset-id", default="FlowRank/labeled_emails")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 44 |
p.add_argument("--model-name", default="distilbert-base-uncased")
|
| 45 |
p.add_argument("--hub-model-id", default="FlowRank/mailSort")
|
| 46 |
p.add_argument("--output-dir", default="outputs")
|
|
@@ -54,6 +60,7 @@ def _parse_args() -> Config:
|
|
| 54 |
a = p.parse_args()
|
| 55 |
return Config(
|
| 56 |
dataset_id=a.dataset_id,
|
|
|
|
| 57 |
model_name=a.model_name,
|
| 58 |
hub_model_id=a.hub_model_id,
|
| 59 |
output_dir=a.output_dir,
|
|
@@ -67,8 +74,9 @@ def _parse_args() -> Config:
|
|
| 67 |
)
|
| 68 |
|
| 69 |
|
| 70 |
-
def _load_ds(dataset_id: str, seed: int) -> DatasetDict:
|
| 71 |
-
|
|
|
|
| 72 |
if "train" in ds and "test" in ds:
|
| 73 |
return ds # already split
|
| 74 |
# fallback: split if only a single split exists
|
|
@@ -99,7 +107,7 @@ def _compute_metrics(eval_pred):
|
|
| 99 |
def main() -> int:
|
| 100 |
cfg = _parse_args()
|
| 101 |
|
| 102 |
-
ds = _load_ds(cfg.dataset_id, seed=cfg.seed)
|
| 103 |
train_split = "train" if "train" in ds else list(ds.keys())[0]
|
| 104 |
test_split = "test" if "test" in ds else ("validation" if "validation" in ds else None)
|
| 105 |
|
|
|
|
| 18 |
@dataclass(frozen=True)
|
| 19 |
class Config:
|
| 20 |
dataset_id: str
|
| 21 |
+
dataset_revision: str | None
|
| 22 |
model_name: str
|
| 23 |
hub_model_id: str
|
| 24 |
output_dir: str
|
|
|
|
| 42 |
def _parse_args() -> Config:
|
| 43 |
p = argparse.ArgumentParser(description="Train & push email classifier to Hugging Face Hub.")
|
| 44 |
p.add_argument("--dataset-id", default="FlowRank/labeled_emails")
|
| 45 |
+
p.add_argument(
|
| 46 |
+
"--dataset-revision",
|
| 47 |
+
default=None,
|
| 48 |
+
help="Git revision of the dataset repo (branch, tag, or commit).",
|
| 49 |
+
)
|
| 50 |
p.add_argument("--model-name", default="distilbert-base-uncased")
|
| 51 |
p.add_argument("--hub-model-id", default="FlowRank/mailSort")
|
| 52 |
p.add_argument("--output-dir", default="outputs")
|
|
|
|
| 60 |
a = p.parse_args()
|
| 61 |
return Config(
|
| 62 |
dataset_id=a.dataset_id,
|
| 63 |
+
dataset_revision=a.dataset_revision,
|
| 64 |
model_name=a.model_name,
|
| 65 |
hub_model_id=a.hub_model_id,
|
| 66 |
output_dir=a.output_dir,
|
|
|
|
| 74 |
)
|
| 75 |
|
| 76 |
|
| 77 |
+
def _load_ds(dataset_id: str, seed: int, revision: str | None = None) -> DatasetDict:
|
| 78 |
+
kwargs = {"revision": revision} if revision else {}
|
| 79 |
+
ds = load_dataset(dataset_id, **kwargs)
|
| 80 |
if "train" in ds and "test" in ds:
|
| 81 |
return ds # already split
|
| 82 |
# fallback: split if only a single split exists
|
|
|
|
| 107 |
def main() -> int:
|
| 108 |
cfg = _parse_args()
|
| 109 |
|
| 110 |
+
ds = _load_ds(cfg.dataset_id, seed=cfg.seed, revision=cfg.dataset_revision)
|
| 111 |
train_split = "train" if "train" in ds else list(ds.keys())[0]
|
| 112 |
test_split = "test" if "test" in ds else ("validation" if "validation" in ds else None)
|
| 113 |
|