Spaces:
Running on Zero
Running on Zero
Download utils/preprocessing.py from wraithklu/toxiguard-api: direct link, hf CLI and curl.
- Browser
- Download file 5.5 kB
-
https://huggingface.co/spaces/wraithklu/toxiguard-api/resolve/main/utils/preprocessing.py
- Command line
-
hf download hf://spaces/wraithklu/toxiguard-api/utils/preprocessing.py
-
curl -L -o preprocessing.py https://huggingface.co/spaces/wraithklu/toxiguard-api/resolve/main/utils/preprocessing.py
5.5 kB
| """ | |
| ToxiGuard AI β Text Preprocessing Pipeline | |
| ============================================ | |
| Two distinct preprocessing pipelines optimised for different consumers: | |
| 1. preprocess_for_rules(text) β str | |
| Aggressive normalisation for the keyword rule engine. | |
| - Lowercases, strips URLs/emails, de-obfuscates leet-speak | |
| - Strips punctuation and non-ASCII (ASCII-safe for pattern matching) | |
| 2. preprocess_for_model(text) β str | |
| Light clean for DeBERTa tokenizer. | |
| - Removes URLs and excessive whitespace | |
| - Preserves unicode, emojis, and casing | |
| - DeBERTa's tokenizer handles the rest | |
| 3. preprocess(text) β dict [backward-compatible wrapper] | |
| Returns {"clean_text": ..., "rule_text": ..., "tokens": [...]} | |
| """ | |
| import re | |
| import string | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # LEET-SPEAK DE-OBFUSCATION MAP (rule engine only) | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| _OBFUSCATION_MAP: dict[str, str] = { | |
| "@": "a", | |
| "$": "s", | |
| "0": "o", | |
| "1": "i", | |
| "3": "e", | |
| "4": "a", | |
| "5": "s", | |
| "7": "t", | |
| "*": "", | |
| "!": "", | |
| "_": "", | |
| "-": " ", | |
| } | |
| _URL_RE = re.compile(r"https?://\S+|www\.\S+", re.IGNORECASE) | |
| _EMAIL_RE = re.compile(r"\S+@\S+\.\S+") | |
| _WHITESPACE_RE = re.compile(r"\s+") | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # PIPELINE 1 β Rule engine (aggressive, ASCII-safe) | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def preprocess_for_rules(text: str) -> str: | |
| """ | |
| Normalise text for the keyword rule engine. | |
| Steps: | |
| 1. Lowercase + strip | |
| 2. Remove URLs and email addresses | |
| 3. De-obfuscate leet-speak characters (@ β a, $ β s, etc.) | |
| 4. Drop non-ASCII (covers emoji that can't map to leet-speak) | |
| 5. Remove punctuation | |
| 6. Collapse whitespace | |
| """ | |
| if not text: | |
| return "" | |
| text = text.lower().strip() | |
| text = _URL_RE.sub(" ", text) | |
| text = _EMAIL_RE.sub(" ", text) | |
| for char, replacement in _OBFUSCATION_MAP.items(): | |
| text = text.replace(char, replacement) | |
| # Drop non-ASCII (emoji, exotic unicode) | |
| text = text.encode("ascii", "ignore").decode() | |
| # Remove punctuation but keep spaces | |
| text = text.translate(str.maketrans("", "", string.punctuation)) | |
| text = _WHITESPACE_RE.sub(" ", text).strip() | |
| return text | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # PIPELINE 2 β DeBERTa tokenizer (light clean, unicode-safe) | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def preprocess_for_model(text: str) -> str: | |
| """ | |
| Light normalisation for DeBERTa. | |
| DeBERTa's SentencePiece tokenizer handles: | |
| - Casing (it's uncased internally) | |
| - Punctuation | |
| - Unicode and emojis | |
| We only remove noise that adds no semantic value: | |
| - URLs | |
| - Email addresses | |
| - Excessive whitespace | |
| """ | |
| if not text: | |
| return "" | |
| text = _URL_RE.sub(" [URL] ", text) | |
| text = _EMAIL_RE.sub(" [EMAIL] ", text) | |
| text = _WHITESPACE_RE.sub(" ", text).strip() | |
| return text | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # BACKWARD-COMPAT WRAPPER | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def tokenize(text: str) -> list[str]: | |
| """Split rule-preprocessed text into tokens.""" | |
| if not text: | |
| return [] | |
| return text.split() | |
| def preprocess(text: str) -> dict: | |
| """ | |
| Full preprocessing pipeline β backward-compatible wrapper. | |
| Returns: | |
| { | |
| "clean_text": str β rule-safe (aggressive, ASCII) | |
| "model_text": str β model-safe (light, unicode) | |
| "tokens": list β tokens from clean_text | |
| } | |
| """ | |
| rule_text = preprocess_for_rules(text) | |
| model_text = preprocess_for_model(text) | |
| return { | |
| "clean_text": rule_text, # kept for backward compat | |
| "model_text": model_text, | |
| "tokens": tokenize(rule_text), | |
| } | |
| __all__ = [ | |
| "preprocess", | |
| "preprocess_for_rules", | |
| "preprocess_for_model", | |
| "tokenize", | |
| ] | |