angelsg213 commited on
Commit
b9e50c8
·
verified ·
1 Parent(s): 4f6c6e5

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +105 -140
app.py CHANGED
@@ -16,122 +16,105 @@ import time
16
  import numpy as np
17
  import wave
18
 
19
- # Para TTS emocional
20
- try:
21
- from gtts import gTTS
22
- GTTS_AVAILABLE = True
23
- except ImportError:
24
- GTTS_AVAILABLE = False
25
- print("⚠️ gTTS no disponible. Instala con: pip install gtts")
 
 
 
26
 
27
  # ============= GENERAR AUDIO CON EMOCIÓN MEJORADO =============
28
  # ============= GENERAR AUDIO CON EMOCIÓN MEJORADO =============
29
  # ============= GENERAR AUDIO CON EMOCIÓN MEJORADO =============
30
  # ============= GENERAR AUDIO CON EMOCIÓN Y ANÁLISIS DE SENTIMIENTO =============
31
- # ============= GENERAR AUDIO CON EMOCIÓN - VERSIÓN CORREGIDA =============
32
  def generar_audio_respuesta(texto, client):
33
- """TTS emocional FUNCIONAL con gTTS (Google Text-to-Speech) - Diciembre 2024"""
34
-
35
- try:
36
- # Limpiar y preparar texto
37
- texto_limpio = texto.replace("*", "").replace("#", "").replace("`", "").replace("€", " euros").strip()
38
- oraciones = re.split(r'[.!?]+', texto_limpio)
39
- oraciones = [o.strip() for o in oraciones if o.strip() and len(o.strip()) > 10]
40
- texto_audio = ". ".join(oraciones[:5]) + "." if len(oraciones) > 5 else ". ".join(oraciones) + "."
41
-
42
- if len(texto_audio) > 500:
43
- texto_audio = texto_audio[:497] + "..."
44
-
45
- print(f"🎤 Generando audio para: '{texto_audio[:100]}...'")
46
-
47
- # PASO 1: Análisis emocional
48
- emocion_detectada = "neutral"
49
- confianza = 0.5
50
-
51
- try:
52
- print("🧠 Analizando emoción...")
53
- emotion_response = client.text_classification(
54
- text=texto_audio[:512],
55
- model="finiteautomata/beto-sentiment-analysis"
56
- )
57
- if emotion_response and len(emotion_response) > 0:
58
- label = emotion_response[0]['label'].lower()
59
- sentiment_to_emotion = {
60
- 'pos': 'joy',
61
- 'positive': 'joy',
62
- 'neu': 'neutral',
63
- 'neutral': 'neutral',
64
- 'neg': 'sadness',
65
- 'negative': 'sadness'
66
- }
67
- emocion_detectada = sentiment_to_emotion.get(label, 'neutral')
68
- confianza = emotion_response[0]['score']
69
- print(f"😊 Emoción: {emocion_detectada} (confianza: {confianza:.2%})")
70
- except Exception as e:
71
- print(f"⚠️ Error en análisis emocional: {str(e)[:100]}")
72
-
73
- # PASO 2: Generar audio con gTTS
74
- print("🔊 Generando audio con Google TTS...")
75
-
76
- if GTTS_AVAILABLE:
77
- tts = gTTS(text=texto_audio, lang='es', slow=False)
78
- timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
79
- audio_path = f"audio_emocional_{emocion_detectada}_{timestamp}.mp3"
80
- tts.save(audio_path)
81
-
82
- if os.path.exists(audio_path) and os.path.getsize(audio_path) > 1000:
83
- print(f"✅ Audio generado: {audio_path} ({os.path.getsize(audio_path)} bytes)")
84
- return audio_path, emocion_detectada, confianza
85
-
86
- print("⚠️ Intentando método alternativo...")
87
- return generar_audio_alternativo(texto, client)
88
-
89
- except Exception as e:
90
- print(f"❌ Error general: {str(e)}")
91
- return None, "neutral", 0.5
92
-
93
- def generar_audio_alternativo(texto, client):
94
- """Método alternativo usando HuggingFace TTS"""
95
- emocion_detectada = "neutral"
96
- confianza = 0.5
97
 
 
98
  texto_limpio = texto.replace("*", "").replace("#", "").replace("`", "").replace("€", " euros").strip()
99
  oraciones = re.split(r'[.!?]+', texto_limpio)
100
  oraciones = [o.strip() for o in oraciones if o.strip() and len(o.strip()) > 10]
101
- texto_audio = ". ".join(oraciones[:3]) + "."
102
-
103
  if len(texto_audio) > 400:
104
  texto_audio = texto_audio[:397] + "..."
