Update app.py
Browse files
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 |
-
|
|
|
|
| 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°
|
| 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, #
|
| 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:
|
| 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
|
| 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,
|
| 587 |
return
|
| 588 |
|
|
|
|
| 589 |
yield [
|
| 590 |
gr.update(visible=True),
|
| 591 |
gr.update(visible=False),
|
| 592 |
-
None, None, None, None, None,
|
| 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,
|
| 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,
|
| 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 |
-
#
|
| 644 |
custom_css = """
|
| 645 |
-
|
| 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 |
-
/*
|
| 661 |
-
.
|
| 662 |
-
|
| 663 |
-
|
| 664 |
-
}
|
| 665 |
-
.
|
| 666 |
-
|
| 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 |
-
.
|
| 672 |
-
|
| 673 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 674 |
@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } }
|
| 675 |
"""
|
| 676 |
|
| 677 |
-
|
| 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
|
| 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
|
| 690 |
with gr.Row():
|
| 691 |
-
with gr.Column():
|
| 692 |
-
gr.HTML('<div class="step-header">Paso 1:
|
| 693 |
-
audio_input = gr.Audio(label="🎤
|
|
|
|
|
|
|
|
|
|
|
|
|
| 694 |
|
| 695 |
-
|
| 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:#
|
| 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="😌
|
| 711 |
-
sent = gr.Label(label="💭
|
| 712 |
trans = gr.Textbox(label="📝 Transcripción del relato", lines=2)
|
| 713 |
with gr.Row():
|
| 714 |
-
|
| 715 |
-
|
|
|
|
| 716 |
with gr.Row():
|
| 717 |
-
|
| 718 |
-
|
| 719 |
|
| 720 |
group_components.append(tab)
|
| 721 |
|
| 722 |
-
# PASO 3: Descarga
|
| 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 |
-
|
|
|
|
| 734 |
)
|
| 735 |
|
| 736 |
clear_btn.click(
|
| 737 |
fn=clear_all,
|
| 738 |
inputs=[],
|
| 739 |
-
|
|
|
|
| 740 |
)
|
| 741 |
|
| 742 |
publish_btn.click(fn=publish_to_github, inputs=[html_download], outputs=[publish_status])
|
| 743 |
|
| 744 |
-
#
|
| 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"> </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)
|