fix: integrate deepseek, resolve silent google api errors, fix google cloud keys
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2s

This commit is contained in:
2026-05-17 17:11:06 +02:00
parent 669cf7fde8
commit b50419e2ec
2062 changed files with 272359 additions and 523 deletions

View File

@@ -835,6 +835,8 @@ class SettingsConfig(BaseModel):
ollama: ProviderSettings = ProviderSettings() # dev-only in UI
openrouter: ProviderSettings = ProviderSettings() # "Traduction IA Essentielle"
openrouter_premium: ProviderSettings = ProviderSettings() # "Traduction IA Premium"
deepseek: ProviderSettings = ProviderSettings()
minimax: ProviderSettings = ProviderSettings()
zai: ProviderSettings = ProviderSettings()
smtp: SmtpSettings = SmtpSettings()
fallback_chain: str = "google,google_cloud,deepl,openrouter,openrouter_premium,openai,deepseek,zai"
@@ -903,6 +905,8 @@ async def get_settings(admin_id: str = Depends(require_admin)):
payload["openrouter_premium"] = _merge_env(settings.openrouter_premium, key_env="OPENROUTER_API_KEY", model_env="OPENROUTER_PREMIUM_MODEL", default_model="anthropic/claude-3.5-haiku")
payload["openai"] = _merge_env(settings.openai, key_env="OPENAI_API_KEY", model_env="OPENAI_MODEL", default_model="gpt-4o-mini")
payload["deepl"] = _merge_env(settings.deepl, key_env="DEEPL_API_KEY")
payload["deepseek"] = _merge_env(settings.deepseek, key_env="DEEPSEEK_API_KEY", model_env="DEEPSEEK_MODEL", default_model="deepseek-chat")
payload["minimax"] = _merge_env(settings.minimax, key_env="MINIMAX_API_KEY", model_env="MINIMAX_MODEL", default_model="abab6.5s-chat")
payload["zai"] = _merge_env(settings.zai, key_env="ZAI_API_KEY", model_env="ZAI_MODEL", url_env="ZAI_BASE_URL", default_model="grok-2-1212", default_url="https://api.x.ai/v1")
payload["ollama"] = _merge_env(settings.ollama, url_env="OLLAMA_BASE_URL", model_env="OLLAMA_MODEL", default_url="http://localhost:11434", default_model="llama3")
payload["google_cloud"] = _merge_env(settings.google_cloud, key_env="GOOGLE_CLOUD_API_KEY")
@@ -935,6 +939,8 @@ async def get_settings(admin_id: str = Depends(require_admin)):
"openai": bool(os.getenv("OPENAI_API_KEY", "").strip()),
"openrouter": has_openrouter,
"openrouter_premium": has_openrouter, # same key, different model
"deepseek": bool(os.getenv("DEEPSEEK_API_KEY", "").strip()),
"minimax": bool(os.getenv("MINIMAX_API_KEY", "").strip()),
"zai": bool(os.getenv("ZAI_API_KEY", "").strip()),
"ollama": bool(os.getenv("OLLAMA_BASE_URL", "").strip()),
"google_cloud": bool(os.getenv("GOOGLE_CLOUD_API_KEY", "").strip()),
@@ -1070,6 +1076,14 @@ async def test_provider(
status_code=200, content={"available": True, "usage": str(usage)}
)
elif provider == "openrouter_premium":
current.openrouter_premium = _update_provider(current.openrouter_premium, update_data)
elif provider == "deepseek":
current.deepseek = _update_provider(current.deepseek, update_data)
elif provider == "minimax":
current.minimax = _update_provider(current.minimax, update_data)
elif provider == "zai":
current.zai = _update_provider(current.zai, update_data)
elif provider == "openai":
api_key = _key(provider_config.api_key, "OPENAI_API_KEY")
if not api_key:

View File

