Horizon-Labs's picture
v1.0: multilingual punctuation + truecasing (base)
b11a6e7 verified
Raw History Blame Contribute Delete
1.6 kB
"""Punctuation + truecasing: joint per-word labels = the punctuation mark that follows the word (punct/common.py: 0 . , ? - :) x the
word's casing. Casing classes from the original text: 'lower' (no upper-case first letter), 'Cap' (first cased letter upper, not all
upper), 'UPPER' (all cased letters upper, >= 2 of them). Words without cased letters (CJK, Arabic, ...) are 'lower'.
Inputs are always lowercased (ASR-style); the model restores marks and casing together."""
import os, sys
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "punct"))
from common import LABELS as PUNCT, NOSPACE, lower_keep_len # noqa: F401
CASES = ["lower", "Cap", "UPPER"]
LABELS = [f"{p}|{c}" for p in PUNCT for c in CASES]
L2I = {l: i for i, l in enumerate(LABELS)}
def case_of(word):
cased = [ch for ch in word if ch.lower() != ch.upper()]
if not cased:
return 0
if len(cased) >= 2 and all(ch.isupper() for ch in cased):
return 2
return 1 if cased[0].isupper() else 0
def unit_cases(text, ends, nospace):
"""case class per unit of a cased text; units end at `ends` (exclusive offsets)."""
out, prev = [], 0
for e in ends:
if nospace:
s = e - 1
else:
s = text.rfind(" ", 0, e) + 1
out.append(case_of(text[max(s, prev):e])); prev = e
return out
def apply_case(word, c):
if c == 2:
return word.upper()
if c == 1:
for i, ch in enumerate(word):
if ch.lower() != ch.upper():
return word[:i] + ch.upper() + word[i + 1:]
return word