Cosio commited on
Commit
6dbad96
verified
1 Parent(s): 4211b92

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +225 -0
  2. requirements.txt +5 -0
app.py ADDED
@@ -0,0 +1,225 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py
2
+ import gradio as gr
3
+ import pandas as pd
4
+ import PyPDF2
5
+ import requests
6
+ import io
7
+ import json
8
+ import os # Para manejar variables de entorno si fuera necesario en un entorno real
9
+
10
+ # Variable global para almacenar el texto extra铆do de la base de conocimientos
11
+ # Se vac铆a cada vez que se carga un nuevo archivo.
12
+ knowledge_base_text = ""
13
+
14
+ # Longitud m谩xima del contexto que se pasar谩 al modelo de lenguaje.
15
+ # Los modelos de lenguaje tienen l铆mites en la cantidad de texto que pueden procesar.
16
+ # Si la base de conocimientos es muy grande, se truncar谩.
17
+ MAX_CONTEXT_LENGTH = 8000 # Caracteres
18
+
19
+ def load_knowledge_base(file):
20
+ """
21
+ Carga un archivo (CSV, XLSX, PDF) y extrae su contenido de texto para usarlo
22
+ como base de conocimientos.
23
+
24
+ Args:
25
+ file: Un objeto de archivo de Gradio (gr.File), que contiene la ruta temporal del archivo subido.
26
+
27
+ Returns:
28
+ str: Un mensaje de estado indicando si la carga fue exitosa o si hubo un error.
29
+ """
30
+ global knowledge_base_text
31
+ knowledge_base_text = "" # Limpiar la base de conocimientos anterior al cargar una nueva
32
+
33
+ if file is None:
34
+ return "Por favor, sube un archivo para la base de conocimientos."
35
+
36
+ file_path = file.name # La ruta temporal del archivo subido por Gradio
37
+ file_extension = file_path.split('.')[-1].lower()
38
+
39
+ try:
40
+ if file_extension == 'csv':
41
+ # Leer archivos CSV usando pandas
42
+ df = pd.read_csv(file_path)
43
+ knowledge_base_text = df.to_string(index=False) # Convertir DataFrame a cadena de texto
44
+ elif file_extension == 'xlsx':
45
+ # Leer archivos XLSX usando pandas (requiere openpyxl)
46
+ df = pd.read_excel(file_path)
47
+ knowledge_base_text = df.to_string(index=False) # Convertir DataFrame a cadena de texto
48
+ elif file_extension == 'pdf':
49
+ # Leer archivos PDF usando PyPDF2
50
+ with open(file_path, 'rb') as f:
51
+ reader = PyPDF2.PdfReader(f)
52
+ for page_num in range(len(reader.pages)):
53
+ page = reader.pages[page_num]
54
+ # Extraer texto de cada p谩gina y a帽adirlo a la base de conocimientos
55
+ knowledge_base_text += page.extract_text() + "\n"
56
+ else:
57
+ return "Formato de archivo no soportado. Por favor, sube un archivo .csv, .xlsx o .pdf."
58
+
59
+ # Truncar la base de conocimientos si excede la longitud m谩xima del contexto
60
+ if len(knowledge_base_text) > MAX_CONTEXT_LENGTH:
61
+ knowledge_base_text = knowledge_base_text[:MAX_CONTEXT_LENGTH] + "\n... [Contenido truncado debido a la longitud m谩xima del contexto]"
62
+ return f"Base de conocimientos cargada exitosamente (truncada a {MAX_CONTEXT_LENGTH} caracteres). 隆Ahora puedes chatear!"
63
+ else:
64
+ return "Base de conocimientos cargada exitosamente. 隆Ahora puedes chatear!"
65
+
66
+ except Exception as e:
67
+ knowledge_base_text = "" # Limpiar la base de conocimientos en caso de error
68
+ return f"Error al cargar la base de conocimientos: {e}. Aseg煤rate de que el archivo no est茅 corrupto o vac铆o."
69
+
70
+ def get_llm_response(prompt_text, context_text, personality_setting):
71
+ """
72
+ Genera una respuesta utilizando la API de Gemini, incorporando el contexto
73
+ de la base de conocimientos y la personalidad seleccionada.
74
+
75
+ Args:
76
+ prompt_text (str): La pregunta del usuario.
77
+ context_text (str): El texto de la base de conocimientos que se usar谩 como contexto.
78
+ personality_setting (str): La personalidad deseada para el bot (e.g., "amigable", "formal").
79
+
80
+ Returns:
81
+ str: La respuesta generada por el modelo de lenguaje, o un mensaje de error.
82
+ """
83
+ # Construir la instrucci贸n del sistema para guiar el comportamiento del LLM
84
+ system_instruction = (
85
+ f"Eres un asistente de IA con una personalidad {personality_setting}. "
86
+ "Responde a las preguntas de manera 煤til y concisa, utilizando la informaci贸n "
87
+ "proporcionada en el contexto si es relevante. Si la respuesta no est谩 en el contexto, "
88
+ "usa tu conocimiento general. Responde siempre en espa帽ol."
89
+ )
90
+
91
+ # Combinar la instrucci贸n del sistema, el contexto y la pregunta del usuario en un solo prompt
92
+ full_prompt = f"{system_instruction}\n\nContexto:\n{context_text}\n\nPregunta: {prompt_text}"
93
+
94
+ # Preparar el historial de chat para la API de Gemini
95
+ chat_history = []
96
+ chat_history.append({"role": "user", "parts": [{"text": full_prompt}]})
97
+
98
+ # Carga 煤til para la solicitud a la API de Gemini
99
+ payload = {
100
+ "contents": chat_history,
101
+ "generationConfig": {
102
+ "responseMimeType": "text/plain" # Solicitar una respuesta en texto plano
103
+ }
104
+ }
105
+
106
+ # La clave de la API se deja vac铆a seg煤n las instrucciones para el entorno Canvas.
107
+ # En un despliegue real, esto deber铆a manejarse de forma segura (e.g., variables de entorno).
108
+ api_key = "" # Canvas inyectar谩 la clave API en tiempo de ejecuci贸n
109
+ api_url = f"https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash:generateContent?key={api_key}"
110
+
111
+ try:
112
+ # Realizar la solicitud POST a la API de Gemini
113
+ response = requests.post(api_url, headers={'Content-Type': 'application/json'}, data=json.dumps(payload))
114
+ response.raise_for_status() # Lanzar una excepci贸n para c贸digos de estado HTTP de error (4xx o 5xx)
115
+ result = response.json() # Parsear la respuesta JSON
116
+
117
+ # Extraer el texto de la respuesta del modelo
118
+ if result.get("candidates") and len(result["candidates"]) > 0 and \
119
+ result["candidates"][0].get("content") and result["candidates"][0]["content"].get("parts") and \
120
+ len(result["candidates"][0]["content"]["parts"]) > 0:
121
+ return result["candidates"][0]["content"]["parts"][0]["text"]
122
+ else:
123
+ print("Error: Estructura de respuesta inesperada de la API del LLM.", result)
124
+ return "Lo siento, no pude generar una respuesta. Hubo un problema con la API del modelo."
125
+ except requests.exceptions.RequestException as e:
126
+ # Manejar errores de conexi贸n o HTTP
127
+ print(f"Error al llamar a la API de Gemini: {e}")
128
+ return f"Lo siento, hubo un error de conexi贸n al intentar obtener una respuesta: {e}"
129
+ except json.JSONDecodeError as e:
130
+ # Manejar errores al decodificar la respuesta JSON
131
+ print(f"Error al decodificar la respuesta JSON de la API: {e}")
132
+ return "Lo siento, hubo un problema al procesar la respuesta del modelo."
133
+ except Exception as e:
134
+ # Manejar cualquier otra excepci贸n inesperada
135
+ print(f"Ocurri贸 un error inesperado al obtener la respuesta del LLM: {e}")
136
+ return "Lo siento, ocurri贸 un error inesperado al intentar obtener una respuesta."
137
+
138
+
139
+ def chat(user_message, personality_setting):
140
+ """
141
+ Funci贸n principal del chatbot que procesa el mensaje del usuario y genera una respuesta.
142
+
143
+ Args:
144
+ user_message (str): El mensaje o pregunta del usuario.
145
+ personality_setting (str): La personalidad seleccionada para el bot.
146
+
147
+ Returns:
148
+ str: La respuesta generada por el bot.
149
+ """
150
+ if not user_message:
151
+ return "Por favor, escribe un mensaje para que el bot pueda responder."
152
+
153
+ # Usar la base de conocimientos global como contexto para el LLM
154
+ # Si no hay base de conocimientos cargada, se indica al LLM que no hay contexto.
155
+ context_for_llm = knowledge_base_text if knowledge_base_text else "No hay una base de conocimientos cargada."
156
+
157
+ # Obtener la respuesta del modelo de lenguaje
158
+ bot_response = get_llm_response(user_message, context_for_llm, personality_setting)
159
+ return bot_response
160
+
161
+ # Configuraci贸n de la interfaz de Gradio
162
+ with gr.Blocks(title="Chatbot de Base de Conocimientos") as demo:
163
+ gr.Markdown(
164
+ """
165
+ # 馃 Chatbot de Base de Conocimientos Configurable
166
+ Sube un archivo (CSV, XLSX, PDF) para que el bot lo use como base de conocimientos.
167
+ Luego, selecciona una personalidad y haz tus preguntas.
168
+ """
169
+ )
170
+
171
+ with gr.Row():
172
+ # Componente para subir archivos
173
+ file_input = gr.File(label="Sube tu base de conocimientos (.csv, .xlsx, .pdf)", type="filepath")
174
+ # Bot贸n para cargar la base de conocimientos
175
+ load_button = gr.Button("Cargar Base de Conocimientos")
176
+ # Cuadro de texto para mostrar el estado de la carga
177
+ status_output = gr.Textbox(label="Estado de la Carga", interactive=False)
178
+
179
+ # Configurar la acci贸n del bot贸n de carga
180
+ load_button.click(
181
+ fn=load_knowledge_base, # Funci贸n a llamar
182
+ inputs=file_input, # Entrada de la funci贸n
183
+ outputs=status_output # Salida de la funci贸n
184
+ )
185
+
186
+ gr.Markdown("---") # Separador visual
187
+
188
+ with gr.Row():
189
+ # Desplegable para seleccionar la personalidad del bot
190
+ personality_dropdown = gr.Dropdown(
191
+ label="Personalidad del Bot",
192
+ choices=["amigable", "formal", "creativo", "anal铆tico"], # Opciones de personalidad
193
+ value="amigable", # Valor predeterminado
194
+ interactive=True
195
+ )
196
+ # Cuadro de texto para que el usuario escriba su pregunta
197
+ user_query_input = gr.Textbox(label="Tu Pregunta", placeholder="Escribe tu pregunta aqu铆...")
198
+ # Bot贸n para enviar la pregunta
199
+ chat_button = gr.Button("Enviar Pregunta")
200
+
201
+ # Cuadro de texto para mostrar la respuesta del bot
202
+ bot_response_output = gr.Textbox(label="Respuesta del Bot", interactive=False)
203
+
204
+ # Configurar la acci贸n del bot贸n de chat
205
+ chat_button.click(
206
+ fn=chat, # Funci贸n a llamar
207
+ inputs=[user_query_input, personality_dropdown], # Entradas de la funci贸n
208
+ outputs=bot_response_output # Salida de la funci贸n
209
+ )
210
+
211
+ # Ejemplos para facilitar las pruebas r谩pidas del bot
212
+ gr.Examples(
213
+ examples=[
214
+ ["驴Qu茅 es un chatbot?", "amigable"],
215
+ ["Dame un resumen de la informaci贸n cargada.", "anal铆tico"],
216
+ ["驴C贸mo puedo usar este bot?", "formal"]
217
+ ],
218
+ inputs=[user_query_input, personality_dropdown],
219
+ outputs=bot_response_output,
220
+ fn=chat, # La funci贸n que se ejecuta al seleccionar un ejemplo
221
+ cache_examples=False # No almacenar en cach茅 los resultados de los ejemplos
222
+ )
223
+
224
+ # Para ejecutar la aplicaci贸n Gradio (esto lo har谩 Hugging Face Spaces autom谩ticamente)
225
+ # demo.launch()
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ gradio==4.36.1
2
+ pandas==2.2.2
3
+ PyPDF2==3.0.1
4
+ requests==2.32.3
5
+ openpyxl==3.1.2