@@ -157,6 +157,40 @@ async def get_available_providers():
"model": model,
})
# DeepSeek direct — if configured
if _is_enabled("deepseek", key_var="DEEPSEEK_API_KEY"):
ds_cfg = getattr(settings, "deepseek", None)
model = _resolve_model(
ds_cfg.model if ds_cfg else None,
"DEEPSEEK_MODEL",
"deepseek-chat",
)
available.append({
"id": "deepseek",
"label": "DeepSeek V3",
"description": "Traduction IA avancée via DeepSeek",
"mode": "llm",
"tier": "pro",
"model": model,
})
# MiniMax direct — if configured
if _is_enabled("minimax", key_var="MINIMAX_API_KEY"):
mm_cfg = getattr(settings, "minimax", None)
model = _resolve_model(
mm_cfg.model if mm_cfg else None,
"MINIMAX_MODEL",
"abab6.5s-chat",
)
available.append({
"id": "minimax",
"label": "MiniMax",
"description": "Traduction IA via MiniMax",
"mode": "llm",
"tier": "pro",
"model": model,
})
# z.AI / xAI Grok — if configured
if _is_enabled("zai", key_var="ZAI_API_KEY"):
zai_cfg = getattr(settings, "zai", None)

View File

@@ -998,10 +998,12 @@ async def _run_translation_job(
# quota / network errors don't kill the job — deep_translator is tried
# as a best-effort second chance.
if _p == "google":
# the user might have set GOOGLE_API_KEY instead of GOOGLE_CLOUD_API_KEY
gc_key = _cfg(
getattr(_admin_cfg.google_cloud, "api_key", None),
"GOOGLE_CLOUD_API_KEY",
)
) or os.getenv("GOOGLE_API_KEY", "").strip()
if gc_key:
from services.providers.google_cloud_provider import LegacyGoogleCloudAdapter
from services.translation_service import GoogleTranslationProvider
@@ -1037,6 +1039,30 @@ async def _run_translation_job(
model=openai_model,
system_prompt=full_prompt,
)
elif _p == "deepseek":
from services.translation_service import OpenAITranslationProvider as _OAI
ds_key = _cfg(getattr(_admin_cfg, "deepseek", None) and _admin_cfg.deepseek.api_key, "DEEPSEEK_API_KEY")
ds_model = _cfg(getattr(_admin_cfg, "deepseek", None) and _admin_cfg.deepseek.model, "DEEPSEEK_MODEL", "deepseek-chat")
ds_url = "https://api.deepseek.com/v1"
if ds_key:
translation_provider = _OAI(
api_key=ds_key,
model=ds_model,
base_url=ds_url,
system_prompt=full_prompt,
)
elif _p == "minimax":
from services.translation_service import OpenAITranslationProvider as _OAI
mm_key = _cfg(getattr(_admin_cfg, "minimax", None) and _admin_cfg.minimax.api_key, "MINIMAX_API_KEY")
mm_model = _cfg(getattr(_admin_cfg, "minimax", None) and _admin_cfg.minimax.model, "MINIMAX_MODEL", "abab6.5s-chat")
mm_url = "https://api.minimax.chat/v1"
if mm_key:
translation_provider = _OAI(
api_key=mm_key,
model=mm_model,
base_url=mm_url,
system_prompt=full_prompt,
)
elif _p == "deepl":
deepl_key = _cfg(_admin_cfg.deepl.api_key, "DEEPL_API_KEY")
if deepl_key:
@@ -1243,10 +1269,16 @@ async def _run_translation_job(
logger.info(f"Job {job_id}: Completed successfully")
except Exception as e:
tracker.set_error(str(e))
# Check if this is our structured TranslationProviderError
if type(e).__name__ == "TranslationProviderError":
tracker.set_error(e.message)
logger.error(f"Job {job_id}: Provider Failed - {e.code}: {e.message}")
else:
tracker.set_error(str(e))
logger.error(f"Job {job_id}: Failed - {e}")
# Record translation failure metric
record_translation(provider=provider, file_type=file_extension or "unknown", duration=0, status="error")
logger.error(f"Job {job_id}: Failed - {e}")
finally:
if webhook_url: