Token Classification
Transformers
Safetensors
ONNX
Transformers.js
modernbert
punctuation
punctuation-restoration
asr
speech-recognition
transcription
mmbert
Instructions to use seamon67/Punctuation-Restoration with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- Transformers
How to use seamon67/Punctuation-Restoration with Transformers:
# Use a pipeline as a high-level helper from transformers import pipeline pipe = pipeline("token-classification", model="seamon67/Punctuation-Restoration")# pip install -U transformers accelerate # Load model directly from transformers import AutoTokenizer, AutoModelForTokenClassification tokenizer = AutoTokenizer.from_pretrained("seamon67/Punctuation-Restoration") model = AutoModelForTokenClassification.from_pretrained("seamon67/Punctuation-Restoration", device_map="auto") - Transformers.js
How to use seamon67/Punctuation-Restoration with Transformers.js:
// npm i @huggingface/transformers import { pipeline } from '@huggingface/transformers'; // Allocate pipeline const pipe = await pipeline('token-classification', 'seamon67/Punctuation-Restoration'); - Notebooks
- Google Colab
- Kaggle
Download code/punct/common.py from seamon67/Punctuation-Restoration: direct link, hf CLI and curl.
- Browser
- Download file 5.07 kB
-
https://huggingface.co/seamon67/Punctuation-Restoration/resolve/main/code/punct/common.py
- Command line
-
hf download hf://seamon67/Punctuation-Restoration/code/punct/common.py
-
curl -L -o common.py https://huggingface.co/seamon67/Punctuation-Restoration/resolve/main/code/punct/common.py
5.07 kB
| """Punctuation restoration: shared text normalisation (training data, evaluation, inference helper). | |
| Labels = those of oliverguhr/fullstop-punctuation-multilang-large and kredor/punctuate-all, so the models are drop-ins | |
| for the `deepmultilingualpunctuation` package: "0" (none) . , ? - : - each is the mark that FOLLOWS a word. | |
| Mapping: ! ; … and script full stops (。!.।॥۔።။։) -> "."; ,、،፣ -> ","; ?؟፧ (and ";" in Greek) -> "?"; :-> ":"; | |
| a free-standing dash (- – — --) -> "-". Inverted marks ¿ ¡ are removed. Marks between digits (3.14, 1,000, 10:30) are text. | |
| Units: whitespace words; for Chinese and Japanese every non-space character is a unit. | |
| """ | |
| import re | |
| LABELS = ["0", ".", ",", "?", "-", ":"] | |
| L2I = {l: i for i, l in enumerate(LABELS)} | |
| NOSPACE = {"cmn_Hani", "jpn_Jpan", "zho_Hans", "zho_Hant", "yue_Hani", "wuu_Hani"} | |
| SKIP = {"tha_Thai", "lao_Laoo", "khm_Khmr", "mya_Mymr", "bod_Tibt"} # no comparable punctuation conventions | |
| MAP = {".": ".", "!": ".", ";": ".", "…": ".", "。": ".", "!": ".", ".": ".", "।": ".", "॥": ".", "۔": ".", "።": ".", "။": ".", | |
| "։": ".", ";": ".", "؛": ".", "。": ".", | |
| ",": ",", ",": ",", "、": ",", "،": ",", "፣": ",", "、": ",", | |
| "?": "?", "?": "?", "؟": "?", "፧": "?", ";": ".", | |
| ":": ":", ":": ":"} | |
| DROP = set("¿¡") | |
| DASH = re.compile(r"^(?:-{1,2}|–|—)$") | |
| PRI = {"?": 4, ".": 3, ":": 2, "-": 1, ",": 1, "0": 0} | |
| def _marks(lang): | |
| m = dict(MAP) | |
| if lang == "ell_Grek": | |
| m[";"] = "?"; m[";"] = "?" | |
| return m | |
| def _between_digits(s, i): | |
| return 0 < i < len(s) - 1 and s[i - 1].isdigit() and s[i + 1].isdigit() and s[i] in ".,:" | |
| def units(text, lang): | |
| """original punctuated text -> (clean text, unit ends (char offsets in clean text), labels (strings)). | |
| The clean text is what a user would feed: target marks removed, other symbols (quotes, brackets, hyphens) kept.""" | |
| m = _marks(lang) | |
| if lang in NOSPACE: | |
| out, ends, labs = [], [], [] | |
| for i, c in enumerate(text): | |
| if c in DROP: | |
| continue | |
| if c in m and not _between_digits(text, i) or (c in "-–—" and lang in NOSPACE and c != "-"): | |
| lab = m.get(c, "-") | |
| if labs and PRI[lab] > PRI[labs[-1]]: | |
| labs[-1] = lab | |
| continue | |
| if c.isspace(): | |
| if out and not out[-1].isspace(): | |
| out.append(" ") | |
| continue | |
| out.append(c) | |
| ends.append(len(out)); labs.append("0") | |
| return "".join(out).strip(), ends, labs | |
| words, labs, dots = [], [], [] | |
| for w in text.split(): | |
| if DASH.match(w): | |
| if words and labs[-1] == "0": | |
| labs[-1] = "-" | |
| continue | |
| core, lab, trailing = [], "0", True | |
| for i in range(len(w) - 1, -1, -1): # label = strongest mark in the trailing non-alphanumeric run | |
| c = w[i] | |
| if c.isalnum(): | |
| trailing = False | |
| if c in m and not _between_digits(w, i): | |
| if trailing and PRI[m[c]] > PRI[lab]: | |
| lab = m[c] | |
| continue | |
| if c in DROP: | |
| continue | |
| core.append(c) | |
| core = "".join(reversed(core)) | |
| if not core.strip() or not any(ch.isalnum() for ch in core) and not core.strip("\"'«»„“”‘’()[]{}*"): | |
| if words and PRI[lab] > PRI[labs[-1]]: | |
| labs[-1] = lab | |
| if not core.strip(): | |
| continue | |
| words.append(core); labs.append(lab); dots.append(lab == "." and w.rstrip("\"'»”’)]").endswith(".")) | |
| for i in range(len(words) - 1): # "." before a lowercase word is an abbreviation (e.g., U.S. policy), not a full stop | |
| if dots[i] and words[i + 1][:1].islower(): | |
| labs[i] = "0" | |
| clean, ends, pos = [], [], 0 | |
| for w in words: | |
| if clean: | |
| pos += 1 | |
| pos += len(w); ends.append(pos); clean.append(w) | |
| return " ".join(clean), ends, labs | |
| def lower_keep_len(t): | |
| return "".join(c.lower() if len(c.lower()) == 1 else c for c in t) | |
| def token_labels(offsets, ends, labs): | |
| """token offsets (fast tokenizer) -> label id per token: a token that ends where a unit ends gets the unit's label, | |
| other tokens -100 (inside a unit, special tokens).""" | |
| at = dict(zip(ends, labs)) | |
| out = [] | |
| for s, e in offsets: | |
| out.append(L2I[at[e]] if e > s and e in at else -100) | |
| return out | |
| def unit_preds(offsets, pred_ids, ends): | |
| """per-token predicted label ids -> label string per unit (the token ending at the unit end; "0" if none does).""" | |
| at = {e: p for (s, e), p in zip(offsets, pred_ids) if e > s} | |
| return [LABELS[at[e]] if e in at else "0" for e in ends] | |
| def restore(clean, ends, labs): | |
| out, prev = [], 0 | |
| for e, l in zip(ends, labs): | |
| out.append(clean[prev:e] + ("" if l == "0" else (" -" if l == "-" else l))); prev = e | |
| return "".join(out) + clean[prev:] | |