Prompt-Builder / src /core /language.py
ArielJoe's picture
feat: cross-detector language policy + tidy structure & file naming
5ddfd1f
Raw
History Blame Contribute Delete
2.14 kB
"""
Penentuan bahasa untuk routing detektor.
Sistem ini difokuskan ke Bahasa Indonesia. Teks yang terdeteksi sebagai Inggris
dikembalikan sebagai "en" dan tidak diproses lebih lanjut oleh pipeline. Teks
tanpa huruf dikembalikan sebagai "unknown".
Deteksi menggunakan wordfreq: tiap kata dibandingkan frekuensi Zipf-nya di corpus
Inggris vs Indonesia. Bila Inggris mengungguli Indonesia pada ≥65% kata yang punya
signal (minimum 3 kata), teks diklasifikasikan sebagai "en".
"""
from __future__ import annotations
import re
from dataclasses import dataclass
from typing import Literal
LanguageCode = Literal["id", "en", "unknown"]
_HAS_LETTER = re.compile(r"[A-Za-z]")
_MIN_SIGNAL_WORDS = 3 # minimum kata berkontribusi agar deteksi berlaku
_EN_DOMINANCE_THRESH = 0.65 # proporsi "en > id" untuk diklasifikasi Inggris
@dataclass(frozen=True)
class LanguageDetection:
"""Hasil pendeteksian bahasa. Hanya field language yang dipakai pemanggil."""
language: LanguageCode
def detect_language(text: str) -> LanguageDetection:
"""
Deteksi bahasa teks secara ringan menggunakan wordfreq.
Returns:
"en" — teks didominasi kata-kata Inggris
"id" — teks Indonesia atau campuran (default)
"unknown" — teks tidak mengandung huruf
"""
if not text or not _HAS_LETTER.search(text):
return LanguageDetection("unknown")
try:
from wordfreq import zipf_frequency, tokenize # type: ignore[import]
words = [w for w in tokenize(text, "en") if _HAS_LETTER.search(w) and len(w) > 2]
if len(words) >= _MIN_SIGNAL_WORDS:
en_wins = id_wins = 0
for w in words:
ef = zipf_frequency(w, "en")
if_ = zipf_frequency(w, "id")
if ef > if_:
en_wins += 1
elif if_ > ef:
id_wins += 1
total = en_wins + id_wins
if total >= _MIN_SIGNAL_WORDS and en_wins / total > _EN_DOMINANCE_THRESH:
return LanguageDetection("en")
except Exception:
pass
return LanguageDetection("id")