Spaces:
Paused
Paused
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
# -*- coding: utf-8 -*-
|
| 2 |
"""
|
| 3 |
Centralita Torá — HuggingFace Space (Gradio)
|
| 4 |
-
Leer hebreo + español · canto Trope real y Voz Divina cercana y limpia
|
| 5 |
"""
|
| 6 |
import os, glob, json, tempfile, html, asyncio, subprocess, shutil, re
|
| 7 |
import urllib.request
|
|
@@ -26,20 +26,58 @@ VOZ_PITCH = "+5Hz"
|
|
| 26 |
FONDO = "fondo.mp3"
|
| 27 |
FONDO_VOL = 0.18
|
| 28 |
|
| 29 |
-
# IA de Estudio (Groq)
|
| 30 |
MODELO_ESTUDIA = "openai/gpt-oss-120b"
|
| 31 |
CARPETA = "libros"
|
| 32 |
GROQ_URL = "https://api.groq.com/openai/v1/chat/completions"
|
| 33 |
GROQ_KEY = os.environ.get("GROQ_API_KEY")
|
| 34 |
|
| 35 |
|
| 36 |
-
# ---
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
def procesar_audio_narrador(ruta):
|
| 38 |
"""Efecto cercano y limpio para el narrador."""
|
| 39 |
if not shutil.which("ffmpeg"):
|
| 40 |
return ruta
|
| 41 |
|
| 42 |
-
# Menos eco, más presencia cercana (frecuencias medias y altas claras)
|
| 43 |
filtros = [
|
| 44 |
"atempo=0.92",
|
| 45 |
"bass=g=5:f=120",
|
|
@@ -317,24 +355,33 @@ def render(nombre, cap):
|
|
| 317 |
plano_es, plano_he = [], []
|
| 318 |
|
| 319 |
for v in vs:
|
| 320 |
-
# Limpieza de residuos HTML del JSON
|
| 321 |
he_raw = v.get("he", "").replace(" ", " ").replace("{פ}", "").replace("{ס}", "").strip()
|
| 322 |
es_raw = v.get("es", "").replace(" ", " ").strip()
|
| 323 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 324 |
he = html.escape(he_raw)
|
| 325 |
-
es = html.escape(es_raw)
|
| 326 |
-
|
| 327 |
fila = f"<div class='verso'><span class='num'>{v.get('n','')}</span>"
|
| 328 |
if he:
|
| 329 |
fila += f"<span class='he'>{he}</span>"
|
| 330 |
-
plano_he.append(he_raw)
|
| 331 |
-
if es:
|
| 332 |
-
fila += f"<span class='es'>{es}</span>"
|
| 333 |
-
plano_es.append(es_raw)
|
| 334 |
fila += "</div>"
|
| 335 |
filas.append(fila)
|
|
|
|
|
|
|
|
|
|
|
|
|
| 336 |
|
| 337 |
-
return f"<div class='pasaje'>{''.join(filas)}</div>",
|
| 338 |
|
| 339 |
|
| 340 |
def estudiar(mensaje, historial, contexto):
|
|
|
|
| 1 |
# -*- coding: utf-8 -*-
|
| 2 |
"""
|
| 3 |
Centralita Torá — HuggingFace Space (Gradio)
|
| 4 |
+
Leer hebreo + español · canto Trope real y Voz Divina cercana y limpia con refinamiento exegético por Groq
|
| 5 |
"""
|
| 6 |
import os, glob, json, tempfile, html, asyncio, subprocess, shutil, re
|
| 7 |
import urllib.request
|
|
|
|
| 26 |
FONDO = "fondo.mp3"
|
| 27 |
FONDO_VOL = 0.18
|
| 28 |
|
| 29 |
+
# IA de Estudio y Refinamiento (Groq)
|
| 30 |
MODELO_ESTUDIA = "openai/gpt-oss-120b"
|
| 31 |
CARPETA = "libros"
|
| 32 |
GROQ_URL = "https://api.groq.com/openai/v1/chat/completions"
|
| 33 |
GROQ_KEY = os.environ.get("GROQ_API_KEY")
|
| 34 |
|
| 35 |
|
| 36 |
+
# --- REFINAMIENTO DE TRADUCCIÓN CON GROQ (SENTIDO TRADICIONAL) ---
|
| 37 |
+
def refinar_texto_con_groq(texto_literal):
|
| 38 |
+
"""
|
| 39 |
+
Toma el texto literal/interlinear y lo transforma mediante Groq
|
| 40 |
+
a un español fluido, claro y con el sentido tradicional exacto.
|
| 41 |
+
"""
|
| 42 |
+
if not GROQ_KEY or not texto_literal.strip():
|
| 43 |
+
return texto_literal
|
| 44 |
+
|
| 45 |
+
sistema = (
|
| 46 |
+
"Eres un experto en traducción bíblica y exégesis tradicional hebrea. "
|
| 47 |
+
"Tu tarea es tomar el texto literal o interlinear proporcionado y transformarlo "
|
| 48 |
+
"a un español fluido, claro y con el sentido tradicional exacto, "
|
| 49 |
+
"manteniendo la profundidad, el respeto y la fidelidad al texto original sin perder naturalidad."
|
| 50 |
+
)
|
| 51 |
+
|
| 52 |
+
cuerpo = {
|
| 53 |
+
"model": MODELO_ESTUDIA,
|
| 54 |
+
"temperature": 0.3,
|
| 55 |
+
"max_tokens": 2000,
|
| 56 |
+
"messages": [
|
| 57 |
+
{"role": "system", "content": sistema},
|
| 58 |
+
{"role": "user", "content": f"Por favor, da forma y sentido natural al siguiente texto manteniendo su tradición:\n\n{texto_literal}"}
|
| 59 |
+
]
|
| 60 |
+
}
|
| 61 |
+
|
| 62 |
+
try:
|
| 63 |
+
data = json.dumps(cuerpo).encode("utf-8")
|
| 64 |
+
req = urllib.request.Request(GROQ_URL, data=data, method="POST")
|
| 65 |
+
req.add_header("Content-Type", "application/json")
|
| 66 |
+
req.add_header("Authorization", f"Bearer {GROQ_KEY}")
|
| 67 |
+
with urllib.request.urlopen(req, timeout=90) as r:
|
| 68 |
+
d = json.load(r)
|
| 69 |
+
return (d["choices"][0]["message"]["content"] or "").strip()
|
| 70 |
+
except Exception as e:
|
| 71 |
+
print(f"Error refinando con Groq: {e}")
|
| 72 |
+
return texto_literal
|
| 73 |
+
|
| 74 |
+
|
| 75 |
+
# --- PROCESAMIENTO ACÚSTICO FFMPEG (ESPAÑOL MÁS CERCANO Y SIN ECO EXCESIVO) ---
|
| 76 |
def procesar_audio_narrador(ruta):
|
| 77 |
"""Efecto cercano y limpio para el narrador."""
|
| 78 |
if not shutil.which("ffmpeg"):
|
| 79 |
return ruta
|
| 80 |
|
|
|
|
| 81 |
filtros = [
|
| 82 |
"atempo=0.92",
|
| 83 |
"bass=g=5:f=120",
|
|
|
|
| 355 |
plano_es, plano_he = [], []
|
| 356 |
|
| 357 |
for v in vs:
|
|
|
|
| 358 |
he_raw = v.get("he", "").replace(" ", " ").replace("{פ}", "").replace("{ס}", "").strip()
|
| 359 |
es_raw = v.get("es", "").replace(" ", " ").strip()
|
| 360 |
|
| 361 |
+
if he_raw:
|
| 362 |
+
plano_he.append(he_raw)
|
| 363 |
+
if es_raw:
|
| 364 |
+
plano_es.append(es_raw)
|
| 365 |
+
|
| 366 |
+
# Procesamos el texto en español con Groq para obtener el sentido tradicional fluido
|
| 367 |
+
texto_bruto_es = " ".join(plano_es)
|
| 368 |
+
texto_refinado_es = refinar_texto_con_groq(texto_bruto_es) if texto_bruto_es else ""
|
| 369 |
+
|
| 370 |
+
# Renderizamos los versículos en hebreo
|
| 371 |
+
for v in vs:
|
| 372 |
+
he_raw = v.get("he", "").replace(" ", " ").replace("{פ}", "").replace("{ס}", "").strip()
|
| 373 |
he = html.escape(he_raw)
|
|
|
|
|
|
|
| 374 |
fila = f"<div class='verso'><span class='num'>{v.get('n','')}</span>"
|
| 375 |
if he:
|
| 376 |
fila += f"<span class='he'>{he}</span>"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 377 |
fila += "</div>"
|
| 378 |
filas.append(fila)
|
| 379 |
+
|
| 380 |
+
# Añadimos la traducción con sentido tradicional generada por Groq
|
| 381 |
+
if texto_refinado_es:
|
| 382 |
+
filas.append(f"<div class='verso' style='margin-top: 15px; border-top: 1px solid rgba(255,255,255,0.1); padding-top: 10px;'><span class='es'><b>Traducción con sentido tradicional:</b><br>{html.escape(texto_refinado_es)}</span></div>")
|
| 383 |
|
| 384 |
+
return f"<div class='pasaje'>{''.join(filas)}</div>", texto_refinado_es, " ".join(plano_he)
|
| 385 |
|
| 386 |
|
| 387 |
def estudiar(mensaje, historial, contexto):
|