Commit
·
cdcc94d
1
Parent(s):
5edad88
Se modifica la función procesar_tickets para un mejor procesamiento
Browse files
app.py
CHANGED
@@ -9,6 +9,7 @@ import torch
|
|
9 |
import logging
|
10 |
from dotenv import load_dotenv
|
11 |
from transformers import pipeline, AutoTokenizer
|
|
|
12 |
|
13 |
# Configurar logging
|
14 |
logging.basicConfig(level=logging.INFO)
|
@@ -35,6 +36,12 @@ URGENCY_PATTERNS = [ # Patrones
|
|
35 |
|
36 |
# 2. Clase para manejo de tickets
|
37 |
class TicketSystem:
|
|
|
|
|
|
|
|
|
|
|
|
|
38 |
def __init__(self):
|
39 |
self.mode = os.getenv("TICKET_API_MODE", "simulated")
|
40 |
self.tickets = []
|
@@ -203,52 +210,58 @@ def clasificar_texto(text: str) -> str:
|
|
203 |
return clasificar_con_palabras_clave(text)
|
204 |
|
205 |
# 5. Función para procesar archivos CSV
|
206 |
-
def procesar_tickets(input_csv, output_csv):
|
207 |
-
"""
|
|
|
|
|
|
|
|
|
208 |
try:
|
209 |
df = pd.read_csv(input_csv)
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
216 |
categorias_pred = []
|
217 |
urgencias = []
|
218 |
-
|
219 |
logger.info("Iniciando procesamiento de tickets...")
|
220 |
-
|
221 |
-
for i, descripcion in enumerate(df['descripcion']):
|
222 |
-
# Clasificar categoría
|
223 |
descripcion_str = str(descripcion)
|
224 |
categoria = clasificar_texto(descripcion_str)
|
225 |
categorias_pred.append(categoria)
|
226 |
-
|
227 |
-
# Detectar urgencia
|
228 |
urgencia = es_urgente(descripcion_str)
|
229 |
urgencias.append(urgencia)
|
230 |
-
|
231 |
logger.info(f"Ticket {i+1}: '{descripcion_str[:30]}...' -> Categoría: {categoria}, Urgente: {urgencia}")
|
232 |
-
|
233 |
df['categoria'] = categorias_pred
|
234 |
df['urgente'] = urgencias
|
235 |
-
|
236 |
-
# Guardar resultados
|
237 |
df.to_csv(output_csv, index=False)
|
238 |
logger.info(f"Resultados guardados en {output_csv}")
|
239 |
-
|
240 |
-
# Separar tickets urgentes
|
241 |
urgentes = df[df['urgente']]
|
242 |
if not urgentes.empty:
|
243 |
-
urgentes_csv = "tickets_urgentes.csv"
|
244 |
urgentes.to_csv(urgentes_csv, index=False)
|
245 |
logger.info(f"⚠️ {len(urgentes)} tickets urgentes guardados en '{urgentes_csv}'")
|
246 |
-
return df, urgentes_csv
|
247 |
else:
|
248 |
logger.info("No se encontraron tickets urgentes")
|
249 |
-
return df, None
|
250 |
except Exception as e:
|
251 |
logger.error(f"❌ Error procesando CSV: {e}")
|
|
|
252 |
|
253 |
|
254 |
# 6. Inicializar sistema de tickets para la interfaz web
|
@@ -345,42 +358,44 @@ with gr.Blocks(title="Sistema de Soporte Inteligente", theme=gr.themes.Soft()) a
|
|
345 |
outputs=ticket_db
|
346 |
)
|
347 |
"""
|
348 |
-
|
349 |
# Función wrapper para procesar CSV
|
350 |
def procesar_csv_wrapper(archivo):
|
|
|
|
|
|
|
351 |
if archivo is None:
|
352 |
return "❌ No se subió ningún archivo", None, None, gr.update(visible=False)
|
353 |
-
|
354 |
try:
|
355 |
-
# Obtener ruta temporal del archivo subido
|
356 |
file_path = archivo.name
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
|
|
|
|
|
|
362 |
if result is not None:
|
363 |
-
# Si hay tickets urgentes, mostrar el enlace
|
364 |
if urgentes_file:
|
365 |
return (
|
366 |
-
"✅ Procesamiento completado con éxito",
|
367 |
output_file,
|
368 |
urgentes_file,
|
369 |
gr.update(visible=True)
|
370 |
)
|
371 |
else:
|
372 |
return (
|
373 |
-
"✅ Procesamiento completado
|
374 |
output_file,
|
375 |
None,
|
376 |
gr.update(visible=False)
|
377 |
)
|
378 |
else:
|
379 |
return "❌ Error procesando el archivo", None, None, gr.update(visible=False)
|
380 |
-
|
381 |
except Exception as e:
|
382 |
return f"❌ Error: {str(e)}", None, None, gr.update(visible=False)
|
383 |
-
|
384 |
process_btn.click(
|
385 |
fn=procesar_csv_wrapper,
|
386 |
inputs=file_input,
|
@@ -389,11 +404,29 @@ with gr.Blocks(title="Sistema de Soporte Inteligente", theme=gr.themes.Soft()) a
|
|
389 |
|
390 |
# 9. Ejecutar la aplicación
|
391 |
if __name__ == "__main__":
|
392 |
-
#
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
import logging
|
10 |
from dotenv import load_dotenv
|
11 |
from transformers import pipeline, AutoTokenizer
|
12 |
+
import sys
|
13 |
|
14 |
# Configurar logging
|
15 |
logging.basicConfig(level=logging.INFO)
|
|
|
36 |
|
37 |
# 2. Clase para manejo de tickets
|
38 |
class TicketSystem:
|
39 |
+
def limpiar_historial(self, filename="tickets_db.json"):
|
40 |
+
"""Limpia el historial de tickets simulados."""
|
41 |
+
self.tickets = []
|
42 |
+
self.next_id = 1000
|
43 |
+
self.save_to_json(filename)
|
44 |
+
return True
|
45 |
def __init__(self):
|
46 |
self.mode = os.getenv("TICKET_API_MODE", "simulated")
|
47 |
self.tickets = []
|
|
|
210 |
return clasificar_con_palabras_clave(text)
|
211 |
|
212 |
# 5. Función para procesar archivos CSV
|
213 |
+
def procesar_tickets(input_csv, output_csv=None):
|
214 |
+
"""
|
215 |
+
Procesa un archivo CSV con tickets y genera resultados clasificados.
|
216 |
+
- Permite nombres únicos para archivos de salida.
|
217 |
+
- Valida la existencia de la columna 'descripcion' (case-insensitive).
|
218 |
+
"""
|
219 |
try:
|
220 |
df = pd.read_csv(input_csv)
|
221 |
+
# Buscar columna 'descripcion' de forma flexible
|
222 |
+
desc_col = None
|
223 |
+
for col in df.columns:
|
224 |
+
if col.strip().lower() == 'descripcion':
|
225 |
+
desc_col = col
|
226 |
+
break
|
227 |
+
if not desc_col:
|
228 |
+
raise ValueError("El CSV debe contener una columna llamada 'descripcion' (no se encontró, revise el encabezado)")
|
229 |
+
|
230 |
+
# Validar duplicados
|
231 |
+
num_duplicados = df.duplicated(subset=[desc_col]).sum()
|
232 |
+
if num_duplicados > 0:
|
233 |
+
logger.warning(f"Se encontraron {num_duplicados} tickets duplicados (por descripción) en el archivo CSV.")
|
234 |
+
# Nombres únicos para archivos de salida
|
235 |
+
timestamp = time.strftime("%Y%m%d_%H%M%S")
|
236 |
+
if not output_csv:
|
237 |
+
output_csv = f"tickets_clasificados_{timestamp}.csv"
|
238 |
+
urgentes_csv = f"tickets_urgentes_{timestamp}.csv"
|
239 |
+
|
240 |
categorias_pred = []
|
241 |
urgencias = []
|
|
|
242 |
logger.info("Iniciando procesamiento de tickets...")
|
243 |
+
for i, descripcion in enumerate(df[desc_col]):
|
|
|
|
|
244 |
descripcion_str = str(descripcion)
|
245 |
categoria = clasificar_texto(descripcion_str)
|
246 |
categorias_pred.append(categoria)
|
|
|
|
|
247 |
urgencia = es_urgente(descripcion_str)
|
248 |
urgencias.append(urgencia)
|
|
|
249 |
logger.info(f"Ticket {i+1}: '{descripcion_str[:30]}...' -> Categoría: {categoria}, Urgente: {urgencia}")
|
|
|
250 |
df['categoria'] = categorias_pred
|
251 |
df['urgente'] = urgencias
|
|
|
|
|
252 |
df.to_csv(output_csv, index=False)
|
253 |
logger.info(f"Resultados guardados en {output_csv}")
|
|
|
|
|
254 |
urgentes = df[df['urgente']]
|
255 |
if not urgentes.empty:
|
|
|
256 |
urgentes.to_csv(urgentes_csv, index=False)
|
257 |
logger.info(f"⚠️ {len(urgentes)} tickets urgentes guardados en '{urgentes_csv}'")
|
258 |
+
return df, urgentes_csv, output_csv, len(df), len(urgentes), num_duplicados
|
259 |
else:
|
260 |
logger.info("No se encontraron tickets urgentes")
|
261 |
+
return df, None, output_csv, len(df), 0, num_duplicados
|
262 |
except Exception as e:
|
263 |
logger.error(f"❌ Error procesando CSV: {e}")
|
264 |
+
raise
|
265 |
|
266 |
|
267 |
# 6. Inicializar sistema de tickets para la interfaz web
|
|
|
358 |
outputs=ticket_db
|
359 |
)
|
360 |
"""
|
361 |
+
|
362 |
# Función wrapper para procesar CSV
|
363 |
def procesar_csv_wrapper(archivo):
|
364 |
+
"""
|
365 |
+
Procesa el archivo CSV subido y retorna mensajes y archivos de salida únicos.
|
366 |
+
"""
|
367 |
if archivo is None:
|
368 |
return "❌ No se subió ningún archivo", None, None, gr.update(visible=False)
|
|
|
369 |
try:
|
|
|
370 |
file_path = archivo.name
|
371 |
+
result, urgentes_file, output_file, total, urgentes_count, duplicados = procesar_tickets(file_path)
|
372 |
+
resumen = f"Total tickets procesados: {total}. "
|
373 |
+
if duplicados > 0:
|
374 |
+
resumen += f"Duplicados detectados: {duplicados}. "
|
375 |
+
if urgentes_count > 0:
|
376 |
+
resumen += f"Tickets urgentes: {urgentes_count}. "
|
377 |
+
else:
|
378 |
+
resumen += "No se encontraron tickets urgentes. "
|
379 |
if result is not None:
|
|
|
380 |
if urgentes_file:
|
381 |
return (
|
382 |
+
f"✅ Procesamiento completado con éxito. {resumen}Resultados: {output_file}",
|
383 |
output_file,
|
384 |
urgentes_file,
|
385 |
gr.update(visible=True)
|
386 |
)
|
387 |
else:
|
388 |
return (
|
389 |
+
f"✅ Procesamiento completado. {resumen}Resultados: {output_file}",
|
390 |
output_file,
|
391 |
None,
|
392 |
gr.update(visible=False)
|
393 |
)
|
394 |
else:
|
395 |
return "❌ Error procesando el archivo", None, None, gr.update(visible=False)
|
|
|
396 |
except Exception as e:
|
397 |
return f"❌ Error: {str(e)}", None, None, gr.update(visible=False)
|
398 |
+
|
399 |
process_btn.click(
|
400 |
fn=procesar_csv_wrapper,
|
401 |
inputs=file_input,
|
|
|
404 |
|
405 |
# 9. Ejecutar la aplicación
|
406 |
if __name__ == "__main__":
|
407 |
+
# Si se pasa un archivo CSV como argumento, procesar en modo batch
|
408 |
+
if len(sys.argv) > 1:
|
409 |
+
input_csv = sys.argv[1]
|
410 |
+
logger.info(f"Procesando archivo: {input_csv}")
|
411 |
+
|
412 |
+
try:
|
413 |
+
result, urgentes, salida, total, urgentes_count, duplicados = procesar_tickets(input_csv)
|
414 |
+
logger.info(f"Total tickets procesados: {total}")
|
415 |
+
logger.info(f"Duplicados detectados: {duplicados}")
|
416 |
+
logger.info(f"Tickets urgentes: {urgentes_count}")
|
417 |
+
logger.info(f"Archivo de resultados: {salida}")
|
418 |
+
|
419 |
+
if urgentes:
|
420 |
+
logger.info(f"Archivo de tickets urgentes: {urgentes}")
|
421 |
+
else:
|
422 |
+
logger.info("No se encontraron tickets urgentes.")
|
423 |
+
except Exception as e:
|
424 |
+
logger.error(f"Error procesando el archivo: {e}")
|
425 |
+
sys.exit(1)
|
426 |
+
else:
|
427 |
+
# Modo interfaz web
|
428 |
+
demo.launch(
|
429 |
+
server_name="0.0.0.0",
|
430 |
+
server_port=7860,
|
431 |
+
show_error=True
|
432 |
+
)
|