mauroleguiok commited on
Commit
e02ceab
·
verified ·
1 Parent(s): a0e54de

Delete copia_de_modelo_chatbot_final_3_con_gradio.py

Browse files
copia_de_modelo_chatbot_final_3_con_gradio.py DELETED
@@ -1,578 +0,0 @@
1
- # -*- coding: utf-8 -*-
2
- """Copia de Modelo_Chatbot_Final_3_con_Gradio.ipynb
3
-
4
- Automatically generated by Colab.
5
-
6
- Original file is located at
7
- https://colab.research.google.com/drive/1sFAltehLtdNpHoQVsiDeikgSJkIDTWrD
8
- """
9
-
10
- !pip install language-tool-python
11
-
12
- !pip install transformers==4.17
13
-
14
- import warnings
15
- warnings.filterwarnings('ignore')
16
-
17
- import json
18
- import numpy as np
19
- import pandas as pd
20
- import random
21
- from matplotlib import pyplot as plt
22
- import seaborn as sns
23
- from wordcloud import WordCloud,STOPWORDS
24
- import missingno as msno
25
-
26
- from sklearn.feature_extraction.text import CountVectorizer
27
- from sklearn.model_selection import train_test_split
28
- from sklearn.metrics import accuracy_score, precision_recall_fscore_support
29
-
30
- #from keras.preprocessing import text
31
- import keras
32
- from keras.models import Sequential
33
- from keras.layers import Dense,Embedding,LSTM,Dropout
34
- from keras.callbacks import ReduceLROnPlateau
35
-
36
- from tensorflow.keras.preprocessing.sequence import pad_sequences
37
- import nltk
38
- from nltk import word_tokenize
39
- from nltk.stem import PorterStemmer
40
-
41
- import torch
42
- from torch.utils.data import Dataset
43
-
44
- from transformers import AutoTokenizer, TFAutoModelForSequenceClassification
45
- from transformers import pipeline
46
- from transformers import DistilBertTokenizerFast
47
- from transformers import BertForSequenceClassification, BertTokenizerFast
48
- from transformers import TFDistilBertForSequenceClassification, Trainer, TFTrainingArguments
49
- from transformers import BertTokenizer, TFBertForSequenceClassification, BertConfig
50
- from transformers import TrainingArguments, Trainer, EarlyStoppingCallback
51
-
52
- import re
53
-
54
- import language_tool_python
55
- import logging
56
- import spacy
57
-
58
- def load_json_file(filename):
59
- with open(filename) as f:
60
- file = json.load(f)
61
- return file
62
-
63
- filename = '/content/intents_aumentado.json'
64
-
65
- intents = load_json_file(filename)
66
-
67
- def create_df():
68
- df = pd.DataFrame({
69
- 'Pattern' : [],
70
- 'Tag' : []
71
- })
72
-
73
- return df
74
-
75
- df = create_df()
76
- df
77
-
78
- def extract_json_info(json_file, df):
79
-
80
- for intent in json_file['intents']:
81
-
82
- for pattern in intent['patterns']:
83
-
84
- sentence_tag = [pattern, intent['tag']]
85
- df.loc[len(df.index)] = sentence_tag
86
-
87
- return df
88
-
89
- df = extract_json_info(intents, df)
90
- df.head()
91
-
92
- df2 = df.copy()
93
- df2.head()
94
-
95
- import nltk
96
- nltk.download('punkt_tab')
97
-
98
- stemmer = PorterStemmer()
99
- ignore_words=['?', '!', ',', '.']
100
-
101
- def preprocess_pattern(pattern):
102
- words = word_tokenize(pattern.lower())
103
- stemmed_words = [stemmer.stem(word) for word in words if word not in ignore_words]
104
- return " ".join(stemmed_words)
105
-
106
- df['Pattern'] = df['Pattern'].apply(preprocess_pattern)
107
-
108
- df2.head()
109
-
110
- labels = df2['Tag'].unique().tolist()
111
- labels = [s.strip() for s in labels]
112
- labels
113
-
114
- num_labels = len(labels)
115
- id2label = {id:label for id, label in enumerate(labels)}
116
- label2id = {label:id for id, label in enumerate(labels)}
117
-
118
- id2label
119
-
120
- label2id
121
-
122
- df2['labels'] = df2['Tag'].map(lambda x: label2id[x.strip()])
123
- df2.head()
124
-
125
- X = list(df2['Pattern'])
126
- X[:5]
127
-
128
- y = list(df2['labels'])
129
- y[:5]
130
-
131
- X_train,X_test,y_train,y_test = train_test_split(X,y,random_state = 123)
132
-
133
- model_name = "dccuchile/bert-base-spanish-wwm-cased"
134
- max_len = 256
135
-
136
- tokenizer = BertTokenizer.from_pretrained(model_name,
137
- max_length=max_len)
138
-
139
- model = BertForSequenceClassification.from_pretrained(model_name,
140
- num_labels=num_labels,
141
- id2label=id2label,
142
- label2id = label2id)
143
-
144
- train_encoding = tokenizer(X_train, truncation=True, padding=True)
145
- test_encoding = tokenizer(X_test, truncation=True, padding=True)
146
-
147
- full_data = tokenizer(X, truncation=True, padding=True)
148
-
149
- class DataLoader(Dataset):
150
-
151
- def __init__(self, encodings, labels):
152
-
153
- self.encodings = encodings
154
- self.labels = labels
155
-
156
- def __getitem__(self, idx):
157
-
158
- item = {key: torch.tensor(val[idx]) for key, val in self.encodings.items()}
159
- item['labels'] = torch.tensor(self.labels[idx])
160
- return item
161
-
162
- def __len__(self):
163
-
164
- return len(self.labels)
165
-
166
- train_dataloader = DataLoader(train_encoding, y_train)
167
- test_dataloader = DataLoader(test_encoding, y_test)
168
-
169
- fullDataLoader = DataLoader(full_data, y_test)
170
-
171
- def compute_metrics(pred):
172
-
173
- labels = pred.label_ids
174
- preds = pred.predictions.argmax(-1)
175
- precision, recall, f1, _ = precision_recall_fscore_support(labels, preds, average='macro')
176
- acc = accuracy_score(labels, preds)
177
-
178
- return {
179
- 'accuracy': acc,
180
- 'f1': f1,
181
- 'precision': precision,
182
- 'recall': recall
183
- }
184
-
185
- # Parametros finales del modelo
186
- training_args = TrainingArguments(
187
- output_dir='./output', # Carpeta donde se guardarán los modelos entrenados y checkpoints
188
- do_train=True,
189
- do_eval=True,
190
- num_train_epochs=30, # Número total de épocas (pasadas completas por el dataset de entrenamiento)
191
- per_device_train_batch_size=8, # Tamaño del batch de entrenamiento por dispositivo (GPU o CPU)
192
- per_device_eval_batch_size=32, # Tamaño del batch de evaluación por dispositivo (mayor para evaluar más rápido)
193
- gradient_accumulation_steps=4, # Acumula gradientes por 4 pasos antes de hacer una actualización (simula batch más grande)
194
- learning_rate=2e-5, # Tasa de aprendizaje inicial
195
- warmup_ratio=0.1, # Porcentaje de pasos de calentamiento (warmup) sobre el total de pasos de entrenamiento
196
- weight_decay=0.1, # Regularización para evitar overfitting penalizando grandes pesos
197
- lr_scheduler_type="cosine", # Tipo de scheduler para modificar la tasa de aprendizaje (coseno en este caso)
198
- fp16=True, # Usa precisión mixta (float16) para acelerar entrenamiento si hay soporte (ej. en GPUs)
199
- evaluation_strategy="steps",
200
- eval_steps=50, # Evalúa el modelo cada 50 pasos de entrenamiento
201
- save_strategy="steps",
202
- save_steps=50, # Guarda el modelo cada 50 pasos
203
- save_total_limit=3, # Mantiene solo los últimos 3 checkpoints, borra los anteriores
204
- logging_strategy="steps",
205
- logging_dir='./multi-class-logs', # Carpeta donde se guardarán los logs de entrenamiento cada 50 pasos
206
- logging_steps=50, #
207
- load_best_model_at_end=True, # Carga automáticamente el mejor modelo evaluado al finalizar el entrenamiento
208
- metric_for_best_model="f1", # Métrica que se usa para definir cuál fue el "mejor" modelo
209
- greater_is_better=True
210
- )
211
-
212
- trainer = Trainer(
213
- model=model,
214
- args=training_args,
215
- train_dataset=train_dataloader,
216
- eval_dataset=test_dataloader,
217
- compute_metrics=compute_metrics,
218
- callbacks=[EarlyStoppingCallback(early_stopping_patience=3)] # Frena el entrenamiento si no mejora la métrica de evaluación después de 3 evaluaciones consecutiva
219
- )
220
-
221
- import os
222
-
223
- os.environ["WANDB_API_KEY"] = "4fb9dff0336a34ab812e86f91b6c3a877cb25b36"
224
-
225
- import wandb
226
- wandb.login()
227
-
228
- trainer.train()
229
-
230
- q=[trainer.evaluate(eval_dataset=df2) for df2 in [train_dataloader, test_dataloader]]
231
-
232
- pd.DataFrame(q, index=["train","test"]).iloc[:,:5]
233
-
234
- def predict(text):
235
-
236
- inputs = tokenizer(text, padding=True, truncation=True, max_length=512, return_tensors="pt").to("cuda")
237
- outputs = model(**inputs)
238
-
239
- probs = outputs[0].softmax(1)
240
- pred_label_idx = probs.argmax()
241
- pred_label = model.config.id2label[pred_label_idx.item()]
242
-
243
- return probs, pred_label_idx, pred_label
244
-
245
- text = "Hola"
246
- predict(text)
247
-
248
- model_path = "chatbot"
249
- trainer.save_model(model_path)
250
- tokenizer.save_pretrained(model_path)
251
-
252
- !kaggle kernels output eyadgk/build-a-chatbot-with-bert-eda-vis -p /path/to/dest
253
-
254
- model_path = "/content/chatbot"
255
-
256
-
257
- model = BertForSequenceClassification.from_pretrained(model_path)
258
- tokenizer= BertTokenizerFast.from_pretrained(model_path)
259
- chatbot= pipeline("text-classification", model=model, tokenizer=tokenizer)
260
-
261
- chatbot("Hola")
262
-
263
- negaciones = [
264
- "no", "nunca", "nadie", "ningún", "ninguna", "nada",
265
- "jamás", "jamas", "ni", "tampoco", "de ninguna manera",
266
- "en absoluto", "en ningún caso", "no es cierto",
267
- "no estoy de acuerdo", "no me parece", "no creo",
268
- "no quiero", "no puedo", "no quiero hacerlo", "no acepto", "no gracias"
269
- ]
270
-
271
- afirmaciones = [
272
- "sí", "si", "claro", "por supuesto", "entendido", "estoy de acuerdo",
273
- "acepto", "exacto", "correcto", "eso es", "está bien", "esta bien",
274
- "claro que sí", "lo creo", "es cierto", "sin duda", "así es", "claro que si"
275
- "perfecto", "me parece bien", "seguro", "definitivamente", "por supuesto"
276
- ]
277
-
278
- # Asumiendo que intents ya está definido
279
- def obtener_respuesta_aleatoria(tag):
280
- """Busca el intent correspondiente al tag y devuelve una respuesta aleatoria."""
281
- for intent in intents['intents']:
282
- if intent['tag'] == tag:
283
- return random.choice(intent['responses'])
284
- return "No tengo respuesta para eso."
285
-
286
- # Asumiendo que intents ya está definido
287
- def obtener_lista_de_respuesta(tag):
288
- """Busca el intent correspondiente al tag y devuelve una respuesta aleatoria."""
289
- for intent in intents['intents']:
290
- if intent['tag'] == tag:
291
- return intent['responses']
292
- return "No tengo respuesta para eso."
293
-
294
- historial_respuestas = {}
295
-
296
- def obtener_respuesta_sin_repetir(label):
297
- global historial_respuestas
298
-
299
- # Si es la primera vez que se usa el label, inicializar historial
300
- if label not in historial_respuestas:
301
- historial_respuestas[label] = []
302
-
303
- respuestas_posibles = obtener_lista_de_respuesta(label) # Lista de respuestas disponibles para el tag
304
-
305
- # Filtrar respuestas que aún no se usaron
306
- respuestas_disponibles = [r for r in respuestas_posibles if r not in historial_respuestas[label]]
307
-
308
- if not respuestas_disponibles:
309
- historial_respuestas[label] = [] # Resetear historial cuando se agoten todas
310
-
311
- # Elegir una nueva respuesta sin repetir
312
- nueva_respuesta = random.choice([r for r in respuestas_posibles if r not in historial_respuestas[label]])
313
-
314
- # Agregarla al historial
315
- historial_respuestas[label].append(nueva_respuesta)
316
-
317
- return nueva_respuesta
318
-
319
- def corregir_preguntas(texto, idioma='es'):
320
- """
321
- Corrige la ortografía y gramática del texto usando LanguageTool.
322
- También ajusta signos de interrogación y acentos en palabras interrogativas.
323
- Ignora correcciones sobre las palabras: 'unaj', 'arturo', 'jauretche'.
324
- """
325
- try:
326
- # Agregar "?" si el texto tiene 3 o más palabras y no termina con "?"
327
- if len(texto.split()) >= 3 and not texto.endswith("?"):
328
- texto += "?"
329
-
330
- # Palabras a ignorar (en minúsculas)
331
- palabras_ignorar = ["unaj", "arturo", "jauretche", "profode"]
332
- reemplazos = {}
333
-
334
- # Reemplazar palabras ignoradas por marcadores temporales
335
- def reemplazar_ignoradas(match):
336
- palabra = match.group(0)
337
- marcador = f"__IGNORAR_{len(reemplazos)}__"
338
- reemplazos[marcador] = palabra
339
- return marcador
340
-
341
- patron_ignorar = re.compile(r'\b(' + '|'.join(palabras_ignorar) + r')\b', re.IGNORECASE)
342
- texto_temporal = patron_ignorar.sub(reemplazar_ignoradas, texto)
343
-
344
- # Inicializar el corrector de LanguageTool
345
- tool = language_tool_python.LanguageToolPublicAPI(idioma)
346
-
347
- # Obtener las correcciones sugeridas
348
- texto_corregido = tool.correct(texto_temporal)
349
-
350
- # Restaurar las palabras ignoradas
351
- for marcador, palabra_original in reemplazos.items():
352
- texto_corregido = texto_corregido.replace(marcador, palabra_original)
353
-
354
- # Diccionario con palabras interrogativas y sus versiones acentuadas
355
- palabras_interrogativas = {
356
- "como": "cómo", "cuando": "cuándo", "donde": "dónde", "que": "qué",
357
- "quien": "quién", "cual": "cuál", "cuanto": "cuánto"
358
- }
359
-
360
- # Si la oración es interrogativa, corregir solo la primera palabra interrogativa
361
- if texto_corregido.endswith("?"):
362
- palabras = texto_corregido[:-1].split() # Remover "?" y dividir en palabras
363
- primera_encontrada = False
364
-
365
- for i, palabra in enumerate(palabras):
366
- palabra_limpia = palabra.lower().strip("¿") # Remover el signo "¿" si existe
367
-
368
- # Si es una palabra interrogativa y es la primera encontrada, corregir
369
- if palabra_limpia in palabras_interrogativas:
370
- if not primera_encontrada:
371
- palabras[i] = palabras_interrogativas[palabra_limpia]
372
- primera_encontrada = True
373
-
374
- texto_corregido = " ".join(palabras) + "?"
375
-
376
- # Asegurar que la oración comienza con "¿"
377
- if not texto_corregido.startswith("¿"):
378
- texto_corregido = "¿" + texto_corregido
379
-
380
- # Mantener solo el último signo "¿" y eliminar los anteriores
381
- if texto_corregido.count("¿") > 1:
382
- ultima_pos = texto_corregido.rfind("¿")
383
- texto_corregido = texto_corregido[:ultima_pos].replace("¿", "") + texto_corregido[ultima_pos:]
384
-
385
- return texto_corregido
386
-
387
- except Exception:
388
- return texto
389
-
390
- def normalizar_clave(texto):
391
- reemplazos = {
392
- "á": "a", "é": "e", "í": "i", "ó": "o", "ú": "u",
393
- "ä": "a", "ë": "e", "ï": "i", "ö": "o", "ü": "u"
394
- }
395
- for acentuada, normal in reemplazos.items():
396
- texto = texto.replace(acentuada, normal)
397
-
398
- return texto.strip().replace(" ", "+")
399
-
400
- estado_chatbot = {
401
- "esperando_confirmacion": False,
402
- "opciones": [],
403
- "texto_original": ""
404
- }
405
-
406
- def obtener_respuesta_chatbot(text):
407
- global estado_chatbot
408
-
409
- # Si no está esperando confirmación, resetea su estado antes de procesar la nueva consulta
410
- if not estado_chatbot["esperando_confirmacion"]:
411
- estado_chatbot["opciones"] = [] # Limpia opciones anteriores
412
- estado_chatbot["texto_original"] = "" # Resetea el estado previo
413
-
414
- if estado_chatbot["esperando_confirmacion"]:
415
- if text.lower() in afirmaciones:
416
- estado_chatbot["esperando_confirmacion"] = False # Se resetea el estado
417
- respuesta = obtener_respuesta_sin_repetir(estado_chatbot["opciones"][0]["label"])
418
- estado_chatbot["opciones"] = [] # Limpia opciones anteriores
419
- estado_chatbot["texto_original"] = "" # Resetea el estado previo
420
- return respuesta
421
- elif text.lower() in negaciones:
422
- if len(estado_chatbot["opciones"]) > 1:
423
- estado_chatbot["esperando_confirmacion"] = False # Se resetea el estado
424
- return obtener_respuesta_sin_repetir(estado_chatbot["opciones"][1]["label"])
425
- else:
426
- estado_chatbot["esperando_confirmacion"] = False # Se resetea el estado
427
- return "No tengo más opciones, ¿podés reformular la pregunta?"
428
-
429
- else:
430
- return "Por favor, respondé 'sí' o 'no'."
431
-
432
- prediction = chatbot(text)
433
- prediction = sorted(prediction, key=lambda x: x["score"], reverse=True) # Ordenar por score
434
-
435
- label_principal = prediction[0]["label"]
436
- score_principal = prediction[0]["score"]
437
-
438
- if score_principal >= 0.1:
439
- print("(Grado de seguridad en la respuesta: ", score_principal, ")")
440
- return obtener_respuesta_sin_repetir(label_principal)
441
-
442
- elif 0.20 <= score_principal < 0.4:
443
- estado_chatbot["esperando_confirmacion"] = True
444
- estado_chatbot["opciones"] = prediction[:2]
445
- estado_chatbot["texto_original"] = text
446
-
447
- opciones_texto = ", ".join(
448
- [f"{alt['label']} ({alt['score']:.2f})" for alt in estado_chatbot["opciones"]]
449
- )
450
- return f"No estoy seguro de la respuesta correscta. ¿Te referís a alguna de estas opciones? Opción 1: {opciones_texto} (Si/No)"
451
-
452
- else:
453
- print(f"No tengo una respuesta precisa. ¿Puedes decirme una palabra clave de tu pregunta para que pueda ayudarte? Ingresa una o dos palabras:")
454
- clave = input().lower() # No es necesario str()
455
- clave = normalizar_clave(clave)
456
-
457
- # Verificar si la palabra clave no es una negación
458
- if clave not in negaciones:
459
- # Si no es una negación, proporcionar el enlace
460
- return f"Prueba consultando el siguiente enlace: https://www.unaj.edu.ar/?s={clave} o reformula tu pregunta. Escribela a continuación:"
461
- else:
462
- # Si la clave es una negación, podrías manejarlo aquí
463
- return "Comprendo, intenta reformular tu pregunta por favor para que pueda entenderla. Prueba usando frases cortas y claras."
464
-
465
- faq = ['¿Cuándo puedo inscribirme a carreras?', '¿Qué carreras tiene la UNAJ?', '¿Qué posgrados tiene la UNAJ?', '¿Qué cursos de oficios tiene la UNAJ y cómo puedo inscribirme?', '¿Qué otras propuestas de formación ofrece la UNAJ?', '¿Puedo estudiar idiomas en la UNAJ?', '¿Qué hago si no puedo ingresar al SIU GUARANÍ?', '¿Cuándo comienza y termina el cuatrimestre?', '¿Dónde encuentro el calendario académico?', '¿Cuándo puedo reincorporarme?', '¿Cuándo puedo cambiar de carrera?', '¿Cómo pido equivalencias?', '¿Cómo pido una licencia estudiantil?']
466
-
467
- for f in faq:
468
- print(f)
469
- print(obtener_respuesta_chatbot(corregir_preguntas(f.lower())))
470
- print("-------------------------------------------------------------------------------------------------------------------------------------")
471
-
472
- # Instalar librerías necesarias
473
- !pip install gradio pyngrok
474
-
475
- import gradio as gr
476
- from pyngrok import ngrok
477
-
478
- !ngrok authtoken 2joTtbK1dLq8wGpfwu3aUzz3r83_3RtvMEa2QazhDFauAHHaG
479
-
480
- import pandas as pd
481
- from datetime import datetime
482
- from bs4 import BeautifulSoup
483
-
484
- # Nombre del archivo CSV
485
- feedback_file = "feedback.csv"
486
-
487
- # Inicializar CSV si no existe
488
- def init_csv():
489
- try:
490
- pd.read_csv(feedback_file)
491
- except FileNotFoundError:
492
- df = pd.DataFrame(columns=["timestamp", "question", "response", "feedback"])
493
- df.to_csv(feedback_file, index=False)
494
-
495
- # Extrae el texto de la respuesta HTML
496
- def limpiar_html(texto_html):
497
- return BeautifulSoup(texto_html, "html.parser").get_text()
498
-
499
- # Guardar el feedback cuando se hace clic en "Nuevo Mensaje"
500
- def guardar_feedback(question, response, feedback):
501
- timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
502
- response_limpia = limpiar_html(response)
503
- new_data = pd.DataFrame([[timestamp, question, response_limpia, feedback]],
504
- columns=["timestamp", "question", "response", "feedback"])
505
- new_data.to_csv(feedback_file, mode='a', header=False, index=False)
506
- return "", "", 10, gr.update(interactive=False) # limpia todo y desactiva "Nuevo Mensaje"
507
-
508
- # Convierte las URL en hipervinculos clickeables
509
- def convertir_urls_a_links(texto):
510
- # Expresión regular para encontrar URLs
511
- url_pattern = r"(https?://[^\s]+)"
512
- # Reemplaza cada URL por una etiqueta <a>
513
- return re.sub(url_pattern, r'<a href="\1" target="_blank">\1</a>', texto)
514
-
515
- # Simulación de respuesta del chatbot (reemplazar por tu modelo real)
516
- def chatbot_response(question):
517
- mensaje_corregido = corregir_preguntas(question)
518
- respuesta_raw = obtener_respuesta_chatbot(mensaje_corregido)
519
- respuesta = convertir_urls_a_links(respuesta_raw)
520
-
521
- # Agrega un contenedor con estilo para simular una caja
522
- respuesta_contenedor = f"""
523
- <div style='background-color:#2b2b2b; color:#f1f1f1; border:0px solid #515057;
524
- padding:10px; border-radius:5px; white-space:pre-wrap'>
525
- {respuesta}
526
- </div>
527
- """
528
-
529
- return respuesta_contenedor, gr.update(visible=True, interactive=True)
530
-
531
- # Inicializamos el CSV
532
- init_csv()
533
-
534
- # Interfaz Gradio
535
- with gr.Blocks(css="""
536
- body {
537
- background-color: black;
538
- color: #00ffff;
539
- }
540
- .gr-button {
541
- background-color: #00ffff !important;
542
- color: black !important;
543
- }
544
- .gr-textbox textarea, .gr-number input {
545
- background-color: #111;
546
- color: #00ffff;
547
- border: 1px solid #00ffff;
548
- }
549
- """) as demo:
550
- with gr.Row():
551
- gr.HTML("<div style='flex:1'></div><img src='https://guarani.unaj.edu.ar/_comp/unaj/img/logo-transparente.png' height='60px' style='margin:10px'/>")
552
-
553
- gr.Markdown("# Chatbot UNAJ\n## Hola! Soy Arturito, el bot de la UNAJ y estoy para responder tus preguntas sobre la Universidad Nacional Arturo Jauretche")
554
-
555
- question_input = gr.Textbox(label="Mensaje", placeholder="Escribí tu consulta...")
556
- submit_btn = gr.Button("Enviar Mensaje")
557
-
558
- # Se usa un HTML para que los links de la respuesta sean clickeables
559
- response_output = gr.HTML()
560
-
561
- # Se coloca un slider que permite captar el feedback de la respuesta
562
- feedback_slider = gr.Slider(minimum=1, maximum=10, value=10, step=1,
563
- label="¿Qué tan útil fue la respuesta? (1 = Nada útil, 10 = Muy útil)", interactive=True)
564
-
565
- # Aparece un boton para "Nuevo Mensaje" que limpia el cuadro de "Mensaje" y guarda la respuesta y puntuación.
566
- new_message_btn = gr.Button("Nuevo Mensaje", visible=False)
567
-
568
- # Evento al hacer clic en "Enviar Mensaje"
569
- submit_btn.click(fn=chatbot_response,
570
- inputs=question_input,
571
- outputs=[response_output, new_message_btn])
572
-
573
- # Evento al hacer clic en "Nuevo Mensaje"
574
- new_message_btn.click(fn=guardar_feedback,
575
- inputs=[question_input, response_output, feedback_slider],
576
- outputs=[question_input, response_output, feedback_slider, new_message_btn])
577
-
578
- demo.launch(share=True)