Spaces:
Sleeping
Sleeping
import gradio as gr | |
import re | |
import random | |
from collections import defaultdict | |
from typing import Dict, List, Tuple | |
class NgramModel: | |
def __init__(self): | |
# Diccionarios para almacenar n-gramas y sus frecuencias | |
self.ngram_dicts = { | |
1: defaultdict(int), | |
2: defaultdict(int), | |
3: defaultdict(int), | |
4: defaultdict(int), | |
5: defaultdict(int) | |
} | |
self.is_trained = False | |
def preprocess_text(self, text: str) -> List[str]: | |
"""Preprocesa el texto para tokenizarlo en palabras.""" | |
# Convertir a minúsculas y eliminar caracteres especiales | |
text = text.lower() | |
text = re.sub(r'[^\w\s]', ' ', text) | |
# Dividir en palabras y eliminar espacios extra | |
words = [word.strip() for word in text.split() if word.strip()] | |
return words | |
def train(self, text: str): | |
"""Entrena el modelo creando diccionarios de n-gramas.""" | |
# Reiniciar los diccionarios | |
self.ngram_dicts = { | |
1: defaultdict(int), | |
2: defaultdict(int), | |
3: defaultdict(int), | |
4: defaultdict(int), | |
5: defaultdict(int) | |
} | |
words = self.preprocess_text(text) | |
# Crear n-gramas para n=1 hasta n=5 | |
for n in range(1, 6): | |
for i in range(len(words) - n + 1): | |
ngram = tuple(words[i:i + n]) | |
self.ngram_dicts[n][ngram] += 1 | |
self.is_trained = True | |
def get_random_unigram(self) -> Tuple[str, str]: | |
"""Selecciona una palabra aleatoria del diccionario de 1-gramas.""" | |
# Obtener todas las palabras únicas de los 1-gramas | |
unigrams = [(ngram[0], freq) for ngram, freq in self.ngram_dicts[1].items()] | |
if not unigrams: | |
return "", "No hay palabras disponibles en el modelo." | |
# Seleccionar una palabra aleatoria y su frecuencia | |
word, freq = random.choice(unigrams) | |
explanation = "No se encontraron coincidencias para el contexto proporcionado.\n" | |
explanation += "Seleccionando palabra aleatoria del vocabulario:\n\n" | |
explanation += "Candidatos disponibles:\n" | |
# Mostrar todas las palabras disponibles ordenadas por frecuencia | |
sorted_unigrams = sorted(unigrams, key=lambda x: x[1], reverse=True) | |
for w, f in sorted_unigrams: | |
explanation += f"- '{w}' (frecuencia: {f})" | |
if w == word: | |
explanation += " ← SELECCIONADA ALEATORIAMENTE" | |
explanation += "\n" | |
return word, explanation | |
def predict_next_word(self, text: str) -> Tuple[str, str]: | |
"""Predice la siguiente palabra basada en el contexto.""" | |
if not self.is_trained: | |
return "", "El modelo no ha sido entrenado aún." | |
words = self.preprocess_text(text) | |
if not words: | |
return self.get_random_unigram() | |
# Buscar coincidencias empezando por el n-grama más largo | |
for n in range(min(5, len(words) + 1), 1, -1): # Note: ahora empezamos en n>1 | |
context = tuple(words[-(n-1):]) # Tomamos n-1 palabras como contexto | |
# Recoger coincidencias exactas | |
candidates = {} | |
for ngram, freq in self.ngram_dicts[n].items(): | |
if ngram[:-1] == context: # Solo coincidencias exactas del contexto | |
candidates[ngram[-1]] = freq | |
if candidates: # Si encontramos coincidencias exactas | |
# Encontrar la frecuencia máxima | |
max_freq = max(candidates.values()) | |
# Obtener todas las palabras con la frecuencia máxima | |
max_candidates = [word for word, freq in candidates.items() if freq == max_freq] | |
# Seleccionar aleatoriamente entre los candidatos con frecuencia máxima | |
next_word = random.choice(max_candidates) | |
# Crear explicación detallada | |
explanation = f"Predicción basada en {n}-grama\n\n" | |
explanation += f"Contexto utilizado: {' '.join(context)}\n\n" | |
explanation += "Candidatos encontrados:\n" | |
# Ordenar candidatos por frecuencia | |
sorted_candidates = sorted(candidates.items(), key=lambda x: x[1], reverse=True) | |
for word, freq in sorted_candidates: | |
explanation += f"- '{word}' (frecuencia: {freq})" | |
if freq == max_freq: | |
explanation += " ← CANDIDATO MÁXIMA FRECUENCIA" | |
if word == next_word: | |
explanation += " ← SELECCIONADA" | |
explanation += "\n" | |
if len(max_candidates) > 1: | |
explanation += "\nNota: Se seleccionó aleatoriamente entre las palabras con máxima frecuencia." | |
return next_word, explanation | |
# Si no se encontraron coincidencias en ningún n-grama, usar selección aleatoria | |
return self.get_random_unigram() | |
# Crear interfaz con Gradio | |
def create_interface(): | |
model = NgramModel() | |
def train_model(text_input, file_input): | |
"""Entrena el modelo con texto o archivo.""" | |
if file_input is not None: | |
training_text = file_input | |
elif text_input.strip(): | |
training_text = text_input | |
else: | |
return "Por favor, proporcione texto de entrenamiento." | |
model.train(training_text) | |
return "Modelo entrenado exitosamente." | |
def predict(input_text): | |
"""Realiza la predicción y actualiza el texto de entrada.""" | |
if not model.is_trained: | |
return input_text, "", "El modelo no ha sido entrenado aún." | |
next_word, explanation = model.predict_next_word(input_text) | |
new_text = input_text.strip() + " " + next_word if input_text.strip() else next_word | |
return new_text, next_word, explanation | |
# Crear interfaz con Gradio | |
def create_interface(): | |
model = NgramModel() | |
def train_model(text_input, file_input): | |
"""Entrena el modelo con texto o archivo.""" | |
if file_input is not None: | |
training_text = file_input | |
elif text_input.strip(): | |
training_text = text_input | |
else: | |
return "Por favor, proporcione texto de entrenamiento." | |
model.train(training_text) | |
return "Modelo entrenado exitosamente." | |
def predict(input_text): | |
"""Realiza la predicción y actualiza el texto de entrada.""" | |
if not model.is_trained: | |
return input_text, "", "El modelo no ha sido entrenado aún." | |
next_word, explanation = model.predict_next_word(input_text) | |
new_text = input_text.strip() + " " + next_word if input_text.strip() else next_word | |
return new_text, next_word, explanation | |
# Crear la interfaz con estilo mejorado | |
with gr.Blocks(css=""" | |
.logo { | |
display: flex; | |
justify-content: center; | |
margin-bottom: 1rem; | |
} | |
.container { | |
max-width: 900px; | |
margin: auto; | |
} | |
.centered-title { | |
text-align: center !important; | |
} | |
.centered-title h1 { | |
text-align: center !important; | |
margin-bottom: 1.5rem; | |
} | |
.centered-title h2 { | |
text-align: center !important; | |
margin-bottom: 1rem; | |
} | |
""") as interface: | |
with gr.Column(elem_classes="container"): | |
# Logo centrado | |
#gr.HTML(""" | |
# <div class="logo"> | |
# <img src="https://programamos.es/web/wp-content/uploads/2014/09/ProgramamosLogo.png" | |
# alt="Programamos Logo" | |
# style="height: 100px; object-fit: contain;"> | |
# </div> | |
#""") | |
#with gr.Column(elem_classes="centered-title"): | |
# gr.Markdown("# ¡Construye tu propio miniGPT!") | |
# gr.Markdown("### En la pestaña Entrenamiento puedes copiar o subir un texto base y entrenar tu miniGPT") | |
# gr.Markdown("### En la pestaña Predicción puedes comenzar a escribir un texto y usar tu miniGPT para continuarlo automáticamente") | |
with gr.Tab("Entrenamiento"): | |
text_input = gr.Textbox( | |
label="Texto de entrenamiento", | |
lines=5, | |
placeholder="Introduce aquí el texto para entrenar el modelo..." | |
) | |
file_input = gr.File( | |
label="O sube un archivo de texto", | |
file_types=[".txt"] | |
) | |
train_button = gr.Button( | |
"Entrenar modelo", | |
variant="primary" | |
) | |
train_output = gr.Textbox( | |
label="Estado del entrenamiento", | |
interactive=False | |
) | |
train_button.click( | |
fn=train_model, | |
inputs=[text_input, file_input], | |
outputs=train_output | |
) | |
with gr.Tab("Predicción"): | |
input_text = gr.Textbox( | |
label="Introduce texto", | |
placeholder="Escribe aquí el texto para predecir la siguiente palabra..." | |
) | |
predict_button = gr.Button( | |
"Predecir siguiente palabra", | |
variant="primary" | |
) | |
predicted_word = gr.Textbox( | |
label="Palabra predicha", | |
interactive=False | |
) | |
explanation = gr.Textbox( | |
label="Explicación", | |
lines=10, | |
interactive=False | |
) | |
predict_button.click( | |
fn=predict, | |
inputs=input_text, | |
outputs=[input_text, predicted_word, explanation] | |
) | |
return interface | |
# Crear y lanzar la interfaz | |
interface = create_interface() | |
interface.launch() |