Quickstart

Installation & Usage guide for our application.

System Requirements:

  • 1GB RAM (without semantic comparator) | 1.5GB RAM (with semantic comparator)
  • Docker version 27.3.1
  • Docker Compose version v2.29.7
  • The following ports should be free: 8080, 9090, 8501

Launch Containers

1

Step 1: Setup docker-compose file

Begin by creating a docker-compose file in a fresh directory:

version: '3.8'

services:
  comparit-syntactic:
    image: jawad571/comparit-syntactic:2.0.0
    ports:
      - "8080:8080"

  comparit-semantic:
    image: jawad571/comparit-semantic:1.0.0
    ports:
      - "9090:9090"
    environment:
      - EMBEDDING_MODEL=glove
  user-interface:
    image: jawad571/comparit-user-interface:1.0.0
    ports:
      - "8501:8501"
    environment:
      - COMPARIT_SYNTACTIC_URL=http://comparit-syntactic:8080
      - COMPARIT_SEMANTIC_URL=http://comparit-semantic:9090
2

Step 2: Start Containers

sudo docker-compose up
3

Step 3: Access The User Interface

http://localhost:8501

With this setup, you’ll have a ready-to-use Comparit containers to start playing with.

User Interface

Programmatic Invocation

The following python code serves as an adapter to best utilize the endpoints exposed by the comparit containers. Sample scripts from the examples can be used to explore the usage further.

import requests
import json
import os
from dotenv import load_dotenv

load_dotenv()