105
 
106
- modelos_tts = ["facebook/mms-tts-spa"]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
 
108
  for modelo in modelos_tts:
109
  try:
110
  print(f"🔊 Probando: {modelo}")
111
- audio_data = client.text_to_speech(text=texto_audio, model=modelo)
112
 
 
 
 
 
 
 
 
113
  timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
114
- audio_path = f"audio_{timestamp}.wav"
115
 
116
  with open(audio_path, "wb") as f:
117
  if isinstance(audio_data, bytes):
118
  f.write(audio_data)
119
  elif hasattr(audio_data, 'read'):
120
  f.write(audio_data.read())
 
 
121
  else:
 
122
  for chunk in audio_data:
123
  if chunk:
124
  f.write(chunk if isinstance(chunk, bytes) else bytes(chunk))
125
 
126
- if os.path.exists(audio_path) and os.path.getsize(audio_path) > 1000:
127
- print(f"✅ Audio generado con {modelo}")
128
- return audio_path, emocion_detectada, confianza
129
- else:
130
- if os.path.exists(audio_path):
 
 
 
 
 
131
  os.remove(audio_path)
 
132
  except Exception as e:
133
- print(f"❌ Error con {modelo}: {str(e)[:100]}")
 
 
134
 
 
135
  return None, emocion_detectada, confianza
136
 
137
  # ============= ASISTENTE IA CONVERSACIONAL =============
