File size: 11,827 Bytes
bd386c3
a9c50ff
 
 
 
bd386c3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a9c50ff
 
bd386c3
a9c50ff
bd386c3
 
 
 
 
a9c50ff
 
bd386c3
a9c50ff
bd386c3
 
 
 
 
 
 
 
 
 
 
 
a9c50ff
bd386c3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a9c50ff
bd386c3
 
 
 
a9c50ff
bd386c3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a9c50ff
bd386c3
a9c50ff
 
 
 
 
 
bd386c3
a9c50ff
 
 
 
bd386c3
a9c50ff
 
 
 
 
 
 
 
bd386c3
a9c50ff
 
 
 
 
 
 
 
bd386c3
 
 
 
 
 
 
 
a9c50ff
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
bd386c3
a9c50ff
 
 
 
 
 
 
bd386c3
 
a9c50ff
 
 
 
bd386c3
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
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
import logging
import gradio as gr 
from ctransformers import AutoModelForCausalLM
import threading
from langdetect import detect, DetectorFactory
from langid import classify
import spacy
import os
import psutil
import time

# Obtener el proceso actual
process = psutil.Process(os.getpid())

# Función para imprimir el uso de CPU y RAM
def print_resource_usage():
    while True:  # Crear un bucle infinito para que se ejecute continuamente
        cpu_usage = process.cpu_percent(interval=1)
        ram_usage = process.memory_info().rss / (1024 * 1024)  # Convertir bytes a MB
        pid = str(process.pid)
        print(f"Uso de CPU: {cpu_usage}%")
        print(f"Uso de RAM: {ram_usage} MB")
        print(f"PID: {pid}")
        time.sleep(10)  # Esperar 2 segundos antes de la próxima impresión

# Crear y empezar un hilo para el monitoreo de recursos
monitoring_thread = threading.Thread(target=print_resource_usage)
monitoring_thread.daemon = True  # Establecer como un daemon para que no bloquee el programa de terminar
monitoring_thread.start()


# Configuración del logger
logging.basicConfig(filename='chatterIA_logs.txt', level=logging.INFO, 
                    format='%(asctime)s %(levelname)s:%(message)s')

DetectorFactory.seed = 0  # Para obtener resultados consistentes en la detección del idioma (outputs)

# Introducimos un mensaje para el modelo para que hable solo en español y con respeto
system_message ="Eres un asistente que siempre responde en español. A cualquiera de sus peticiones y nunca hablas en ningún otro idioma"

# Cargar el modelo una sola vez
model_instance = None

# Cargar el modelo que detecta el idioma de los mensajes solo 1 vez. (inputs)
nlp_sm = spacy.load("es_core_news_sm")
def load_llm():
    
    global model_instance

    if model_instance is None:
        print("Cargando el modelo...")
        model_instance = AutoModelForCausalLM.from_pretrained(
            "TheBloke/Llama-2-7B-Chat-GGUF",
            model_file='llama-2-7b-chat.Q5_K_M.gguf',
            model_type='llama',
            max_new_tokens=2048,
            context_length = 4096,
            repetition_penalty=1.13,
            temperature=0.1
        )
        print("Modelo cargado éxitosamente")
    else:
        print("Ya se ha cargado el modelo anteriormente")
    
    return model_instance
def truncate_history(history, max_tokens=2048):
    truncated_history = []
    total_tokens = 0
    for user_msg, bot_msg in reversed(history):
        # Asegurarse de que ni user_msg ni bot_msg sean None
        user_msg = user_msg if user_msg is not None else ""
        bot_msg = bot_msg if bot_msg is not None else ""
        
        msg_tokens = len(user_msg.split()) + len(bot_msg.split())
        if total_tokens + msg_tokens > max_tokens:
            break
        truncated_history.insert(0, (user_msg, bot_msg))
        total_tokens += msg_tokens
    return truncated_history
def clean_response(response):
    code_block_count = response.count("```")
    
    if code_block_count % 2 != 0:
        last_occurrence_index = response.rfind("```")
        response = response[:last_occurrence_index] + response[last_occurrence_index+3:]
    
    return response

