fix: Google Cloud API translation key environment and fallback logic
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2s
This commit is contained in:
@@ -105,6 +105,7 @@ services:
|
||||
- STRIPE_PRO_PRICE_ID=${STRIPE_PRO_PRICE_ID:-}
|
||||
- STRIPE_BUSINESS_PRICE_ID=${STRIPE_BUSINESS_PRICE_ID:-}
|
||||
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID:-}
|
||||
- GOOGLE_CLOUD_API_KEY=${GOOGLE_CLOUD_API_KEY:-}
|
||||
volumes:
|
||||
- uploads_data:/app/uploads
|
||||
- outputs_data:/app/outputs
|
||||
|
||||
@@ -836,6 +836,47 @@ def _estimate_pages(file_path: Path, file_extension: str) -> int:
|
||||
return 1
|
||||
|
||||
|
||||
class _GoogleCloudWithFallback:
|
||||
"""Tries Google Cloud API first, falls back to deep_translator on error.
|
||||
|
||||
This avoids a hard crash when the Cloud API key is invalid, quota is
|
||||
exceeded, or the network is unreachable. The legacy GoogleTranslator
|
||||
(deep_translator, free, no key) is used as a best-effort fallback.
|
||||
"""
|
||||
|
||||
def __init__(self, cloud_adapter, legacy_provider):
|
||||
self.cloud = cloud_adapter
|
||||
self.legacy = legacy_provider
|
||||
self.provider_name = "google_cloud_with_fallback"
|
||||
|
||||
def translate(self, text, target_language, source_language="auto"):
|
||||
try:
|
||||
return self.cloud.translate(text, target_language, source_language)
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
"google_cloud_failed_fallback_to_legacy",
|
||||
error=str(e)[:200],
|
||||
)
|
||||
return self.legacy.translate(text, target_language, source_language)
|
||||
|
||||
def translate_batch(
|
||||
self, texts, target_language, source_language="auto", **kwargs
|
||||
):
|
||||
try:
|
||||
return self.cloud.translate_batch(
|
||||
texts, target_language, source_language
|
||||
)
|
||||
except Exception as e:
|
||||
logger.warning(
|
||||
"google_cloud_batch_failed_fallback_to_legacy",
|
||||
error=str(e)[:200],
|
||||
text_count=len(texts),
|
||||
)
|
||||
return self.legacy.translate_batch(
|
||||
texts, target_language, source_language
|
||||
)
|
||||
|
||||
|
||||
async def _run_translation_job(
|
||||
job_id: str,
|
||||
input_path: Path,
|
||||
@@ -953,6 +994,9 @@ async def _run_translation_job(
|
||||
|
||||
# "google" (default classic mode): use Google Cloud API key if available,
|
||||
# otherwise fall back to deep_translator (legacy, no key).
|
||||
# When the Cloud API key IS present, wrap it in a fallback so that
|
||||
# quota / network errors don't kill the job — deep_translator is tried
|
||||
# as a best-effort second chance.
|
||||
if _p == "google":
|
||||
gc_key = _cfg(
|
||||
getattr(_admin_cfg.google_cloud, "api_key", None),
|
||||
@@ -960,8 +1004,13 @@ async def _run_translation_job(
|
||||
)
|
||||
if gc_key:
|
||||
from services.providers.google_cloud_provider import LegacyGoogleCloudAdapter
|
||||
translation_provider = LegacyGoogleCloudAdapter(gc_key)
|
||||
logger.info("google_provider_using_cloud_api", job_id=job_id)
|
||||
from services.translation_service import GoogleTranslationProvider
|
||||
cloud_adapter = LegacyGoogleCloudAdapter(gc_key)
|
||||
legacy_fallback = GoogleTranslationProvider()
|
||||
translation_provider = _GoogleCloudWithFallback(
|
||||
cloud_adapter, legacy_fallback
|
||||
)
|
||||
logger.info("google_provider_using_cloud_api_with_fallback", job_id=job_id)
|
||||
else:
|
||||
logger.info("google_provider_no_cloud_key_using_legacy", job_id=job_id)
|
||||
|
||||
@@ -1142,7 +1191,7 @@ async def _run_translation_job(
|
||||
if attempted > 0:
|
||||
ratio = changed / attempted
|
||||
logger.info(f"Job {job_id}: translation stats — {changed}/{attempted} texts changed ({ratio:.0%})")
|
||||
if ratio < 0.15 and changed == 0:
|
||||
if changed == 0:
|
||||
error_msg = (
|
||||
f"Translation failed: 0 out of {attempted} texts were translated. "
|
||||
f"The provider ({provider}) may be unavailable or misconfigured. "
|
||||
@@ -1151,6 +1200,12 @@ async def _run_translation_job(
|
||||
logger.error(f"Job {job_id}: {error_msg}")
|
||||
tracker.set_error(error_msg)
|
||||
return
|
||||
elif ratio < 0.05:
|
||||
# Very suspicious — likely partial failure, warn but don't block
|
||||
logger.warning(
|
||||
f"Job {job_id}: suspiciously low translation rate: "
|
||||
f"{changed}/{attempted} ({ratio:.1%})"
|
||||
)
|
||||
|
||||
if user_id:
|
||||
await tier_quota_service.increment_on_success(user_id)
|
||||
|
||||
Reference in New Issue
Block a user