Cosio commited on
Commit
5ece554
·
verified ·
1 Parent(s): 6dbad96

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +225 -225
app.py CHANGED
@@ -1,225 +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()
 
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()