Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
898 changes: 377 additions & 521 deletions LivescriptV2.01.py

Large diffs are not rendered by default.

491 changes: 176 additions & 315 deletions README.md

Large diffs are not rendered by default.

20 changes: 20 additions & 0 deletions settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"subtitle_color": "#FFFFFF",
"background_color": "#000000",
"background_opacity": 0.75,
"subtitle_size": 16,
"subtitle_font": "Arial",
"language": "English",
"block_size": 3000,
"model_path": "vosk-model-small-en-us-0.15",
"window_width": 1200,
"window_height": 1500,
"window_padding": 20,
"delay_threshold": 3.0,
"ran_before": true,
"show_about_on_startup": true,
"appearance_mode": "dark",
"translation_enabled": true,
"translation_target_language": "English",
"translation_backend": "ArgosTranslate"
}
225 changes: 119 additions & 106 deletions translator.py
Original file line number Diff line number Diff line change
@@ -1,139 +1,156 @@
import argostranslate.package
import argostranslate.translate
from transformers import MarianMTModel, MarianTokenizer
"""
Translator using deep-translator with better language detection
"""
from deep_translator import GoogleTranslator
import threading


# --- Base Translator Class ---
class BaseTranslator:
"""A base class for all translation backends."""

def __init__(self, from_lang_name, to_lang_name, status_callback=None):
self.from_lang_name = from_lang_name
self.to_lang_name = to_lang_name
self.status_callback = status_callback
self.is_ready = False

def translate(self, text):
"""Translates a given text."""
raise NotImplementedError

def check_and_install_model(self):
"""Checks if the required model is installed and downloads it if not."""
pass

def _update_status(self, message, color="gray"):
if self.status_callback:
self.status_callback(message, color)


class ArgosTranslator(BaseTranslator):
"""Translator using the Argos Translate library (offline)."""

def __init__(self, from_lang_name, to_lang_name, status_callback=None):
super().__init__(from_lang_name, to_lang_name, status_callback)
self.translator = None
self.from_lang = None
self.to_lang = None
self.check_model()

def check_model(self):
try:
installed_languages = argostranslate.translate.get_installed_languages()
self.from_lang = next((lang for lang in installed_languages if lang.name == self.from_lang_name), None)
self.to_lang = next((lang for lang in installed_languages if lang.name == self.to_lang_name), None)

if self.from_lang and self.to_lang:
self.translator = self.from_lang.get_translation(self.to_lang)
if self.translator:
self._update_status(f"Argos model for {self.from_lang_name} -> {self.to_lang_name} found.", "green")
self.is_ready = True
else:
# Languages are installed, but the specific translation isn't
self._update_status(
f"Argos translation for {self.from_lang_name} -> {self.to_lang_name} not found. Please install from Settings.",
"orange")
self.is_ready = False
else:
# One or both languages are not installed
self._update_status(
f"Argos language model for '{self.from_lang_name}' or '{self.to_lang_name}' not installed.",
"orange")
self.is_ready = False

except Exception as e:
self._update_status(f"Error checking Argos model: {e}", "red")
self.is_ready = False
self.from_lang = self._get_lang_code(from_lang_name)
self.to_lang = self._get_lang_code(to_lang_name)
self.is_ready = True
self._update_status(f"Google Translate ready: {from_lang_name} -> {to_lang_name}", "green")

def _get_lang_code(self, lang_name):
"""Convert language name to Google Translate code - EXPANDED MAP"""
lang_map = {
'english': 'en',
'hindi': 'hi',
'telugu': 'te',
'tamil': 'ta',
'japanese': 'ja',
'french': 'fr',
'german': 'de',
'spanish': 'es',
'chinese': 'zh-cn',
'arabic': 'ar',
'russian': 'ru',
'portuguese': 'pt',
'italian': 'it',
'korean': 'ko',
'dutch': 'nl',
'turkish': 'tr',
'polish': 'pl',
'swedish': 'sv',
'vietnamese': 'vi',
'thai': 'th',
'gujarati': 'gu',
'kannada': 'kn',
'malayalam': 'ml',
'marathi': 'mr',
'punjabi': 'pa',
'bengali': 'bn',
'urdu': 'ur',
'oriya': 'or',
'assamese': 'as'
}
# Try exact match first, then lowercase
result = lang_map.get(lang_name.lower(), 'en')
print(f"Language mapping: {lang_name} -> {result}") # Debug
return result

def translate(self, text):
if not self.is_ready or not self.translator:
return f"[No Argos Model] {text}"
if not text or not text.strip():
return text
try:
return self.translator.translate(text)
print(f"Translating: '{text[:50]}...' from {self.from_lang} to {self.to_lang}") # Debug

# Try with explicit source language
translator = GoogleTranslator(source=self.from_lang, target=self.to_lang)
result = translator.translate(text)
print(f"Translation result: '{result[:50]}...'") # Debug
return result

except Exception as e:
print(f"Argos translation error: {e}")
return f"[Translation Error] {text}"
print(f"Translation error (explicit source): {e}")
try:
# Fallback: auto-detect source
translator = GoogleTranslator(source='auto', target=self.to_lang)
result = translator.translate(text)
print(f"Fallback result: '{result[:50]}...'")
return result
except Exception as e2:
print(f"Translation error (auto-detect): {e2}")
return f"[Error] {text}"