def format_history_for_model(history):
    new_history = "\n".join(f"{user_msg}\n{bot_msg}".strip() for user_msg, bot_msg in history)
    new_history += "\nRespuesta:"
    return new_history


def detectar_idioma_con_spacy(texto):
    doc = nlp_sm(texto, disable=["parser","ner"])
    return True

def prepare_message(message):
    # Primero, intenta detectar el idioma con langid
    lang, confidence = classify(message)
    if lang == 'es':
        return str(message)  # Si langid está seguro de que es español, retorna el mensaje
    
    # Si el mensaje es muy corto y langid no lo clasifica definitivamente como español,
    # utiliza SpaCy como una verificación adicional.
    if len(message.split()) <= 3:  # Considera ajustar este umbral según tus necesidades
        es_espanol_spacy = detectar_idioma_con_spacy(message)
        if es_espanol_spacy:
            return str(message)  # Si SpaCy procesa el texto sin problemas, asume que es español
    
    # Si ninguna de las verificaciones anteriores concluye que el mensaje es en español, retorna None
    return None

def llm_function(message, chat_history ):
    try:
        print(f"Mensaje principal:{message}")
        logging.info(f"Tipo de Message: {type(message)}, Message: {message}")
        message = str(message)
        message_str = str(message)

        # Aquí puedes añadir cualquier validación adicional del mensaje
        if not message_str.strip():
            logging.info("El mensaje está vacío o solo contiene espacios.")
            return "Por favor, envía un mensaje no vacío.", chat_history

        # Continuar con el procesamiento...
        logging.info(f"Message: {message_str}")
        
        print(f"Historial del Chat (segun el chatbot)")
        for i in chat_history:
            print (i)
        print("Fin de variables desde el chat")
            
        llm = load_llm()
        message = prepare_message(message)
        
        if message is None:
            return f"Por favor, envía tu mensaje en español. Actualmente idioma es: {detect(message)}"
        chat_history = truncate_history(chat_history + [(message, "")])  # Añadir el mensaje actual al historial
        
        print("Historial del chat antes de formateo")
        for i in chat_history:
            print (i)
        print("Fin de historial previo a formateo")
        formatted_history = format_history_for_model(chat_history)  # Formatear el historial para el modelo
        
        full_message = f"{system_message}\n{formatted_history}"
        print (f"Mensaje completo: {full_message}")
        response = llm(full_message)  # Generar respuesta
        cleaned_response = clean_response(response)
        
        logging.info(f"Message: {message}")
        logging.info(f"Response: {response}")
        
        try:
            response_language = detect(response)
            print(f"Idioma en response_language: {response_language}")
            print(f"Response:{response}")
            if response_language != 'es':
                return "Lo siento, pero no puedo responder correctamente en español a esa pregunta."
            else:
                cleaned_response = clean_response(response)
                return cleaned_response
        except Exception as e:
            logging.error(f"Error al detectar el idioma: {e}")
            return "Hubo un error al procesar tu mensaje."
    except Exception as e:
        logging.error(f"Error al procesar el mensaje:  {e}")
        return "Hubo un error al procesar tu mensaje, revisa que sea un mensaje completo."

def llm_function_with_timeout(message, chat_history, timeout=180):
    result = [None]  # Lista para almacenar el resultado
    def target():
        # Intentar adquirir el semáforo antes de ejecutar la función
        result[0] = llm_function(message, chat_history)

    thread = threading.Thread(target=target)
    thread.start()
    thread.join(timeout)
    if thread.is_alive():
        # Si el thread todavía está vivo después del timeout, se asume que está bloqueado y se debe manejar
        thread.join()
        return "Tu pregunta no ha podido ser respondida en el tiempo estimado. Por favor, intenta de nuevo o reformula tu pregunta."
    return result[0]

      
title = "ChatterIA"

