#
#   python_llm_antonimos_dataset.py
#
#   A partir de un dataset con frases en español genera uno nuevo con antónimos de las frases del dataset original
#
#   REQUISITOS:
#       Para pruebas descargar los siguientes modelos de Ollama de: https://ollama.com/search
#           gemma4:12b
#           qwen2.5:14b
#           translategemma:12b  (recomendado)
#
#   Rogelio Ferreira Escutia - octubre/2026
#

# Bibliotecas necesarias (no requieren instalar nada a través de PyPi)
import csv
import sys
import time
import datetime

# Bibliotecas utilizadas que hay que instalar
import ollama
from ollama import Client, ResponseError

# Dataset original en español
DATASET_SPANISH_ORIGINAL = "dataset_032_robot_ordenes_spanish_50_a_3.csv"
# Dataset nuevo que se va a crear con frases antónimas
DATASET_SPANISH_ANTONYMS = "dataset_036_robot_ordenes_spanish_antonimos_3.csv"
# LLM que se utilizará para generar los antónimos
LLM_MODEL = "translategemma:12b"

# Función que pregunta por los metadatos
def preguntar_metadatos():
    global LLM_MODEL
    global device
    global llm_model_name
    global test_name
    device = ""
    llm_model_name = ""
    test_name = ""
    lista = []
    lista.append("Metadatos - Rogelio Ferreira Escutia")
    print("\nPreguntar Metadatos:")
    while True:
        print("\nSeleccionar tipo de pruebas:")
        print("\t1.- Generar un dataset de Sinónimos en Español a partir de otro dataset")
        print("\t2.- Generar un dataset de Antónimos en Español a partir de otro dataset")
        print("\t3.- Calcula la similitud entre frases y sus sinónimos con ayuda de un LLM")
        opcion = input("Elige opción (1-3): ")
        if opcion == "1":
            lista.append("Prueba: Generar un dataset de Sinónimos en Español a partir de otro dataset")
            test_name = "sinonimos"
            break
        if opcion == "2":
            lista.append("Prueba: Generar un dataset de Antónimos en Español a partir de otro dataset")
            test_name = "antonimos"
            break
        if opcion == "3":
            lista.append("Prueba: Calcula la similitud entre frases y sus sinónimos con ayuda de un LLM")
            test_name = "similitud"
            break
        else:
            print("\nOpción no válida. Por favor, introduce 1 a 3")
    while True:
        print("\nSeleccionar Dispositivo:")
        print("\t1.- Jetson Nano con 4 GB RAM")
        print("\t2.- Raspberry Pi 5 con 8 GB RAM")
        print("\t3.- Orin Nano con 8 GB RAM")
        print("\t4.- Raspberry Pi 5 con 16 GB RAM")
        print("\t5.- MiniPC Linux con 16 GB RAM")
        print("\t6.- MacBook Pro M3 con 18 GB RAM")
        opcion = input("Elige opción (1-6): ")
        if opcion == "1":
            lista.append("Dispositivo: Jetson Nano con 4 GB RAM")
            device = "jetson_nano"
            break
        if opcion == "2":
            lista.append("Dispositivo: Raspberry Pi 5 con 8 GB RAM")
            device = "raspberry_pi_5"
            break
        if opcion == "3":
            lista.append("Dispositivo: Orin Nano con 8 GB RAM")
            device = "orin_nano"
            break
        if opcion == "4":
            lista.append("Dispositivo: Raspberry Pi 5 con 16 GB RAM")
            device = "raspberry_pi_5"
            break
        if opcion == "5":
            lista.append("Dispositivo: MiniPC Linux con 16 GB RAM")
            device = "mini_pc_linux"
            break
        if opcion == "6":
            lista.append("Dispositivo: MacBook Pro M3 con 18 GB RAM")
            device = "macbook_pro_m3"
            break
        else:
            print("\nOpción no válida. Por favor, introduce 1 a 6")
    while True:
        print("\nSeleccionar Algoritmo Utilizado:")
        print("\t1.- No se utilizó ningún Algoritmo específico")
        print("\t2.- Similitud Coseno")
        opcion = input("Elige opción (1-2): ")
        if opcion == "1":
            lista.append("Algoritmo: No se utilizó ningún Algoritmo específico")
            break
        if opcion == "2":
            lista.append("Algoritmo: Similitud Coseno")
            break
        else:
            print("\nOpción no válida. Por favor, introduce 1 a 2")
    while True:
        print("\nSeleccionar Modelo Utilizado (LLM):")
        print("\t1.- No se utilizó ningún Modelo")
        print("\t2.- embeddinggemma-2:270m")
        print("\t3.- embeddinggemma:300m")
        print("\t4.- bge-m3:567m")
        print("\t5.- qwen3-embedding:0.6b")
        print("\t6.- gemma4:12b")
        print("\t7.- qwen2.5:14b")
        print("\t8.- translategemma:12b")
        opcion = input("Elige opción (1-8): ")
        if opcion == "1":
            lista.append("LLM: No se utilizó ningún Modelo")
            LLM_MODEL = "none"
            llm_model_name = "none"
            break
        if opcion == "2":
            lista.append("LLM: embeddinggemma-2:270m")
            LLM_MODEL = "embeddinggemma-2:270m"
            llm_model_name = "embeddinggemma-2_270m"
            break
        if opcion == "3":
            lista.append("LLM: embeddinggemma:300m")
            LLM_MODEL = "embeddinggemma:300m"
            llm_model_name = "embeddinggemma_300m"
            break
        if opcion == "4":
            lista.append("LLM: bge-m3:567m")
            LLM_MODEL = "bge-m3:567m"
            llm_model_name = "bge-m3_567m"
            break
        if opcion == "5":
            lista.append("LLM: qwen3-embedding:0.6b")
            LLM_MODEL = "qwen3-embedding:0.6b"
            llm_model_name = "qwen3-embedding_0-6b"
            break
        if opcion == "6":
            lista.append("LLM: gemma4:12b")
            LLM_MODEL = "gemma4:12b"
            llm_model_name = "gemma4_12b"
            break
        if opcion == "7":
            lista.append("LLM: qwen2.5:14b")
            LLM_MODEL = "qwen2.5:14b"
            llm_model_name = "qwen2-5_14b"
            break
        if opcion == "8":
            lista.append("LLM: translategemma:12b")
            LLM_MODEL = "translategemma:12b"
            llm_model_name = "translategemma_12b"
            break
        else:
            print("\nOpción no válida. Por favor, introduce 1 a 6")
    return lista

