File size: 4,431 Bytes
1818339 | 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 | from __future__ import annotations
from dataclasses import dataclass
from typing import Optional, List
from langdetect import detect, DetectorFactory, LangDetectException
from lingua import Language, LanguageDetectorBuilder
# Optional INLD (Hinglish detector)
try:
from INLD.INLD import detect as inld_detect
INLD_AVAILABLE = True
except ImportError:
INLD_AVAILABLE = False
# Make langdetect deterministic
DetectorFactory.seed = 0
# Languages covered by the TextDetox toxicity models (15) + Hinglish code "hin"
# en, ru, uk, de, es, am, zh, ar, hi, it, fr, he, hin, ja, tt
SUPPORTED_LANGUAGES = {
"en", "ru", "uk", "de", "es", "am", "zh", "ar",
"hi", "it", "fr", "he", "hin", "ja", "tt"
}
# Subset we can currently detect reliably with langdetect+lingua
ALLOWED_LANGUAGES = {
"en", "ru", "uk", "de", "es", "ar",
"hi", "zh", "it", "fr", "he", "ja"
}
LINGUA_LANG_MAP = {
Language.ENGLISH: "en",
Language.RUSSIAN: "ru",
Language.UKRAINIAN: "uk",
Language.GERMAN: "de",
Language.SPANISH: "es",
Language.ARABIC: "ar",
Language.HINDI: "hi",
Language.CHINESE: "zh",
Language.ITALIAN: "it",
Language.FRENCH: "fr",
Language.HEBREW: "he",
Language.JAPANESE: "ja",
}
lingua_detector = LanguageDetectorBuilder.from_languages(
*LINGUA_LANG_MAP.keys()
).build()
@dataclass
class LanguageResult:
lang: str # final classification (en, ru, hin, other, ...)
langdetect: str # raw langdetect output
lingua: str # raw lingua output
detector: str # "agreement" | "inld" | "other"
def normalize(code: str) -> str:
if not code:
return "unknown"
code = code.lower().strip()
if code in {"zh-cn", "zh-tw"}:
return "zh"
if code == "iw":
return "he"
return code
def run_inld(text: str) -> Optional[str]:
"""
Run INLD and return 'hin' (Hinglish) if detected.
INLD returns ['hng'], ['hi'], ['en'], etc.
"""
if not INLD_AVAILABLE:
return None
try:
result = inld_detect(text)
if result and result[0].lower() == "hng":
return "hin"
except Exception:
pass
return None
def detect_language(text: str) -> LanguageResult:
if not text or not text.strip():
return LanguageResult("other", "unknown", "unknown", "other")
text = text.strip()
# -------- langdetect --------
try:
ld_code = normalize(detect(text))
except LangDetectException:
ld_code = "unknown"
# -------- lingua --------
lingua_lang = lingua_detector.detect_language_of(text)
if lingua_lang is None:
li_code = "unknown"
else:
li_code = LINGUA_LANG_MAP.get(lingua_lang, "unknown")
# -------- agreement rule --------
if ld_code == li_code and ld_code in ALLOWED_LANGUAGES:
return LanguageResult(
lang=ld_code,
langdetect=ld_code,
lingua=li_code,
detector="agreement",
)
# -------- INLD fallback (Hinglish) --------
inld_lang = run_inld(text)
if inld_lang:
return LanguageResult(
lang=inld_lang,
langdetect=ld_code,
lingua=li_code,
detector="inld",
)
# -------- final fallback --------
# For now, am + tt and low-confidence cases go here
return LanguageResult(
lang="other",
langdetect=ld_code,
lingua=li_code,
detector="other",
)
def detect_language_code(text: str) -> str:
"""
Convenience helper: just returns the final language code.
"""
return detect_language(text).lang
def detect_language_batch(texts: List[str]) -> List[LanguageResult]:
return [detect_language(t) for t in texts]
def detect_language_codes(texts: List[str]) -> List[str]:
return [detect_language(t).lang for t in texts]
if __name__ == "__main__":
tests = [
"Hello, how are you?",
"Привет, как дела?",
"नमस्ते, आप कैसे हैं?",
"Hola, ¿cómo estás?",
"こんにちは、お元気ですか?",
"ye ek example hai",
"Bhai aaj kya kar rahe ho?",
"lol ok",
""
]
for t in tests:
r = detect_language(t)
print(
f"{t!r:35} → {r.lang:9} | "
f"ld={r.langdetect:5} | li={r.lingua:5} | via={r.detector}"
)
|