Instructions to use zero0303/maya2-mlx-dynamic-8bit with libraries, inference providers, notebooks, and local apps. Follow these links to get started.
- Libraries
- MLX
How to use zero0303/maya2-mlx-dynamic-8bit with MLX:
# Download the model from the Hub pip install huggingface_hub[hf_xet] hf download zero0303/maya2-mlx-dynamic-8bit --local-dir maya2-mlx-dynamic-8bit
- Notebooks
- Google Colab
- Kaggle
- Local Apps Settings
- LM Studio
- Atomic Chat
File size: 16,420 Bytes
23c283a | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | """Targeted pre/post rules around the vendored normaliser (maya3.text.tn), derived from the eval rows that still
failed with text normalisation on.
The vendored copy stays byte-identical. Each rule rewrites one input shape that the strict normaliser either rejects
(it then falls back to reading the span character by character: "15-08-25" -> "one five minus zero eight minus two
five") or reads in a way listeners do not expect (a PIN code as "five lakh sixty thousand thirty eight"):
R1 date_2y DD-MM-YY, DD/MM/YY, DD.MM.YY -> four-digit year (pivot: 00-50 -> 20xx, 51-99 -> 19xx),
then the normaliser's own date reading
R2 expiry MM/YY or MM/YYYY next to an expiry / validity / date word or a CVV -> "<month> <year>"
R3 fy_range 2023-24 (second part = next year) -> "<year> <two-digit number>"
R4 digit_groups 4111 2233 4455 6677, 98765 43210, 1800 123 4567 (>= 10 digits in space-separated groups)
-> one digit run, which the normaliser reads digit by digit
R5 pin_keyword PIN / पिन / ... followed by 4-6 digits -> digit by digit
R6 pincode a bare 6-digit number (no currency or unit next to it, no grouping commas) -> digit by digit
R7 version v4.5.2 -> "v four point five point two" (language's decimal word)
R8 ta_date_year Tamil "ஆகஸ்ட் 15, 2025" -> "15 ஆகஸ்ட் 2025" (the normaliser keeps the year)
R10 pct_range 3.5%-4% -> 3.5-4% (the normaliser's own percent range)
R11 per_price ₹500/kg -> "<amount> <per word> K G"
R12 per_annum 8.5% p.a. -> "P A" (en: "per annum")
R9 paise rupee amounts with two decimals read "<n> rupees <m> paise" in every language (the tables of
bn en gu kn ml mr pa ta had no paise word, so they read "point five zero rupees")
post:
P1 tag_comma a piece that ends in "," before an inline [tag] keeps its comma (the normaliser turns a trailing
comma into a full stop, and the model then ends the sentence at the tag)
P2 uri_dash "-" inside an e-mail / URL is spoken in the request language, not as the English word "dash"
P3 uri_acronym lowercase acronym labels in an e-mail / URL (sbi, kyc, hdfc in hdfcbank, sbi in onlinesbi) are
spelled letter by letter in the request language; other labels keep their English spelling
Language-table corrections (Assamese lexicon, "per" units, sub-domain hosts) live in maya3.text.lexicon.
"""
from __future__ import annotations
import re
__all__ = ["pre", "post", "install", "RULES"]
RULES = ("date_2y", "expiry", "fy_range", "digit_groups", "pin_keyword", "pincode", "version", "ta_date_year",
"paise", "pct_range", "per_price", "per_annum", "tag_comma", "uri_dash", "uri_acronym")
PAISE = {"en": "paise", "bn": "পয়সা", "gu": "પૈસા", "kn": "ಪೈಸೆ", "ml": "പൈസ", "mr": "पैसे", "pa": "ਪੈਸੇ",
"ta": "பைசா"} # hi as or te already have one
DASH = {"hi": "डैश", "mr": "डॅश", "bn": "ড্যাশ", "as": "ডেশ্ব", "gu": "ડૅશ", "pa": "ਡੈਸ਼", "or": "ଡ୍ୟାସ୍",
"ta": "டாஷ்", "te": "డాష్", "kn": "ಡ್ಯಾಶ್", "ml": "ഡാഷ്"}
# expiry / validity / date words (any language; matched case-insensitively in the 40 characters before the span)
_EXPIRY_WORDS = [
"expiry", "expires", "expire", "exp", "valid", "validity", "thru", "expiration",
"एक्सपायरी", "समाप्ति", "वैधता", "मुदत", "समाप्ती",
"মেয়াদ", "মেয়াদ", "এক্সপায়ারি", "এক্সপায়ারি", "এক্সপায়াৰী", "ম্যাদ",
"એક્સપાયરી", "સમાપ્તિ", "માન્યતા", "ਮਿਆਦ", "ਐਕਸਪਾਇਰੀ",
"காலாவதி", "எக்ஸ்பைரி", "గడువు", "ఎక్స్పైరీ", "ఎక్స్పైరీ",
"ಮುಕ್ತಾಯ", "ಅಂತಿಮ ದಿನಾಂಕ", "ಎಕ್ಸ್ಪೈರಿ", "കാലാവധി", "എക്സ്പയറി", "ମିଆଦ", "ଏକ୍ସପାୟାରୀ", "ସମାପ୍ତି",
]
_DATE_WORDS = ["date", "तारीख", "तिथि", "दिनांक", "डेट", "তারিখ", "তাৰিখ", "તારીખ", "ડેટ", "ਤਾਰੀਖ਼", "ਤਾਰੀਖ", "ਡੇਟ",
"தேதி", "டேட்", "తేదీ", "డేట్", "ದಿನಾಂಕ", "ಡೇಟ್", "തീയതി", "ഡേറ്റ്", "ତାରିଖ", "ଡେଟ୍"]
_alt = lambda ws: "|".join(sorted(map(re.escape, ws), key=len, reverse=True))
_EXPIRY_RE = re.compile(_alt(_EXPIRY_WORDS), re.I)
_DATE_RE = re.compile(_alt(_DATE_WORDS), re.I)
_PIN_WORDS = ["pin", "पिन", "पिनकोड", "ಪಿನ್", "పిన్", "பின்", "പിൻ", "পিন", "ପିନ", "ਪਿੰਨ", "ਪਿਨ", "પિન"]
_PIN_RE = re.compile(r"(?<![\w])(?:" + "|".join(map(re.escape, _PIN_WORDS)) + r")(?:[\s-]*(?:code|कोड|কোড|કોડ|ਕੋਡ|କୋଡ|ಕೋಡ್|కోడ్|கோட்|കോഡ്))?"
r"(?:\s*(?:no\.?|number|नंबर|नम्बर))?\s*[:\-]?\s*(\d{4,6})(?![\d,]|\.\d)", re.I)
# words right after a number that make it an amount / quantity (R6 must not read those digit by digit)
_AMOUNT_AFTER = re.compile(
r"\s*(?:rupees?|rs\.?|inr|dollars?|usd|paise|lakh|crore|thousand|people|users|customers|km|kg|kms|"
r"रुपये|रुपए|रुपया|रु\.?|लाख|करोड़|हज़ार|हजार|लोग|লাখ|টাকা|টকা|কোটি|રૂપિયા|લાખ|ਰੁਪਏ|ਲੱਖ|ரூபாய்|ரூ\.?|லட்சம்|"
r"రూపాయలు|రూ\.?|లక్షల|ರೂಪಾಯಿ|ರೂ\.?|ಲಕ್ಷ|രൂപ|ലക്ഷം|ଟଙ୍କା|ଲକ୍ଷ|ਕਰੋੜ|कोटी)(?![\w])", re.I)
_CURRENCY_BEFORE = re.compile(r"(?:₹|\$|€|£|\brs\.?|\binr|रु\.?|ரூ\.?|రూ\.?|ರೂ\.?)\s*$", re.I)
_NUMBER_WORD_BEFORE = re.compile(
r"(?:\bno\.?|\bnumber|\bplot|\bflat|\bhouse|\bdoor|\bh\.\s?no\.?|नंबर|नम्बर|क्रमांक|नं\.?|নং|নম্বর|নম্বৰ|ਨੰਬਰ|નંબર|ନମ୍ବର|"
r"எண்|నంబర్|ಸಂಖ್ಯೆ|ನಂಬರ್|നമ്പർ)\s*[:\-]?\s*$", re.I)
_TA_MONTHS = ["ஜனவரி", "பிப்ரவரி", "மார்ச்", "ஏப்ரல்", "மே", "ஜூன்", "ஜூலை", "ஆகஸ்ட்", "செப்டம்பர்", "அக்டோபர்",
"நவம்பர்", "டிசம்பர்"]
_URI_RE = re.compile(r"https?://\S+|www\.\S+|\b[\w.%+\-]+@[\w.\-]+\.[A-Za-z]{2,}|\b[A-Za-z][\w.\-]*@[A-Za-z][A-Za-z0-9]{1,15}\b|\b[A-Za-z][\w\-]*(?:\.[A-Za-z0-9][\w\-]*)*\.(?:com|org|net|ai|io|co|dev|app|edu|gov|in)(?:\.(?:in|uk|us))?(?:[/?#][^\s<>]*)?")
# P3: lowercase acronym labels inside e-mail / URL hosts and paths are spelled letter by letter (sbi.co.in ->
# "S B I dot co dot in", hdfcbank.com -> "H D F C bank dot com"); other labels keep their English spelling.
_URI_ACRONYMS = {"sbi", "hdfc", "icici", "kyc", "irctc", "pnb", "rbi", "idbi", "npci", "uidai", "epfo", "mf", "lic",
"upi", "gst", "sms", "atm", "emi", "bob", "boi", "uco", "iob", "nsdl", "cdsl", "pnr", "otp", "ifsc"}
_URI_ACR_PREFIX = ("icici", "irctc", "uidai", "hdfc", "idbi", "npci", "epfo", "sbi", "pnb", "kyc", "rbi")
_URI_ACR_SUFFIX = ("sbi", "mf")
_SPELL_UNITS = {"kg", "km", "gm", "g", "ml", "ltr", "l"} # R11: read letter by letter (as the normaliser reads "15 kg")
_installed = False
def install(on: bool = True):
"""R9: add the paise word to the language tables that lack it (bn en gu kn ml mr pa ta), so the normaliser's own
main+sub-unit path reads ₹95.41 as "<n> rupees <m> paise" (with its native scale words and case suffixes).
The tables are module-level; install(False) removes the added words again (used only by rules=False, the
eval-parity mode; do not mix rules=False with concurrent rules=True calls)."""
global _installed
if on == _installed:
return
from maya3.text.tn.normalize import language_table
for code, word in PAISE.items():
sym = language_table(code).SYM
if on:
sym.setdefault("paisa", word)
elif sym.get("paisa") == word:
del sym["paisa"]
_installed = on
def _table(lang):
from maya3.text.tn.normalize import language_table
return language_table(lang)
def _tn_id_context(L, before):
"""True when the normaliser itself will read the next number digit by digit (an ID keyword such as PIN / OTP /
number in the three tokens before it); the rule then leaves the span alone so the normaliser's postposition
sandhi ("...ಒಂದರಲ್ಲಿ") is kept."""
from maya3.text.tn import normalize as _N # the function; its module holds the keyword sets
import sys
mod = sys.modules["maya3.text.tn.normalize"]
kws = mod._ID_KEYWORDS_EN | mod._OTP_INPUT_WORDS | {w.lower() for w in L.ID_KEYWORDS}
toks = re.findall(r"[\w#\u0900-\u0DFF']+", before.replace("\u200c", "").lower())[-3:]
return any(t in kws for t in toks)
def _digits(L, s):
return ", ".join(L.digit(int(c)) for c in s)
def _year4(yy):
y = int(yy)
return 2000 + y if y <= 50 else 1900 + y
def _decimal_word(L):
w = L.decimal(1, "2")
a, b = L.cardinal(1), L.digit(2)
return w[len(a):len(w) - len(b)].strip() if w.startswith(a) and w.endswith(b) else "point"
def pre(text: str, lang: str) -> str:
"""Apply R1-R8 outside e-mail / URL spans (those are identifiers, spelled by the normaliser)."""
try:
L = _table(lang)
except Exception:
return text
out, pos = [], 0
for m in _URI_RE.finditer(text):
out.append(_pre(text[pos:m.start()], lang, L)); out.append(m.group(0)); pos = m.end()
out.append(_pre(text[pos:], lang, L))
return "".join(out)
def _pre(text, lang, L):
t = text
# R10 percent ranges written with the sign twice: 3.5%-4% (the normaliser read "...percentminus four percent")
t = re.sub(r"(?<![\d.])(\d+(?:\.\d+)?)\s?%\s?[-–]\s?(\d+(?:\.\d+)?)\s?%", r"\1-\2%", t)
# R11 price per unit: ₹500/kg (the "/" was dropped and "kg" left in Latin letters)
def r11(m):
unit, per = m.group(2), L.SYM.get("per") or "per"
if lang != "en" and unit.lower() in _SPELL_UNITS:
unit = " ".join(L.letter(c) for c in unit.upper())
return f"{m.group(1)} {per} {unit}"
t = re.sub(r"((?:[₹$€£]|\b(?:Rs\.?|INR)\s?)\s?\d[\d,]*(?:\.\d+)?)\s?/\s?(kg|km|gm|g|ml|ltr|l|day|month|night|year|person)\b", r11, t,
flags=re.I)
# R12 "p.a." (per annum) after a rate was left as the raw token "p.a."
t = re.sub(r"(?<![\w.])[pP]\.\s?[aA]\.?(?![\w])", lambda m: "per annum" if lang == "en" else f"{L.letter('P')} {L.letter('A')}", t)
# R7 version strings
def r7(m):
parts = m.group(1).split(".")
dw = _decimal_word(L)
return f"{L.letter('v')} " + f" {dw} ".join(L.cardinal(int(p)) for p in parts)
t = re.sub(r"(?<![\w.])[vV](\d+(?:\.\d+){1,3})(?![\w]|\.\d)", r7, t)
# R4 space-separated digit groups (card / phone numbers): join into one run (>= 10 digits in total)
def r4(m):
groups = m.group(0).split()
return "".join(groups) if sum(len(g) for g in groups) >= 10 else m.group(0)
t = re.sub(r"(?<![\d,.])(?:\d{4,5}(?: \d{3,5}){1,3}|\d{2,4} \d{3,4} \d{4})(?![\d,]|\.\d)", r4, t)
# R1 dates with a two-digit year
def r1(m):
d, sep, mo, yy = m.group(1), m.group(2), m.group(3), m.group(4)
if not (1 <= int(d) <= 31 and 1 <= int(mo) <= 12):
return m.group(0)
if sep == "-" and len(d) == 1 and len(mo) == 1: # 8-2-45: a door number, not a date
return m.group(0)
if _NUMBER_WORD_BEFORE.search(t[max(0, m.start() - 16):m.start()]): # "House No. 12-5-24", "ঘৰ নং ..."
return m.group(0)
return f"{d}{sep}{mo}{sep}{_year4(yy)}"
t = re.sub(r"(?<![\d/.\-])(\d{1,2})([/.\-])(\d{1,2})\2(\d{2})(?![\d/\-]|\.\d)", r1, t)
# R2 card expiry / month-year next to an expiry, date or CVV word
def r2(m):
mo, y = int(m.group(1)), m.group(2)
before = t[max(0, m.start() - 40):m.start()]
after = t[m.end():m.end() + 40]
strong = _EXPIRY_RE.search(before) or re.search(r"\bcvv\b", before + " " + after, re.I)
weak = _DATE_RE.search(before) and (len(y) == 4 or int(y) > 12) # second part > 12: not DD/MM, so MM/YY
if not (strong or weak):
return m.group(0)
year = int(y) if len(y) == 4 else 2000 + int(y)
return f"{L.month(mo)} {L.year(year)}"
t = re.sub(r"(?<![\d/.\-])(0?[1-9]|1[0-2])/(\d{2}|20\d{2})(?![\d/]|\.\d)", r2, t)
# R3 financial-year ranges 2023-24
def r3(m):
y, yy = int(m.group(1)), int(m.group(2))
if (y + 1) % 100 != yy:
return m.group(0)
return f"{L.year(y)} {L.cardinal(yy)}"
t = re.sub(r"(?<![\d\-])((?:19|20)\d{2})[-–](\d{2})(?![\d\-])", r3, t)
# R5 PIN keyword + digits
def r5(m):
if _tn_id_context(L, t[max(0, m.start(1) - 60):m.start(1)]):
return m.group(0)
return m.group(0)[:m.start(1) - m.start(0)] + _digits(L, m.group(1))
t = _PIN_RE.sub(r5, t)
# R6 bare six-digit numbers (Indian PIN codes): digit by digit unless an amount / quantity
def r6(m):
before = t[max(0, m.start() - 8):m.start()]
if (_CURRENCY_BEFORE.search(before) or _AMOUNT_AFTER.match(t, m.end())
or re.search(r"[A-Za-z0-9]\s?-\s?$|[#÷×*/+=<>]\s*$", before) # ID suffix (CUST-567890), #ref, maths
or re.match(r"\s*[÷×*/+=<>^]", t[m.end():])
or _tn_id_context(L, re.split(r"[.!?;।॥\n]", t[max(0, m.start() - 60):m.start()])[-1])):
return m.group(0)
return _digits(L, m.group(0))
t = re.sub(r"(?<![\d,.₹$#\w])[1-9]\d{5}(?![\d,]|\.\d|\s*%)", r6, t)
# R8 Tamil "Month D, YYYY" -> "D Month YYYY"
if lang == "ta":
months = "|".join(_TA_MONTHS)
t = re.sub(rf"(?<!\w)({months})\s+(\d{{1,2}}),?\s+(\d{{4}})(?!\d)", r"\2 \1 \3", t)
return t
TAG_COMMA = False # P1 off: no measured gain (6 vs 6 backstop cuts on the 14 affected emotion rows x2 seeds)
def post(out: str, seg: str, lang: str, before_tag: bool) -> str:
# P1 keep a trailing comma that precedes an inline [tag] (disabled, see TAG_COMMA)
if TAG_COMMA and before_tag and seg.rstrip().endswith(",") and out.rstrip().endswith("."):
out = out.rstrip()[:-1] + ","
# P2 spoken hyphen inside e-mail / URL in the request language
uris = [m.group(0) for m in _URI_RE.finditer(seg)]
if lang in DASH and uris:
out = re.sub(r"(?<=\s)dash(?=\s)", DASH[lang], out)
# P3 acronym labels inside e-mail / URL
labels = {w for u in uris for w in re.findall(r"[a-z]+", re.sub(r"^https?://", "", u))
if w in _URI_ACRONYMS or w.startswith(_URI_ACR_PREFIX) or w.endswith(_URI_ACR_SUFFIX)}
if labels:
try:
L = _table(lang)
except Exception:
return out
spell = lambda w: " ".join(L.letter(c.upper()) for c in w)
def p3(m):
w = m.group(0)
if w in _URI_ACRONYMS:
return spell(w)
for a in _URI_ACR_PREFIX:
if w.startswith(a) and len(w) - len(a) >= 3:
return spell(a) + " " + w[len(a):]
for a in _URI_ACR_SUFFIX:
if w.endswith(a) and len(w) - len(a) >= 4:
return w[:-len(a)] + " " + spell(a)
return w
out = re.sub(r"(?<![\w.@/])(?:" + "|".join(sorted(map(re.escape, labels), key=len, reverse=True)) + r")(?![\w]|[.@/\-]\w)",
p3, out)
return out
|