comparit_syntactic_url = os.getenv("COMPARIT_SYNTACTIC_URL") if os.getenv("COMPARIT_SYNTACTIC_URL") else "http://localhost:8080"
comparit_semantic_url = os.getenv("COMPARIT_SEMANTIC_URL") if os.getenv("COMPARIT_SEMANTIC_URL") else "http://localhost:9090"
class Adapter:
    def compare_ecore_models_syntactically_and_semantically(groundTruthModelEcore, predictedModelEcore, config, remove_artifacts = True):
        model_level_json = {}
        class_level_json = {}

        ground_truth_model_emf = Adapter.get_emfatic_from_ecore(groundTruthModelEcore)
        predicted_truth_model_emf = Adapter.get_emfatic_from_ecore(predictedModelEcore)

        response_syntactic = Adapter.compare_ecore_models_syntactically(
            groundTruthModelEcore, predictedModelEcore, config)

        response_semantic = Adapter.compare_emfatic_models_semantically(ground_truth_model_emf, predicted_truth_model_emf)
        
        class_level_json = response_syntactic["classLevelJson"]
        model_level_json = {**response_syntactic["modelLevelJson"], **response_semantic, **response_syntactic["time"]}
        if remove_artifacts:
            os.remove(groundTruthModelEcore)
            os.remove(predictedModelEcore)
            os.remove(ground_truth_model_emf)
            os.remove(predicted_truth_model_emf)
            os.remove(config)
        return model_level_json, class_level_json
            
    def compare_emfatic_models_syntactically_and_semantically(ground_truth_model_emf, predicted_truth_model_emf, config, remove_artifacts = True):
        model_level_json = {}
        class_level_json = {}

        groundTruthModelEcore = Adapter.get_ecore_model_from_emfatic(ground_truth_model_emf)
        predictedModelEcore = Adapter.get_ecore_model_from_emfatic(predicted_truth_model_emf)

        response_syntactic = Adapter.compare_ecore_models_syntactically(
            groundTruthModelEcore, predictedModelEcore, config)

        response_semantic = Adapter.compare_emfatic_models_semantically(ground_truth_model_emf, predicted_truth_model_emf)
        
        class_level_json = response_syntactic["classLevelJson"]
        model_level_json = {**response_syntactic["modelLevelJson"], **response_semantic, **response_syntactic["time"]}
        if remove_artifacts:
            os.remove(groundTruthModelEcore)
            os.remove(predictedModelEcore)
            os.remove(ground_truth_model_emf)
            os.remove(predicted_truth_model_emf)
            os.remove(config)
        return model_level_json, class_level_json

    def compare_uml2_models_syntactically_and_semantically(ground_truth_model_uml2, predicted_truth_model_uml2, config, remove_artifacts = True):
        model_level_json = {}
        class_level_json = {}

        groundTruthModelEcore = Adapter.get_ecore_model_from_uml2(ground_truth_model_uml2)
        predictedModelEcore = Adapter.get_ecore_model_from_uml2(predicted_truth_model_uml2)
        
        ground_truth_model_emf = Adapter.get_emfatic_from_ecore(groundTruthModelEcore)
        predicted_truth_model_emf = Adapter.get_emfatic_from_ecore(predictedModelEcore)

        response_syntactic = Adapter.compare_ecore_models_syntactically(
            groundTruthModelEcore, predictedModelEcore, config)

        response_semantic = Adapter.compare_emfatic_models_semantically(ground_truth_model_emf, predicted_truth_model_emf)
        
        class_level_json = response_syntactic["classLevelJson"]
        model_level_json = {**response_syntactic["modelLevelJson"], **response_semantic, **response_syntactic["time"]}
        if remove_artifacts:
            os.remove(groundTruthModelEcore)
            os.remove(predictedModelEcore)
            os.remove(ground_truth_model_emf)
            os.remove(predicted_truth_model_emf)
            os.remove(ground_truth_model_uml2)
            os.remove(predicted_truth_model_uml2)
            os.remove(config)
        return model_level_json, class_level_json
    
    def compare_models_syntactically_and_semantically(
        ground_truth_model_ecore,
        predicted_model_ecore,
        ground_truth_model_emf, 
        predicted_truth_model_emf, 
        config
    ):
        model_level_json = {}
        class_level_json = {}

        response_syntactic = Adapter.compare_ecore_models_syntactically(ground_truth_model_ecore, predicted_model_ecore, config)
        response_semantic = Adapter.compare_emfatic_models_semantically(ground_truth_model_emf, predicted_truth_model_emf)
        
        class_level_json = response_syntactic["classLevelJson"]
        model_level_json = {**response_syntactic["modelLevelJson"], **response_semantic, **response_syntactic["time"]}
        return model_level_json, class_level_json
    
    def compare_emfatic_models_semantically(ground_truth_emfatic, predicted_emfatic):
        with open(ground_truth_emfatic, 'r') as groundTruthModel, open(predicted_emfatic, 'r') as predictedModel:
            groundTruthModelEmfatic = groundTruthModel.read()
            predictedModelEmfatic = predictedModel.read()
            nlp_comparator_endpoint = f'{comparit_semantic_url}/nlp-compare'
            response = requests.post(
                nlp_comparator_endpoint,
                headers={'Content-Type': 'application/json', 'Connection': 'keep-alive'},
                json={"groundTruthModelEmfatic": groundTruthModelEmfatic,
                    "predictedModelEmfatic": predictedModelEmfatic}
            )
            nlp_compare_result = response.text
            nlp_compare_result = json.loads(nlp_compare_result)
            return nlp_compare_result
    
    def compare_ecore_models_syntactically(ground_truth_model, predicted_model, config):
        with open(ground_truth_model, 'rb') as groundTruthModel, open(predicted_model, 'rb') as predictedModel, open(config, 'rb') as config_file:
            yamtl_comparator_endpoint = f'{comparit_syntactic_url}/compare'
            response = requests.post(
                yamtl_comparator_endpoint,
                files={
                    "groundTruthModel": groundTruthModel,
                    "predictedModel": predictedModel,
                    "config": config_file
                },
            )
            result = response.json()
        return result
    
    def get_ecore_model_from_emfatic(emfaticFilePath):
        comparator_url = f'{comparit_syntactic_url}/emfatic2ecore'
        with open(emfaticFilePath) as emfaticModel:
            ecoreFromEmfaticResponse = requests.post(
                comparator_url,
                files={"emfaticModel":emfaticModel}
            )

        ecore_path = emfaticFilePath.replace(".emf", ".ecore")
        with open(ecore_path, "w") as file:
            file.write(ecoreFromEmfaticResponse.text)  
        return ecore_path

    def get_ecore_model_from_uml2(umlFilePath):
        comparator_url = f'{comparit_syntactic_url}/uml2Toecore'
        with open(umlFilePath) as uml2Model:
            ecoreFromUml2Response = requests.post(
                comparator_url,
                files={"uml2Model":uml2Model}
            )

        ecore_path = umlFilePath.replace(".uml", ".ecore")
        with open(ecore_path, "w") as file:
            file.write(ecoreFromUml2Response.text)  
        return ecore_path
            
    def get_emfatic_from_ecore(ecoreModelFilePath):
        comparator_url = f'{comparit_syntactic_url}/ecore2emfatic'
        with open(ecoreModelFilePath) as emfaticModel:
            ecoreFromEmfaticResponse = requests.post(
                comparator_url,
                files={"ecoreModel":emfaticModel}
            )
        emf_path = ecoreModelFilePath.replace(".ecore", ".emf")
        with open(emf_path, "w") as file:
            file.write(ecoreFromEmfaticResponse.text)
        return emf_path