Despliegue privado de translategemma-27b-it para traducción multilingüe en empresas

La necesidad de procesar contenido en múltiples idiomas crece a medida que las organizaciones amplían su presencia internacional. Contratos, documentación técnica, correos de clientes y materiales de marketing son solo algunos ejemplos de contenidos que requieren traducción rápida, precisa y, en muchos casos, confidencial. translategemma-27b-it es un modelo de traducción basado en Google Gemma 3 que permite ejecutar un servicio de traducción de 55 idiomas directamente en infraestructura propia, sin depender de APIs externas.

En este artículo se describe cómo poner en producción este modelo en un entorno local o privado, analizando sus capacidades, opciones de despliegue, optimizaciones y casos de uso prácticos orientados a medianas empresas y departamentos corporativos.

Motivación para una solución de traducción privada

Las empresas que manejan información sensible enfrentan limitaciones importantes cuando usan servicios de traducción en la nube:

  • Confidencialidad: documentos legales, técnicos o médicos no siempre pueden salir de la red corporativa.
  • Coste operativo: los modelos de pago por palabra o por carácter se vuelven costosos con volúmenes elevados.
  • Latencia: una solución local elimina la dependencia de la red y acelera respuestas críticas.
  • Personalización: cada sector tiene terminología específica que los traductores genéricos no capturan siempre bien.

Contar con una infraestructura privada resuelve estos problemas y permite adaptar el modelo a las necesidades internas.

Capacidades principales de translategemma-27b-it

Cobertura de 55 idiomas

El modelo soporta traducción entre 55 lenguas principales, incluyendo:

  • Asiáticas: chino, japonés, coreano, tailandés, vietnamita.
  • Europeas: inglés, español, francés, alemán, italiano, ruso, portugués.
  • Otras: árabe, hindi, turco, hebreo, entre otras.

Esta cobertura permite atender la mayor parte de los mercados internacionales con una única plataforma.

Traducción de texto e imágenes

El modelo admite dos modalidades:

  • Texto: recibe una cadena de texto y devuelve la traducción.
  • Imagen: procesa imágenes de hasta 896×896 píxeles, identifica el texto presente y lo traduce.

La capacidad multimodal resulta útil para documentos escaneados, fotografías de pizarras, capturas de pantalla o manuales ilustrados.

Diseño ligero y adaptable

Entre sus características técnicas destacan:

  • Ventana de contexto de 2K tokens, suficiente para la mayoría de documentos cortos y medios.
  • Requisitos de hardware moderados para un modelo de 27 mil millones de parámetros.
  • Preprocesamiento automático de imágenes antes de la inferencia.

Preparación del entorno de producción

Requisitos de hardware recomendados

Componente Mínimo Recomendado
CPU 8 núcleos 16+ núcleos
RAM 32 GB 64 GB o más
Almacenamiento SSD 50 GB SSD 200 GB
GPU Opcional NVIDIA con 16+ GB VRAM

Instalación con Ollama

La forma más sencilla de ejecutar el modelo es mediante Ollama, una herramienta diseñada para desplegar modelos locales de forma similar a cómo Docker gestiona contenedores.

1. Instalar Ollama

# Linux / macOS
curl -fsSL https://ollama.ai/install.sh | sh

# Windows: descargar instalador desde https://ollama.ai/download

2. Iniciar el servicio

ollama serve

3. Descargar el modelo

# Versión 27B recomendada para producción
ollama pull translategemma:27b

# Alternativa ligera si el hardware es limitado
ollama pull translategemma:7b

4. Verificar funcionamiento

ollama run translategemma:27b "Hello, how are you?"

Exposición del modelo como servicio

Opción A: API con FastAPI

En lugar de invocar ollama run mediante subprocess, es más robusto consumir la API REST que Ollama expone por defecto en http://localhost:11434.

from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import httpx

servidor = FastAPI()
OLLAMA_URL = "http://localhost:11434/api/generate"

class PeticionTraduccion(BaseModel):
    texto: str
    origen: str = "auto"
    destino: str = "en"

def crear_instruccion(texto: str, origen: str, destino: str) -> str:
    return (
        f"Traduce el siguiente texto de {origen} a {destino}. "
        f"Mantén la terminología técnica y el tono original. "
        f"Devuelve únicamente la traducción, sin comentarios adicionales.\n\n"
        f"{texto}"
    )

@servidor.post("/traducir")
async def traducir(peticion: PeticionTraduccion):
    if not peticion.texto.strip():
        raise HTTPException(status_code=400, detail="El texto no puede estar vacío")

    cuerpo = {
        "model": "translategemma:27b",
        "prompt": crear_instruccion(peticion.texto, peticion.origen, peticion.destino),
        "stream": False
    }

    async with httpx.AsyncClient() as cliente:
        respuesta = await cliente.post(OLLAMA_URL, json=cuerpo, timeout=120.0)
        datos = respuesta.json()

    return {
        "original": peticion.texto,
        "traduccion": datos.get("response", "").strip(),
        "origen": peticion.origen,
        "destino": peticion.destino
    }

Opción B: contenedor Docker

