angelsg213 commited on
Commit
4b977ae
·
verified ·
1 Parent(s): 24d312b

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +584 -67
app.py CHANGED
@@ -88,24 +88,26 @@ Responde ahora:"""
88
 
89
  return "❌ No se pudo obtener respuesta del asistente IA", None
90
 
91
- # ============= GENERAR AUDIO DE LA RESPUESTA CON AVATAR ROBÓTICO =============
92
  def generar_audio_respuesta(texto, client):
93
  """Convierte la respuesta de texto a audio usando TTS avanzado"""
94
 
95
  modelos_tts = [
96
  "facebook/mms-tts-spa",
97
  "microsoft/speecht5_tts",
98
- "facebook/fastspeech2-en-ljspeech"
 
99
  ]
100
 
101
  # Limitar texto para TTS
102
- texto_corto = texto[:500] if len(texto) > 500 else texto
103
 
104
  for modelo in modelos_tts:
105
  try:
106
  print(f"🔊 Generando audio con: {modelo}")
107
 
108
- audio = client.text_to_speech(
 
109
  text=texto_corto,
110
  model=modelo
111
  )
@@ -115,15 +117,21 @@ def generar_audio_respuesta(texto, client):
115
  audio_path = f"respuesta_audio_{timestamp}.wav"
116
 
117
  with open(audio_path, "wb") as f:
118
- f.write(audio)
 
 
 
 
 
119
 
120
- print(f"✅ Audio generado: {audio_path}")
121
  return audio_path
122
-
123
  except Exception as e:
124
- print(f"❌ Error generando audio con {modelo}: {str(e)}")
125
  continue
126
 
 
127
  return None
128
 
129
  # ============= ANÁLISIS DE SENTIMIENTO DE FACTURA =============
@@ -369,7 +377,265 @@ Formato profesional y conciso:"""
369
  except:
370
  return "No se pudo generar el resumen ejecutivo"
371
 
372
- # ============= EXTRACTOR DE GASTOS DEDUCIBLES =============
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
373
  def extraer_gastos_deducibles(datos_json, texto, client):
374
  """Identifica qué parte de la factura es deducible fiscalmente"""
375
 
@@ -629,20 +895,105 @@ def json_a_csv(datos_json):
629
 
630
  return pd.DataFrame(filas)
631
 
632
- # ============= GENERAR CSV DE TRADUCCIÓN =============
633
- def traduccion_a_csv(traduccion_texto, idioma):
634
- """Convierte el texto traducido en un CSV"""
 
 
 
635
 
636
  timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
637
  csv_filename = f"factura_traducida_{idioma}_{timestamp}.csv"
638
 
