jfforero commited on
Commit
6384cfb
·
verified ·
1 Parent(s): 03741aa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +65 -58
app.py CHANGED
@@ -48,7 +48,8 @@ model_path = "mymodel_SER_LSTM_RAVDESS.h5"
48
  model = load_emotion_model(model_path)
49
 
50
  model_size = "small"
51
- whisper_model = WhisperModel(model_size, device="cpu", compute_type="int8")
 
52
 
53
  def load_musicgen_model():
54
  try:
@@ -174,6 +175,8 @@ def upscale_image(image, target_width=4096, target_height=2048):
174
  return img
175
  with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp:
176
  image.save(tmp.name, "JPEG", quality=95)
 
 
177
  response = requests.post(
178
  "https://api.deepai.org/api/torch-srgan",
179
  files={"image": open(tmp.name, "rb")},
@@ -337,7 +340,7 @@ def get_predictions(audio_input, chunk_duration=120):
337
  return results
338
 
339
  # ============================================================
340
- # 7. Generación del visor HTML 360° (Avión Rojo Coral Incorporado)
341
  # ============================================================
342
 
343
  def create_360_viewer_html(image_paths, audio_paths, output_path):
@@ -345,6 +348,7 @@ def create_360_viewer_html(image_paths, audio_paths, output_path):
345
  for img_path in image_paths:
346
  try:
347
  img = Image.open(img_path)
 
348
  img = img.resize((2048, 1024), Image.Resampling.LANCZOS)
349
  buf = BytesIO()
350
  img.save(buf, format="JPEG", quality=75, optimize=True)
@@ -387,7 +391,7 @@ def create_360_viewer_html(image_paths, audio_paths, output_path):
387
  padding: 18px 50px; font-size: 16px; background: #2a2a3a; color: #666;
388
  border-radius: 30px; font-weight: bold; cursor: pointer;
389
  }}
