Spaces:
Runtime error
Runtime error
Aryan Mishra commited on
Commit ·
2f9be58
1
Parent(s): db13628
feat: Phase 2 - preprocessing and EDA pipeline
Browse files- data/.gitignore +0 -1
- data/processed.dvc +0 -6
- data/raw.dvc +3 -3
- dvc.lock +68 -0
- dvc.yaml +24 -0
- notebooks/01_data_exploration.ipynb +0 -0
- src/data/dataset.py +70 -0
- src/data/hindi_loader.py +55 -0
- src/data/lang_detect.py +41 -0
- src/data/preprocess.py +33 -0
- src/data/transliterate.py +40 -0
- tests/test_lang_detect.py +18 -0
data/.gitignore
CHANGED
|
@@ -1,2 +1 @@
|
|
| 1 |
/raw
|
| 2 |
-
/processed
|
|
|
|
| 1 |
/raw
|
|
|
data/processed.dvc
DELETED
|
@@ -1,6 +0,0 @@
|
|
| 1 |
-
outs:
|
| 2 |
-
- md5: d751713988987e9331980363e24189ce.dir
|
| 3 |
-
size: 0
|
| 4 |
-
nfiles: 0
|
| 5 |
-
hash: md5
|
| 6 |
-
path: processed
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
data/raw.dvc
CHANGED
|
@@ -1,6 +1,6 @@
|
|
| 1 |
outs:
|
| 2 |
-
- md5:
|
| 3 |
-
size:
|
| 4 |
-
nfiles:
|
| 5 |
hash: md5
|
| 6 |
path: raw
|
|
|
|
| 1 |
outs:
|
| 2 |
+
- md5: 0d10b4997c93bd1bce4a9d53a6e4748e.dir
|
| 3 |
+
size: 7943297
|
| 4 |
+
nfiles: 21
|
| 5 |
hash: md5
|
| 6 |
path: raw
|
dvc.lock
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
schema: '2.0'
|
| 2 |
+
stages:
|
| 3 |
+
preprocess_semeval:
|
| 4 |
+
cmd: PYTHONPATH=. python src/data/dataset.py
|
| 5 |
+
deps:
|
| 6 |
+
- path: data/raw/semeval_laptops
|
| 7 |
+
hash: md5
|
| 8 |
+
md5: 834bf3cc7b3d9216331adae54c9239c6.dir
|
| 9 |
+
size: 1104115
|
| 10 |
+
nfiles: 9
|
| 11 |
+
- path: data/raw/semeval_restaurants
|
| 12 |
+
hash: md5
|
| 13 |
+
md5: 07f540b34a0561f20908aaa70012defb.dir
|
| 14 |
+
size: 1625908
|
| 15 |
+
nfiles: 9
|
| 16 |
+
- path: src/data/dataset.py
|
| 17 |
+
hash: md5
|
| 18 |
+
md5: 4199a5c7d112040180779168f7da1a4a
|
| 19 |
+
size: 2761
|
| 20 |
+
- path: src/data/lang_detect.py
|
| 21 |
+
hash: md5
|
| 22 |
+
md5: ca10825874c1eeb68e199e0e178d8f94
|
| 23 |
+
size: 1053
|
| 24 |
+
- path: src/data/preprocess.py
|
| 25 |
+
hash: md5
|
| 26 |
+
md5: c01401432dfeb6e32e928d47570caa21
|
| 27 |
+
size: 855
|
| 28 |
+
- path: src/data/transliterate.py
|
| 29 |
+
hash: md5
|
| 30 |
+
md5: 2ab5e443eb6123188986e975586f42b8
|
| 31 |
+
size: 1404
|
| 32 |
+
outs:
|
| 33 |
+
- path: data/processed/semeval_test.jsonl
|
| 34 |
+
hash: md5
|
| 35 |
+
md5: 2c4581091b4aeb29a0734e44fd3a5656
|
| 36 |
+
size: 263576
|
| 37 |
+
- path: data/processed/semeval_train.jsonl
|
| 38 |
+
hash: md5
|
| 39 |
+
md5: 04b5486dc6a7c62d1289804bd373eeaa
|
| 40 |
+
size: 971123
|
| 41 |
+
preprocess_hindi:
|
| 42 |
+
cmd: PYTHONPATH=. python src/data/hindi_loader.py
|
| 43 |
+
deps:
|
| 44 |
+
- path: data/raw/amazon_hindi/hindi_sentiment.jsonl
|
| 45 |
+
hash: md5
|
| 46 |
+
md5: 152317207b7015c46f6260a93c2cd756
|
| 47 |
+
size: 1140222
|
| 48 |
+
- path: src/data/hindi_loader.py
|
| 49 |
+
hash: md5
|
| 50 |
+
md5: 6ffae4a0c61907d396b4e693beb6a23a
|
| 51 |
+
size: 1826
|
| 52 |
+
- path: src/data/lang_detect.py
|
| 53 |
+
hash: md5
|
| 54 |
+
md5: ca10825874c1eeb68e199e0e178d8f94
|
| 55 |
+
size: 1053
|
| 56 |
+
- path: src/data/preprocess.py
|
| 57 |
+
hash: md5
|
| 58 |
+
md5: c01401432dfeb6e32e928d47570caa21
|
| 59 |
+
size: 855
|
| 60 |
+
- path: src/data/transliterate.py
|
| 61 |
+
hash: md5
|
| 62 |
+
md5: 2ab5e443eb6123188986e975586f42b8
|
| 63 |
+
size: 1404
|
| 64 |
+
outs:
|
| 65 |
+
- path: data/processed/amazon_hindi.jsonl
|
| 66 |
+
hash: md5
|
| 67 |
+
md5: 29825aafaee80993c9fcb89669bb27ce
|
| 68 |
+
size: 304642
|
dvc.yaml
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
stages:
|
| 2 |
+
preprocess_semeval:
|
| 3 |
+
cmd: PYTHONPATH=. python src/data/dataset.py
|
| 4 |
+
deps:
|
| 5 |
+
- src/data/dataset.py
|
| 6 |
+
- src/data/preprocess.py
|
| 7 |
+
- src/data/lang_detect.py
|
| 8 |
+
- src/data/transliterate.py
|
| 9 |
+
- data/raw/semeval_restaurants
|
| 10 |
+
- data/raw/semeval_laptops
|
| 11 |
+
outs:
|
| 12 |
+
- data/processed/semeval_train.jsonl
|
| 13 |
+
- data/processed/semeval_test.jsonl
|
| 14 |
+
|
| 15 |
+
preprocess_hindi:
|
| 16 |
+
cmd: PYTHONPATH=. python src/data/hindi_loader.py
|
| 17 |
+
deps:
|
| 18 |
+
- src/data/hindi_loader.py
|
| 19 |
+
- src/data/preprocess.py
|
| 20 |
+
- src/data/lang_detect.py
|
| 21 |
+
- src/data/transliterate.py
|
| 22 |
+
- data/raw/amazon_hindi/hindi_sentiment.jsonl
|
| 23 |
+
outs:
|
| 24 |
+
- data/processed/amazon_hindi.jsonl
|
notebooks/01_data_exploration.ipynb
CHANGED
|
The diff for this file is too large to render.
See raw diff
|
|
|
src/data/dataset.py
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from datasets import load_from_disk
|
| 4 |
+
from collections import defaultdict
|
| 5 |
+
from src.config import RAW_DIR, SEMEVAL_TRAIN_PATH, SEMEVAL_TEST_PATH
|
| 6 |
+
from src.data.preprocess import clean
|
| 7 |
+
from src.data.lang_detect import detect_language
|
| 8 |
+
|
| 9 |
+
def process_semeval():
|
| 10 |
+
rest_path = RAW_DIR / "semeval_restaurants"
|
| 11 |
+
lap_path = RAW_DIR / "semeval_laptops"
|
| 12 |
+
|
| 13 |
+
rest_data = load_from_disk(str(rest_path))
|
| 14 |
+
lap_data = load_from_disk(str(lap_path))
|
| 15 |
+
|
| 16 |
+
train_samples = defaultdict(list)
|
| 17 |
+
test_samples = defaultdict(list)
|
| 18 |
+
|
| 19 |
+
for ds_name, ds, source_name in [("train", rest_data["train"], "restaurants"),
|
| 20 |
+
("test", rest_data["test"], "restaurants"),
|
| 21 |
+
("train", lap_data["train"], "laptops"),
|
| 22 |
+
("test", lap_data["test"], "laptops")]:
|
| 23 |
+
target = train_samples if ds_name == "train" else test_samples
|
| 24 |
+
for row in ds:
|
| 25 |
+
text = row["text"]
|
| 26 |
+
span = row["span"]
|
| 27 |
+
label = row["label"]
|
| 28 |
+
|
| 29 |
+
target[(text, source_name)].append({
|
| 30 |
+
"term": span,
|
| 31 |
+
"polarity": label
|
| 32 |
+
})
|
| 33 |
+
|
| 34 |
+
SEMEVAL_TRAIN_PATH.parent.mkdir(parents=True, exist_ok=True)
|
| 35 |
+
|
| 36 |
+
for path, data_dict in [(SEMEVAL_TRAIN_PATH, train_samples), (SEMEVAL_TEST_PATH, test_samples)]:
|
| 37 |
+
total = 0
|
| 38 |
+
lang_counts = defaultdict(int)
|
| 39 |
+
with open(path, "w", encoding="utf-8") as f:
|
| 40 |
+
for (text, source), aspects in data_dict.items():
|
| 41 |
+
lang = detect_language(text)
|
| 42 |
+
cleaned_text = clean(text, lang)
|
| 43 |
+
lang_counts[lang] += 1
|
| 44 |
+
|
| 45 |
+
final_aspects = []
|
| 46 |
+
for aspect in aspects:
|
| 47 |
+
term_clean = clean(aspect["term"], lang)
|
| 48 |
+
from_idx = cleaned_text.find(term_clean)
|
| 49 |
+
to_idx = from_idx + len(term_clean) if from_idx != -1 else -1
|
| 50 |
+
final_aspects.append({
|
| 51 |
+
"term": term_clean,
|
| 52 |
+
"polarity": aspect["polarity"],
|
| 53 |
+
"from": from_idx,
|
| 54 |
+
"to": to_idx
|
| 55 |
+
})
|
| 56 |
+
|
| 57 |
+
sample = {
|
| 58 |
+
"text": cleaned_text,
|
| 59 |
+
"language": lang,
|
| 60 |
+
"aspect_terms": final_aspects,
|
| 61 |
+
"source": source
|
| 62 |
+
}
|
| 63 |
+
f.write(json.dumps(sample, ensure_ascii=False) + "\n")
|
| 64 |
+
total += 1
|
| 65 |
+
|
| 66 |
+
print(f"SemEval {path.stem} samples: {total}")
|
| 67 |
+
print(f"SemEval {path.stem} languages: {dict(lang_counts)}")
|
| 68 |
+
|
| 69 |
+
if __name__ == "__main__":
|
| 70 |
+
process_semeval()
|
src/data/hindi_loader.py
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
from pathlib import Path
|
| 3 |
+
from src.config import RAW_DIR, AMAZON_HINDI_PATH
|
| 4 |
+
from src.data.preprocess import clean
|
| 5 |
+
from src.data.lang_detect import detect_language
|
| 6 |
+
|
| 7 |
+
def process_hindi():
|
| 8 |
+
raw_path = RAW_DIR / "amazon_hindi" / "hindi_sentiment.jsonl"
|
| 9 |
+
if not raw_path.exists():
|
| 10 |
+
print(f"File not found: {raw_path}")
|
| 11 |
+
return
|
| 12 |
+
|
| 13 |
+
AMAZON_HINDI_PATH.parent.mkdir(parents=True, exist_ok=True)
|
| 14 |
+
|
| 15 |
+
total = 0
|
| 16 |
+
lang_counts = {"hi": 0, "hinglish": 0, "en": 0, "other": 0}
|
| 17 |
+
|
| 18 |
+
with open(raw_path, "r", encoding="utf-8") as fin, \
|
| 19 |
+
open(AMAZON_HINDI_PATH, "w", encoding="utf-8") as fout:
|
| 20 |
+
for line in fin:
|
| 21 |
+
row = json.loads(line)
|
| 22 |
+
text = row.get("INDIC REVIEW", row.get("text", ""))
|
| 23 |
+
if not text:
|
| 24 |
+
continue
|
| 25 |
+
|
| 26 |
+
label = str(row.get("LABEL", row.get("label", ""))).lower()
|
| 27 |
+
if label == "0" or label == "negative":
|
| 28 |
+
label = "negative"
|
| 29 |
+
elif label == "1" or label == "positive":
|
| 30 |
+
label = "positive"
|
| 31 |
+
else:
|
| 32 |
+
label = "neutral"
|
| 33 |
+
|
| 34 |
+
lang = detect_language(text)
|
| 35 |
+
if lang in lang_counts:
|
| 36 |
+
lang_counts[lang] += 1
|
| 37 |
+
else:
|
| 38 |
+
lang_counts[lang] = 1
|
| 39 |
+
|
| 40 |
+
cleaned_text = clean(text, lang)
|
| 41 |
+
|
| 42 |
+
sample = {
|
| 43 |
+
"text": cleaned_text,
|
| 44 |
+
"language": lang,
|
| 45 |
+
"label": label,
|
| 46 |
+
"source": "amazon_hindi"
|
| 47 |
+
}
|
| 48 |
+
fout.write(json.dumps(sample, ensure_ascii=False) + "\n")
|
| 49 |
+
total += 1
|
| 50 |
+
|
| 51 |
+
print(f"Hindi samples processed: {total}")
|
| 52 |
+
print(f"Hindi language distribution: {lang_counts}")
|
| 53 |
+
|
| 54 |
+
if __name__ == "__main__":
|
| 55 |
+
process_hindi()
|
src/data/lang_detect.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import re
|
| 2 |
+
import fasttext
|
| 3 |
+
from src.config import FASTTEXT_MODEL_PATH
|
| 4 |
+
from pathlib import Path
|
| 5 |
+
|
| 6 |
+
_model = None
|
| 7 |
+
|
| 8 |
+
def get_model():
|
| 9 |
+
global _model
|
| 10 |
+
if _model is None:
|
| 11 |
+
_model = fasttext.load_model(str(FASTTEXT_MODEL_PATH))
|
| 12 |
+
return _model
|
| 13 |
+
|
| 14 |
+
def detect_language(text: str) -> str:
|
| 15 |
+
"""Detects if text is en, hi, hinglish, or other."""
|
| 16 |
+
if not text or not text.strip():
|
| 17 |
+
return "other"
|
| 18 |
+
|
| 19 |
+
has_alpha = bool(re.search(r'[^\W\d_]', text))
|
| 20 |
+
if not has_alpha:
|
| 21 |
+
return "other"
|
| 22 |
+
|
| 23 |
+
text = text.replace('\n', ' ')
|
| 24 |
+
model = get_model()
|
| 25 |
+
predictions = model.predict(text, k=1)
|
| 26 |
+
label = predictions[0][0].replace("__label__", "")
|
| 27 |
+
|
| 28 |
+
has_latin = bool(re.search(r'[a-zA-Z]', text))
|
| 29 |
+
has_devanagari = bool(re.search(r'[\u0900-\u097F]', text))
|
| 30 |
+
|
| 31 |
+
is_hinglish = has_latin and has_devanagari
|
| 32 |
+
|
| 33 |
+
if is_hinglish and label in ["en", "hi"]:
|
| 34 |
+
return "hinglish"
|
| 35 |
+
|
| 36 |
+
if label == "en":
|
| 37 |
+
return "en"
|
| 38 |
+
elif label == "hi":
|
| 39 |
+
return "hi"
|
| 40 |
+
else:
|
| 41 |
+
return "other"
|
src/data/preprocess.py
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import re
|
| 2 |
+
import unicodedata
|
| 3 |
+
from src.data.transliterate import transliterate
|
| 4 |
+
|
| 5 |
+
def clean(text: str, language: str) -> str:
|
| 6 |
+
"""Clean text by lowercasing, removing URLs/mentions/hashtags, normalizing unicode, stripping whitespace."""
|
| 7 |
+
if not text:
|
| 8 |
+
return ""
|
| 9 |
+
|
| 10 |
+
# lowercase
|
| 11 |
+
text = text.lower()
|
| 12 |
+
|
| 13 |
+
# remove URLs
|
| 14 |
+
text = re.sub(r'http\S+|www\.\S+', '', text)
|
| 15 |
+
|
| 16 |
+
# remove mentions
|
| 17 |
+
text = re.sub(r'@\w+', '', text)
|
| 18 |
+
|
| 19 |
+
# remove hashtags
|
| 20 |
+
text = re.sub(r'#\w+', '', text)
|
| 21 |
+
|
| 22 |
+
# Apply transliteration only for hi/hinglish inputs
|
| 23 |
+
if language in ["hi", "hinglish"]:
|
| 24 |
+
text = transliterate(text, language)
|
| 25 |
+
|
| 26 |
+
# normalize unicode
|
| 27 |
+
text = unicodedata.normalize("NFKC", text)
|
| 28 |
+
|
| 29 |
+
# strip whitespace
|
| 30 |
+
text = text.strip()
|
| 31 |
+
text = re.sub(r'\s+', ' ', text)
|
| 32 |
+
|
| 33 |
+
return text
|
src/data/transliterate.py
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import logging
|
| 2 |
+
import unicodedata
|
| 3 |
+
import re
|
| 4 |
+
from typing import Optional
|
| 5 |
+
|
| 6 |
+
logger = logging.getLogger(__name__)
|
| 7 |
+
|
| 8 |
+
try:
|
| 9 |
+
from indicnlp.transliterate.unicode_transliterate import ItransTransliterator
|
| 10 |
+
HAS_INDIC_NLP = True
|
| 11 |
+
except ImportError:
|
| 12 |
+
HAS_INDIC_NLP = False
|
| 13 |
+
logger.warning("indic-nlp-library not found. Transliteration will fallback to basic unicode handling.")
|
| 14 |
+
|
| 15 |
+
def transliterate(text: str, src_lang: str) -> str:
|
| 16 |
+
"""Romanize Devanagari text."""
|
| 17 |
+
if src_lang not in ["hi", "hinglish"]:
|
| 18 |
+
return text
|
| 19 |
+
|
| 20 |
+
if HAS_INDIC_NLP:
|
| 21 |
+
try:
|
| 22 |
+
# We will process word by word if needed, but itrans translates string.
|
| 23 |
+
# actually to_itrans takes devanagari and romanizes it.
|
| 24 |
+
roman_text = ItransTransliterator.to_itrans(text, "hi")
|
| 25 |
+
except Exception as e:
|
| 26 |
+
logger.warning(f"indicnlp transliteration failed: {e}")
|
| 27 |
+
roman_text = text
|
| 28 |
+
else:
|
| 29 |
+
# Fallback to basic unicode normalization
|
| 30 |
+
roman_text = unicodedata.normalize("NFKD", text).encode("ascii", "ignore").decode("utf-8")
|
| 31 |
+
|
| 32 |
+
if not roman_text:
|
| 33 |
+
roman_text = text
|
| 34 |
+
|
| 35 |
+
# Normalize common Hinglish spellings
|
| 36 |
+
# replace acha / accha -> achha
|
| 37 |
+
roman_text = re.sub(r'\baccha\b', 'achha', roman_text, flags=re.IGNORECASE)
|
| 38 |
+
roman_text = re.sub(r'\bacha\b', 'achha', roman_text, flags=re.IGNORECASE)
|
| 39 |
+
|
| 40 |
+
return roman_text
|
tests/test_lang_detect.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from src.data.lang_detect import detect_language
|
| 2 |
+
|
| 3 |
+
def test_detect_language():
|
| 4 |
+
samples = [
|
| 5 |
+
("This is a simple English sentence.", "en"),
|
| 6 |
+
("The food was amazing!", "en"),
|
| 7 |
+
("यह एक हिंदी वाक्य है।", "hi"),
|
| 8 |
+
("मुझे यह उत्पाद बहुत पसंद आया।", "hi"),
|
| 9 |
+
("The phone is great but battery life kharab hai.", "en"), # no devanagari -> en
|
| 10 |
+
("Phone bahut badhiya hai, लेकिन battery is bad.", "hinglish"),
|
| 11 |
+
("I love this! मुझे यह पसंद है", "hinglish"),
|
| 12 |
+
("Bonjour tout le monde", "other"),
|
| 13 |
+
("12345 67890 !@#", "other"),
|
| 14 |
+
("Just english text with 123", "en"),
|
| 15 |
+
("सिर्फ हिंदी 123", "hi")
|
| 16 |
+
]
|
| 17 |
+
for text, expected in samples:
|
| 18 |
+
assert detect_language(text) == expected, f"Failed on '{text}', expected {expected}"
|