class MarianTranslator(BaseTranslator):
"""Translator using Hugging Face MarianMT models (offline)."""
LANG_CODE_MAP = {
"English": "en", "French": "fr", "German": "de", "Spanish": "es",
"Russian": "ru", "Chinese": "zh", "Italian": "it", "Portuguese": "pt",
"Dutch": "nl", "Japanese": "jap", "Arabic": "ar", "Hindi": "hi",
}

def __init__(self, from_lang_name, to_lang_name, status_callback=None):
super().__init__(from_lang_name, to_lang_name, status_callback)
self.model = None
self.tokenizer = None
self.model_name = None
self.check_model()

def check_model(self):
from_code = self.LANG_CODE_MAP.get(self.from_lang_name)
to_code = self.LANG_CODE_MAP.get(self.to_lang_name)

if not from_code or not to_code:
self._update_status(f"MarianMT does not support {self.from_lang_name} or {self.to_lang_name}.", "red")
self.is_ready = False
return

self.model_name = f'Helsinki-NLP/opus-mt-{from_code}-{to_code}'
self._update_status(f"Checking for MarianMT model: {self.model_name}...", "gray")

try:
# from_pretrained checks local cache first. This avoids re-downloading.
self.tokenizer = MarianTokenizer.from_pretrained(self.model_name)
self.model = MarianMTModel.from_pretrained(self.model_name)
self._update_status(f"MarianMT model '{self.model_name}' is ready.", "green")
self.is_ready = True
except Exception:
self._update_status(f"Model '{self.model_name}' not found. Download from Settings.", "orange")
self.is_ready = False
self.from_lang = self._get_lang_code(from_lang_name)
self.to_lang = self._get_lang_code(to_lang_name)
self.is_ready = True
self._update_status(f"Google Translate ready: {from_lang_name} -> {to_lang_name}", "green")

def _get_lang_code(self, lang_name):
"""Convert language name to Google Translate code"""
lang_map = {
'english': 'en',
'hindi': 'hi',
'telugu': 'te',
'tamil': 'ta',
'japanese': 'ja',
'french': 'fr',
'german': 'de',
'spanish': 'es',
'chinese': 'zh-cn',
'arabic': 'ar',
'russian': 'ru',
'portuguese': 'pt',
'italian': 'it',
'korean': 'ko',
'dutch': 'nl',
'turkish': 'tr',
'polish': 'pl',
'swedish': 'sv',
'vietnamese': 'vi',
'thai': 'th'
}
return lang_map.get(lang_name.lower(), 'en')

def translate(self, text):
if not self.is_ready or not self.model or not self.tokenizer:
return f"[No MarianMT Model] {text}"

if not text or not text.strip():
return text
try:
tokenized_text = self.tokenizer(text, return_tensors="pt", padding=True)
translated_tokens = self.model.generate(**tokenized_text)
return self.tokenizer.decode(translated_tokens[0], skip_special_tokens=True)
translator = GoogleTranslator(source=self.from_lang, target=self.to_lang)
return translator.translate(text)
except Exception as e:
print(f"MarianMT translation error: {e}")
return f"[MarianMT Error] {text}"
print(f"Translation error: {e}")
try:
translator = GoogleTranslator(source='auto', target=self.to_lang)
return translator.translate(text)
except Exception as e2:
print(f"Translation fallback error: {e2}")
return f"[Error] {text}"


def get_translator(settings, status_callback=None):
"""Factory function to get the correct translator instance."""
if not settings.get("translation_enabled"):
if not settings.get("translation_enabled", True):
return None

backend = settings.get("translation_backend", "ArgosTranslate")
from_lang = settings.get("language", "English").split(" ")[0]
from_lang = settings.get("language", "English")
to_lang = settings.get("translation_target_language", "Spanish")

print(f"Creating translator: {from_lang} -> {to_lang} using {backend}") # Debug

if backend == "ArgosTranslate":
return ArgosTranslator(from_lang, to_lang, status_callback)
elif backend == "MarianMT":
Expand All @@ -143,15 +160,11 @@ def get_translator(settings, status_callback=None):


def get_available_argos_languages():
"""Helper to get a list of all unique language names from Argos packages."""
try:
argostranslate.package.update_package_index()
packages = argostranslate.package.get_available_packages()
lang_names = set()
for pkg in packages:
lang_names.add(pkg.from_name)
lang_names.add(pkg.to_name)
return sorted(list(lang_names))
except Exception as e:
print(f"Could not fetch Argos language list: {e}")
return ["English", "Spanish", "French", "German"] # Fallback
"""Return list of supported languages"""
return [
"English", "Hindi", "Telugu", "Tamil", "Japanese", "French",
"German", "Spanish", "Chinese", "Arabic", "Russian", "Portuguese",
"Italian", "Korean", "Dutch", "Turkish", "Polish", "Swedish",
"Vietnamese", "Thai", "Gujarati", "Kannada", "Malayalam",
"Marathi", "Punjabi", "Bengali", "Urdu"
]
Loading