390
- button.ready {{ background: linear-gradient(135deg, #ff7f50 0%, #cd2323 100%); color: white; }}
391
  </style>
392
  <script>
393
  AFRAME.registerComponent('paper-plane-mesh', {{
@@ -409,9 +413,8 @@ def create_360_viewer_html(image_paths, audio_paths, output_path):
409
  geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
410
  geometry.setIndex(indices);
411
  geometry.computeVertexNormals();
412
- // Color modificado a Rojo Coral (0xFF7F50)
413
  const material = new THREE.MeshStandardMaterial({{
414
- color: 0xFF7F50,
415
  roughness: 0.4,
416
  metalness: 0.1,
417
  side: THREE.DoubleSide,
@@ -574,7 +577,7 @@ async def github_callback(request: Request):
574
  return HTMLResponse(f"Error: {str(e)}", status_code=500)
575
 
576
  # ============================================================
577
- # 9. Lógica de Interfaz y Funciones de Gradio (Mejoras Visuales)
578
  # ============================================================
579
 
580
  MAX_SEGMENTS = 1
@@ -583,15 +586,17 @@ group_components = []
583
 
584
  def process_and_display(audio_input):
585
  if not audio_input:
586
- yield [gr.update(visible=False), gr.update(visible=False), None, None, None, None, None, None, None, None, "⚠️ Por favor, graba o sube un audio primero."]
587
  return
588
 
 
589
  yield [
590
  gr.update(visible=True),
591
  gr.update(visible=False),
592
- None, None, None, None, None, None, None, None, "⏳ Procesando audio y generando entorno virtual con IA..."
593
  ]
594
 
 
595
  results = get_predictions(audio_input, chunk_duration=120)
596
 
597
  if len(results) > 0:
@@ -606,28 +611,28 @@ def process_and_display(audio_input):
606
 
607
  info_msg = "✅ Entorno generado con éxito."
608
 
 
609
  yield [
610
  gr.update(visible=False),
611
  gr.update(visible=True),
612
  res["emotion"],
613
  res["transcription"],
614
  res["sentiment"],
 
615
  res["image"],
616
- res["image_360"],
617
- res["music"],
618
  res["music"],
619
  viewer_html_path,
620
  info_msg
621
  ]
622
  else:
623
- yield [gr.update(visible=False), gr.update(visible=False), None, None, None, None, None, None, None, None, "❌ Error al procesar el audio."]
624
 
625
  def clear_all():
626
  return [
627
  None,
628
  gr.update(visible=False),
629
  gr.update(visible=False),
630
- None, None, None, None, None, None, None, None, ""
631
  ]
632
 
633
  def publish_to_github(html_file_path):
@@ -640,88 +645,87 @@ def publish_to_github(html_file_path):
640
  return f"🔐 [Autorizar en GitHub]({auth_url}) (se abrirá una ventana)"
641
  return auth_url
642
 
643
- # Inyección CSS: Fondo estrictamente oscuro y remoción de blanco/contrastes defectuosos
644
  custom_css = """
645
- body, .gradio-container, html {
646
- background-color: #121212 !important;
647
- color: #e0e0e0 !important;
648
- }
649
  .gradio-container {
 
 
650
  max-width: 100% !important;
651
  width: 100% !important;
652
  padding-left: 20px !important;
653
  padding-right: 20px !important;
 
654
  }
655
  .row, .column, .tabs, .tabitem, .gr-group {
656
  width: 100% !important;
657
  max-width: 100% !important;
658
  flex-grow: 1 !important;
659
  }
660
- /* Forzar fondos oscuros en bloques internos de Gradio */
661
- .gr-box, .gr-panel, .gr-button, .input-container, .output-container, .gr-form, .gr-wrapper {
662
- background-color: #1e1e1e !important;
663
- border-color: #2d2d2d !important;
664
- }
665
- .main-title { text-align: center; font-size: 52px !important; font-weight: 900; margin-bottom: 0px; color: #ff7f50; }
666
- .sub-title { text-align: center; font-size: 20px !important; color: #888; margin-top: 5px; margin-bottom: 15px; font-style: italic; }
667
- .question-title { text-align: center; font-size: 22px !important; color: #fff; margin-bottom: 25px; font-weight: 600; }
668
- .step-header { font-size: 18px !important; font-weight: 700; margin-bottom: 10px; color: #ff7f50; margin-top: 15px; }
669
- .download-section { background: #1e1e1e !important; border: 1px solid #2d2d2d; padding: 15px; border-radius: 12px; margin: 25px 0; width: 100% !important; }
670
  audio { max-height: 50px !important; width: 100% !important; }
671
- .file-download button, .file-download a { font-size: 12px !important; padding: 4px 8px !important; }
672
- .gr-box { border-radius: 12px; }
673
- .loader { border: 4px solid #333; border-top: 4px solid #ff7f50; border-radius: 50%; width: 50px; height: 50px; animation: spin 1s linear infinite; margin: 20px auto; }
 
 
 
 
674
  @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
675
  """
676
 
677
- # Inicializar Tema en Modo Oscuro (Dark Mode) nativo
678
- theme = gr.themes.Soft(primary_hue="red", secondary_hue="orange", font=gr.themes.GoogleFont("Inter")).set(
679
- body_background_fill="*neutral_950",
680
- block_background_fill="*neutral_900",
681
- block_border_color="*neutral_800"
682
- )
683
 
684
- with gr.Blocks(title="BELLO", fill_width=True, theme=theme) as interface:
685
  gr.HTML('<div class="main-title">Bello</div>')
686
  gr.HTML('<div class="sub-title">Lo que acaba por no terminar</div>')
687
  gr.HTML('<div class="question-title">¿Cómo, dónde y cuándo te perdiste? (Física o emocionalmente)</div>')
688
 
689
- # PASO 1: Grabación + Botones acoplados verticalmente abajo
690
  with gr.Row():
691
- with gr.Column():
692
- gr.HTML('<div class="step-header">Paso 1: Record + Generate</div>')
693
- audio_input = gr.Audio(label="🎤 Micrófono / Grabadora", type="filepath", sources=["microphone", "upload"])
 
 
 
 
694
 
695
- # Sub-fila interna para colocar los botones debajo del reproductor/editor de audio
696
- with gr.Row():
697
- process_btn = gr.Button("🚀 Generar EVA", variant="primary", size="lg")
698
- clear_btn = gr.Button("🗑️ Limpiar", variant="secondary")
699
-
700
- # Visualizador de carga y resultados (Texto Paso 2 removido por completo)
701
  with gr.Row():
702
  with gr.Column(scale=1):
 
 
703
  loading_indicator = gr.Group(visible=False)
704
  with loading_indicator:
705
- gr.HTML('<div class="loader"></div><p style="text-align:center; font-weight:bold; color:#ff7f50;">La IA está dibujando tu panorama y componiendo tu música...</p>')
706
 
707
  with gr.TabItem("Resultado de la Experiencia", visible=False) as tab:
708
  with gr.Group():
709
  with gr.Row():
710
- emo = gr.Label(label="😌 Emoción Detectada")
711
- sent = gr.Label(label="💭 Sentimiento Analizado")
712
  trans = gr.Textbox(label="📝 Transcripción del relato", lines=2)
713
  with gr.Row():
714
- img_out = gr.Image(label="🖼️ Vista Previa Panorama 360°", height=320)
715
- img_file = gr.File(label="📁 Descargar Imagen 360° (.jpg)")
 
716
  with gr.Row():
717
- audio_out = gr.Audio(label="🎶 Música Generada por IA")
718
- audio_file = gr.File(label="📁 Descargar Audio (.wav)")
719
 
720
  group_components.append(tab)
721
 
722
- # PASO 3: Descarga e Inmersión
723
  with gr.Group(elem_classes="download-section"):
724
  gr.HTML('<div class="step-header">Paso 3: Descargar e Inmersión</div>')
 
725
  html_download = gr.File(label="📥 Descargar Visor Inmersivo HTML 360°", type="filepath", interactive=False)
726
  publish_btn = gr.Button("📤 Publicar Escena en GitHub (Gist)", variant="primary")
727
  publish_status = gr.Markdown("")
@@ -730,20 +734,23 @@ with gr.Blocks(title="BELLO", fill_width=True, theme=theme) as interface:
730
  process_btn.click(
731
  fn=process_and_display,
732
  inputs=[audio_input],
733
- outputs=[loading_indicator, tab, emo, trans, sent, img_out, img_file, audio_out, audio_file, html_download, publish_status]
 
734
  )
735
 
736
  clear_btn.click(
737
  fn=clear_all,
738
  inputs=[],
739
- outputs=[audio_input, loading_indicator, tab, emo, trans, sent, img_out, img_file, audio_out, audio_file, html_download, publish_status]
 
740
  )
741
 
742
  publish_btn.click(fn=publish_to_github, inputs=[html_download], outputs=[publish_status])
743
 
744
- # Forzar la inicialización con el CSS personalizado oscuro
745
  app = mount_gradio_app(fastapi_app, interface, path="/", theme=theme, css=custom_css)
746
 
747
  if __name__ == "__main__":
748
  import uvicorn
 
749
  uvicorn.run(app, host="0.0.0.0", port=7860)
 
48
  model = load_emotion_model(model_path)
49
 
50
  model_size = "small"
51
+ # Usamos CPU y float32 para mayor compatibilidad, cambiar si hay GPU
52
+ whisper_model = WhisperModel(model_size, device="cpu", compute_type="float32")
53
 
54
  def load_musicgen_model():
55
  try:
 
175
  return img
176
  with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp:
177
  image.save(tmp.name, "JPEG", quality=95)
178
+ # Nota: torch-srgan puede no estar disponible o requerir pago en DeepAI.
179
+ # Se usa como marcador de posición. Si falla, redimensiona localmente.
180
  response = requests.post(
181
  "https://api.deepai.org/api/torch-srgan",
182
  files={"image": open(tmp.name, "rb")},
 
340
  return results
341
 
342
  # ============================================================
343
+ # 7. Generación del visor HTML 360°
344
  # ============================================================
345
 
346
  def create_360_viewer_html(image_paths, audio_paths, output_path):
 
348
  for img_path in image_paths:
349
  try:
350
  img = Image.open(img_path)
351
+ # Redimensionar para reducir el tamaño del HTML base64
352
  img = img.resize((2048, 1024), Image.Resampling.LANCZOS)
353
  buf = BytesIO()
354
  img.save(buf, format="JPEG", quality=75, optimize=True)
 
391
  padding: 18px 50px; font-size: 16px; background: #2a2a3a; color: #666;
392
  border-radius: 30px; font-weight: bold; cursor: pointer;
393
  }}
394
+ button.ready {{ background: linear-gradient(135deg, #f53737 0%, #cd2323 100%); color: white; }}
395
  </style>
396
  <script>
397
  AFRAME.registerComponent('paper-plane-mesh', {{
 
413
  geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));
414
  geometry.setIndex(indices);
415
  geometry.computeVertexNormals();
 
416
  const material = new THREE.MeshStandardMaterial({{
417
+ color: 0xf53737,
418
  roughness: 0.4,
419
  metalness: 0.1,
420
  side: THREE.DoubleSide,
 
577
  return HTMLResponse(f"Error: {str(e)}", status_code=500)
578
 
579
  # ============================================================
580
+ # 9. Lógica de Interfaz y Funciones de Gradio
581
  # ============================================================
582
 
583
  MAX_SEGMENTS = 1
 
586
 
587
  def process_and_display(audio_input):
588
  if not audio_input:
589
+ yield [gr.update(visible=False), gr.update(visible=False), None, None, None, None, None, "⚠️ Por favor, graba o sube un audio primero."]
590
  return
591
 
592
+ # Iniciar estado de carga y ocultar contenedor anterior
593
  yield [
594
  gr.update(visible=True),
595
  gr.update(visible=False),
596
+ None, None, None, None, None, "⏳ Procesando audio y generando el entorno virtual afectivo..."
597
  ]
598
 
599
+ # Procesar solo el primer segmento (MAX_SEGMENTS = 1)
600
  results = get_predictions(audio_input, chunk_duration=120)
601
 
602
  if len(results) > 0:
 
611
 
612
  info_msg = "✅ Entorno generado con éxito."
613
 
614
+ # Actualizar la GUI
615
  yield [
616
  gr.update(visible=False),
617
  gr.update(visible=True),
618
  res["emotion"],
619
  res["transcription"],
620
  res["sentiment"],
621
+ # Gradio Image y Audio tienen icono de descarga incorporado
622
  res["image"],
 
 
623
  res["music"],
624
  viewer_html_path,
625
  info_msg
626
  ]
627
  else:
628
+ yield [gr.update(visible=False), gr.update(visible=False), None, None, None, None, None, "❌ Error al procesar el audio."]
629
 
630
  def clear_all():
631
  return [
632
  None,
633
  gr.update(visible=False),
634
  gr.update(visible=False),
635
+ None, None, None, None, None, None, ""
636
  ]
637
 
638
  def publish_to_github(html_file_path):
 
645
  return f"🔐 [Autorizar en GitHub]({auth_url}) (se abrirá una ventana)"
646
  return auth_url
647
 
648
+ # Estilos CSS adaptados para Gradio 6 Full Width y FONDO CIELO AZUL OSCURO
649
  custom_css = """
650
+ /* FONDO CIELO TARDE NOCHE AZUL OSCURO */
 
 
 
651
  .gradio-container {
652
+ background-color: #0a192f !important;
653
+ background-image: radial-gradient(circle at center, #112240 0%, #0a192f 100%) !important;
654
  max-width: 100% !important;
655
  width: 100% !important;
656
  padding-left: 20px !important;
657
  padding-right: 20px !important;
658
+ color: #e6f1ff !important;
659
  }
660
  .row, .column, .tabs, .tabitem, .gr-group {
661
  width: 100% !important;
662
  max-width: 100% !important;
663
  flex-grow: 1 !important;
664
  }
665
+ /* Estilos de texto para contrastar */
666
+ .main-title { text-align: center; font-size: 52px !important; font-weight: 900; margin-bottom: 0px; color: #ff3737; text-shadow: 0 0 10px rgba(255,55,55,0.5); }
667
+ .sub-title { text-align: center; font-size: 20px !important; color: #8892b0; margin-top: 5px; margin-bottom: 15px; font-style: italic; }
668
+ .question-title { text-align: center; font-size: 22px !important; color: #ccd6f6; margin-bottom: 25px; font-weight: 600; }
669
+ .step-header { font-size: 18px !important; font-weight: 700; margin-bottom: 10px; color: #f53737; margin-top: 15px; }
670
+ .download-section { background: rgba(23, 42, 69, 0.7); padding: 15px; border-radius: 12px; margin: 25px 0; width: 100% !important; border: 1px solid #1e3a61; }
671
+
 
 
 
672
  audio { max-height: 50px !important; width: 100% !important; }
673
+ .gr-box { border-radius: 12px; background-color: rgba(17, 34, 64, 0.5); border: 1px solid #1e3a61; }
674
+
675
+ /* Ajustes de contraste para componentes de entrada/salida */
676
+ .gr-input, .gr-textbox, .gr-markdown { color: #e6f1ff !important; }
677
+ .gr-label { color: #8892b0 !important; }
678
+
679
+ .loader { border: 4px solid #172a45; border-top: 4px solid #f53737; border-radius: 50%; width: 50px; height: 50px; animation: spin 1s linear infinite; margin: 20px auto; }
680
  @keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
681
  """
682
 
683
+ theme = gr.themes.Soft(primary_hue="red", secondary_hue="orange", font=gr.themes.GoogleFont("Inter"))
 
 
 
 
 
684
 
685
+ with gr.Blocks(title="BELLO", fill_width=True) as interface:
686
  gr.HTML('<div class="main-title">Bello</div>')
687
  gr.HTML('<div class="sub-title">Lo que acaba por no terminar</div>')
688
  gr.HTML('<div class="question-title">¿Cómo, dónde y cuándo te perdiste? (Física o emocionalmente)</div>')
689
 
690
+ # PASO 1: Grabación Ancha
691
  with gr.Row():
692
+ with gr.Column(scale=4):
693
+ gr.HTML('<div class="step-header">Paso 1: Graba tu voz: Registra tu experiencia</div>')
694
+ audio_input = gr.Audio(label="🎤 Entrada de Audio", type="filepath", sources=["microphone"])
695
+ with gr.Column(scale=1, min_width=200):
696
+ gr.HTML('<div class="step-header">&nbsp;</div>')
697
+ process_btn = gr.Button("🚀 Generar ", variant="primary", size="lg")
698
+ clear_btn = gr.Button("🗑️ Limpiar", variant="secondary")
699
 
700
+ # PASO 2: Resultados debajo de los botones
 
 
 
 
 
701
  with gr.Row():
702
  with gr.Column(scale=1):
703
+ gr.HTML('<div class="step-header">Paso 2: Generar Entorno Virtual Afectivo </div>')
704
+
705
  loading_indicator = gr.Group(visible=False)
706
  with loading_indicator:
707
+ gr.HTML('<div class="loader"></div><p style="text-align:center; font-weight:bold; color:#f53737;">La IA está dibujando tu panorama y componiendo tu música...</p>')
708
 
709
  with gr.TabItem("Resultado de la Experiencia", visible=False) as tab:
710
  with gr.Group():
711
  with gr.Row():
712
+ emo = gr.Label(label="😌 Tono emocional")
713
+ sent = gr.Label(label="💭 Análisis sentimental")
714
  trans = gr.Textbox(label="📝 Transcripción del relato", lines=2)
715
  with gr.Row():
716
+ # Imagen y Audio de Gradio ya tienen botones de descarga incorporados
717
+ # SE ELIMINAimg_out = gr.Image(label="🖼️ Vista Previa Panorama 360°", height=320)
718
+ gr.File para imagen
719
  with gr.Row():
720
+ # SE ELIMINAaudio_out = gr.Audio(label="🎶 Música Generada por IA")
721
+ gr.File para audio
722
 
723
  group_components.append(tab)
724
 
725
+ # PASO 3: Descarga
726
  with gr.Group(elem_classes="download-section"):
727
  gr.HTML('<div class="step-header">Paso 3: Descargar e Inmersión</div>')
728
+ # Este componente sí es necesario porque es un archivo HTML generado, no una imagen/audio estándar
729
  html_download = gr.File(label="📥 Descargar Visor Inmersivo HTML 360°", type="filepath", interactive=False)
730
  publish_btn = gr.Button("📤 Publicar Escena en GitHub (Gist)", variant="primary")
731
  publish_status = gr.Markdown("")
 
734
  process_btn.click(
735
  fn=process_and_display,
736
  inputs=[audio_input],
737
+ # Se ajustan las salidas eliminando img_file y audio_file
738
+ outputs=[loading_indicator, tab, emo, trans, sent, img_out, audio_out, html_download, publish_status]
739
  )
740
 
741
  clear_btn.click(
742
  fn=clear_all,
743
  inputs=[],
744
+ # Se ajustan las salidas eliminando img_file y audio_file
745
+ outputs=[audio_input, loading_indicator, tab, emo, trans, sent, img_out, audio_out, html_download, publish_status]
746
  )
747
 
748
  publish_btn.click(fn=publish_to_github, inputs=[html_download], outputs=[publish_status])
749
 
750
+ # Corrección para Gradio 6.0: Pasar el tema y CSS dentro de mount_gradio_app
751
  app = mount_gradio_app(fastapi_app, interface, path="/", theme=theme, css=custom_css)
752
 
753
  if __name__ == "__main__":
754
  import uvicorn
755
+ # Ejecutar uvicorn apuntando a la aplicación FastAPI 'app'
756
  uvicorn.run(app, host="0.0.0.0", port=7860)