lecturatanaj / app.py
Cristobal299's picture
Upload 3 files
b4ac5d7 verified
Raw
History Blame Contribute Delete
7.59 kB
import gradio as gr
# ──────────────────────────────────────────────
# CAPÍTULOS DEL GÉNESIS
# ──────────────────────────────────────────────
CAPITULOS = [
{"titulo": "Génesis · Capítulo 1", "archivo": "audio/genesis_01.mp3"},
{"titulo": "Génesis · Capítulo 2", "archivo": "audio/genesis_02.mp3"},
{"titulo": "Génesis · Capítulo 3", "archivo": "audio/genesis_03.mp3"},
{"titulo": "Génesis · Capítulo 4", "archivo": "audio/genesis_04.mp3"},
{"titulo": "Génesis · Capítulo 5", "archivo": "audio/genesis_05.mp3"},
{"titulo": "Génesis · Capítulo 6", "archivo": "audio/genesis_06.mp3"},
{"titulo": "Génesis · Capítulo 7", "archivo": "audio/genesis_07.mp3"},
{"titulo": "Génesis · Capítulo 8", "archivo": "audio/genesis_08.mp3"},
{"titulo": "Génesis · Capítulo 9", "archivo": "audio/genesis_09.mp3"},
{"titulo": "Génesis · Capítulo 10", "archivo": "audio/genesis_10.mp3"},
]
TOTAL = len(CAPITULOS)
def cargar_capitulo(indice, autoplay=False):
"""Devuelve el update del reproductor + el texto del capítulo actual."""
indice = max(0, min(indice, TOTAL - 1))
cap = CAPITULOS[indice]
texto = f"📖 Reproduciendo ahora: **{cap['titulo']}** ({indice + 1} de {TOTAL})"
return (
gr.update(value=cap["archivo"], autoplay=autoplay),
texto,
indice,
)
def iniciar_desde_boton(indice_boton):
audio, texto, idx = cargar_capitulo(indice_boton, autoplay=True)
return audio, texto, idx
def iniciar_todo():
return iniciar_desde_boton(0)
def al_terminar_capitulo(indice_actual):
siguiente = indice_actual + 1
if siguiente >= TOTAL:
return (
gr.update(value=CAPITULOS[indice_actual]["archivo"], autoplay=False),
f"✨ Has completado el Libro del Génesis, capítulos 1 al {TOTAL}. La lectura ha concluido en paz. ✨",
indice_actual,
)
return cargar_capitulo(siguiente, autoplay=True)
# ──────────────────────────────────────────────
# ESTILO CELESTIAL Y DIVINO
# ──────────────────────────────────────────────
CSS = """
@import url('https://fonts.googleapis.com/css2?family=Cinzel:wght@500;700&family=EB+Garamond:ital@0;1&display=swap');
.gradio-container {
background: radial-gradient(ellipse at top, #0b1030 0%, #05061a 55%, #000000 100%) !important;
background-attachment: fixed !important;
position: relative;
overflow-x: hidden;
}
.gradio-container::before {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
background-image:
radial-gradient(1.5px 1.5px at 20% 30%, #ffffff 100%, transparent 0),
radial-gradient(1.5px 1.5px at 65% 15%, #ffe9b8 100%, transparent 0),
radial-gradient(2px 2px at 80% 55%, #ffffff 100%, transparent 0),
radial-gradient(1px 1px at 40% 80%, #ffffff 100%, transparent 0),
radial-gradient(1.5px 1.5px at 90% 80%, #ffe9b8 100%, transparent 0),
radial-gradient(1px 1px at 10% 65%, #ffffff 100%, transparent 0),
radial-gradient(2px 2px at 55% 45%, #ffffff 100%, transparent 0),
radial-gradient(1.5px 1.5px at 30% 10%, #ffffff 100%, transparent 0);
background-repeat: repeat;
background-size: 700px 700px;
animation: centellear 6s ease-in-out infinite alternate;
opacity: 0.6;
z-index: 0;
}
@keyframes centellear {
from { opacity: 0.35; }
to { opacity: 0.85; }
}
#titulo-divino {
text-align: center;
font-family: 'Cinzel', serif;
color: #f4dfa3;
text-shadow: 0 0 18px rgba(244, 223, 163, 0.55), 0 0 40px rgba(120, 90, 200, 0.35);
font-size: 2.4em;
letter-spacing: 3px;
margin-bottom: 0;
}
#subtitulo-divino {
text-align: center;
font-family: 'EB Garamond', serif;
font-style: italic;
color: #c9c3e8;
font-size: 1.15em;
margin-top: 4px;
margin-bottom: 25px;
}
.panel-celestial {
background: linear-gradient(160deg, rgba(20, 20, 55, 0.75), rgba(8, 8, 25, 0.85)) !important;
border: 1px solid rgba(244, 223, 163, 0.35) !important;
border-radius: 18px !important;
box-shadow: 0 0 35px rgba(120, 90, 200, 0.25), inset 0 0 25px rgba(244, 223, 163, 0.05) !important;
padding: 20px !important;
}
#estado-lectura {
text-align: center;
font-family: 'EB Garamond', serif;
color: #f4dfa3;
font-size: 1.2em;
margin-top: 10px;
min-height: 30px;
}
.boton-capitulo button {
background: linear-gradient(180deg, rgba(40, 35, 90, 0.9), rgba(15, 12, 45, 0.9)) !important;
border: 1px solid rgba(244, 223, 163, 0.4) !important;
color: #f4dfa3 !important;
font-family: 'Cinzel', serif !important;
border-radius: 12px !important;
transition: all 0.25s ease-in-out !important;
}
.boton-capitulo button:hover {
background: linear-gradient(180deg, rgba(90, 70, 160, 0.95), rgba(30, 20, 70, 0.95)) !important;
box-shadow: 0 0 18px rgba(244, 223, 163, 0.5) !important;
transform: translateY(-2px);
}
#boton-principal button {
background: linear-gradient(180deg, #f4dfa3, #c9a24d) !important;
color: #16112e !important;
font-family: 'Cinzel', serif !important;
font-weight: 700 !important;
font-size: 1.15em !important;
border-radius: 14px !important;
border: none !important;
box-shadow: 0 0 25px rgba(244, 223, 163, 0.6) !important;
padding: 14px !important;
}
#boton-principal button:hover {
box-shadow: 0 0 40px rgba(244, 223, 163, 0.9) !important;
transform: scale(1.02);
}
footer { display: none !important; }
"""
with gr.Blocks(css=CSS, title="Génesis · Lectura Sagrada", theme=gr.themes.Base()) as demo:
indice_state = gr.State(0)
gr.HTML(
"""
<div id="titulo-divino">✦ GÉNESIS ✦</div>
<div id="subtitulo-divino">El Libro del Principio — Capítulos 1 al 10, narrados en voz</div>
"""
)
with gr.Column(elem_classes="panel-celestial"):
reproductor = gr.Audio(
label="Reproductor Sagrado",
interactive=False,
autoplay=False,
value=CAPITULOS[0]["archivo"],
)
estado = gr.Markdown(
f"📖 Listo para comenzar: **{CAPITULOS[0]['titulo']}**",
elem_id="estado-lectura",
)
boton_iniciar = gr.Button(
"▶ Iniciar la Lectura Completa del Génesis",
elem_id="boton-principal",
)
gr.Markdown("### O elige un capítulo:")
with gr.Row():
botones = []
for i in range(TOTAL):
b = gr.Button(f"Cap. {i + 1}", elem_classes="boton-capitulo")
botones.append(b)
# Encadenar automáticamente al terminar cada capítulo
reproductor.stop(
fn=al_terminar_capitulo,
inputs=indice_state,
outputs=[reproductor, estado, indice_state],
)
boton_iniciar.click(
fn=iniciar_todo,
inputs=None,
outputs=[reproductor, estado, indice_state],
)
for i, b in enumerate(botones):
b.click(
fn=lambda i=i: iniciar_desde_boton(i),
inputs=None,
outputs=[reproductor, estado, indice_state],
)
if __name__ == "__main__":
demo.launch()