File size: 10,490 Bytes
c66dd38
 
34e66b1
c66dd38
 
 
b4e355c
c66dd38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7cbbc68
 
 
 
 
 
 
 
 
c66dd38
7cbbc68
c66dd38
 
 
 
 
 
 
 
34e66b1
 
37c86e7
 
34e66b1
 
 
 
37c86e7
 
34e66b1
0b9d805
 
37c86e7
 
 
 
 
 
 
 
 
34e66b1
 
 
c66dd38
 
 
 
 
 
0b9d805
 
 
c66dd38
0b9d805
 
c66dd38
0b9d805
f364d82
c66dd38
0b9d805
 
f364d82
0b9d805
34e66b1
 
 
 
 
 
 
 
f364d82
 
 
0b9d805
f364d82
34e66b1
 
 
f364d82
 
34e66b1
 
f364d82
 
 
 
34e66b1
 
 
c66dd38
 
37c86e7
34e66b1
c66dd38
 
 
 
 
5735c27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c66dd38
 
 
 
 
 
 
 
 
 
 
 
 
28fc8c3
c66dd38
28fc8c3
c66dd38
 
28fc8c3
 
 
c66dd38
b4e355c
 
 
 
 
 
 
 
 
 
 
5735c27
 
 
 
 
 
 
 
 
 
 
b4e355c
 
 
c7190e0
 
 
 
 
 
 
c66dd38
c7190e0
 
 
 
b4e355c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c66dd38
b4e355c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c66dd38
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
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()