description = """
ChatterIA es un modelo de lenguaje que funciona como un asistente con infinidad de conocimientos, pero no infalible. Si desconoces el uso de este modelo, aqu&iacute; tienes unas instrucciones para optimizar su uso:
<ul>
<li>Las respuestas de este modelo pueden no ser siempre precisas, al depender de su configuración, capacidad de interpretación y contextualización</li>
<li>Usa este modelo bajo tu responsabilidad.</li>
<li>Si no o obtienes respuesta a tu consulta, intenta volver a reformularla.</li>
<li>Si necesitas alguna aclaraci&oacute;n o tienes cualquier otra duda, puedes enviar un correo electr&oacute;nico a soporte: <a href='mailto:[email protected]'> Mandar email </a>. o revisar nuestras gu&iacute;as: <a href='http://fuentezuelas.com/ia/playground/ChatterIA/index.php#guias'> Acceder a gu&iacute;as </a></li>
<li>Es importante que sepas este sitio es de uso educativo. El env&iacute;o de mensajes masivos puede dar error.</li>
</ul>
"""

theme = 'Taithrah/Minimal'

examples = [
    'Escribe un código de python para conectarte con una base de datos en MySQL y liste todas las tablas.',
     'Escribe un poema sobre el otoño con rima consonante y en forma de soneto.',
     'Resume el argumento de "El Quijote", y explícaselo a un niño de 5 años para que le interese.',
     'Dime como fusionar dos diccionarios en Python y diferentes usos que puede tener esto.',
     'Dime que debo considerar al comprar un coche usado y que me recomiendas saber al respecto.',
     'Explica la teoría de la relatividad de Einstein para estudiantes de primaria.',
     'Dime cuáles podrían ser las implicaciones de la inteligencia artificial en el empleo.',
     'Redacta un correo para mi jefe en el cual, quiero pedirle un aumento de salario.',
     'Escribe una cancion que dure aproximadamente 2 minutos y que trate sobre la desigualdad en España.'
]
css = """
#component-0 {
    height:auto !important; 
    min-height:400px !important; 
    overflow:auto !important;
} 
#component-0 .chatbot{
    text-align:justify !important;
    padding: 5px 20px !important; 
}
#component-3 div{
    display:flex;
    justify-content:center;
}
#component-3 h1{
    font-size:2rem;
    text-align:center !important;
}
#component-4 p{ 
    font-size:18px;
    margin-bottom:25px;
}
#component-4 ul{
    padding-left:5%;
}
#component-4 li{
    font-size:16px;
} 
#component-4 li::first-letter{
    margin-left:-10px;
}
.gallery-item{ 
    flex:1 0 33%; 
    align-self:center; 
    height:75px;
}
footer{
    display:none !important;
}
@media only screen and (max-width:600px){
    #component-0 .chatbot{
    text-align:justify !important;
    padding: 5px 20px !important; 
}
    #component-3 h1{
        font-size:1.5rem;
        text-align:center !important;
    }
    #component-4 p{ 
        font-size:14px;
        text-align:justify;
    } 
    #component-4 li{
        font-size:12px;
        paddding:20px;
    }
    #component-4 li::first-letter{
        margin-left:-10px;
    }
    #component-5{
        display:flex;
        flex-direction:row;
    }
    #component-5 button{
        flex: 1 1 30%;
    }
    .gallery-item{ 
        flex:1 0 100%;
        height:100px;
    }
    #component-0 pre, #component-0 code{ 
        max-width: 100%; /* Asegura que el bloque de código no sea más ancho que su contenedor */
        box-sizing: border-box; /* Incluye padding y border dentro del ancho y alto del elemento */
        white-space: pre-wrap; /* Mantiene el formato pero permite el ajuste de palabras */
        word-break: break-all; /* Permite que las palabras se rompan para evitar desbordamiento */
        overflow-x: auto; /* Permite desplazamiento horizontal dentro del bloque de código si es necesario */
        overflow-y: hidden; /* Oculta el desbordamiento vertical, no debería ser necesario con pre-wrap */
    } 
}
"""
demo= gr.ChatInterface(
    fn = llm_function_with_timeout,
    chatbot=gr.Chatbot(label="ChatterIA"),
    textbox= gr.Textbox(placeholder="Envía tu mensaje...", lines=3, max_lines=10),
    title=title,
    description = description,
    theme = theme,
    examples = examples,
    css = css,
    cache_examples=False,
    submit_btn = "📤 Enviar",
    retry_btn = "🔁 Reenviar",
    undo_btn = "🔙 Deshacer",
    clear_btn= "🗑 Limpiar",
).launch()