Para producción se recomienda empaquetar el servicio en un contenedor. El siguiente Dockerfile instala Ollama, descarga el modelo y levanta la API.

FROM python:3.11-slim

WORKDIR /app

# Instalar dependencias del sistema
RUN apt-get update && apt-get install -y curl && rm -rf /var/lib/apt/lists/*

# Instalar Ollama
RUN curl -fsSL https://ollama.ai/install.sh | sh

# Descargar modelo durante la construcción
RUN ollama serve & \
    sleep 5 && \
    ollama pull translategemma:27b

# Dependencias de Python
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY main.py .

EXPOSE 8000

CMD ["python", "main.py"]

El archivo requirements.txt incluiría:

fastapi
uvicorn
httpx

Opción C: cliente para integración con aplicaciones existentes

import httpx
from typing import Optional

class ClienteTraduccion:
    def __init__(self, url_base: str = "http://localhost:8000"):
        self.url_base = url_base

    def traducir(self, texto: str, destino: str, origen: str = "auto") -> str:
        payload = {
            "texto": texto,
            "origen": origen,
            "destino": destino
        }
        respuesta = httpx.post(f"{self.url_base}/traducir", json=payload, timeout=60.0)
        respuesta.raise_for_status()
        return respuesta.json()["traduccion"]

# Ejemplo de uso
if __name__ == "__main__":
    cliente = ClienteTraduccion()
    resultado = cliente.traducir("Bienvenido a nuestro producto", destino="en")
    print(resultado)

Optimización del rendimiento

Procesamiento por lotes

El siguiente ejemplo muestra cómo traducir múltiples frases en paralelo usando un grupo limitado de workers.

from concurrent.futures import ThreadPoolExecutor, as_completed

class TraductorPorLotes:
    def __init__(self, cliente, max_workers: int = 4):
        self.cliente = cliente
        self.max_workers = max_workers

    def traducir_lote(self, textos: list[str], destino: str) -> list[str]:
        tareas = {}
        with ThreadPoolExecutor(max_workers=self.max_workers) as ejecutor:
            for texto in textos:
                futuro = ejecutor.submit(self.cliente.traducir, texto, destino)
                tareas[futuro] = texto

        resultados = {}
        for futuro in as_completed(tareas):
            original = tareas[futuro]
            try:
                resultados[original] = futuro.result()
            except Exception as exc:
                resultados[original] = f"[error: {exc}]"

        return [resultados[t] for t in textos]

Caché de traducciones

Almacenar en caché los textos ya traducidos reduce costes computacionales y mejora la latencia.

import hashlib
import json
import os
from datetime import datetime, timedelta

class CacheTraducciones:
    def __init__(self, ruta: str = "cache.json", horas_vida: int = 48):
        self.ruta = ruta
        self.vida = timedelta(hours=horas_vida)
        self.datos = self._cargar()

    def _clave(self, texto: str, origen: str, destino: str) -> str:
        mezcla = f"{texto}::{origen}::{destino}"
        return hashlib.sha256(mezcla.encode()).hexdigest()

    def _cargar(self) -> dict:
        if not os.path.exists(self.ruta):
            return {}
        with open(self.ruta, "r", encoding="utf-8") as f:
            return json.load(f)

    def guardar(self):
        with open(self.ruta, "w", encoding="utf-8") as f:
            json.dump(self.datos, f, ensure_ascii=False, indent=2)

    def obtener(self, texto: str, origen: str, destino: str) -> str | None:
        clave = self._clave(texto, origen, destino)
        entrada = self.datos.get(clave)
        if not entrada:
            return None
        fecha = datetime.fromisoformat(entrada["fecha"])
        if datetime.now() - fecha < self.vida:
            return entrada["resultado"]
        return None

    def almacenar(self, texto: str, origen: str, destino: str, resultado: str):
        clave = self._clave(texto, origen, destino)
        self.datos[clave] = {
            "origen": origen,
            "destino": destino,
            "resultado": resultado,
            "fecha": datetime.now().isoformat()
        }
        self.guardar()

Casos de uso prácticos

Comercio electrónico multilingüe

Automatizar la traducción de catálogos de productos a varios idiomas.

class CatalogoMultilingue:
    def __init__(self, cliente: ClienteTraduccion, idiomas: list[str]):
        self.cliente = cliente
        self.idiomas = idiomas

    def localizar_producto(self, producto: dict) -> dict:
        localizado = {}
        for idioma in self.idiomas:
            localizado[idioma] = {
                "titulo": self.cliente.traducir(producto["titulo"], idioma),
                "descripcion": self.cliente.traducir(producto["descripcion"], idioma),
                "especificaciones": {
                    clave: self.cliente.traducir(valor, idioma)
                    for clave, valor in producto.get("especificaciones", {}).items()
                }
            }
        return localizado

Documentación técnica corporativa

Traducir documentos largos dividiéndolos en bloques manejables.

<class><code>class TraductorDocumentos:
    def __init__(self, cliente: ClienteTraduccion, tamano_bloque: int = 5):
        self.cliente = cliente
        self.tamano_bloque = tamano_bloque

    def traducir_archivo(self, ruta: str, destino: str) -> str:
        with open(ruta, "r", encoding="utf-8") as f:
            contenido = f.read()

        bloques = contenido.split("\n\n")
        traducidos = []

        for i in range(0, len(bloques), self.tamano_bloque):
            lote = bloques[i:i + self.tamano_bloque]
            traducidos.extend(self.cliente.traducir_lote(lote, destino))

        return "\n\n".join(traducidos)
</code></class>

Atención al cliente multilingüe

class SoporteMultilingue:
    def __init__(self, cliente: ClienteTraduccion):
        self.cliente = cliente

    def responder(self, mensaje_cliente: str, idioma_cliente: str, idioma_equipo: str = "es") -> dict:
        traduccion_entrada = self.cliente.traducir(
            mensaje_cliente, destino=idioma_equipo, origen=idioma_cliente
        )
        # Aquí se conectaría con el sistema de respuestas del equipo
        respuesta_equipo = self._generar_respuesta(traduccion_entrada)

        respuesta_cliente = self.cliente.traducir(
            respuesta_equipo, destino=idioma_cliente, origen=idioma_equipo
        )

        return {
            "mensaje_original": mensaje_cliente,
            "traduccion_interna": traduccion_entrada,
            "respuesta traducida": respuesta_cliente
        }

    def _generar_respuesta(self, mensaje: str) -> str:
        return f"Gracias por contactarnos. Hemos recibido: {mensaje}"

Traducción de imágenes

Para traducir imágenes se combina un motor OCR con el modelo de traducción.

class TraductorImagenes:
    def __init__(self, ocr, cliente: ClienteTraduccion):
        self.ocr = ocr
        self.cliente = cliente

    def traducir(self, ruta_imagen: str, destino: str) -> str:
        texto_extraido = self.ocr.extraer(ruta_imagen)
        if not texto_extraido:
            return "No se detectó texto en la imagen."
        return self.cliente.traducir(texto_extraido, destino=destino)

    def traducir_varias(self, rutas: list[str], destino: str) -> dict:
        resultados = {}
        for ruta in rutas:
            try:
                resultados[ruta] = {
                    "estado": "ok",
                    "traduccion": self.traducir(ruta, destino)
                }
            except Exception as exc:
                resultados[ruta] = {
                    "estado": "error",
                    "detalle": str(exc)
                }
        return resultados

Optimización de la calidad de traducción

Prompts especializados

El diseño del prompt influye notablemente en el resultado. A continuación se muestran plantillas orientadas a distintos dominios.

Traducción técnica

Actúa como traductor técnico especializado. Traduce el siguiente texto de {origen} a {destino} respetando estas reglas:
1. Conserva los términos técnicos de forma consistente.
2. No traduzcas bloques de código, nombres de variables ni comandos.
3. Usa el estilo propio de la documentación técnica en {destino}.

Texto:
{texto}

Localización de marketing

Eres un experto en localización de contenidos de marketing. Traduce de {origen} a {destino} adaptando el mensaje a la cultura del público objetivo, manteniendo el tono persuasivo y la identidad de marca.

Texto:
{texto}

Monitorización de calidad

Es recomendable registrar métricas básicas para detectar degradaciones en la calidad.

import re

class EvaluadorCalidad:
    @staticmethod
    def metricas_basicas(original: str, traduccion: str) -> dict:
        urls_original = set(re.findall(r"https?://\S+", original))
        urls_traduccion = set(re.findall(r"https?://\S+", traduccion))

        return {
            "ratio_longitud": len(traduccion) / max(len(original), 1),
            "urls_conservadas": urls_original == urls_traduccion,
            "numeros_conservados": re.findall(r"\d+", original) == re.findall(r"\d+", traduccion)
        }

Comparativa con servicios tradicionales

Aspecto Servicio de traducción externo translategemma desplegado en privado
Inversión inicial Baja Media (hardware propio)
Coste operativo Por uso continuo Bajo tras la inicio
Privacidad de datos Depende del proveedor Control total
Latencia Variable con la red Muy baja
Personalización Limitada Total

Roadmap de implementación

Fase 1: Validación (1-2 semanas)

  • Desplegar en un entorno de pruebas.
  • Seleccionar 1 o 2 escenarios representativos.
  • Evaluar calidad y rendimiento.

Fase 2: Despliegue piloto (2-4 semanas)

  • Migrar a producción con uso controlado.
  • Integrar con sistemas clave.
  • Implementar monitorización y registro de fallos.

Fase 3: Escalado (1-2 meses)

  • Ampliar a todos los departamentos relevantes.
  • Optimizar prompts y tiempos de respuesta.
  • Definir procedimientos de mantenimiento.

Recomendaciones finales

  • Comienza por un caso de uso concreto de alto valor.
  • Diseña prompts específicos por dominio para mejorar la precisión.
  • Activa caché desde el primer día para aprovechar repeticiones.
  • Monitoriza la calidad con reglas automatizables antes de ampliar el despliegue.
  • Planfiica el hardware en función del volumen esperado y de la necesidad de respuesta en tiempo real.

Etiquetas: TranslateGemma ollama FastAPI Docker Google Gemma 3

Publicado el 7-3 04:07