# Recibe una lista y con ella genera un archivo de texto
def generar_archivo_txt(lista, nombre_archivo):
    with open(nombre_archivo, "w", encoding="utf-8") as f:
       for i, elemento in enumerate(lista):
          f.write(str(elemento))
          if i < len(lista) - 1:
             f.write("\n")
    return

# Función que llama al LLM para generar los antónimos
def llm_antonyms(phrase: str, model_name: str) -> str:
    system_prompt = (
       "You are an expert in Spanish linguistics and stylistics. "
       "For every sentence I send you in Spanish, your job is to respond with a single Spanish sentence that has the opposite meaning (its antonym)."
       "Return only the phrase that is an antonym of the original, without any intro, extra explanation, or quotes."
    )
    try:
        response = ollama.chat(
             model=model_name,
             messages=[
                 {"role": "system", "content": system_prompt},
                 {"role": "user", "content": phrase},
            ],
            options={
                "temperature": 0.1,		# Baja temperatura para una alta precisión
                "keep_alive": '-1',		# Para que se mantenga cargado el modelo en memoria de forma indefinida
            },
        )
        return response["message"]["content"].strip()
    except ollama.ResponseError as e:
        print(f"Ollama API error: {e.error}", file=sys.stderr)
        sys.exit(1)
    except Exception as e:
        print(f"Unexpected error: {e}", file=sys.stderr)
        sys.exit(1)

#
#       PROGRAMA PRINCIPAL
#
print("\nGeneración de un dataset de antónimos a partir de otro dataset\n")

# Inicializar los Metadatos
metadatos = []
device = ""
llm_model_name = ""
test_name = ""

# Preguntar Metadatos
metadatos = preguntar_metadatos()

# Registra el inicio del procesamiento
print("\n\tIniciando Procesamiento...\n")
inicio = datetime.datetime.now()
with open(
    DATASET_SPANISH_ORIGINAL, mode="r", newline="", encoding="utf-8") as entrada, open(
         DATASET_SPANISH_ANTONYMS, mode="w", newline="", encoding="utf-8") as salida:
    reader = csv.reader(entrada)
    standard_writer = csv.writer(salida)
    prev_row = None
    contador = 0
    for current_row in reader:
        if prev_row is not None:
            contador = contador + 1
            texto_original = prev_row[0] 
            print(contador, " Original: ", texto_original)
            antonimo = llm_antonyms(texto_original, LLM_MODEL)
            print(contador, " Antónimo: ", antonimo)
            standard_writer.writerow([antonimo])
        prev_row = current_row
    if prev_row is not None:
        contador = contador + 1
        texto_original = prev_row[0] 
        print(contador, " Original: ", texto_original)
        antonimo = llm_antonyms(texto_original, LLM_MODEL)
        print(contador, " Antónimo: ", antonimo)
        csv.writer(salida, lineterminator="").writerow([antonimo])
fin = datetime.datetime.now()
tiempo_ejecucion = fin - inicio
print("\nProceso Terminado! - Tiempo total: " + str(tiempo_ejecucion), "\n")

# Agregando los Metadatos de Fecha, Hora y Tiempo de Ejecución
fecha_actual = datetime.datetime.now().strftime("%Y-%m-%d")
cadena = "Fecha: " + fecha_actual
metadatos.append(cadena)
hora_actual = datetime.datetime.now().strftime("%H:%M:%S.%f")
cadena = "Hora: " + hora_actual
metadatos.append(cadena)
cadena = "Tiempo: " + str(tiempo_ejecucion)   
metadatos.append(cadena)

# Generando archivo TXT
nombre_archivo_txt = str(fecha_actual) + "-" + str(hora_actual) + "_" + device + "_" + llm_model_name + "_" + test_name + ".txt"
generar_archivo_txt(metadatos, nombre_archivo_txt)

# Impresión de Metadatos
print("\nMetadatos Recolectados:\n\n", metadatos)
print("\nNombre del archivo generado: ", nombre_archivo_txt, "\n")