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
Files changed (2) hide show
  1. app.py +1 -1
  2. 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-28 22:17 UTC &middot; fixed en-jap Helsinki-NLP naming exception</sub>
329
  """
330
  )
331
 
 
325
  **Upload Audio &rarr; Select Audio Window &rarr; Detect Language & Generate Transcript
326
  &rarr; Preview & Choose Languages &rarr; Generate Translations &rarr; Copy / Download**
327
 
328
+ <sub>build: 2026-06-30 08:57 UTC &middot; 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
- Cached forever per pair: this is public catalog data, not something
235
- that changes mid-session, and reusing it means the second person (or
236
- the second transcript) asking about the same source language is
237
- instant.
 
 
 
 
 
 
 
 
 
 
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
- return False
247
- except Exception: # pragma: no cover - network hiccup, treat as unavailable
248
- return False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 _marian_model_exists(source_language, target_language):
256
  return True
257
  if source_language != "en" and target_language != "en":
258
- return _marian_model_exists(source_language, "en") and _marian_model_exists("en", target_language)
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