|
|
import os
|
|
|
import tempfile
|
|
|
import time
|
|
|
from gtts import gTTS
|
|
|
import streamlit as st
|
|
|
|
|
|
|
|
|
try:
|
|
|
from googletrans import Translator
|
|
|
TRANSLATOR_AVAILABLE = True
|
|
|
except ImportError:
|
|
|
TRANSLATOR_AVAILABLE = False
|
|
|
|
|
|
|
|
|
import requests
|
|
|
import json
|
|
|
|
|
|
class TranslationAgent:
|
|
|
def __init__(self):
|
|
|
if TRANSLATOR_AVAILABLE:
|
|
|
self.translator = Translator()
|
|
|
else:
|
|
|
self.translator = None
|
|
|
|
|
|
self.languages = {
|
|
|
'en': 'English',
|
|
|
'es': 'Spanish',
|
|
|
'fr': 'French',
|
|
|
'de': 'German',
|
|
|
'it': 'Italian',
|
|
|
'pt': 'Portuguese',
|
|
|
'ru': 'Russian',
|
|
|
'zh': 'Chinese',
|
|
|
'ja': 'Japanese',
|
|
|
'ko': 'Korean',
|
|
|
'ar': 'Arabic',
|
|
|
'hi': 'Hindi',
|
|
|
'tr': 'Turkish',
|
|
|
'pl': 'Polish',
|
|
|
'nl': 'Dutch',
|
|
|
'sv': 'Swedish',
|
|
|
'da': 'Danish',
|
|
|
'no': 'Norwegian',
|
|
|
'fi': 'Finnish',
|
|
|
'cs': 'Czech',
|
|
|
'hu': 'Hungarian',
|
|
|
'ro': 'Romanian',
|
|
|
'bg': 'Bulgarian',
|
|
|
'hr': 'Croatian',
|
|
|
'sk': 'Slovak',
|
|
|
'sl': 'Slovenian',
|
|
|
'et': 'Estonian',
|
|
|
'lv': 'Latvian',
|
|
|
'lt': 'Lithuanian',
|
|
|
'mt': 'Maltese',
|
|
|
'ga': 'Irish',
|
|
|
'cy': 'Welsh',
|
|
|
'eu': 'Basque',
|
|
|
'ca': 'Catalan',
|
|
|
'gl': 'Galician',
|
|
|
'is': 'Icelandic',
|
|
|
'mk': 'Macedonian',
|
|
|
'sq': 'Albanian',
|
|
|
'be': 'Belarusian',
|
|
|
'uk': 'Ukrainian',
|
|
|
'he': 'Hebrew',
|
|
|
'th': 'Thai',
|
|
|
'vi': 'Vietnamese',
|
|
|
'id': 'Indonesian',
|
|
|
'ms': 'Malay',
|
|
|
'tl': 'Filipino',
|
|
|
'sw': 'Swahili',
|
|
|
'am': 'Amharic',
|
|
|
'bn': 'Bengali',
|
|
|
'gu': 'Gujarati',
|
|
|
'kn': 'Kannada',
|
|
|
'ml': 'Malayalam',
|
|
|
'mr': 'Marathi',
|
|
|
'ne': 'Nepali',
|
|
|
'or': 'Odia',
|
|
|
'pa': 'Punjabi',
|
|
|
'si': 'Sinhala',
|
|
|
'ta': 'Tamil',
|
|
|
'te': 'Telugu',
|
|
|
'ur': 'Urdu',
|
|
|
'my': 'Myanmar',
|
|
|
'km': 'Khmer',
|
|
|
'lo': 'Lao',
|
|
|
'ka': 'Georgian',
|
|
|
'hy': 'Armenian',
|
|
|
'az': 'Azerbaijani',
|
|
|
'kk': 'Kazakh',
|
|
|
'ky': 'Kyrgyz',
|
|
|
'mn': 'Mongolian',
|
|
|
'tg': 'Tajik',
|
|
|
'tk': 'Turkmen',
|
|
|
'uz': 'Uzbek',
|
|
|
'fa': 'Persian',
|
|
|
'ps': 'Pashto',
|
|
|
'sd': 'Sindhi',
|
|
|
'so': 'Somali',
|
|
|
'xh': 'Xhosa',
|
|
|
'zu': 'Zulu',
|
|
|
'af': 'Afrikaans'
|
|
|
}
|
|
|
|
|
|
|
|
|
self.tts_map = {
|
|
|
'zh': 'zh-cn',
|
|
|
'or': 'hi',
|
|
|
'ps': 'fa',
|
|
|
'sd': 'ur',
|
|
|
'ky': 'ru',
|
|
|
'kk': 'ru',
|
|
|
'tg': 'ru',
|
|
|
'tk': 'ru',
|
|
|
'uz': 'ru',
|
|
|
'am': 'ar',
|
|
|
'my': 'th',
|
|
|
'km': 'th',
|
|
|
'lo': 'th',
|
|
|
}
|
|
|
|
|
|
def translate_with_googletrans(self, text, source_lang=None, target_lang='en'):
|
|
|
"""Try translation with googletrans library"""
|
|
|
try:
|
|
|
if source_lang:
|
|
|
result = self.translator.translate(text, src=source_lang, dest=target_lang)
|
|
|
else:
|
|
|
result = self.translator.translate(text, dest=target_lang)
|
|
|
|
|
|
return {
|
|
|
'translated_text': result.text,
|
|
|
'detected_language': result.src,
|
|
|
'target_language': target_lang,
|
|
|
'original_text': text
|
|
|
}
|
|
|
except Exception as e:
|
|
|
raise Exception(f"GoogleTrans failed: {str(e)}")
|
|
|
|
|
|
def translate_with_api(self, text, source_lang=None, target_lang='en'):
|
|
|
"""Fallback translation using direct API"""
|
|
|
try:
|
|
|
base_url = "https://translate.googleapis.com/translate_a/single"
|
|
|
|
|
|
params = {
|
|
|
'client': 'gtx',
|
|
|
'sl': source_lang if source_lang else 'auto',
|
|
|
'tl': target_lang,
|
|
|
'dt': 't',
|
|
|
'q': text
|
|
|
}
|
|
|
|
|
|
headers = {
|
|
|
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
|
|
|
}
|
|
|
|
|
|
response = requests.get(base_url, params=params, headers=headers, timeout=10)
|
|
|
response.raise_for_status()
|
|
|
|
|
|
result = response.json()
|
|
|
|
|
|
translated_text = ""
|
|
|
if result and len(result) > 0 and result[0]:
|
|
|
for sentence in result[0]:
|
|
|
if sentence and sentence[0]:
|
|
|
translated_text += sentence[0]
|
|
|
|
|
|
detected_lang = result[2] if len(result) > 2 else (source_lang or 'auto')
|
|
|
|
|
|
return {
|
|
|
'translated_text': translated_text if translated_text.strip() else text,
|
|
|
'detected_language': detected_lang,
|
|
|
'target_language': target_lang,
|
|
|
'original_text': text
|
|
|
}
|
|
|
|
|
|
except Exception as e:
|
|
|
raise Exception(f"API translation failed: {str(e)}")
|
|
|
|
|
|
def translate_text(self, text, source_lang=None, target_lang='en'):
|
|
|
"""
|
|
|
Translate text with multiple fallbacks
|
|
|
"""
|
|
|
|
|
|
if TRANSLATOR_AVAILABLE and self.translator:
|
|
|
try:
|
|
|
return self.translate_with_googletrans(text, source_lang, target_lang)
|
|
|
except:
|
|
|
pass
|
|
|
|
|
|
|
|
|
try:
|
|
|
return self.translate_with_api(text, source_lang, target_lang)
|
|
|
except:
|
|
|
pass
|
|
|
|
|
|
|
|
|
return {
|
|
|
'translated_text': text,
|
|
|
'detected_language': source_lang or 'auto',
|
|
|
'target_language': target_lang,
|
|
|
'original_text': text
|
|
|
}
|
|
|
|
|
|
def text_to_speech(self, text, language='en'):
|
|
|
"""
|
|
|
Convert text to speech with fallbacks
|
|
|
"""
|
|
|
try:
|
|
|
|
|
|
tts_lang = self.tts_map.get(language, language)
|
|
|
|
|
|
|
|
|
tts = gTTS(text=text, lang=tts_lang, slow=False)
|
|
|
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.mp3')
|
|
|
temp_file.close()
|
|
|
tts.save(temp_file.name)
|
|
|
|
|
|
return temp_file.name
|
|
|
|
|
|
except Exception as e:
|
|
|
|
|
|
try:
|
|
|
if language != 'en':
|
|
|
tts = gTTS(text=text, lang='en', slow=False)
|
|
|
temp_file = tempfile.NamedTemporaryFile(delete=False, suffix='.mp3')
|
|
|
temp_file.close()
|
|
|
tts.save(temp_file.name)
|
|
|
return temp_file.name
|
|
|
else:
|
|
|
raise e
|
|
|
except:
|
|
|
raise Exception(f"Text-to-speech failed: {str(e)}")
|
|
|
|
|
|
def translate_and_speak(self, text, source_lang=None, target_lang='en'):
|
|
|
"""
|
|
|
Complete workflow: translate text and generate speech
|
|
|
"""
|
|
|
try:
|
|
|
|
|
|
translation_result = self.translate_text(text, source_lang, target_lang)
|
|
|
|
|
|
|
|
|
audio_file = self.text_to_speech(
|
|
|
translation_result['translated_text'],
|
|
|
target_lang
|
|
|
)
|
|
|
|
|
|
|
|
|
return {
|
|
|
'original_text': text,
|
|
|
'translated_text': translation_result['translated_text'],
|
|
|
'detected_language': translation_result['detected_language'],
|
|
|
'target_language': target_lang,
|
|
|
'audio_file': audio_file
|
|
|
}
|
|
|
|
|
|
except Exception as e:
|
|
|
raise Exception(f"Translation and speech generation failed: {str(e)}")
|
|
|
|
|
|
def get_supported_languages(self):
|
|
|
"""Get supported languages"""
|
|
|
return self.languages.copy()
|
|
|
|
|
|
def cleanup_temp_files(self, file_path):
|
|
|
"""Clean up temporary files"""
|
|
|
try:
|
|
|
if os.path.exists(file_path):
|
|
|
os.unlink(file_path)
|
|
|
except:
|
|
|
pass |