Spaces:
Sleeping
Sleeping
elevenlabs support fix
Browse files- translator_app/translator/__pycache__/views.cpython-314.pyc +0 -0
- translator_app/translator/services/__pycache__/translation_service.cpython-314.pyc +0 -0
- translator_app/translator/services/language_support.py +17 -2
- translator_app/translator/services/translation_service.py +1 -1
- translator_app/translator/templates/translator/translator.html +3 -4
- translator_app/translator/views.py +17 -3
- translator_app/translator_project/__pycache__/settings.cpython-314.pyc +0 -0
- translator_app/translator_project/settings.py +3 -6
translator_app/translator/__pycache__/views.cpython-314.pyc
CHANGED
|
Binary files a/translator_app/translator/__pycache__/views.cpython-314.pyc and b/translator_app/translator/__pycache__/views.cpython-314.pyc differ
|
|
|
translator_app/translator/services/__pycache__/translation_service.cpython-314.pyc
CHANGED
|
Binary files a/translator_app/translator/services/__pycache__/translation_service.cpython-314.pyc and b/translator_app/translator/services/__pycache__/translation_service.cpython-314.pyc differ
|
|
|
translator_app/translator/services/language_support.py
CHANGED
|
@@ -49,10 +49,10 @@ MODEL_LANGUAGE_SUPPORT = {
|
|
| 49 |
"madlad": {"en", "sw", "rw", "fr", "ar"},
|
| 50 |
# DeepL has no coverage at all for sw/lg/nyn/ach/teo/lgg/rw.
|
| 51 |
"deepl_fallback": {"en", "fr", "ar"},
|
| 52 |
-
"
|
| 53 |
}
|
| 54 |
|
| 55 |
-
FALLBACK_MODEL = "
|
| 56 |
|
| 57 |
# ElevenLabs eleven_multilingual_v2's real language list (per their docs as
|
| 58 |
# of mid-2026). None of your East African languages are on it - only en/fr/ar
|
|
@@ -64,6 +64,21 @@ ELEVENLABS_MULTILINGUAL_V2_LANGUAGES = {
|
|
| 64 |
"fi", "bg", "hr", "sk", "ta",
|
| 65 |
}
|
| 66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 67 |
|
| 68 |
def supported_codes(model):
|
| 69 |
"""Set of codes a model supports, or None if unrestricted."""
|
|
|
|
| 49 |
"madlad": {"en", "sw", "rw", "fr", "ar"},
|
| 50 |
# DeepL has no coverage at all for sw/lg/nyn/ach/teo/lgg/rw.
|
| 51 |
"deepl_fallback": {"en", "fr", "ar"},
|
| 52 |
+
"google": None,
|
| 53 |
}
|
| 54 |
|
| 55 |
+
FALLBACK_MODEL = "google"
|
| 56 |
|
| 57 |
# ElevenLabs eleven_multilingual_v2's real language list (per their docs as
|
| 58 |
# of mid-2026). None of your East African languages are on it - only en/fr/ar
|
|
|
|
| 64 |
"fi", "bg", "hr", "sk", "ta",
|
| 65 |
}
|
| 66 |
|
| 67 |
+
ELEVENLABS_V3_LANGUAGES = {
|
| 68 |
+
"af", "sq", "am", "ar", "hy", "as", "az", "ba", "eu", "be",
|
| 69 |
+
"bn", "bos", "bg", "my", "ca", "ceb", "ny", "zh", "hr", "cs",
|
| 70 |
+
"da", "nl", "en", "eo", "et", "fil", "fi", "fr", "gl", "ka",
|
| 71 |
+
"de", "el", "gu", "ht", "ha", "haw", "he", "hi", "hmn", "hu",
|
| 72 |
+
"is", "ig", "id", "ga", "it", "ja", "jv", "kn", "kk", "km",
|
| 73 |
+
"rw", "ko", "ku", "ky", "lo", "la", "lv", "ln", "lt", "lb",
|
| 74 |
+
"mk", "mg", "ms", "ml", "mt", "mi", "mr", "mn", "ne", "no",
|
| 75 |
+
"or", "om", "ps", "fa", "pl", "pt", "pa", "ro", "ru", "sm",
|
| 76 |
+
"gd", "sr", "st", "sn", "sd", "si", "sk", "sl", "so", "es",
|
| 77 |
+
"su", "sw", "sv", "tg", "ta", "tt", "te", "th", "tr", "tk",
|
| 78 |
+
"uk", "ur", "ug", "uz", "vi", "cy", "xh", "yi", "yo", "zu"
|
| 79 |
+
}
|
| 80 |
+
|
| 81 |
+
|
| 82 |
|
| 83 |
def supported_codes(model):
|
| 84 |
"""Set of codes a model supports, or None if unrestricted."""
|
translator_app/translator/services/translation_service.py
CHANGED
|
@@ -87,7 +87,7 @@ class TranslationService:
|
|
| 87 |
|
| 88 |
if model == "deepl_fallback":
|
| 89 |
outcome = self._translate_deepl(text, source_language, target_language)
|
| 90 |
-
elif model == "
|
| 91 |
# Explicit, user-selectable Google fallback. Reuses the exact
|
| 92 |
# same free-fallback call already used internally elsewhere in
|
| 93 |
# this class - no new translation logic introduced.
|
|
|
|
| 87 |
|
| 88 |
if model == "deepl_fallback":
|
| 89 |
outcome = self._translate_deepl(text, source_language, target_language)
|
| 90 |
+
elif model == "google":
|
| 91 |
# Explicit, user-selectable Google fallback. Reuses the exact
|
| 92 |
# same free-fallback call already used internally elsewhere in
|
| 93 |
# this class - no new translation logic introduced.
|
translator_app/translator/templates/translator/translator.html
CHANGED
|
@@ -85,13 +85,12 @@
|
|
| 85 |
</button>
|
| 86 |
<button id="copy-result" type="button"
|
| 87 |
class="hidden rounded-full bg-mist px-3 py-1 text-xs font-bold text-primary hover:bg-stone-200 transition">
|
| 88 |
-
|
| 89 |
</button>
|
| 90 |
</div>
|
| 91 |
</div>
|
| 92 |
<p id="translated-text" aria-live="polite"
|
| 93 |
-
class="relative flex-1 whitespace-pre-wrap font-display text-2xl leading-relaxed text-primary">
|
| 94 |
-
<span class="text-stone-300">Your translation will appear here.</span>
|
| 95 |
</p>
|
| 96 |
<p id="result-meta" class="mt-4 text-xs text-stone-400 border-t border-stone-100 pt-3"></p>
|
| 97 |
</section>
|
|
@@ -220,7 +219,7 @@
|
|
| 220 |
const srcOk = modelSelect.value === 'madlad' || !sourceSelect.value || allowed.has(sourceSelect.value);
|
| 221 |
const tgtOk = !targetSelect.value || allowed.has(targetSelect.value);
|
| 222 |
if (!srcOk || !tgtOk) {
|
| 223 |
-
modelSelect.value = '
|
| 224 |
syncLanguagesForModel();
|
| 225 |
message.textContent = 'Switched to Google Translate (fallback) - the previous model doesn\'t support this language.';
|
| 226 |
}
|
|
|
|
| 85 |
</button>
|
| 86 |
<button id="copy-result" type="button"
|
| 87 |
class="hidden rounded-full bg-mist px-3 py-1 text-xs font-bold text-primary hover:bg-stone-200 transition">
|
| 88 |
+
Copy
|
| 89 |
</button>
|
| 90 |
</div>
|
| 91 |
</div>
|
| 92 |
<p id="translated-text" aria-live="polite"
|
| 93 |
+
class="relative flex-1 whitespace-pre-wrap font-display text-2xl leading-relaxed text-primary"><span class="text-stone-300">Your translation will appear here.</span>
|
|
|
|
| 94 |
</p>
|
| 95 |
<p id="result-meta" class="mt-4 text-xs text-stone-400 border-t border-stone-100 pt-3"></p>
|
| 96 |
</section>
|
|
|
|
| 219 |
const srcOk = modelSelect.value === 'madlad' || !sourceSelect.value || allowed.has(sourceSelect.value);
|
| 220 |
const tgtOk = !targetSelect.value || allowed.has(targetSelect.value);
|
| 221 |
if (!srcOk || !tgtOk) {
|
| 222 |
+
modelSelect.value = 'google';
|
| 223 |
syncLanguagesForModel();
|
| 224 |
message.textContent = 'Switched to Google Translate (fallback) - the previous model doesn\'t support this language.';
|
| 225 |
}
|
translator_app/translator/views.py
CHANGED
|
@@ -38,7 +38,7 @@ def translator(request):
|
|
| 38 |
'models': settings.TRANSLATION_MODELS,
|
| 39 |
'default_model': settings.TRANSLATION_DEFAULT_MODEL,
|
| 40 |
'model_language_support_json': model_language_support,
|
| 41 |
-
'elevenlabs_languages_json': sorted(language_support.
|
| 42 |
})
|
| 43 |
|
| 44 |
|
|
@@ -118,6 +118,20 @@ def translate_api(request):
|
|
| 118 |
return JsonResponse(result)
|
| 119 |
|
| 120 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 121 |
@require_POST
|
| 122 |
def text_to_speech(request):
|
| 123 |
if not settings.ELEVENLABS_API_KEY:
|
|
@@ -139,7 +153,7 @@ def text_to_speech(request):
|
|
| 139 |
|
| 140 |
# Fail fast client-side instead of burning an API call: ElevenLabs'
|
| 141 |
# multilingual model has no voice for these languages yet.
|
| 142 |
-
if lang and lang not in language_support.
|
| 143 |
return JsonResponse(
|
| 144 |
{
|
| 145 |
'error': 'ElevenLabs does not have a voice for this language yet.',
|
|
@@ -158,7 +172,7 @@ def text_to_speech(request):
|
|
| 158 |
},
|
| 159 |
json={
|
| 160 |
'text': text,
|
| 161 |
-
'model_id':
|
| 162 |
},
|
| 163 |
timeout=20,
|
| 164 |
)
|
|
|
|
| 38 |
'models': settings.TRANSLATION_MODELS,
|
| 39 |
'default_model': settings.TRANSLATION_DEFAULT_MODEL,
|
| 40 |
'model_language_support_json': model_language_support,
|
| 41 |
+
'elevenlabs_languages_json': sorted(language_support.ELEVENLABS_V3_LANGUAGES),
|
| 42 |
})
|
| 43 |
|
| 44 |
|
|
|
|
| 118 |
return JsonResponse(result)
|
| 119 |
|
| 120 |
|
| 121 |
+
def get_elevenlabs_model(lang_code: str) -> str:
|
| 122 |
+
"""
|
| 123 |
+
Returns the cheapest compatible ElevenLabs model ID for a given language code.
|
| 124 |
+
Falls back to v3 if v2 does not support it.
|
| 125 |
+
"""
|
| 126 |
+
clean_code = lang_code.lower().strip()
|
| 127 |
+
|
| 128 |
+
if clean_code in language_support.ELEVENLABS_MULTILINGUAL_V2_LANGUAGES:
|
| 129 |
+
return "eleven_multilingual_v2"
|
| 130 |
+
elif clean_code in language_support.ELEVENLABS_V3_LANGUAGES:
|
| 131 |
+
return "eleven_v3"
|
| 132 |
+
else:
|
| 133 |
+
raise ValueError(f"Language code '{lang_code}' is not supported by any ElevenLabs model.")
|
| 134 |
+
|
| 135 |
@require_POST
|
| 136 |
def text_to_speech(request):
|
| 137 |
if not settings.ELEVENLABS_API_KEY:
|
|
|
|
| 153 |
|
| 154 |
# Fail fast client-side instead of burning an API call: ElevenLabs'
|
| 155 |
# multilingual model has no voice for these languages yet.
|
| 156 |
+
if lang and lang not in language_support.ELEVENLABS_V3_LANGUAGES:
|
| 157 |
return JsonResponse(
|
| 158 |
{
|
| 159 |
'error': 'ElevenLabs does not have a voice for this language yet.',
|
|
|
|
| 172 |
},
|
| 173 |
json={
|
| 174 |
'text': text,
|
| 175 |
+
'model_id': get_elevenlabs_model(lang),
|
| 176 |
},
|
| 177 |
timeout=20,
|
| 178 |
)
|
translator_app/translator_project/__pycache__/settings.cpython-314.pyc
CHANGED
|
Binary files a/translator_app/translator_project/__pycache__/settings.cpython-314.pyc and b/translator_app/translator_project/__pycache__/settings.cpython-314.pyc differ
|
|
|
translator_app/translator_project/settings.py
CHANGED
|
@@ -91,7 +91,6 @@ USE_TZ = True
|
|
| 91 |
|
| 92 |
# Static files
|
| 93 |
STATIC_URL = "static/"
|
| 94 |
-
# STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
|
| 95 |
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
|
| 96 |
|
| 97 |
# Media files
|
|
@@ -101,15 +100,14 @@ MEDIA_ROOT = os.path.join(BASE_DIR, "media")
|
|
| 101 |
# Default primary key field type
|
| 102 |
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
| 103 |
|
| 104 |
-
# ML translation service
|
| 105 |
-
# https://<account>-<space>.hf.space/api/translate
|
| 106 |
MODEL_API_URL = os.getenv("MODEL_API_URL")
|
| 107 |
TRANSLATION_DEFAULT_MODEL = os.getenv("TRANSLATION_DEFAULT_MODEL", "nllb")
|
| 108 |
TRANSLATION_MODELS = (
|
| 109 |
("nllb", "NLLB-200 (600M 路 Fast)"),
|
| 110 |
("nllb_1_3b", "NLLB-200 (1.3B 路 Accurate)"),
|
| 111 |
("madlad", "MADLAD-400 (3B 路 Large)"),
|
| 112 |
-
("
|
| 113 |
)
|
| 114 |
TRANSLATION_MODEL_ENGINES = {
|
| 115 |
"nllb": "nllb",
|
|
@@ -132,6 +130,5 @@ if TRANSLATION_API_KEY:
|
|
| 132 |
# never send it to the browser. Get a key at https://elevenlabs.io/app/settings/api-keys
|
| 133 |
# and a voice ID from https://elevenlabs.io/app/voice-library
|
| 134 |
ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
|
| 135 |
-
ELEVENLABS_VOICE_ID = os.getenv("ELEVENLABS_VOICE_ID", "
|
| 136 |
-
ELEVENLABS_MODEL_ID = os.getenv("ELEVENLABS_MODEL_ID", "eleven_multilingual_v2")
|
| 137 |
ELEVENLABS_TTS_URL = "https://api.elevenlabs.io/v1/text-to-speech/{voice_id}"
|
|
|
|
| 91 |
|
| 92 |
# Static files
|
| 93 |
STATIC_URL = "static/"
|
|
|
|
| 94 |
STATIC_ROOT = os.path.join(BASE_DIR, "staticfiles")
|
| 95 |
|
| 96 |
# Media files
|
|
|
|
| 100 |
# Default primary key field type
|
| 101 |
DEFAULT_AUTO_FIELD = "django.db.models.BigAutoField"
|
| 102 |
|
| 103 |
+
# ML translation service
|
|
|
|
| 104 |
MODEL_API_URL = os.getenv("MODEL_API_URL")
|
| 105 |
TRANSLATION_DEFAULT_MODEL = os.getenv("TRANSLATION_DEFAULT_MODEL", "nllb")
|
| 106 |
TRANSLATION_MODELS = (
|
| 107 |
("nllb", "NLLB-200 (600M 路 Fast)"),
|
| 108 |
("nllb_1_3b", "NLLB-200 (1.3B 路 Accurate)"),
|
| 109 |
("madlad", "MADLAD-400 (3B 路 Large)"),
|
| 110 |
+
("google", "Google Translate"),
|
| 111 |
)
|
| 112 |
TRANSLATION_MODEL_ENGINES = {
|
| 113 |
"nllb": "nllb",
|
|
|
|
| 130 |
# never send it to the browser. Get a key at https://elevenlabs.io/app/settings/api-keys
|
| 131 |
# and a voice ID from https://elevenlabs.io/app/voice-library
|
| 132 |
ELEVENLABS_API_KEY = os.getenv("ELEVENLABS_API_KEY")
|
| 133 |
+
ELEVENLABS_VOICE_ID = os.getenv("ELEVENLABS_VOICE_ID", "hpp4J3VqNfWAUOO0d1Us")
|
|
|
|
| 134 |
ELEVENLABS_TTS_URL = "https://api.elevenlabs.io/v1/text-to-speech/{voice_id}"
|