Spaces:
Running
Running
Tu Nombre commited on
Commit Β·
38d8665
1
Parent(s): 907148e
fase 2: cliente lee config (voz, subtitulos)
Browse files- cliente_template.py +25 -3
- main.py +6 -6
cliente_template.py
CHANGED
|
@@ -13,6 +13,19 @@ import edge_tts
|
|
| 13 |
from moviepy.editor import VideoFileClip, AudioFileClip, TextClip, CompositeVideoClip
|
| 14 |
|
| 15 |
NICHO = "NICHO_PLACEHOLDER"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 16 |
CLIENT_EMAIL = "EMAIL_PLACEHOLDER"
|
| 17 |
HF_REPO = "REPO_PLACEHOLDER"
|
| 18 |
|
|
@@ -52,7 +65,16 @@ async def pipeline():
|
|
| 52 |
guion = generar_guion()
|
| 53 |
log("Guion listo")
|
| 54 |
STATUS = "Generando voz..."
|
| 55 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 56 |
log("Voz lista")
|
| 57 |
STATUS = "Descargando fondo..."
|
| 58 |
h = {"Authorization": PEXELS_KEY}
|
|
@@ -94,9 +116,9 @@ async def pipeline():
|
|
| 94 |
palabras = guion.split()
|
| 95 |
frases = [" ".join(palabras[i:i+6]) for i in range(0,len(palabras),6)]
|
| 96 |
t_f = voz.duration / max(len(frases),1)
|
| 97 |
-
txts = [TextClip(t.upper(), fontsize=72, color="#D4AF37", font="DejaVu-Sans-Bold",
|
| 98 |
stroke_color="black", stroke_width=2, method="caption",
|
| 99 |
-
size=(clip.w*0.8,None)).set_start(i*t_f).set_duration(t_f).set_pos(("center",0.75), relative=True)
|
| 100 |
for i,t in enumerate(frases)]
|
| 101 |
final = CompositeVideoClip([clip]+txts).set_audio(voz)
|
| 102 |
final.write_videofile("out.mp4", fps=15, codec="libx264", preset="ultrafast", logger=None, threads=2)
|
|
|
|
| 13 |
from moviepy.editor import VideoFileClip, AudioFileClip, TextClip, CompositeVideoClip
|
| 14 |
|
| 15 |
NICHO = "NICHO_PLACEHOLDER"
|
| 16 |
+
import json as _json
|
| 17 |
+
try:
|
| 18 |
+
CONFIG = _json.loads("""CONFIG_PLACEHOLDER""")
|
| 19 |
+
except:
|
| 20 |
+
CONFIG = {}
|
| 21 |
+
|
| 22 |
+
# Mapeo de voces edge-tts
|
| 23 |
+
VOCES = {
|
| 24 |
+
"es": {"masculina": "es-ES-AlvaroNeural", "femenina": "es-ES-ElviraNeural"},
|
| 25 |
+
"en": {"masculina": "en-US-GuyNeural", "femenina": "en-US-JennyNeural"},
|
| 26 |
+
"pt": {"masculina": "pt-BR-AntonioNeural", "femenina": "pt-BR-FranciscaNeural"},
|
| 27 |
+
"fr": {"masculina": "fr-FR-HenriNeural", "femenina": "fr-FR-DeniseNeural"}
|
| 28 |
+
}
|
| 29 |
CLIENT_EMAIL = "EMAIL_PLACEHOLDER"
|
| 30 |
HF_REPO = "REPO_PLACEHOLDER"
|
| 31 |
|
|
|
|
| 65 |
guion = generar_guion()
|
| 66 |
log("Guion listo")
|
| 67 |
STATUS = "Generando voz..."
|
| 68 |
+
voz_ia_on = CONFIG.get("voz_ia", True)
|
| 69 |
+
if voz_ia_on:
|
| 70 |
+
idioma_v = CONFIG.get("idioma", "es")
|
| 71 |
+
genero_v = CONFIG.get("voz_genero", "masculina")
|
| 72 |
+
voz_seleccionada = VOCES.get(idioma_v, VOCES["es"]).get(genero_v, "es-ES-AlvaroNeural")
|
| 73 |
+
await edge_tts.Communicate(guion, voz_seleccionada).save("voz.mp3")
|
| 74 |
+
else:
|
| 75 |
+
# Sin voz IA: crear audio en silencio
|
| 76 |
+
import subprocess
|
| 77 |
+
subprocess.run(["ffmpeg","-y","-f","lavfi","-i","anullsrc=r=44100:cl=mono","-t","60","voz.mp3"], capture_output=True)
|
| 78 |
log("Voz lista")
|
| 79 |
STATUS = "Descargando fondo..."
|
| 80 |
h = {"Authorization": PEXELS_KEY}
|
|
|
|
| 116 |
palabras = guion.split()
|
| 117 |
frases = [" ".join(palabras[i:i+6]) for i in range(0,len(palabras),6)]
|
| 118 |
t_f = voz.duration / max(len(frases),1)
|
| 119 |
+
txts = [TextClip(t.upper(), fontsize=72, color=CONFIG.get("color_subtitulos","#D4AF37"), font="DejaVu-Sans-Bold",
|
| 120 |
stroke_color="black", stroke_width=2, method="caption",
|
| 121 |
+
size=(clip.w*0.8,None)).set_start(i*t_f).set_duration(t_f).set_pos(("center", {"arriba":0.15,"centro":0.5,"abajo":0.75}.get(CONFIG.get("posicion_subtitulos","abajo"),0.75)), relative=True)
|
| 122 |
for i,t in enumerate(frases)]
|
| 123 |
final = CompositeVideoClip([clip]+txts).set_audio(voz)
|
| 124 |
final.write_videofile("out.mp4", fps=15, codec="libx264", preset="ultrafast", logger=None, threads=2)
|
main.py
CHANGED
|
@@ -114,7 +114,7 @@ cargar_clientes()
|
|
| 114 |
# ββββββββββββββββββββββββββββββββββββββββββ
|
| 115 |
# CREAR SPACE EN HUGGING FACE
|
| 116 |
# ββββββββββββββββββββββββββββββββββββββββββ
|
| 117 |
-
async def crear_space(nicho: str, email: str, tipo: str = "largo") -> str:
|
| 118 |
space_id = f"tb-{re.sub(r'[^a-z0-9]','', nicho.lower()[:12])}-{int(time.time())%9999}"
|
| 119 |
cuentas = [
|
| 120 |
(os.environ.get("HF_TOKEN_5",""), os.environ.get("HF_USER_5","Alejandro")),
|
|
@@ -131,7 +131,7 @@ async def crear_space(nicho: str, email: str, tipo: str = "largo") -> str:
|
|
| 131 |
headers = {"Authorization": f"Bearer {token_actual}", "Content-Type": "application/json"}
|
| 132 |
|
| 133 |
with open("cliente_template.py", "r") as _f:
|
| 134 |
-
main_code = _f.read().replace("NICHO_PLACEHOLDER", nicho).replace("EMAIL_PLACEHOLDER", email).replace("REPO_PLACEHOLDER", f"{hf_user_actual}/{space_id}").replace("GROQ_PLACEHOLDER", os.environ.get("GROQ_KEY","")).replace("PEXELS_PLACEHOLDER", os.environ.get("PEXELS_KEY","")).replace("TIPO_PLACEHOLDER", tipo)
|
| 135 |
|
| 136 |
req = "gradio\ngroq\nedge-tts\nmoviepy==1.0.3\nrequests\nhttpx\ngoogle-api-python-client\ngoogle-auth\ngoogle-auth-oauthlib\nimageio\nimageio-ffmpeg\ndecorator\ntqdm\nPillow\nnumpy\nopencv-python-headless"
|
| 137 |
|
|
@@ -661,14 +661,14 @@ async def crear(request: Request):
|
|
| 661 |
canales_actuales = len(CLIENTES.get(email, {}).get("canales", []))
|
| 662 |
if canales_actuales >= limite:
|
| 663 |
return JSONResponse({"error": f"Has alcanzado el limite de tu plan {plan} ({limite} canales)"}, status_code=400)
|
| 664 |
-
#
|
| 665 |
-
|
|
|
|
|
|
|
| 666 |
if not resultado:
|
| 667 |
return JSONResponse({"error": "No se pudo crear el canal"}, status_code=500)
|
| 668 |
u = resultado["url"]
|
| 669 |
repo = resultado["repo"]
|
| 670 |
-
# Parsear preferencias del cliente con Groq
|
| 671 |
-
config_parsed = await parsear_config_groq(config_libre)
|
| 672 |
# Guardar en CLIENTES
|
| 673 |
if email not in CLIENTES:
|
| 674 |
CLIENTES[email] = {"canales": [], "plan": plan}
|
|
|
|
| 114 |
# ββββββββββββββββββββββββββββββββββββββββββ
|
| 115 |
# CREAR SPACE EN HUGGING FACE
|
| 116 |
# ββββββββββββββββββββββββββββββββββββββββββ
|
| 117 |
+
async def crear_space(nicho: str, email: str, tipo: str = "largo", config_parsed: dict = None) -> str:
|
| 118 |
space_id = f"tb-{re.sub(r'[^a-z0-9]','', nicho.lower()[:12])}-{int(time.time())%9999}"
|
| 119 |
cuentas = [
|
| 120 |
(os.environ.get("HF_TOKEN_5",""), os.environ.get("HF_USER_5","Alejandro")),
|
|
|
|
| 131 |
headers = {"Authorization": f"Bearer {token_actual}", "Content-Type": "application/json"}
|
| 132 |
|
| 133 |
with open("cliente_template.py", "r") as _f:
|
| 134 |
+
main_code = _f.read().replace("NICHO_PLACEHOLDER", nicho).replace("EMAIL_PLACEHOLDER", email).replace("REPO_PLACEHOLDER", f"{hf_user_actual}/{space_id}").replace("GROQ_PLACEHOLDER", os.environ.get("GROQ_KEY","")).replace("PEXELS_PLACEHOLDER", os.environ.get("PEXELS_KEY","")).replace("TIPO_PLACEHOLDER", tipo).replace("CONFIG_PLACEHOLDER", __import__("json").dumps(config_parsed or {}))
|
| 135 |
|
| 136 |
req = "gradio\ngroq\nedge-tts\nmoviepy==1.0.3\nrequests\nhttpx\ngoogle-api-python-client\ngoogle-auth\ngoogle-auth-oauthlib\nimageio\nimageio-ffmpeg\ndecorator\ntqdm\nPillow\nnumpy\nopencv-python-headless"
|
| 137 |
|
|
|
|
| 661 |
canales_actuales = len(CLIENTES.get(email, {}).get("canales", []))
|
| 662 |
if canales_actuales >= limite:
|
| 663 |
return JSONResponse({"error": f"Has alcanzado el limite de tu plan {plan} ({limite} canales)"}, status_code=400)
|
| 664 |
+
# Parsear preferencias del cliente con Groq ANTES de crear
|
| 665 |
+
config_parsed = await parsear_config_groq(config_libre)
|
| 666 |
+
# Crear el canal pasando la config
|
| 667 |
+
resultado = await crear_space(nicho, email, tipo, config_parsed)
|
| 668 |
if not resultado:
|
| 669 |
return JSONResponse({"error": "No se pudo crear el canal"}, status_code=500)
|
| 670 |
u = resultado["url"]
|
| 671 |
repo = resultado["repo"]
|
|
|
|
|
|
|
| 672 |
# Guardar en CLIENTES
|
| 673 |
if email not in CLIENTES:
|
| 674 |
CLIENTES[email] = {"canales": [], "plan": plan}
|