639
- # Crear DataFrame simple con la traducción
640
- df = pd.DataFrame({
641
- 'Idioma': [idioma],
642
- 'Contenido': [traduccion_texto],
643
- 'Fecha': [datetime.now().strftime('%Y-%m-%d %H:%M:%S')]
644
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
645
 
 
646
  df.to_csv(csv_filename, index=False, encoding='utf-8-sig', sep=',')
647
 
648
  return csv_filename
@@ -955,44 +1306,90 @@ with gr.Blocks(title="Extractor de Facturas con IA Avanzada") as demo:
955
  with gr.Tab("🔬 Análisis Avanzado IA"):
956
  gr.Markdown("""
957
  # 🎯 Suite Completa de Herramientas IA
958
- ### Análisis profesional, detección de fraude, optimización fiscal y más
959
  """)
960
 
961
- with gr.Row():
962
- with gr.Column():
963
- gr.Markdown("### 📊 Análisis de Sentimiento y Riesgos")
964
- btn_sentimiento = gr.Button("🔍 Analizar Riesgos", variant="primary")
965
- resultado_sentimiento = gr.Markdown()
966
-
967
- gr.Markdown("---")
968
- gr.Markdown("### 🚨 Detector de Fraude")
969
- btn_fraude = gr.Button("🛡️ Detectar Irregularidades", variant="primary")
970
- resultado_fraude = gr.Markdown()
971
-
972
- gr.Markdown("---")
973
- gr.Markdown("### 💰 Gastos Deducibles Fiscales")
974
- btn_deducibles = gr.Button("💸 Calcular Deducciones", variant="primary")
975
- resultado_deducibles = gr.Markdown()
976
-
977
- gr.Markdown("---")
978
- gr.Markdown("### 📁 Categorización Automática")
979
- btn_categoria = gr.Button("🏷️ Clasificar Gasto", variant="primary")
980
- resultado_categoria = gr.Markdown()
 
 
 
 
 
 
 
 
 
 
 
 
 
981
 
982
- with gr.Column():
983
- gr.Markdown("### 💡 Sugerencias Inteligentes")
984
- btn_sugerencias = gr.Button("✨ Generar Recomendaciones", variant="primary")
985
- resultado_sugerencias = gr.Markdown()
986
-
987
- gr.Markdown("---")
988
- gr.Markdown("### 📅 Predicción de Fecha de Pago")
989
- btn_prediccion = gr.Button("🔮 Predecir Fecha Óptima", variant="primary")
990
- resultado_prediccion = gr.Markdown()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
991
 
992
- gr.Markdown("---")
993
- gr.Markdown("### 📊 Resumen Ejecutivo")
994
- btn_ejecutivo = gr.Button("📈 Generar Dashboard", variant="primary")
995
- resultado_ejecutivo = gr.Markdown()
 
 
 
 
996
 
997
  # ============= TAB 4: TRADUCCIÓN MULTIIDIOMA =============
998
  with gr.Tab("🌍 Traducción Internacional"):
@@ -1013,8 +1410,8 @@ with gr.Blocks(title="Extractor de Facturas con IA Avanzada") as demo:
1013
 
1014
  gr.Markdown("---")
1015
  gr.Markdown("### Exportar Traducción")
1016
- btn_csv_traduccion = gr.Button("📥 Descargar CSV Traducido", variant="secondary")
1017
- csv_traduccion_output = gr.File(label="📊 CSV de la Traducción")
1018
 
1019
  with gr.Column():
1020
  gr.Markdown("### 📝 Resultado de la Traducción")
@@ -1043,21 +1440,26 @@ with gr.Blocks(title="Extractor de Facturas con IA Avanzada") as demo:
1043
 
1044
  ---
1045
 
1046
- ### 🎯 Funcionalidades Innovadoras:
1047
 
1048
- **🤖 Asistente Virtual:**
1049
- - Avatar robótico interactivo con animaciones
1050
- - Voz sintetizada de alta calidad
1051
- - Respuestas contextuales inteligentes
 
 
 
1052
 
1053
- **🔬 Suite Profesional:**
1054
  - 🚨 **Detector de Fraude:** Identifica irregularidades
1055
- - 💰 **Gastos Deducibles:** Calcula deducciones fiscales
1056
- - 📅 **Predicción de Pagos:** Sugiere fechas óptimas
1057
- - 📊 **Resumen Ejecutivo:** Dashboard para gerencia
1058
- - 🔍 **Análisis de Riesgos:** Detecta urgencias
1059
- - 💡 **Sugerencias IA:** Recomendaciones personalizadas
1060
- - 📁 **Categorización:** Clasifica gastos automáticamente
 
 
1061
 
1062
  **📊 Formatos Mejorados:**
1063
  - CSV tabular con comas como separador
@@ -1238,7 +1640,122 @@ with gr.Blocks(title="Extractor de Facturas con IA Avanzada") as demo:
1238
  csv_file = traduccion_a_csv(traduccion, idioma)
1239
  return csv_file
1240
 
1241
- # Conectar eventos
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1242
  btn_sentimiento.click(fn=ejecutar_sentimiento, inputs=[texto_extraido], outputs=[resultado_sentimiento])
1243
  btn_fraude.click(fn=ejecutar_fraude, inputs=[datos_json_state, texto_extraido], outputs=[resultado_fraude])
1244
  btn_deducibles.click(fn=ejecutar_deducibles, inputs=[datos_json_state, texto_extraido], outputs=[resultado_deducibles])
 
88
 
89
  return "❌ No se pudo obtener respuesta del asistente IA", None
90
 
91
+ # ============= GENERAR AUDIO DE LA RESPUESTA CON MODELO MEJORADO =============
92
  def generar_audio_respuesta(texto, client):
93
  """Convierte la respuesta de texto a audio usando TTS avanzado"""
94
 
95
  modelos_tts = [
96
  "facebook/mms-tts-spa",
97
  "microsoft/speecht5_tts",
98
+ "suno/bark",
99
+ "facebook/fastspeech2-en-200_speaker-cv4",
100
  ]
101
 
102
  # Limitar texto para TTS
103
+ texto_corto = texto[:400] if len(texto) > 400 else texto
104
 
105
  for modelo in modelos_tts:
106
  try:
107
  print(f"🔊 Generando audio con: {modelo}")
108
 
109
+ # Intentar generar audio
110
+ audio_bytes = client.text_to_speech(
111
  text=texto_corto,
112
  model=modelo
113
  )
 
117
  audio_path = f"respuesta_audio_{timestamp}.wav"
118
 
119
  with open(audio_path, "wb") as f:
120
+ if isinstance(audio_bytes, bytes):
121
+ f.write(audio_bytes)
122
+ else:
123
+ # Si es un generador, escribir el contenido
124
+ for chunk in audio_bytes:
125
+ f.write(chunk)
126
 
127
+ print(f"✅ Audio generado exitosamente: {audio_path}")
128
  return audio_path
129
+
130
  except Exception as e:
131
+ print(f"❌ Error con {modelo}: {str(e)}")
132
  continue
133
 
134
+ print("⚠️ No se pudo generar audio con ningún modelo")
135
  return None
136
 
137
  # ============= ANÁLISIS DE SENTIMIENTO DE FACTURA =============
 
377
  except:
378
  return "No se pudo generar el resumen ejecutivo"
379
 
380
+ # ============= ANÁLISIS DE DUPLICADOS =============
381
+ def detectar_facturas_duplicadas(datos_json, client):
382
+ """Analiza si esta factura puede ser un duplicado"""
383
+
384
+ prompt = f"""Analiza esta factura y determina indicadores de duplicación:
385
+
386
+ DATOS: {json.dumps(datos_json, indent=2)}
387
+
388
+ Busca:
389
+ - Patrones de números de factura sospechosos
390
+ - Fechas anómalas
391
+ - Importes repetitivos
392
+
393
+ Responde en JSON:
394
+ {{
395
+ "posible_duplicado": true/false,
396
+ "nivel_confianza": "bajo/medio/alto",
397
+ "indicadores": ["indicador1", "indicador2"],
398
+ "recomendacion": "texto"
399
+ }}"""
400
+
401
+ try:
402
+ response = client.chat.completions.create(
403
+ model="Qwen/Qwen2.5-72B-Instruct",
404
+ messages=[{"role": "user", "content": prompt}],
405
+ max_tokens=300,
406
+ temperature=0.2
407
+ )
408
+
409
+ resultado = response.choices[0].message.content
410
+ resultado = re.sub(r'```json\s*', '', resultado)
411
+ resultado = re.sub(r'```\s*', '', resultado).strip()
412
+
413
+ match = re.search(r'\{.*\}', resultado, re.DOTALL)
414
+ if match:
415
+ return json.loads(match.group(0))
416
+ except:
417
+ pass
418
+
419
+ return {"posible_duplicado": False, "nivel_confianza": "bajo", "indicadores": [], "recomendacion": "No se detectaron patrones duplicados"}
420
+
421
+ # ============= CALCULADORA DE IMPACTO PRESUPUESTARIO =============
422
+ def calcular_impacto_presupuesto(datos_json, client):
423
+ """Calcula el impacto de esta factura en un presupuesto mensual promedio"""
424
+
425
+ total = datos_json.get('totales', {}).get('total', datos_json.get('total', 0))
426
+
427
+ prompt = f"""Analiza el impacto presupuestario de esta factura:
428
+
429
+ Total: {total}€
430
+ Datos: {json.dumps(datos_json, indent=2)}
431
+
432
+ Calcula:
433
+ - Porcentaje sobre presupuesto promedio PYME (10.000€/mes)
434
+ - Nivel de impacto
435
+ - Recomendaciones de planificación
436
+
437
+ Responde en JSON:
438
+ {{
439
+ "impacto_porcentaje": number,
440
+ "nivel_impacto": "bajo/medio/alto/crítico",
441
+ "analisis": "texto",
442
+ "recomendacion_financiera": "texto"
443
+ }}"""
444
+
445
+ try:
446
+ response = client.chat.completions.create(
447
+ model="Qwen/Qwen2.5-72B-Instruct",
448
+ messages=[{"role": "user", "content": prompt}],
449
+ max_tokens=400,
450
+ temperature=0.3
451
+ )
452
+
453
+ resultado = response.choices[0].message.content
454
+ resultado = re.sub(r'```json\s*', '', resultado)
455
+ resultado = re.sub(r'```\s*', '', resultado).strip()
456
+
457
+ match = re.search(r'\{.*\}', resultado, re.DOTALL)
458
+ if match:
459
+ return json.loads(match.group(0))
460
+ except:
461
+ pass
462
+
463
+ return {"impacto_porcentaje": 0, "nivel_impacto": "bajo", "analisis": "No disponible", "recomendacion_financiera": "Consulte con su contador"}
464
+
465
+ # ============= GENERADOR DE RECORDATORIOS =============
466
+ def generar_recordatorios_pago(datos_json, client):
467
+ """Genera recordatorios inteligentes de pago"""
468
+
469
+ prompt = f"""Basándote en esta factura, genera un plan de recordatorios de pago:
470
+
471
+ DATOS: {json.dumps(datos_json, indent=2)}
472
+
473
+ Crea:
474
+ - 3 recordatorios (inicial, intermedio, urgente)
475
+ - Fechas sugeridas
476
+ - Mensajes personalizados
477
+
478
+ Responde en JSON:
479
+ {{
480
+ "recordatorios": [
481
+ {{"tipo": "inicial", "dias_antes": number, "mensaje": "texto"}},
482
+ {{"tipo": "intermedio", "dias_antes": number, "mensaje": "texto"}},
483
+ {{"tipo": "urgente", "dias_antes": number, "mensaje": "texto"}}
484
+ ]
485
+ }}"""
486
+
487
+ try:
488
+ response = client.chat.completions.create(
489
+ model="Qwen/Qwen2.5-72B-Instruct",
490
+ messages=[{"role": "user", "content": prompt}],
491
+ max_tokens=500,
492
+ temperature=0.4
493
+ )
494
+
495
+ resultado = response.choices[0].message.content
496
+ resultado = re.sub(r'```json\s*', '', resultado)
497
+ resultado = re.sub(r'```\s*', '', resultado).strip()
498
+
499
+ match = re.search(r'\{.*\}', resultado, re.DOTALL)
500
+ if match:
501
+ return json.loads(match.group(0))
502
+ except:
503
+ pass
504
+
505
+ return {"recordatorios": []}
506
+
507
+ # ============= ANÁLISIS DE CONDICIONES DE PAGO =============
508
+ def analizar_condiciones_pago(datos_json, texto, client):
509
+ """Analiza las condiciones de pago y sugiere negociaciones"""
510
+
511
+ prompt = f"""Analiza las condiciones de pago de esta factura:
512
+
513
+ DATOS: {json.dumps(datos_json, indent=2)}
514
+ TEXTO: {texto[:2000]}
515
+
516
+ Identifica:
517
+ - Plazo de pago actual
518
+ - Condiciones especiales
519
+ - Oportunidades de negociación
520
+ - Descuentos por pronto pago
521
+
522
+ Responde en JSON:
523
+ {{
524
+ "plazo_actual": "texto",
525
+ "condiciones_especiales": ["condicion1", "condicion2"],
526
+ "oportunidades_negociacion": "texto",
527
+ "sugerencias_mejora": "texto"
528
+ }}"""
529
+
530
+ try:
531
+ response = client.chat.completions.create(
532
+ model="Qwen/Qwen2.5-72B-Instruct",
533
+ messages=[{"role": "user", "content": prompt}],
534
+ max_tokens=400,
535
+ temperature=0.3
536
+ )
537
+
538
+ resultado = response.choices[0].message.content
539
+ resultado = re.sub(r'```json\s*', '', resultado)
540
+ resultado = re.sub(r'```\s*', '', resultado).strip()
541
+
542
+ match = re.search(r'\{.*\}', resultado, re.DOTALL)
543
+ if match:
544
+ return json.loads(match.group(0))
545
+ except:
546
+ pass
547
+
548
+ return {"plazo_actual": "N/A", "condiciones_especiales": [], "oportunidades_negociacion": "No detectadas", "sugerencias_mejora": "Revisar manualmente"}
549
+
550
+ # ============= COMPARADOR CON MERCADO =============
551
+ def comparar_precios_mercado(datos_json, client):
552
+ """Compara los precios de la factura con precios de mercado promedio"""
553
+
554
+ productos = datos_json.get('productos', [])
555
+ if not productos:
556
+ return {"analisis": "No hay productos para comparar"}
557
+
558
+ productos_texto = "\n".join([f"- {p.get('descripcion', 'N/A')}: {p.get('precio_unitario', 0)}€" for p in productos[:5]])
559
+
560
+ prompt = f"""Analiza si estos precios son razonables comparados con el mercado:
561
+
562
+ PRODUCTOS Y PRECIOS:
563
+ {productos_texto}
564
+
565
+ Determina:
566
+ - ¿Los precios son competitivos?
567
+ - ¿Hay precios excesivamente altos?
568
+ - Recomendaciones
569
+
570
+ Responde en JSON:
571
+ {{
572
+ "evaluacion_general": "competitivo/normal/elevado",
573
+ "productos_caros": ["producto1", "producto2"],
574
+ "ahorro_potencial": number,
575
+ "recomendacion": "texto"
576
+ }}"""
577
+
578
+ try:
579
+ response = client.chat.completions.create(
580
+ model="Qwen/Qwen2.5-72B-Instruct",
581
+ messages=[{"role": "user", "content": prompt}],
582
+ max_tokens=400,
583
+ temperature=0.3
584
+ )
585
+
586
+ resultado = response.choices[0].message.content
587
+ resultado = re.sub(r'```json\s*', '', resultado)
588
+ resultado = re.sub(r'```\s*', '', resultado).strip()
589
+
590
+ match = re.search(r'\{.*\}', resultado, re.DOTALL)
591
+ if match:
592
+ return json.loads(match.group(0))
593
+ except:
594
+ pass
595
+
596
+ return {"evaluacion_general": "normal", "productos_caros": [], "ahorro_potencial": 0, "recomendacion": "Precios dentro del rango esperado"}
597
+
598
+ # ============= VALIDADOR DE DATOS FISCALES =============
599
+ def validar_datos_fiscales(datos_json, client):
600
+ """Valida que los datos fiscales sean correctos y completos"""
601
+
602
+ prompt = f"""Valida los datos fiscales de esta factura:
603
+
604
+ DATOS: {json.dumps(datos_json, indent=2)}
605
+
606
+ Verifica:
607
+ - NIF/CIF válido (formato español)
608
+ - IVA correcto (21%, 10%, 4%)
609
+ - Datos obligatorios presentes
610
+ - Formato de factura legal
611
+
612
+ Responde en JSON:
613
+ {{
614
+ "es_valida": true/false,
615
+ "errores": ["error1", "error2"],
616
+ "advertencias": ["advertencia1"],
617
+ "nivel_cumplimiento": "completo/parcial/insuficiente"
618
+ }}"""
619
+
620
+ try:
621
+ response = client.chat.completions.create(
622
+ model="Qwen/Qwen2.5-72B-Instruct",
623
+ messages=[{"role": "user", "content": prompt}],
624
+ max_tokens=400,
625
+ temperature=0.2
626
+ )
627
+
628
+ resultado = response.choices[0].message.content
629
+ resultado = re.sub(r'```json\s*', '', resultado)
630
+ resultado = re.sub(r'```\s*', '', resultado).strip()
631
+
632
+ match = re.search(r'\{.*\}', resultado, re.DOTALL)
633
+ if match:
634
+ return json.loads(match.group(0))
635
+ except:
636
+ pass
637
+
638
+ return {"es_valida": True, "errores": [], "advertencias": [], "nivel_cumplimiento": "completo"}
639
  def extraer_gastos_deducibles(datos_json, texto, client):
640
  """Identifica qué parte de la factura es deducible fiscalmente"""
641
 
 
895
 
896
  return pd.DataFrame(filas)
897
 
898
+ # ============= GENERAR CSV TABULAR DE TRADUCCIÓN =============
899
+ def traduccion_a_csv(datos_json, traduccion_texto, idioma):
900
+ """Convierte la factura traducida en un CSV tabular estructurado"""
901
+
902
+ if not datos_json:
903
+ return None
904
 
905
  timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
906
  csv_filename = f"factura_traducida_{idioma}_{timestamp}.csv"
907
 
908
+ filas = []
909
+
910
+ # Intentar traducir cada campo
911
+ token = os.getenv("aa")
912
+ if token:
913
+ client = InferenceClient(token=token)
914
+
915
+ # Traducir secciones
916
+ try:
917
+ # Información general
918
+ filas.append({
919
+ 'Sección': 'INFORMACIÓN GENERAL' if idioma == 'Español' else 'GENERAL INFORMATION',
920
+ 'Campo': 'Número de Factura' if idioma == 'Español' else 'Invoice Number',
921
+ 'Valor': datos_json.get('numero_factura', 'N/A'),
922
+ 'Tipo': 'Identificador' if idioma == 'Español' else 'Identifier'
923
+ })
924
+ filas.append({
925
+ 'Sección': 'INFORMACIÓN GENERAL' if idioma == 'Español' else 'GENERAL INFORMATION',
926
+ 'Campo': 'Fecha' if idioma == 'Español' else 'Date',
927
+ 'Valor': datos_json.get('fecha', 'N/A'),
928
+ 'Tipo': 'Fecha' if idioma == 'Español' else 'Date'
929
+ })
930
+
931
+ # Emisor
932
+ if 'emisor' in datos_json:
933
+ emisor = datos_json['emisor']
934
+ if isinstance(emisor, dict):
935
+ for key, value in emisor.items():
936
+ filas.append({
937
+ 'Sección': 'EMISOR' if idioma == 'Español' else 'ISSUER',
938
+ 'Campo': key.replace('_', ' ').title(),
939
+ 'Valor': str(value),
940
+ 'Tipo': 'Información' if idioma == 'Español' else 'Information'
941
+ })
942
+
943
+ # Cliente
944
+ if 'cliente' in datos_json:
945
+ cliente = datos_json['cliente']
946
+ if isinstance(cliente, dict):
947
+ for key, value in cliente.items():
948
+ filas.append({
949
+ 'Sección': 'CLIENTE' if idioma == 'Español' else 'CLIENT',
950
+ 'Campo': key.replace('_', ' ').title(),
951
+ 'Valor': str(value),
952
+ 'Tipo': 'Información' if idioma == 'Español' else 'Information'
953
+ })
954
+
955
+ # Productos
956
+ productos = datos_json.get('productos', [])
957
+ if productos:
958
+ for i, prod in enumerate(productos, 1):
959
+ filas.append({
960
+ 'Sección': 'PRODUCTOS' if idioma == 'Español' else 'PRODUCTS',
961
+ 'Campo': f'Producto {i}' if idioma == 'Español' else f'Product {i}',
962
+ 'Valor': prod.get('descripcion', 'N/A'),
963
+ 'Tipo': 'Descripción' if idioma == 'Español' else 'Description'
964
+ })
965
+ filas.append({
966
+ 'Sección': 'PRODUCTOS' if idioma == 'Español' else 'PRODUCTS',
967
+ 'Campo': f'Cantidad P{i}' if idioma == 'Español' else f'Quantity P{i}',
968
+ 'Valor': str(prod.get('cantidad', '')),
969
+ 'Tipo': 'Numérico' if idioma == 'Español' else 'Numeric'
970
+ })
971
+
972
+ # Totales
973
+ totales = datos_json.get('totales', {})
974
+ if totales:
975
+ filas.append({
976
+ 'Sección': 'TOTALES' if idioma == 'Español' else 'TOTALS',
977
+ 'Campo': 'Base Imponible' if idioma == 'Español' else 'Taxable Base',
978
+ 'Valor': str(totales.get('base_imponible', 0)),
979
+ 'Tipo': 'Monetario' if idioma == 'Español' else 'Monetary'
980
+ })
981
+ filas.append({
982
+ 'Sección': 'TOTALES' if idioma == 'Español' else 'TOTALS',
983
+ 'Campo': 'IVA' if idioma == 'Español' else 'VAT',
984
+ 'Valor': str(totales.get('iva', 0)),
985
+ 'Tipo': 'Monetario' if idioma == 'Español' else 'Monetary'
986
+ })
987
+ filas.append({
988
+ 'Sección': 'TOTALES' if idioma == 'Español' else 'TOTALS',
989
+ 'Campo': 'TOTAL',
990
+ 'Valor': str(totales.get('total', 0)),
991
+ 'Tipo': 'Monetario' if idioma == 'Español' else 'Monetary'
992
+ })
993
+ except:
994
+ pass
995
 
996
+ df = pd.DataFrame(filas)
997
  df.to_csv(csv_filename, index=False, encoding='utf-8-sig', sep=',')
998
 
999
  return csv_filename
 
1306
  with gr.Tab("🔬 Análisis Avanzado IA"):
1307
  gr.Markdown("""
1308
  # 🎯 Suite Completa de Herramientas IA
1309
+ ### 12 herramientas profesionales de análisis automático
1310
  """)
1311
 
1312
+ with gr.Tabs():
1313
+ # Sub-tab 1: Análisis Financiero
1314
+ with gr.Tab("💰 Análisis Financiero"):
1315
+ with gr.Row():
1316
+ with gr.Column():
1317
+ gr.Markdown("### 📊 Análisis de Sentimiento")
1318
+ btn_sentimiento = gr.Button("🔍 Analizar Riesgos", variant="primary")
1319
+ resultado_sentimiento = gr.Markdown()
1320
+
1321
+ gr.Markdown("---")
1322
+ gr.Markdown("### 💰 Gastos Deducibles")
1323
+ btn_deducibles = gr.Button("💸 Calcular Deducciones", variant="primary")
1324
+ resultado_deducibles = gr.Markdown()
1325
+
1326
+ gr.Markdown("---")
1327
+ gr.Markdown("### 💵 Impacto Presupuestario")
1328
+ btn_impacto = gr.Button("📊 Calcular Impacto", variant="primary")
1329
+ resultado_impacto = gr.Markdown()
1330
+
1331
+ with gr.Column():
1332
+ gr.Markdown("### 📅 Predicción de Pago")
1333
+ btn_prediccion = gr.Button("🔮 Fecha Óptima", variant="primary")
1334
+ resultado_prediccion = gr.Markdown()
1335
+
1336
+ gr.Markdown("---")
1337
+ gr.Markdown("### 💡 Sugerencias IA")
1338
+ btn_sugerencias = gr.Button("✨ Generar Recomendaciones", variant="primary")
1339
+ resultado_sugerencias = gr.Markdown()
1340
+
1341
+ gr.Markdown("---")
1342
+ gr.Markdown("### 📁 Categorización")
1343
+ btn_categoria = gr.Button("🏷️ Clasificar Gasto", variant="primary")
1344
+ resultado_categoria = gr.Markdown()
1345
 
1346
+ # Sub-tab 2: Seguridad y Validación
1347
+ with gr.Tab("🛡️ Seguridad y Validación"):
1348
+ with gr.Row():
1349
+ with gr.Column():
1350
+ gr.Markdown("### 🚨 Detector de Fraude")
1351
+ btn_fraude = gr.Button("🛡️ Detectar Irregularidades", variant="primary")
1352
+ resultado_fraude = gr.Markdown()
1353
+
1354
+ gr.Markdown("---")
1355
+ gr.Markdown("### 🔍 Detector de Duplicados")
1356
+ btn_duplicados = gr.Button("🔄 Buscar Duplicados", variant="primary")
1357
+ resultado_duplicados = gr.Markdown()
1358
+
1359
+ gr.Markdown("---")
1360
+ gr.Markdown("### ✅ Validador Fiscal")
1361
+ btn_validador = gr.Button("📋 Validar Datos Fiscales", variant="primary")
1362
+ resultado_validador = gr.Markdown()
1363
+
1364
+ with gr.Column():
1365
+ gr.Markdown("### 📝 Condiciones de Pago")
1366
+ btn_condiciones = gr.Button("📄 Analizar Condiciones", variant="primary")
1367
+ resultado_condiciones = gr.Markdown()
1368
+
1369
+ gr.Markdown("---")
1370
+ gr.Markdown("### 🔔 Recordatorios de Pago")
1371
+ btn_recordatorios = gr.Button("⏰ Generar Recordatorios", variant="primary")
1372
+ resultado_recordatorios = gr.Markdown()
1373
+
1374
+ gr.Markdown("---")
1375
+ gr.Markdown("### 📊 Resumen Ejecutivo")
1376
+ btn_ejecutivo = gr.Button("📈 Dashboard Gerencial", variant="primary")
1377
+ resultado_ejecutivo = gr.Markdown()
1378
+
1379
+ # Sub-tab 3: Comparación y Mercado
1380
+ with gr.Tab("📈 Análisis de Mercado"):
1381
+ gr.Markdown("### 💲 Comparador de Precios con Mercado")
1382
+ btn_mercado = gr.Button("🏪 Comparar con Mercado", variant="primary", size="lg")
1383
+ resultado_mercado = gr.Markdown()
1384
 
1385
+ gr.Markdown("""
1386
+ ---
1387
+ **Esta herramienta analiza:**
1388
+ - Precios competitivos vs mercado
1389
+ - ✅ Productos con precios elevados
1390
+ - ✅ Ahorro potencial estimado
1391
+ - ✅ Recomendaciones de negociación
1392
+ """)
1393
 
1394
  # ============= TAB 4: TRADUCCIÓN MULTIIDIOMA =============
1395
  with gr.Tab("🌍 Traducción Internacional"):
 
1410
 
1411
  gr.Markdown("---")
1412
  gr.Markdown("### Exportar Traducción")
1413
+ btn_csv_traduccion = gr.Button("📥 Descargar CSV Tabular Traducido", variant="secondary")
1414
+ csv_traduccion_output = gr.File(label="📊 CSV Traducido (Formato Tabular)")
1415
 
1416
  with gr.Column():
1417
  gr.Markdown("### 📝 Resultado de la Traducción")
 
1440
 
1441
  ---
1442
 
1443
+ ### 🎯 12 Funcionalidades IA Profesionales:
1444
 
1445
+ **💰 Análisis Financiero:**
1446
+ - 🔍 **Análisis de Riesgos:** Detecta urgencias y alertas
1447
+ - 💸 **Gastos Deducibles:** Calcula deducciones fiscales
1448
+ - 📊 **Impacto Presupuestario:** Analiza impacto en presupuesto
1449
+ - 🔮 **Predicción de Pagos:** Fecha óptima de pago
1450
+ - ✨ **Sugerencias IA:** Recomendaciones personalizadas
1451
+ - 🏷️ **Categorización:** Clasifica gastos automáticamente
1452
 
1453
+ **🛡️ Seguridad y Validación:**
1454
  - 🚨 **Detector de Fraude:** Identifica irregularidades
1455
+ - 🔄 **Detector de Duplicados:** Busca facturas duplicadas
1456
+ - **Validador Fiscal:** Verifica datos fiscales
1457
+ - 📄 **Análisis de Condiciones:** Evalúa términos de pago
1458
+ - **Recordatorios:** Plan de recordatorios inteligente
1459
+ - 📈 **Dashboard Ejecutivo:** Resumen para gerencia
1460
+
1461
+ **📈 Análisis de Mercado:**
1462
+ - 💲 **Comparador de Precios:** Compara con mercado
1463
 
1464
  **📊 Formatos Mejorados:**
1465
  - CSV tabular con comas como separador
 
1640
  csv_file = traduccion_a_csv(traduccion, idioma)
1641
  return csv_file
1642
 
1643
+ def ejecutar_duplicados(datos_json):
1644
+ if not datos_json:
1645
+ return "❌ Procesa una factura primero"
1646
+ token = os.getenv("aa")
1647
+ if not token:
1648
+ return "❌ Error de configuración"
1649
+ client = InferenceClient(token=token)
1650
+ resultado = detectar_facturas_duplicadas(datos_json, client)
1651
+ return f"""### 🔄 Análisis de Duplicados
1652
+
1653
+ **¿Es posible duplicado?** {'✅ SÍ' if resultado['posible_duplicado'] else '❌ NO'}
1654
+ **Nivel de confianza:** {resultado['nivel_confianza'].upper()}
1655
+
1656
+ **Indicadores:**
1657
+ {chr(10).join([f"- {ind}" for ind in resultado.get('indicadores', [])]) if resultado.get('indicadores') else '- No se detectaron indicadores'}
1658
+
1659
+ **Recomendación:** {resultado['recomendacion']}"""
1660
+
1661
+ def ejecutar_impacto(datos_json):
1662
+ if not datos_json:
1663
+ return "❌ Procesa una factura primero"
1664
+ token = os.getenv("aa")
1665
+ if not token:
1666
+ return "❌ Error de configuración"
1667
+ client = InferenceClient(token=token)
1668
+ resultado = calcular_impacto_presupuesto(datos_json, client)
1669
+ nivel_emoji = {"bajo": "🟢", "medio": "🟡", "alto": "🟠", "crítico": "🔴"}
1670
+ return f"""### 📊 Impacto Presupuestario
1671
+
1672
+ **Porcentaje del presupuesto:** {resultado['impacto_porcentaje']}%
1673
+ **Nivel de impacto:** {nivel_emoji.get(resultado['nivel_impacto'], '⚪')} {resultado['nivel_impacto'].upper()}
1674
+
1675
+ **Análisis:** {resultado['analisis']}
1676
+
1677
+ **Recomendación Financiera:** {resultado['recomendacion_financiera']}"""
1678
+
1679
+ def ejecutar_recordatorios(datos_json):
1680
+ if not datos_json:
1681
+ return "❌ Procesa una factura primero"
1682
+ token = os.getenv("aa")
1683
+ if not token:
1684
+ return "❌ Error de configuración"
1685
+ client = InferenceClient(token=token)
1686
+ resultado = generar_recordatorios_pago(datos_json, client)
1687
+ recordatorios = resultado.get('recordatorios', [])
1688
+ texto = "### ⏰ Plan de Recordatorios de Pago\n\n"
1689
+ for r in recordatorios:
1690
+ texto += f"**{r.get('tipo', '').upper()}** ({r.get('dias_antes', 0)} días antes):\n"
1691
+ texto += f"{r.get('mensaje', '')}\n\n"
1692
+ return texto if recordatorios else "No se pudieron generar recordatorios"
1693
+
1694
+ def ejecutar_condiciones(datos_json, texto):
1695
+ if not datos_json:
1696
+ return "❌ Procesa una factura primero"
1697
+ token = os.getenv("aa")
1698
+ if not token:
1699
+ return "❌ Error de configuración"
1700
+ client = InferenceClient(token=token)
1701
+ resultado = analizar_condiciones_pago(datos_json, texto, client)
1702
+ return f"""### 📄 Análisis de Condiciones de Pago
1703
+
1704
+ **Plazo Actual:** {resultado['plazo_actual']}
1705
+
1706
+ **Condiciones Especiales:**
1707
+ {chr(10).join([f"- {c}" for c in resultado.get('condiciones_especiales', [])]) if resultado.get('condiciones_especiales') else '- No detectadas'}
1708
+
1709
+ **Oportunidades de Negociación:** {resultado['oportunidades_negociacion']}
1710
+
1711
+ **Sugerencias de Mejora:** {resultado['sugerencias_mejora']}"""
1712
+
1713
+ def ejecutar_mercado(datos_json):
1714
+ if not datos_json:
1715
+ return "❌ Procesa una factura primero"
1716
+ token = os.getenv("aa")
1717
+ if not token:
1718
+ return "❌ Error de configuración"
1719
+ client = InferenceClient(token=token)
1720
+ resultado = comparar_precios_mercado(datos_json, client)
1721
+ eval_emoji = {"competitivo": "✅", "normal": "⚪", "elevado": "⚠️"}
1722
+ return f"""### 💲 Comparación con Precios de Mercado
1723
+
1724
+ **Evaluación General:** {eval_emoji.get(resultado['evaluacion_general'], '⚪')} {resultado['evaluacion_general'].upper()}
1725
+
1726
+ **Productos con Precios Elevados:**
1727
+ {chr(10).join([f"- {p}" for p in resultado.get('productos_caros', [])]) if resultado.get('productos_caros') else '- Todos los precios son razonables'}
1728
+
1729
+ **Ahorro Potencial:** {resultado['ahorro_potencial']}€
1730
+
1731
+ **Recomendación:** {resultado['recomendacion']}"""
1732
+
1733
+ def ejecutar_validador(datos_json):
1734
+ if not datos_json:
1735
+ return "❌ Procesa una factura primero"
1736
+ token = os.getenv("aa")
1737
+ if not token:
1738
+ return "❌ Error de configuración"
1739
+ client = InferenceClient(token=token)
1740
+ resultado = validar_datos_fiscales(datos_json, client)
1741
+ return f"""### ✅ Validación de Datos Fiscales
1742
+
1743
+ **¿Es válida?** {'✅ SÍ' if resultado['es_valida'] else '❌ NO'}
1744
+ **Nivel de Cumplimiento:** {resultado['nivel_cumplimiento'].upper()}
1745
+
1746
+ **Errores Detectados:**
1747
+ {chr(10).join([f"- ❌ {e}" for e in resultado.get('errores', [])]) if resultado.get('errores') else '- No se detectaron errores'}
1748
+
1749
+ **Advertencias:**
1750
+ {chr(10).join([f"- ⚠️ {a}" for a in resultado.get('advertencias', [])]) if resultado.get('advertencias') else '- No hay advertencias'}"""
1751
+
1752
+ # Conectar nuevas funcionalidades
1753
+ btn_duplicados.click(fn=ejecutar_duplicados, inputs=[datos_json_state], outputs=[resultado_duplicados])
1754
+ btn_impacto.click(fn=ejecutar_impacto, inputs=[datos_json_state], outputs=[resultado_impacto])
1755
+ btn_recordatorios.click(fn=ejecutar_recordatorios, inputs=[datos_json_state], outputs=[resultado_recordatorios])
1756
+ btn_condiciones.click(fn=ejecutar_condiciones, inputs=[datos_json_state, texto_extraido], outputs=[resultado_condiciones])
1757
+ btn_mercado.click(fn=ejecutar_mercado, inputs=[datos_json_state], outputs=[resultado_mercado])
1758
+ btn_validador.click(fn=ejecutar_validador, inputs=[datos_json_state], outputs=[resultado_validador])
1759
  btn_sentimiento.click(fn=ejecutar_sentimiento, inputs=[texto_extraido], outputs=[resultado_sentimiento])
1760
  btn_fraude.click(fn=ejecutar_fraude, inputs=[datos_json_state, texto_extraido], outputs=[resultado_fraude])
1761
  btn_deducibles.click(fn=ejecutar_deducibles, inputs=[datos_json_state, texto_extraido], outputs=[resultado_deducibles])