Spaces:
Sleeping
Sleeping
usertea commited on
Commit ·
58a8d7f
1
Parent(s): 815d3aa
EchoScript : 20260630 0857 - _marian_model_exists() , _safe_marian_exists() , HF_TOKEN/HUGGINGFACE_HUB_TOKEN
Browse files- app.py +1 -1
- services/translation.py +48 -11
app.py
CHANGED
|
@@ -325,7 +325,7 @@ with gr.Blocks(title="EchoScript") as demo:
|
|
| 325 |
**Upload Audio → Select Audio Window → Detect Language & Generate Transcript
|
| 326 |
→ Preview & Choose Languages → Generate Translations → Copy / Download**
|
| 327 |
|
| 328 |
-
<sub>build: 2026-06-
|
| 329 |
"""
|
| 330 |
)
|
| 331 |
|
|
|
|
| 325 |
**Upload Audio → Select Audio Window → Detect Language & Generate Transcript
|
| 326 |
→ Preview & Choose Languages → Generate Translations → Copy / Download**
|
| 327 |
|
| 328 |
+
<sub>build: 2026-06-30 08:57 UTC · fixed: rate-limited Hub checks were being cached as "language unavailable"</sub>
|
| 329 |
"""
|
| 330 |
)
|
| 331 |
|
services/translation.py
CHANGED
|
@@ -231,31 +231,68 @@ def _marian_model_exists(source_language: str, target_language: str) -> bool:
|
|
| 231 |
deliberately kept separate from _try_load_marian_engine so the UI can
|
| 232 |
cheaply ask "what's actually available for this source language"
|
| 233 |
without paying the cost of downloading every candidate model.
|
| 234 |
-
|
| 235 |
-
|
| 236 |
-
|
| 237 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 238 |
"""
|
| 239 |
from huggingface_hub import HfApi
|
| 240 |
from huggingface_hub.utils import HfHubHTTPError
|
| 241 |
|
| 242 |
try:
|
| 243 |
-
HfApi().model_info(_marian_repo_id(source_language, target_language))
|
| 244 |
return True
|
| 245 |
-
except HfHubHTTPError:
|
| 246 |
-
|
| 247 |
-
|
| 248 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 249 |
|
| 250 |
|
| 251 |
def _marian_path_exists(source_language: str, target_language: str) -> bool:
|
| 252 |
"""Direct pair, or a source->en->target pivot, whichever is real."""
|
| 253 |
if source_language == target_language:
|
| 254 |
return False
|
| 255 |
-
if
|
| 256 |
return True
|
| 257 |
if source_language != "en" and target_language != "en":
|
| 258 |
-
return
|
| 259 |
return False
|
| 260 |
|
| 261 |
|
|
|
|
| 231 |
deliberately kept separate from _try_load_marian_engine so the UI can
|
| 232 |
cheaply ask "what's actually available for this source language"
|
| 233 |
without paying the cost of downloading every candidate model.
|
| 234 |
+
|
| 235 |
+
Only a confirmed 404 (the repo genuinely doesn't exist) is cached as
|
| 236 |
+
False. Anything else -- rate limiting, a timeout, a transient network
|
| 237 |
+
error -- raises instead of being swallowed into a False. This matters
|
| 238 |
+
because @lru_cache only caches a function's return value, never an
|
| 239 |
+
exception it raised: if this returned False for a rate-limited
|
| 240 |
+
request, that wrong "doesn't exist" answer would be locked in for the
|
| 241 |
+
rest of the session (this is what was hiding Persian as a translation
|
| 242 |
+
target from English, even though Helsinki-NLP/opus-mt-en-fa genuinely
|
| 243 |
+
exists -- a burst of ~30+ unauthenticated existence checks during one
|
| 244 |
+
transcript's language-detection step is enough to get rate-limited).
|
| 245 |
+
Callers must catch the transient case themselves (see
|
| 246 |
+
_safe_marian_exists) and decide what "I don't know yet" should mean
|
| 247 |
+
for that call site, rather than this function silently deciding it.
|
| 248 |
"""
|
| 249 |
from huggingface_hub import HfApi
|
| 250 |
from huggingface_hub.utils import HfHubHTTPError
|
| 251 |
|
| 252 |
try:
|
| 253 |
+
HfApi(token=_hf_token()).model_info(_marian_repo_id(source_language, target_language))
|
| 254 |
return True
|
| 255 |
+
except HfHubHTTPError as exc:
|
| 256 |
+
status_code = getattr(getattr(exc, "response", None), "status_code", None)
|
| 257 |
+
if status_code == 404:
|
| 258 |
+
return False
|
| 259 |
+
raise # 429 / 5xx / etc. -- not proof the model doesn't exist
|
| 260 |
+
|
| 261 |
+
|
| 262 |
+
def _safe_marian_exists(source_language: str, target_language: str) -> bool:
|
| 263 |
+
"""`_marian_model_exists`, but transient failures fail open.
|
| 264 |
+
|
| 265 |
+
A genuine 404 still means "not available". Anything else (rate
|
| 266 |
+
limiting, a network blip) is treated as "available" for this one
|
| 267 |
+
call rather than "unavailable" -- erring toward occasionally offering
|
| 268 |
+
a language whose Hub check happened to fail transiently (the actual
|
| 269 |
+
translate() call will surface a clear per-language error if it truly
|
| 270 |
+
isn't there) rather than silently and permanently hiding one that's
|
| 271 |
+
really there, which is the bug this replaces.
|
| 272 |
+
"""
|
| 273 |
+
try:
|
| 274 |
+
return _marian_model_exists(source_language, target_language)
|
| 275 |
+
except Exception:
|
| 276 |
+
return True
|
| 277 |
+
|
| 278 |
+
|
| 279 |
+
def _hf_token() -> Optional[str]:
|
| 280 |
+
"""An HF token, if one is configured -- raises the unauthenticated
|
| 281 |
+
rate limit that triggers the failure above in the first place.
|
| 282 |
+
Optional; everything here still works without one, just with a lower
|
| 283 |
+
request budget before transient failures become likely.
|
| 284 |
+
"""
|
| 285 |
+
return os.environ.get("HF_TOKEN") or os.environ.get("HUGGINGFACE_HUB_TOKEN")
|
| 286 |
|
| 287 |
|
| 288 |
def _marian_path_exists(source_language: str, target_language: str) -> bool:
|
| 289 |
"""Direct pair, or a source->en->target pivot, whichever is real."""
|
| 290 |
if source_language == target_language:
|
| 291 |
return False
|
| 292 |
+
if _safe_marian_exists(source_language, target_language):
|
| 293 |
return True
|
| 294 |
if source_language != "en" and target_language != "en":
|
| 295 |
+
return _safe_marian_exists(source_language, "en") and _safe_marian_exists("en", target_language)
|
| 296 |
return False
|
| 297 |
|
| 298 |
|