translate-api / app /models /translator.py
knighter75's picture
Initial
93f4eb2
Raw
History Blame Contribute Delete
6.07 kB
from googletrans import Translator, LANGUAGES
import asyncio
from typing import List, Dict, Optional, Tuple
import logging
logger = logging.getLogger(__name__)
class TranslationService:
def __init__(self):
self.translator = Translator()
self.languages = LANGUAGES
# Кэш для обратного поиска языков
self._name_to_code_cache = None
def _build_name_cache(self):
"""Построить кэш для поиска кода языка по названию"""
if self._name_to_code_cache is None:
self._name_to_code_cache = {}
for code, name in self.languages.items():
self._name_to_code_cache[name.lower()] = code
# Добавляем русские названия
russian_names = {
'russian': 'ru', 'английский': 'en', 'немецкий': 'de',
'французский': 'fr', 'испанский': 'es', 'итальянский': 'it',
'португальский': 'pt', 'китайский': 'zh-cn', 'японский': 'ja',
'корейский': 'ko', 'арабский': 'ar', 'турецкий': 'tr'
}
self._name_to_code_cache.update(russian_names)
return self._name_to_code_cache
def get_language_code(self, lang: str) -> str:
"""Получить код языка из названия или кода"""
if not lang or lang == 'auto':
return 'auto'
# Если это уже код языка
if lang in self.languages:
return lang
# Ищем по названию
name_cache = self._build_name_cache()
return name_cache.get(lang.lower(), 'auto')
def get_language_name(self, code: str) -> str:
"""Получить название языка по коду"""
return self.languages.get(code, code)
async def translate(self, text: str, dest: str = 'ru', src: str = 'auto') -> Dict:
"""Асинхронный перевод текста"""
try:
# Получаем коды языков
dest_code = self.get_language_code(dest)
src_code = self.get_language_code(src) if src != 'auto' else 'auto'
# Выполняем перевод в отдельном потоке, так как googletrans не асинхронный
loop = asyncio.get_event_loop()
result = await loop.run_in_executor(
None,
lambda: self.translator.translate(text, src=src_code, dest=dest_code)
)
# Получаем альтернативные переводы (если есть)
alternatives = []
if hasattr(result, 'extra_data') and result.extra_data:
possible_translations = result.extra_data.get('possible-translations', [])
if possible_translations and len(possible_translations) > 0:
for translation_group in possible_translations[:3]:
if translation_group and len(translation_group) > 0:
for translation_item in translation_group[:2]:
if isinstance(translation_item, list) and len(translation_item) > 1:
alternatives.append(translation_item[1])
return {
'original_text': result.origin,
'translated_text': result.text,
'source_lang': result.src,
'target_lang': dest_code,
'source_lang_name': self.get_language_name(result.src),
'target_lang_name': self.get_language_name(dest_code),
'pronunciation': result.pronunciation,
'alternatives': alternatives[:5] if alternatives else None
}
except Exception as e:
logger.error(f"Translation error: {str(e)}")
raise Exception(f"Ошибка перевода: {str(e)}")
async def translate_batch(self, texts: List[str], dest: str = 'ru', src: str = 'auto') -> List[Dict]:
"""Пакетный перевод текстов"""
tasks = [self.translate(text, dest, src) for text in texts]
results = await asyncio.gather(*tasks, return_exceptions=True)
translations = []
for result in results:
if isinstance(result, Exception):
translations.append({
'error': str(result),
'original_text': '',
'translated_text': ''
})
else:
translations.append(result)
return translations
async def detect_language(self, text: str) -> Dict:
"""Определение языка текста"""
try:
loop = asyncio.get_event_loop()
result = await loop.run_in_executor(
None,
lambda: self.translator.detect(text)
)
return {
'lang': result.lang,
'lang_name': self.get_language_name(result.lang),
'confidence': result.confidence
}
except Exception as e:
logger.error(f"Language detection error: {str(e)}")
raise Exception(f"Ошибка определения языка: {str(e)}")
def get_supported_languages(self) -> List[Dict]:
"""Получить список поддерживаемых языков"""
languages = []
for code, name in sorted(self.languages.items()):
languages.append({
'code': code,
'name': name,
'native_name': name # Можно добавить маппинг на родные названия
})
return languages