feat: production deployment - full update with providers, admin, glossaries, pricing, tests
Major changes across backend, frontend, infrastructure: - Provider system with model selection (Google, DeepL, OpenAI, Ollama, Google Cloud) - Admin panel: user management, pricing, settings - Glossary system with CSV import/export - Subscription and tier quota management - Security hardening (rate limiting, API key auth, path traversal fixes) - Docker compose for dev, prod, and IONOS deployment - Alembic migrations for new tables - Frontend: dashboard, pricing page, landing page, i18n (en/fr) - Test suite and verification scripts Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -14,16 +14,10 @@ Features:
|
||||
from typing import List, Optional, Dict, Any
|
||||
import time
|
||||
|
||||
try:
|
||||
import structlog
|
||||
from core.logging import get_logger
|
||||
|
||||
logger = structlog.get_logger(__name__)
|
||||
_HAS_STRUCTLOG = True
|
||||
except ImportError:
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
_HAS_STRUCTLOG = False
|
||||
logger = get_logger(__name__)
|
||||
_HAS_STRUCTLOG = True
|
||||
|
||||
|
||||
def _log_info(event: str, **kwargs):
|
||||
@@ -332,6 +326,41 @@ class LegacyFallbackAdapter:
|
||||
source_language: str = "auto",
|
||||
batch_size: int = 50,
|
||||
) -> List[str]:
|
||||
if not texts:
|
||||
return []
|
||||
|
||||
from .config import ProvidersConfig
|
||||
|
||||
provider_names = ProvidersConfig.get_fallback_chain(self._mode)
|
||||
requests = [
|
||||
TranslationRequest(
|
||||
text=t,
|
||||
target_language=target_language,
|
||||
source_language=source_language,
|
||||
)
|
||||
for t in texts
|
||||
]
|
||||
|
||||
# Try each provider once with a full batch (avoids N× fallback chain walks).
|
||||
for provider_name in provider_names:
|
||||
p = registry.get(provider_name)
|
||||
if p is None:
|
||||
continue
|
||||
if not p.is_available():
|
||||
continue
|
||||
try:
|
||||
responses = p.translate_batch(requests)
|
||||
except Exception:
|
||||
continue
|
||||
if len(responses) != len(requests):
|
||||
continue
|
||||
if all(r.error is None for r in responses):
|
||||
self._last_provider_used = provider_name
|
||||
return [
|
||||
r.translated_text if r.translated_text is not None else texts[i]
|
||||
for i, r in enumerate(responses)
|
||||
]
|
||||
|
||||
results: List[str] = []
|
||||
for t in texts:
|
||||
req = TranslationRequest(
|
||||
|
||||
Reference in New Issue
Block a user