Skip to content

Actividad 1 - Componentes, mediación y configuraciones.

El objetivo de esta actividad es profundizar en el concepto de arquitectura de software basada en servicios y componentes, específicamente en el proceso de selección de componentes y mediación a partir de una arquitectura de referencia.

Los sistemas de traducción básicos que traducen palabra por palabra suelen generar textos con errores ortográficos, falta de contexto y una gramática incorrecta. El sistema propuesto procesa el texto de manera integral para ofrecer traducciones precisas y naturales. Para lograrlo, el sistema no solo debe sustituir palabras, sino que también necesita corregir errores previos en el texto original, buscar los términos más adecuados según el contexto y aplicar las reglas sintácticas correctas del idioma de destino, todo ello con soporte dinámico para múltiples idiomas.

El sistema principal, encapsulado bajo el componente compuesto Sistema Avanzado de Traducción, se divide en los siguientes elementos funcionales:

  • Traductor Central (Orquestador): Actúa como el núcleo de control. Expone la interfaz principal Traducción hacia el exterior (por ejemplo, a una API o interfaz de usuario). Su función es coordinar el flujo de datos, delegando las tareas de procesamiento a los componentes especializados y ensamblando el resultado final.

  • Corrector Ortográfico: Provee la interfaz Revisión Ortográfica. Actúa en la fase de preprocesamiento, limpiando y corrigiendo el texto de origen para garantizar que los errores tipográficos no comprometan la calidad de la traducción.

  • Diccionario Léxico: Provee la interfaz Sugerencias. Recibe las palabras o frases limpias y consulta sus equivalencias, devolviendo las opciones más adecuadas según el contexto semántico.

  • Analizador Gramatical: Provee la interfaz Reglas de Sintaxis. Se encarga del postprocesamiento. Toma las sugerencias del diccionario y las ordena conjugando verbos y ajustando concordancias (género, número, estructura) para que la oración resultante suene natural en el idioma de destino.

  • Base de Datos de Idiomas: Constituye la capa de persistencia estática. Expone la interfaz Paquetes de Idioma. A diferencia de los demás, este componente no es consumido por el orquestador, sino que alimenta de datos directamente al Diccionario Léxico (vocabulario) y al Analizador Gramatical (reglas estructurales).

Se ha diseñado el siguiente diagrama de componentes en UML utilizando la herramienta PlantUML, donde se aprecian las interfaces proporcionadas y requeridas que conectan los módulos del traductor.

Diagrama de Arquitectura del Sistema de Traducción

La arquitectura del Traductor Inteligente se estructura a partir de sus componentes, definiéndolos según las funcionalidades que aportan y las dependencias que necesitan para operar.

C=(R,Rˉ)C = (R, \bar{R}), donde:

  • R={R1,,RN}R = \{R_1, \dots, R_N\}: Servicios proporcionados
  • Rˉ={Rˉ1,,RˉN}\bar{R} = \{\bar{R}_1, \dots, \bar{R}_N\}: Servicios requeridos

Arquitectura del Sistema (AA)

ComponenteServicios Proporcionados (RR)Servicios Requeridos (Rˉ\bar{R})
Traductor CentralRTCR_{TC}RˉCO\bar{R}_{CO}, RˉDL\bar{R}_{DL}, RˉAG\bar{R}_{AG}
Corrector OrtográficoRCOR_{CO}-
Diccionario LéxicoRDLR_{DL}RˉBD\bar{R}_{BD}
Analizador GramaticalRAGR_{AG}RˉBD\bar{R}_{BD}
Base de Datos IdiomasRBDR_{BD}-

Para satisfacer la arquitectura propuesta, se define un conjunto de componentes candidatos que representan el catálogo de software disponible para la composición. Estos candidatos presentan diversas agrupaciones de servicios, algunos cubriendo múltiples necesidades arquitectónicas y otros siendo específicos para una sola tarea. Se incluye una dependencia externa a una API en la nube (RˉAPI\bar{R}_{API}) para evaluar la detección de dependencias no contempladas.

