Spaces:
Sleeping
Sleeping
| """ | |
| preprocess.py β Input normalization pipeline for AnveshAI Edge. | |
| Normalizes raw user input before it reaches the router or engines. | |
| Fixes broken Unicode, arrows, delta signs, superscripts, OCR artifacts, | |
| extra whitespace, and unit prefixes so downstream regex patterns see | |
| consistent ASCII-like text. | |
| Call normalize_input() once at the entry point (classify_intent / solve). | |
| """ | |
| import re | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Superscript / subscript digit tables | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| _SUPERSCRIPT_MAP: dict[str, str] = { | |
| '\u2070': '^0', '\u00b9': '^1', '\u00b2': '^2', '\u00b3': '^3', | |
| '\u2074': '^4', '\u2075': '^5', '\u2076': '^6', '\u2077': '^7', | |
| '\u2078': '^8', '\u2079': '^9', | |
| '\u207a': '^+', '\u207b': '^-', '\u207f': '^n', | |
| '\u00b0': ' degrees', # degree sign Β° β fits naturally here | |
| } | |
| _SUBSCRIPT_MAP: dict[str, str] = { | |
| '\u2080': '_0', '\u2081': '_1', '\u2082': '_2', '\u2083': '_3', | |
| '\u2084': '_4', '\u2085': '_5', '\u2086': '_6', '\u2087': '_7', | |
| '\u2088': '_8', '\u2089': '_9', | |
| } | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Ordered symbol-replacement table | |
| # (longer / more specific entries first to avoid partial overwrites) | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| _SYMBOL_REPLACEMENTS: list[tuple[str, str]] = [ | |
| # ββ Calculus / set / summation symbols ββββββββββββββββββββββββββββββββββββ | |
| ('\u222b', 'integrate '), # β« | |
| ('\u2211', 'sum of '), # β | |
| ('\u220f', 'product of '), # β | |
| ('\u2202', 'd'), # β (partial diff) | |
| ('\u221e', 'oo'), # β | |
| ('\u2207', 'nabla '), # β | |
| # ββ Arrows (longest / most specific first) ββββββββββββββββββββββββββββββββ | |
| ('\u27f9', ' => '), # βΉ long double right | |
| ('\u27f6', ' -> '), # βΆ long right | |
| ('\u21d2', ' => '), # β double right | |
| ('\u2192', ' -> '), # β | |
| ('\u21d0', ' <= '), # β | |
| ('\u2190', ' <- '), # β | |
| ('\u21d4', ' <=> '), # β | |
| ('\u2194', ' <-> '), # β | |
| # ββ Delta / gradient ββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ('\u0394', 'delta '), # Ξ (capital) | |
| ('\u2206', 'delta '), # β (increment sign, often confused with Ξ) | |
| ('\u03b4', 'delta '), # Ξ΄ (lowercase) | |
| # ββ Greek letters (common in science) ββββββββββββββββββββββββββββββββββββ | |
| ('\u03bc', 'micro'), # Β΅ (micro prefix, e.g. Β΅C, Β΅m) | |
| ('\u00b5', 'micro'), # Β΅ (alternative encoding) | |
| ('\u03a9', 'ohm'), # Ξ© | |
| ('\u03c9', 'omega'), # Ο | |
| ('\u03b1', 'alpha'), # Ξ± | |
| ('\u03b2', 'beta'), # Ξ² | |
| ('\u03b3', 'gamma'), # Ξ³ | |
| ('\u03bb', 'lambda'), # Ξ» | |
| ('\u03b8', 'theta'), # ΞΈ | |
| ('\u03c6', 'phi'), # Ο | |
| ('\u03c0', 'pi'), # Ο (only in isolation β keep as 'pi') | |
| ('\u03b5', 'epsilon'), # Ξ΅ | |
| ('\u03c3', 'sigma'), # Ο | |
| ('\u03c4', 'tau'), # Ο | |
| ('\u03b7', 'eta'), # Ξ· | |
| ('\u03ba', 'kappa'), # ΞΊ | |
| ('\u03bd', 'nu'), # Ξ½ | |
| ('\u03c1', 'rho'), # Ο | |
| ('\u03c7', 'chi'), # Ο | |
| # ββ Math operators ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ('\u00d7', ' cross '), # Γ (vector cross / multiplication) | |
| ('\u00f7', '/'), # Γ· | |
| ('\u2212', '-'), # β (unicode minus β ASCII hyphen) | |
| ('\u2013', '-'), # β en dash | |
| ('\u2014', '-'), # β em dash | |
| ('\u00b1', '+/-'), # Β± | |
| ('\u2264', '<='), # β€ | |
| ('\u2265', '>='), # β₯ | |
| ('\u2260', '!='), # β | |
| ('\u2248', '~='), # β | |
| ('\u221a', 'sqrt'), # β | |
| ('\u00b7', '*'), # Β· (middle dot) | |
| # ββ Fractions βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ('\u00bd', '1/2'), # Β½ | |
| ('\u2153', '1/3'), # β | |
| ('\u00bc', '1/4'), # ΒΌ | |
| ('\u00be', '3/4'), # ΒΎ | |
| ('\u2154', '2/3'), # β | |
| # ββ Typographic / OCR artifacts βββββββββββββββββββββββββββββββββββββββββββ | |
| ('\u201c', '"'), ('\u201d', '"'), # " " | |
| ('\u201e', '"'), ('\u201f', '"'), # β β | |
| ('\u2018', "'"), ('\u2019', "'"), # ' ' | |
| ('\u201a', "'"), ('\u201b', "'"), # β β | |
| ('\u00a0', ' '), # non-breaking space | |
| ('\u2009', ' '), # thin space | |
| ('\u200b', ''), # zero-width space | |
| ('\u200c', ''), # zero-width non-joiner | |
| ('\u200d', ''), # zero-width joiner | |
| ('\ufeff', ''), # BOM | |
| ] | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # Compiled patterns for post-substitution cleanup | |
| # βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| _MULTI_SPACE = re.compile(r'[ \t]+') | |
| _MULTI_NL = re.compile(r'\n+') | |
| # Fix "cross " that was inserted between a variable and "product" β keep as-is, | |
| # but collapse "cross product" to "cross product". | |
| _CROSS_SPACE = re.compile(r'cross\s{2,}') | |
| def normalize_input(text: str) -> str: | |
| """ | |
| Normalize a raw user input string. | |
| Returns a cleaned string with: | |
| β’ Unicode superscripts/subscripts replaced with ASCII caret/underscore notation | |
| β’ Mathematical symbols (β«, β, β, Γ, β, Β΅, Β²β¦) replaced with ASCII words | |
| β’ Typographic quotes/dashes/spaces replaced with ASCII equivalents | |
| β’ Multiple spaces collapsed to one | |
| β’ Leading/trailing whitespace stripped | |
| The returned string is *always* a valid str (never None). | |
| """ | |
| if not isinstance(text, str): | |
| return str(text) if text is not None else '' | |
| # 1. Strip | |
| text = text.strip() | |
| if not text: | |
| return text | |
| # 2. Superscript / subscript digits | |
| for ch, repl in _SUPERSCRIPT_MAP.items(): | |
| text = text.replace(ch, repl) | |
| for ch, repl in _SUBSCRIPT_MAP.items(): | |
| text = text.replace(ch, repl) | |
| # 3. Symbol table (order matters: longest / most specific first) | |
| for symbol, repl in _SYMBOL_REPLACEMENTS: | |
| text = text.replace(symbol, repl) | |
| # 4. Post-cleanup | |
| text = _CROSS_SPACE.sub('cross ', text) | |
| text = _MULTI_SPACE.sub(' ', text) | |
| text = _MULTI_NL.sub(' ', text) | |
| text = text.strip() | |
| return text | |