feat: unify multimodels translation providers, remove self-hosting (Ollama/LibreTranslate), and fix local SQLite configuration
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m21s
All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m21s
This commit is contained in:
@@ -1030,6 +1030,13 @@ async def _run_translation_job(
|
||||
source_lang=glossary_source_lang, target_lang=target_lang,
|
||||
)
|
||||
|
||||
from services.providers.google_provider import GoogleTranslationProvider
|
||||
from services.providers.google_cloud_provider import GoogleCloudTranslationProvider
|
||||
from services.providers.deepl_provider import DeepLTranslationProvider
|
||||
from services.providers.openai_provider import OpenAITranslationProvider
|
||||
from services.providers.deepseek_provider import DeepSeekTranslationProvider
|
||||
from services.providers.minimax_provider import MinimaxTranslationProvider
|
||||
|
||||
translation_provider = None
|
||||
_p = provider.lower()
|
||||
|
||||
@@ -1037,24 +1044,34 @@ async def _run_translation_job(
|
||||
# If the Cloud API key is invalid or the API is not enabled, fall back
|
||||
# to the free legacy Google Translate (deep_translator) instead of failing.
|
||||
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 and _google_cloud_key_valid(gc_key, job_id):
|
||||
from services.providers.google_cloud_provider import LegacyGoogleCloudAdapter
|
||||
translation_provider = LegacyGoogleCloudAdapter(gc_key)
|
||||
translation_provider = GoogleCloudTranslationProvider(
|
||||
api_key=gc_key,
|
||||
timeout=int(os.getenv("GOOGLE_CLOUD_TIMEOUT", "30")),
|
||||
max_retries=int(os.getenv("GOOGLE_CLOUD_MAX_RETRIES", "3")),
|
||||
retry_delay=float(os.getenv("GOOGLE_CLOUD_RETRY_DELAY", "1.0")),
|
||||
)
|
||||
logger.info("google_provider_using_cloud_api", extra={"job_id": job_id})
|
||||
else:
|
||||
from services.translation_service import GoogleTranslationProvider
|
||||
translation_provider = GoogleTranslationProvider()
|
||||
translation_provider = GoogleTranslationProvider(
|
||||
use_cache=True,
|
||||
timeout=int(os.getenv("GOOGLE_TRANSLATE_TIMEOUT", "30")),
|
||||
max_retries=int(os.getenv("GOOGLE_TRANSLATE_MAX_RETRIES", "3")),
|
||||
retry_delay=float(os.getenv("GOOGLE_TRANSLATE_RETRY_DELAY", "1.0")),
|
||||
)
|
||||
logger.info("google_provider_using_legacy", extra={"job_id": job_id})
|
||||
|
||||
elif _p in ("openrouter", "llm") and api_key:
|
||||
translation_provider = OpenRouterTranslationProvider(
|
||||
api_key, model, full_prompt
|
||||
translation_provider = OpenAITranslationProvider(
|
||||
api_key=api_key,
|
||||
model=model,
|
||||
base_url="https://openrouter.ai/api/v1",
|
||||
timeout=int(os.getenv("OPENROUTER_TIMEOUT", "60")),
|
||||
)
|
||||
elif _p == "openrouter_premium":
|
||||
premium_key = _cfg(_admin_cfg.openrouter_premium.api_key, "OPENROUTER_API_KEY")
|
||||
@@ -1062,71 +1079,58 @@ async def _run_translation_job(
|
||||
if not premium_key:
|
||||
premium_key = api_key # fall back to main openrouter key
|
||||
if premium_key:
|
||||
translation_provider = OpenRouterTranslationProvider(
|
||||
premium_key, premium_model, full_prompt
|
||||
translation_provider = OpenAITranslationProvider(
|
||||
api_key=premium_key,
|
||||
model=premium_model,
|
||||
base_url="https://openrouter.ai/api/v1",
|
||||
timeout=int(os.getenv("OPENROUTER_TIMEOUT", "60")),
|
||||
)
|
||||
elif _p == "openai":
|
||||
from services.translation_service import OpenAITranslationProvider
|
||||
openai_key = _cfg(_admin_cfg.openai.api_key, "OPENAI_API_KEY")
|
||||
openai_model = _cfg(_admin_cfg.openai.model, "OPENAI_MODEL", "gpt-4o-mini")
|
||||
if openai_key:
|
||||
translation_provider = OpenAITranslationProvider(
|
||||
api_key=openai_key,
|
||||
model=openai_model,
|
||||
system_prompt=full_prompt,
|
||||
timeout=int(os.getenv("OPENAI_TIMEOUT", "60")),
|
||||
)
|
||||
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(
|
||||
translation_provider = DeepSeekTranslationProvider(
|
||||
api_key=ds_key,
|
||||
model=ds_model,
|
||||
base_url=ds_url,
|
||||
system_prompt=full_prompt,
|
||||
timeout=int(os.getenv("DEEPSEEK_TIMEOUT", "60")),
|
||||
)
|
||||
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"
|
||||
mm_model = _cfg(getattr(_admin_cfg, "minimax", None) and _admin_cfg.minimax.model, "MINIMAX_MODEL", "MiniMax-M1")
|
||||
if mm_key:
|
||||
translation_provider = _OAI(
|
||||
translation_provider = MinimaxTranslationProvider(
|
||||
api_key=mm_key,
|
||||
model=mm_model,
|
||||
base_url=mm_url,
|
||||
system_prompt=full_prompt,
|
||||
timeout=int(os.getenv("MINIMAX_TIMEOUT", "60")),
|
||||
)
|
||||
elif _p == "deepl":
|
||||
deepl_key = _cfg(_admin_cfg.deepl.api_key, "DEEPL_API_KEY")
|
||||
if deepl_key:
|
||||
from services.translation_service import DeepLTranslationProvider
|
||||
translation_provider = DeepLTranslationProvider(deepl_key)
|
||||
translation_provider = DeepLTranslationProvider(
|
||||
api_key=deepl_key,
|
||||
timeout=int(os.getenv("DEEPL_TIMEOUT", "30")),
|
||||
)
|
||||
elif _p == "zai":
|
||||
from services.translation_service import OpenAITranslationProvider as _OAI
|
||||
zai_key = _cfg(_admin_cfg.zai.api_key, "ZAI_API_KEY")
|
||||
zai_model = _cfg(_admin_cfg.zai.model, "ZAI_MODEL", "grok-2-1212")
|
||||
zai_url = _cfg(_admin_cfg.zai.base_url, "ZAI_BASE_URL", "https://api.x.ai/v1")
|
||||
if zai_key:
|
||||
translation_provider = _OAI(
|
||||
translation_provider = OpenAITranslationProvider(
|
||||
api_key=zai_key,
|
||||
model=zai_model,
|
||||
base_url=zai_url,
|
||||
system_prompt=full_prompt,
|
||||
timeout=int(os.getenv("ZAI_TIMEOUT", "60")),
|
||||
)
|
||||
elif _p == "ollama":
|
||||
ollama_url = _cfg(_admin_cfg.ollama.base_url, "OLLAMA_BASE_URL", "http://localhost:11434")
|
||||
ollama_model = _cfg(_admin_cfg.ollama.model, "OLLAMA_MODEL", "llama3")
|
||||
translation_provider = OllamaTranslationProvider(
|
||||
ollama_url,
|
||||
ollama_model,
|
||||
ollama_model,
|
||||
full_prompt,
|
||||
)
|
||||
elif _p == "google_cloud":
|
||||
from services.providers.google_cloud_provider import GoogleCloudTranslationProvider
|
||||
gc_key = _cfg(
|
||||
getattr(_admin_cfg.google_cloud, "api_key", None),
|
||||
"GOOGLE_CLOUD_API_KEY",
|
||||
@@ -1147,7 +1151,6 @@ async def _run_translation_job(
|
||||
"google_cloud_key_missing_fallback_to_google",
|
||||
extra={"job_id": job_id},
|
||||
)
|
||||
# translation_provider reste None → legacy Google gratuit
|
||||
|
||||
tracker.update(20, "Preparing translation")
|
||||
|
||||
@@ -1194,6 +1197,8 @@ async def _run_translation_job(
|
||||
if file_extension == ".xlsx":
|
||||
logger.info(f"DEBUG: ExcelTranslator class is {ExcelTranslator} and translate_file is {ExcelTranslator.translate_file}")
|
||||
job_translator = ExcelTranslator(provider=translation_provider)
|
||||
if hasattr(job_translator, "set_custom_prompt"):
|
||||
job_translator.set_custom_prompt(full_prompt)
|
||||
await asyncio.to_thread(
|
||||
job_translator.translate_file,
|
||||
input_path,
|
||||
@@ -1205,6 +1210,8 @@ async def _run_translation_job(
|
||||
)
|
||||
elif file_extension == ".docx":
|
||||
job_translator = WordTranslator(provider=translation_provider)
|
||||
if hasattr(job_translator, "set_custom_prompt"):
|
||||
job_translator.set_custom_prompt(full_prompt)
|
||||
await asyncio.to_thread(
|
||||
job_translator.translate_file,
|
||||
input_path,
|
||||
@@ -1216,6 +1223,8 @@ async def _run_translation_job(
|
||||
)
|
||||
elif file_extension == ".pptx":
|
||||
job_translator = PowerPointTranslator(provider=translation_provider)
|
||||
if hasattr(job_translator, "set_custom_prompt"):
|
||||
job_translator.set_custom_prompt(full_prompt)
|
||||
await asyncio.to_thread(
|
||||
job_translator.translate_file,
|
||||
input_path,
|
||||
@@ -1228,6 +1237,8 @@ async def _run_translation_job(
|
||||
elif file_extension == ".pdf":
|
||||
from translators.pdf_translator import PDFTranslator
|
||||
job_translator = PDFTranslator(provider=translation_provider)
|
||||
if hasattr(job_translator, "set_custom_prompt"):
|
||||
job_translator.set_custom_prompt(full_prompt)
|
||||
actual_output = await asyncio.to_thread(
|
||||
job_translator.translate_file,
|
||||
input_path,
|
||||
|
||||
Reference in New Issue
Block a user