Cβ(A)C_\beta(A): Componentes candidatos

  • C1={RTC,RˉCO,RˉDL,RˉAG}C_1 = \{ R_{TC}, \bar{R}_{CO}, \bar{R}_{DL}, \bar{R}_{AG} \}
  • C2={RCO,RˉBD}C_2 = \{ R_{CO}, \bar{R}_{BD} \}
  • C3={RBD}C_3 = \{ R_{BD} \}
  • C4={RAG,RˉAPI}C_4 = \{ R_{AG}, \bar{R}_{API} \}
  • C5={RDL,RˉBD}C_5 = \{ R_{DL}, \bar{R}_{BD} \}
  • C6={RAG,RˉBD}C_6 = \{ R_{AG}, \bar{R}_{BD} \}
  • C7={RCO}C_7 = \{ R_{CO} \}

En esta sección se describe el programa desarrollado para la actividad, con el fin de obtener todas las configuraciones que satisfacen los requisitos planteados.

2.1. Implementación de la API de TraderConfigs

Section titled “2.1. Implementación de la API de TraderConfigs”

Se ha implementado una API REST que actúa como interfaz entre el cliente y el binario TraderConfigs. Esta transforma solicitudes JSON al formato esperado por el ejecutable y devuelve las configuraciones generadas mediante Python y FastAPI.

  • Directoryapi/
    • Directorybin/
      • TraderConfigs (binario ejecutable)
    • main.py
    • requirements.txt
    • Dockerfile
    • .dockerignore
api/main.py
from collections import defaultdict
from fastapi import FastAPI, HTTPException
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from typing import List, Dict
import subprocess, tempfile, os
app = FastAPI(title="TraderConfigs API")
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"])
class ComponentInput(BaseModel):
index: int
offered: List[str]
required: List[str] = []
class ConfigRequest(BaseModel):
components: List[ComponentInput]
architecture: List[str]
class ConfigResponse(BaseModel):
single_configurations: List[Dict[str, List[str]]]
long_configurations: List[Dict[str, List[str]]]
def to_text(components: List[ComponentInput], architecture: List[str]) -> tuple[str, str]:
comps = "\n".join(f"O: {' '.join(c.offered)}{' I: ' + ' '.join(c.required) if c.required else ''}" for c in components)
arch = f"O: {' '.join(architecture)}"
return comps, arch
def from_text(lines: List[str]) -> List[Dict[str, List[str]]]:
result = []
for line in lines:
config = defaultdict(list)
for part in line.split():
if '.' in part:
comp, svc = part.split('.', 1)
config[comp].append(svc)
result.append(dict(config))
return result
@app.get("/")
def root(): return {"message": "TraderConfigs API"}
@app.post("/generate-configurations", response_model=ConfigResponse)
def generate_configurations(request: ConfigRequest):
comps_text, arch_text = to_text(request.components, request.architecture)
with tempfile.TemporaryDirectory() as tmpdir:
for name, content in [("components.txt", comps_text), ("architecture.txt", arch_text)]:
with open(os.path.join(tmpdir, name), "w") as f: f.write(content)
result = subprocess.run(
[os.path.join(os.path.dirname(__file__), "bin", "TraderConfigs"),
os.path.join(tmpdir, "components.txt"), os.path.join(tmpdir, "architecture.txt")],
cwd=tmpdir, capture_output=True, text=True
)
if result.returncode != 0:
raise HTTPException(500, result.stderr)
single = from_text(open(os.path.join(tmpdir, "single_configurations.out")).readlines()) if os.path.exists(os.path.join(tmpdir, "single_configurations.out")) else []
long = from_text(open(os.path.join(tmpdir, "long_configurations.out")).readlines()) if os.path.exists(os.path.join(tmpdir, "long_configurations.out")) else []
return ConfigResponse(single_configurations=single, long_configurations=long)