@@ -213,16 +196,12 @@ Responde ahora:"""
213
  f.write(f"\nArchivo de audio: {audio_path if audio_path else 'No generado'}\n")
214
  f.write("=" * 60 + "\n")
215
 
216
- if audio_path and os.path.exists(audio_path):
217
  print(f"✅ Audio generado correctamente: {audio_path}")
218
- return respuesta, audio_path, transcripcion_path, emocion, confianza
219
  else:
220
  print("⚠️ No se pudo generar el audio, pero la respuesta está disponible")
221
- timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
222
- audio_vacio = f"audio_no_disponible_{timestamp}.mp3"
223
- with open(audio_vacio, "w") as f:
224
- f.write("")
225
- return respuesta, audio_vacio, transcripcion_path, emocion, confianza
226
 
227
  except Exception as e:
228
  print(f"❌ Error con {modelo}: {str(e)}")
@@ -1551,7 +1530,7 @@ with gr.Blocks(title="Extractor de Facturas con IA Avanzada") as demo:
1551
  label="🎧 Reproducir respuesta en audio",
1552
  type="filepath",
1553
  visible=True,
1554
- autoplay=True
1555
  )
1556
  with gr.Column():
1557
  transcripcion_output = gr.File(
@@ -1772,56 +1751,42 @@ with gr.Blocks(title="Extractor de Facturas con IA Avanzada") as demo:
1772
  outputs=[pdf_output, pdf_status]
1773
  )
1774
 
1775
- # Asistente IA con análisis emocional
1776
  def consultar_ia_con_loading(texto, pregunta):
1777
- if not texto:
1778
- return ("❌ Por favor, procesa una factura primero", None, None, "", gr.update(visible=False))
1779
-
1780
- yield ("🔄 El asistente está analizando tu pregunta...", None, None, "", gr.update(visible=True))
1781
- time.sleep(0.3)
1782
-
1783
- try:
1784
- respuesta, audio, transcripcion, emocion, confianza = asistente_ia_factura(texto, pregunta)
1785
-
1786
- emotion_map = {
1787
- "joy": ("😊", "#4CAF50", "Alegría"),
1788
- "excitement": ("🎉", "#FF9800", "Emoción"),
1789
- "anger": ("😠", "#F44336", "Enfado"),
1790
- "sadness": ("😢", "#2196F3", "Tristeza"),
1791
- "fear": ("😰", "#9C27B0", "Miedo"),
1792
- "surprise": ("😮", "#FF5722", "Sorpresa"),
1793
- "neutral": ("😐", "#607D8B", "Neutral")
1794
- }
1795
-
1796
- emoji, color, nombre = emotion_map.get(emocion, ("😐", "#607D8B", "Neutral"))
1797
-
1798
- emocion_info = f"""
1799
- ### 🎭 Análisis Emocional
1800
-
1801
- <div style="background: linear-gradient(135deg, {color}22 0%, {color}44 100%); padding: 15px; border-radius: 10px; border-left: 4px solid {color};">
1802
- <p style="font-size: 18px; margin: 0;">
1803
- <strong style="color: {color};">{emoji} Emoción detectada: {nombre}</strong>
1804
- </p>
1805
- <p style="margin: 5px 0 0 0; color: #666;">
1806
- Nivel de confianza: {confianza:.1%}
1807
- </p>
1808
- </div>
1809
- """
1810
-
1811
- audio_final = audio if (audio and os.path.exists(audio) and os.path.getsize(audio) > 100) else None
1812
-
1813
- if audio_final:
1814
- print(f"✅ Audio disponible: {audio_final}")
1815
- else:
1816
- print("⚠️ Audio no disponible")
1817
- emocion_info += "\n\n⚠️ *El audio no pudo generarse, pero la respuesta está en texto.*"
1818
-
1819
- yield (respuesta, audio_final, transcripcion, emocion_info, gr.update(visible=False))
1820
-
1821
- except Exception as e:
1822
- error_msg = f"❌ Error: {str(e)[:200]}"
1823
- print(f"Error completo: {str(e)}")
1824
- yield (error_msg, None, None, "", gr.update(visible=False))
1825
 
1826
  btn_consulta_ia.click(
1827
  fn=consultar_ia_con_loading,
 
16
  import numpy as np
17
  import wave
18
 
19
+ # ============= EXTRAER TEXTO DEL PDF =============
20
+ def extraer_texto_pdf(pdf_file):
21
+ try:
22
+ pdf_reader = PyPDF2.PdfReader(pdf_file)
23
+ texto = ""
24
+ for pagina in pdf_reader.pages:
25
+ texto += pagina.extract_text() + "\n"
26
+ return texto
27
+ except Exception as e:
28
+ return f"Error: {str(e)}"
29
 
30
  # ============= GENERAR AUDIO CON EMOCIÓN MEJORADO =============
31
  # ============= GENERAR AUDIO CON EMOCIÓN MEJORADO =============
32
  # ============= GENERAR AUDIO CON EMOCIÓN MEJORADO =============
33
  # ============= GENERAR AUDIO CON EMOCIÓN Y ANÁLISIS DE SENTIMIENTO =============
 
34
  def generar_audio_respuesta(texto, client):
35
+ """TTS emocional FUNCIONAL para español - Actualizado diciembre 2025"""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
 
37
+ # Limpiar y preparar texto (mismo que antes)
38
  texto_limpio = texto.replace("*", "").replace("#", "").replace("`", "").replace("€", " euros").strip()
39
  oraciones = re.split(r'[.!?]+', texto_limpio)
40
  oraciones = [o.strip() for o in oraciones if o.strip() and len(o.strip()) > 10]
41
+ texto_audio = ". ".join(oraciones[:3]) + "." if len(oraciones) > 3 else ". ".join(oraciones) + "."
 
42
  if len(texto_audio) > 400:
43
  texto_audio = texto_audio[:397] + "..."
44
 
45
+ print(f"🎤 Generando audio para: '{texto_audio[:80]}...'")
46
+
47
+ # PASO 1: Análisis emocional (modelo español que SÍ funciona)
48
+ try:
49
+ print("🧠 Analizando emoción...")
50
+ emotion_response = client.text_classification(
51
+ text=texto_audio,
52
+ model="dariolopez/roberta-base-bne-finetuned-EmotionAnalysisSpanish" # Español nativo
53
+ )
54
+ if emotion_response and len(emotion_response) > 0:
55
+ emocion_detectada = emotion_response[0]['label']
56
+ confianza = emotion_response[0]['score']
57
+ print(f"😊 Emoción: {emocion_detectada} (confianza: {confianza:.2%})")
58
+ else:
59
+ emocion_detectada = "neutral"
60
+ confianza = 0.5
61
+ except Exception as e:
62
+ print(f"⚠️ Error emocional: {str(e)[:100]}. Usando neutral.")
63
+ emocion_detectada = "neutral"
64
+ confianza = 0.5
65
+
66
+ # PASO 2: Modelos TTS que SÍ funcionan en 2025 (español prioritario)
67
+ modelos_tts = [
68
+ "facebook/mms-tts-spa", # Español oficial de Meta - Siempre funciona
69
+ "myshell-ai/MeloTTS-Spanish", # Alta calidad, multi-idioma
70
+ "coqui/XTTS-v2" # Fallback versátil (soporta español)
71
+ ]
72
 
73
  for modelo in modelos_tts:
74
  try:
75
  print(f"🔊 Probando: {modelo}")
 
76
 
77
+ # Generar audio
78
+ audio_data = client.text_to_speech(
79
+ text=texto_audio,
80
+ model=modelo
81
+ )
82
+
83
+ # Guardar archivo (mejorado para streams/bytes)
84
  timestamp = datetime.now().strftime('%Y%m%d_%H%M%S')
85
+ audio_path = f"audio_emocional_{emocion_detectada}_{timestamp}.wav"
86
 
87
  with open(audio_path, "wb") as f:
88
  if isinstance(audio_data, bytes):
89
  f.write(audio_data)
90
  elif hasattr(audio_data, 'read'):
91
  f.write(audio_data.read())
92
+ elif hasattr(audio_data, 'content'):
93
+ f.write(audio_data.content)
94
  else:
95
+ # Para iteradores/chunks
96
  for chunk in audio_data:
97
  if chunk:
98
  f.write(chunk if isinstance(chunk, bytes) else bytes(chunk))
99
 
100
+ # Verificar
101
+ if os.path.exists(audio_path):
102
+ size = os.path.getsize(audio_path)
103
+ print(f"📁 Creado: {audio_path} ({size} bytes)")
104
+
105
+ if size > 2000: # Umbral más bajo para MMS
106
+ print(f"✅ ¡AUDIO GENERADO EXITOSAMENTE!")
107
+ return audio_path, emocion_detectada, confianza
108
+ else:
109
+ print(f"⚠️ Archivo pequeño ({size} bytes), borrando...")
110
  os.remove(audio_path)
111
+
112
  except Exception as e:
113
+ error_msg = str(e)
114
+ print(f"❌ Error con {modelo}: {error_msg[:100]}")
115
+ continue
116
 
117
+ print("⚠️ No se generó audio. Verifica límites de API o conexión.")
118
  return None, emocion_detectada, confianza
119
 
120
  # ============= ASISTENTE IA CONVERSACIONAL =============
 
196
  f.write(f"\nArchivo de audio: {audio_path if audio_path else 'No generado'}\n")
197
  f.write("=" * 60 + "\n")
198
 
199
+ if audio_path:
200
  print(f"✅ Audio generado correctamente: {audio_path}")
 
201
  else:
202
  print("⚠️ No se pudo generar el audio, pero la respuesta está disponible")
203
+
204
+ return respuesta, audio_path, transcripcion_path, emocion, confianza
 
 
 
205
 
206
  except Exception as e:
207
  print(f"❌ Error con {modelo}: {str(e)}")
 
1530
  label="🎧 Reproducir respuesta en audio",
1531
  type="filepath",
1532
  visible=True,
1533
+ autoplay=False
1534
  )
1535
  with gr.Column():
1536
  transcripcion_output = gr.File(
 
1751
  outputs=[pdf_output, pdf_status]
1752
  )
1753
 
1754
+ # Asistente IA con análisis emocional
1755
  def consultar_ia_con_loading(texto, pregunta):
1756
+ if not texto:
1757
+ return ("❌ Por favor, procesa una factura primero", None, None, "", gr.update(visible=False))
1758
+
1759
+ yield ("🔄 El asistente está analizando tu pregunta...", None, None, "", gr.update(visible=True))
1760
+ time.sleep(0.3)
1761
+ respuesta, audio, transcripcion, emocion, confianza = asistente_ia_factura(texto, pregunta)
1762
+
1763
+ # Mapeo de emociones a emojis y colores
1764
+ emotion_map = {
1765
+ "joy": ("😊", "#4CAF50", "Alegría"),
1766
+ "excitement": ("🎉", "#FF9800", "Emoción"),
1767
+ "anger": ("😠", "#F44336", "Enfado"),
1768
+ "sadness": ("😢", "#2196F3", "Tristeza"),
1769
+ "fear": ("😰", "#9C27B0", "Miedo"),
1770
+ "surprise": ("😮", "#FF5722", "Sorpresa"),
1771
+ "neutral": ("😐", "#607D8B", "Neutral")
1772
+ }
1773
+
1774
+ emoji, color, nombre = emotion_map.get(emocion, ("😐", "#607D8B", "Neutral"))
1775
+
1776
+ emocion_info = f"""
1777
+ ### 🎭 Análisis Emocional
1778
+
1779
+ <div style="background: linear-gradient(135deg, {color}22 0%, {color}44 100%); padding: 15px; border-radius: 10px; border-left: 4px solid {color};">
1780
+ <p style="font-size: 18px; margin: 0;">
1781
+ <strong style="color: {color};">{emoji} Emoción detectada: {nombre}</strong>
1782
+ </p>
1783
+ <p style="margin: 5px 0 0 0; color: #666;">
1784
+ Nivel de confianza: {confianza:.1%}
1785
+ </p>
1786
+ </div>
1787
+ """
1788
+
1789
+ yield (respuesta, audio, transcripcion, emocion_info, gr.update(visible=False))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1790
 
1791
  btn_consulta_ia.click(
1792
  fn=consultar_ia_con_loading,