import re from typing import Dict, Tuple, Optional from sentence_transformers import SentenceTransformer from langdetect import detect, detect_langs from langdetect.lang_detect_exception import LangDetectException from config.settings import settings class MultilingualManager: def __init__(self): self.vietnamese_model = None self.multilingual_model = None self.current_language = 'vi' self._initialize_models() def _initialize_models(self): """Khởi tạo các mô hình đa ngôn ngữ""" try: print("🔄 Đang tải mô hình embedding tiếng Việt...") self.vietnamese_model = SentenceTransformer(settings.VIETNAMESE_EMBEDDING_MODEL) print("✅ Đã tải mô hình embedding tiếng Việt") except Exception as e: print(f"❌ Lỗi tải mô hình embedding tiếng Việt: {e}") # Fallback to multilingual model self.vietnamese_model = None try: print("🔄 Đang tải mô hình embedding đa ngôn ngữ...") self.multilingual_model = SentenceTransformer( settings.MULTILINGUAL_EMBEDDING_MODEL, trust_remote_code=True ) print("✅ Đã tải mô hình embedding đa ngôn ngữ") except Exception as e: print(f"❌ Lỗi tải mô hình embedding đa ngôn ngữ: {e}") # Fallback to default model try: self.multilingual_model = SentenceTransformer('sentence-transformers/all-MiniLM-L6-v2') print("✅ Đã tải mô hình fallback đa ngôn ngữ") except Exception as fallback_error: print(f"❌ Lỗi tải mô hình fallback: {fallback_error}") self.multilingual_model = None def detect_language(self, text: str, fallback_method: bool = True) -> str: """ Phát hiện ngôn ngữ với độ chính xác cao sử dụng langdetect """ if not text or len(text.strip()) == 0: return 'vi' # Default to Vietnamese # Clean text text = self._clean_text_for_detection(text) if len(text.strip()) < 3: return 'vi' try: # Sử dụng langdetect với xác suất languages = detect_langs(text) # Lấy ngôn ngữ có xác suất cao nhất best_lang = str(languages[0]).split(':')[0] # Map langdetect codes to our codes lang_map = { 'vi': 'vi', 'en': 'en', 'fr': 'fr', 'es': 'es', 'de': 'de', 'ja': 'ja', 'ko': 'ko', 'zh-cn': 'zh', 'zh-tw': 'zh', 'it': 'en', 'pt': 'en', 'ru': 'en', 'ar': 'en' # Fallback to English for others } detected_lang = lang_map.get(best_lang, 'en') # Kiểm tra độ tin cậy confidence = float(str(languages[0]).split(':')[1]) if confidence < 0.6 and fallback_method: # Nếu độ tin cậy thấp, sử dụng fallback method return self._fallback_language_detection(text) print(f"🔍 Phát hiện ngôn ngữ: {detected_lang} (độ tin cậy: {confidence:.2f})") return detected_lang except LangDetectException as e: print(f"⚠️ LangDetect lỗi, sử dụng fallback: {e}") return self._fallback_language_detection(text) if fallback_method else 'vi' except Exception as e: print(f"⚠️ Lỗi phát hiện ngôn ngữ: {e}") return self._fallback_language_detection(text) if fallback_method else 'vi' def _fallback_language_detection(self, text: str) -> str: """ Fallback method sử dụng các quy tắc heuristic """ text_lower = text.lower() # Vietnamese detection với các từ đặc trưng vietnamese_indicators = [ 'của', 'và', 'là', 'có', 'được', 'trong', 'cho', 'với', 'như', 'tôi', 'bạn', 'ông', 'bà', 'anh', 'chị', 'em', 'này', 'kia', 'đó', 'đây', 'không', 'có', 'phải', 'rất', 'nhất', 'các', 'những', 'một', 'hai', 'ba' ] english_indicators = [ 'the', 'and', 'is', 'are', 'for', 'with', 'this', 'that', 'you', 'they', 'what', 'where', 'when', 'why', 'how', 'which', 'who', 'their', 'have', 'has', 'from', 'your', 'will', 'would', 'could', 'should', 'about', 'into', 'through' ] # Đếm số từ chỉ định vi_count = sum(1 for word in vietnamese_indicators if word in text_lower) en_count = sum(1 for word in english_indicators if word in text_lower) # Kiểm tra ký tự đặc biệt vietnamese_chars = set('àáâãèéêìíòóôõùúýăđĩũơưạảấầẩẫậắằẳẵặẹẻẽếềểễệỉịọỏốồổỗộớờởỡợụủứừửữựỳỵỷỹ') vi_char_count = sum(1 for char in text if char in vietnamese_chars) # Quyết định dựa trên các chỉ số if vi_count > en_count or vi_char_count > 2: return 'vi' elif en_count > vi_count: return 'en' else: # Kiểm tra các ngôn ngữ khác bằng ký tự if any(char in text for char in 'あいうえおぁ-んァ-ン'): return 'ja' elif any(char in text for char in '你好'): return 'zh' elif any(char in text for char in '안녕'): return 'ko' elif any(char in text for char in 'àâæçèéêëîïôœùûüÿ'): return 'fr' elif any(char in text for char in 'áéíóúñü'): return 'es' elif any(char in text for char in 'äöüß'): return 'de' else: return 'en' # Mặc định là English def _clean_text_for_detection(self, text: str) -> str: """Làm sạch văn bản để phát hiện ngôn ngữ chính xác hơn""" # Loại bỏ URL, số, ký tự đặc biệt không cần thiết text = re.sub(r'http\S+', '', text) text = re.sub(r'[0-9]+', '', text) text = re.sub(r'[^\w\s]', ' ', text) text = re.sub(r'\s+', ' ', text) return text.strip() def detect_language_with_confidence(self, text: str) -> Tuple[str, float]: """ Phát hiện ngôn ngữ với điểm tin cậy """ if not text or len(text.strip()) < 3: return 'vi', 0.0 try: languages = detect_langs(text) best_lang = str(languages[0]) lang_code, confidence = best_lang.split(':') lang_map = { 'vi': 'vi', 'en': 'en', 'fr': 'fr', 'es': 'es', 'de': 'de', 'ja': 'ja', 'ko': 'ko', 'zh-cn': 'zh', 'zh-tw': 'zh' } detected_lang = lang_map.get(lang_code, 'en') confidence_score = float(confidence) return detected_lang, confidence_score except LangDetectException as e: print(f"⚠️ Lỗi phát hiện ngôn ngữ với confidence: {e}") return 'vi', 0.5 except Exception as e: print(f"⚠️ Lỗi phát hiện ngôn ngữ với confidence: {e}") return 'vi', 0.5 def detect_language_simple(self, text: str) -> str: """ Phát hiện ngôn ngữ đơn giản (nhanh hơn, ít chính xác hơn) """ if not text or len(text.strip()) < 3: return 'vi' try: # Sử dụng detect đơn giản thay vì detect_langs lang_code = detect(text) lang_map = { 'vi': 'vi', 'en': 'en', 'fr': 'fr', 'es': 'es', 'de': 'de', 'ja': 'ja', 'ko': 'ko', 'zh-cn': 'zh', 'zh-tw': 'zh' } return lang_map.get(lang_code, 'en') except LangDetectException: return self._fallback_language_detection(text) except Exception: return 'vi' def get_embedding_model(self, language: str = None) -> Optional[SentenceTransformer]: """Lấy mô hình embedding dựa trên ngôn ngữ đã phát hiện""" if language and language in settings.SUPPORTED_LANGUAGES: lang = language else: lang = self.current_language if lang == 'vi' and self.vietnamese_model is not None: return self.vietnamese_model else: return self.multilingual_model def get_llm_model(self, language: str = None) -> str: """Lấy tên mô hình LLM dựa trên ngôn ngữ đã phát hiện""" if language and language in settings.SUPPORTED_LANGUAGES: lang = language else: lang = self.current_language if lang == 'vi': return settings.VIETNAMESE_LLM_MODEL else: return settings.MULTILINGUAL_LLM_MODEL def get_language_info(self, language: str = None) -> Dict: """Lấy thông tin ngôn ngữ bao gồm mã và tên đầy đủ""" if language and language in settings.SUPPORTED_LANGUAGES: lang = language else: lang = self.current_language language_names = { 'vi': 'Tiếng Việt', 'en': 'English', 'fr': 'Français', 'es': 'Español', 'de': 'Deutsch', 'ja': '日本語', 'ko': '한국어', 'zh': '中文' } return { 'code': lang, 'name': language_names.get(lang, 'Unknown'), 'embedding_model': settings.VIETNAMESE_EMBEDDING_MODEL if lang == 'vi' else settings.MULTILINGUAL_EMBEDDING_MODEL, 'llm_model': settings.VIETNAMESE_LLM_MODEL if lang == 'vi' else settings.MULTILINGUAL_LLM_MODEL, 'embedding_status': 'active' if (self.vietnamese_model if lang == 'vi' else self.multilingual_model) else 'inactive' } def get_supported_languages(self) -> Dict[str, str]: """Lấy danh sách ngôn ngữ được hỗ trợ""" return { 'vi': 'Tiếng Việt', 'en': 'English', 'fr': 'Français', 'es': 'Español', 'de': 'Deutsch', 'ja': '日本語', 'ko': '한국어', 'zh': '中文' } def is_language_supported(self, language: str) -> bool: """Kiểm tra xem ngôn ngữ có được hỗ trợ không""" return language in self.get_supported_languages()