El programa define una API REST con dos endpoints: uno de verificación de estado (GET /) y otro principal (POST /generate-configurations). Utiliza modelos Pydantic para validar la estructura de los datos de entrada y salida. Las funciones auxiliares to_text y from_text transforman los datos entre JSON y el formato de texto plano que el binario TraderConfigs puede procesar. El flujo de ejecución crea archivos temporales, ejecuta el binario y, posteriormente, procesa los resultados obtenidos.

CampoTipoDescripción
componentsArrayLista de componentes del sistema
architectureArrayServicios disponibles

Cada componente:

CampoTipoDescripción
indexIntegerIdentificador único
offeredArrayServicios que ofrece
requiredArrayServicios que requiere
CampoTipoDescripción
single_configurationsArrayConfiguraciones válidas
long_configurationsArrayTodas las combinaciones

En el siguiente ejemplo se utilizan identificadores simplificados de servicios con fines ilustrativos.

Request:

{
"components": [
{"index": 1, "offered": ["CIO"], "required": []},
{"index": 2, "offered": ["CAL"], "required": []}
],
"architecture": ["CAL", "CIO"]
}

Response:

{
"single_configurations": [{"C1": ["CIO"], "C2": ["CAL"]}],
"long_configurations": [{"C1": ["CIO"]}, {"C1": ["CIO"], "C2": ["CAL"]}]
}

Para la interfaz web se han desarrollado cuatro vistas, de las cuales dos corresponden a formularios.

Formulario de entrada de datos, en el que se introduce la arquitectura:

Formulario de entrada de arquitectura

Otro formulario de datos, en el que se introducen los componentes con sus servicios ofrecidos y requeridos:

Formulario de componentes con servicios ofrecidos y requeridos

Después, se presenta un resumen de la arquitectura y de los componentes introducidos:

Resumen de arquitectura y componentes introducidos

Finalmente, se muestra una vista con los resultados obtenidos, en la que se presentan las configuraciones válidas y todas las combinaciones posibles:

Resultados con configuraciones válidas y combinaciones posibles

Tras la ejecución de la aplicación con el algoritmo de TraderConfigs, se obtienen las siguientes configuraciones válidas:

#C1C2C3C4C5C6C7RC
1Traductor_CentralCorrector_OrtograficoBBDD_IdiomasAnalizador_GramaticalDiccionario_Lexico--No
2Traductor_CentralCorrector_OrtograficoBBDD_Idiomas-Diccionario_LexicoAnalizador_Gramatical-
3Traductor_Central-BBDD_IdiomasAnalizador_GramaticalDiccionario_Lexico-Corrector_OrtograficoNo
4Traductor_Central-BBDD_Idiomas-Diccionario_LexicoAnalizador_GramaticalCorrector_Ortografico

Para evaluar qué configuraciones son válidas, se revisan dos criterios clave:

  1. Configuraciones cerradas (columna C): Una configuración es cerrada cuando ninguno de sus componentes depende de servicios externos a la arquitectura definida. En este caso, las configuraciones que incluyen C4 no son cerradas, porque ese candidato necesita un servicio externo (API) que no forma parte de la arquitectura del sistema de traducción. Por eso, en la tabla aparecen como cerradas las configuraciones #2 y #4, mientras que #1 y #3 no lo son.

  2. Respeto de la arquitectura (columna R): Una configuración respeta la arquitectura si los servicios proporcionados por los candidatos pueden asignarse a los servicios exigidos por el diseño original (Traductor_Central, Analizador_Gramatical, Corrector_Ortografico, Diccionario_Lexico y BBDD_Idiomas). En las cuatro configuraciones obtenidas se cumple esta condición, por lo que todas presentan R = Sí.

Atendiendo a estos dos criterios, las configuraciones más adecuadas son #2 y #4, ya que son las únicas que cumplen simultáneamente que respetan la arquitectura y, además, son cerradas.

La actividad se ha desarrollado en el siguiente repositorio de GitHub, donde puede encontrarse el código completo junto con instrucciones adicionales de ejecución:

github.com/aek676/traderconfigs