File size: 17,903 Bytes
6d48dc9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dbf2148
 
 
99c5f5a
 
dbf2148
 
 
 
65be612
 
6d48dc9
65be612
6d48dc9
65be612
 
 
 
 
 
 
 
6d48dc9
65be612
dbf2148
65be612
 
6d48dc9
 
 
 
65be612
 
 
6d48dc9
 
 
 
 
 
 
 
 
 
 
 
dbf2148
 
 
6d48dc9
 
 
 
 
dbf2148
6d48dc9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dbf2148
6d48dc9
 
 
 
 
dbf2148
6d48dc9
 
dbf2148
99c5f5a
6d48dc9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99c5f5a
 
6d48dc9
dbf2148
6d48dc9
 
99c5f5a
 
6d48dc9
dbf2148
6d48dc9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dbf2148
 
 
 
 
6d48dc9
 
 
 
 
 
dbf2148
6d48dc9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dbf2148
6d48dc9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99c5f5a
 
 
6d48dc9
 
 
 
99c5f5a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dbf2148
65be612
6d48dc9
 
 
 
65be612
6d48dc9
65be612
 
 
6d48dc9
7c433d8
65be612
6d48dc9
 
 
 
dbf2148
 
65be612
dbf2148
65be612
6d48dc9
dbf2148
65be612
6d48dc9
 
 
 
 
 
 
 
 
 
 
 
 
 
65be612
 
6d48dc9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99c5f5a
 
 
 
 
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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
# import re
# from typing import Dict, Tuple, Optional
# from sentence_transformers import SentenceTransformer
# from config.settings import settings

# class MultilingualManager:
#     def __init__(self):
#         self.vietnamese_model = None
#         self.multilingual_model = None
#         self.current_language = 'vi' 

#         # Phát hiện thuộc ngôn ngữ dựa trên các mẫu ký tự và từ phổ biến
#         self.language_patterns = {
#             'vi': {
#                 'chars': set('àáâãèéêìíòóôõùúýăđĩũơưạảấầẩẫậắằẳẵặẹẻẽếềểễệỉịọỏốồổỗộớờởỡợụủứừửữựỳỵỷỹ'),
#                 'common_words': ['của', 'và', 'là', 'có', 'được', 'trong', 'cho', 'với', 'như', 'tôi']
#             },
#             'en': {
#                 'chars': set('abcdefghijklmnopqrstuvwxyz'),
#                 'common_words': ['the', 'and', 'is', 'are', 'for', 'with', 'this', 'that', 'you', 'they']
#             },
#             'fr': {
#                 'chars': set('àâæçèéêëîïôœùûüÿ'),
#                 'common_words': ['le', 'la', 'et', 'est', 'dans', 'pour', 'avec', 'vous', 'nous', 'ils']
#             },
#             'es': {
#                 'chars': set('áéíóúñü'),
#                 'common_words': ['el', 'la', 'y', 'es', 'en', 'por', 'con', 'los', 'las', 'del']
#             },
#             'de': {
#                 'chars': set('äöüß'),
#                 'common_words': ['der', 'die', 'das', 'und', 'ist', 'in', 'für', 'mit', 'sich', 'nicht']
#             },
#             'ja': {
#                 'chars': set('ぁ-んァ-ン一-龯'),
#                 'common_words': ['の', 'に', 'は', 'を', 'た', 'で', 'し', 'が', 'ます', 'です']
#             },
#             'ko': {
#                 'chars': set('가-힣'),
#                 'common_words': ['이', '그', '에', '를', '의', '에', '에서', '으로', '하다', '이다']
#             },
#             'zh': {
#                 'chars': set('一-鿌'),
#                 'common_words': ['的', '是', '在', '有', '和', '了', '人', '我', '他', '这']
#             }
#         }
#         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}")
#             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}")
#             self.multilingual_model = None
    
#     def detect_language(self, text: str) -> str:
#         """Phát hiện ngôn ngữ với độ chính xác cao"""
#         if not text or len(text.strip()) == 0:
#             return 'vi'  # Default to Vietnamese
        
#         text_lower = text.lower()
#         scores = {}
        
#         for lang, patterns in self.language_patterns.items():
#             score = 0
            
#             # Score based on special characters
#             char_score = sum(1 for char in text if char in patterns['chars'])
#             score += char_score * 2
            
#             # Score based on common words
#             word_score = sum(1 for word in patterns['common_words'] if word in text_lower)
#             score += word_score
            
#             scores[lang] = score
        
#         # Return language with highest score
#         detected_lang = max(scores.items(), key=lambda x: x[1])[0]
        
#         # If no strong detection, use character-based fallback
#         if max(scores.values()) < 3:
#             vietnamese_chars = set('àáâãèéêìíòóôõùúýăđĩũơưạảấầẩẫậắằẳẵặẹẻẽếềểễệỉịọỏốồổỗộớờởỡợụủứừửữựỳỵỷỹ')
#             if any(char in vietnamese_chars for char in text):
#                 return 'vi'
#             elif 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'
#             else:
#                 return 'en'  # Default to English for other cases
        
#         return detected_lang
#     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"""
#         lang = language if language in settings.SUPPORTED_LANGUAGES else self.current_language
        
#         if lang == 'vi':
#             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"""
#         lang = language if language in settings.SUPPORTED_LANGUAGES else 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 đủ"""
#         lang = language if language in settings.SUPPORTED_LANGUAGES else self.current_language
        
#         model_info = {
#             'vi': {
#                 'name': 'Tiếng Việt',
#                 'embedding_model': settings.VIETNAMESE_EMBEDDING_MODEL,
#                 'llm_model': settings.VIETNAMESE_LLM_MODEL,
#                 'status': 'active' if self.vietnamese_model else 'inactive'
#             },
#             'other': {
#                 'name': 'Multilingual',
#                 'embedding_model': settings.MULTILINGUAL_EMBEDDING_MODEL,
#                 'llm_model': settings.MULTILINGUAL_LLM_MODEL,
#                 'status': 'active' if self.multilingual_model else 'inactive'
#             }
#         }
        
#         if lang == 'vi':
#             return model_info['vi']
#         else:
#             return model_info['other']
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()