Spaces:
Running
Running
Tu Nombre commited on
Commit Β·
5d9ba74
1
Parent(s): c744cc3
upload imagenes/videos del cliente al crear canal
Browse files- cliente_template.py +25 -12
- main.py +41 -9
cliente_template.py
CHANGED
|
@@ -39,6 +39,7 @@ except Exception as e:
|
|
| 39 |
GROQ_KEY = "GROQ_PLACEHOLDER"
|
| 40 |
TIPO_VIDEO = "TIPO_PLACEHOLDER"
|
| 41 |
PEXELS_KEY = "PEXELS_PLACEHOLDER"
|
|
|
|
| 42 |
LOGS = []
|
| 43 |
STATUS = "Iniciando..."
|
| 44 |
|
|
@@ -88,19 +89,31 @@ async def pipeline():
|
|
| 88 |
import subprocess
|
| 89 |
subprocess.run(["ffmpeg","-y","-f","lavfi","-i","anullsrc=r=44100:cl=mono","-t","60","voz.mp3"], capture_output=True)
|
| 90 |
log("Voz lista")
|
| 91 |
-
STATUS = "
|
| 92 |
-
h = {"Authorization": PEXELS_KEY}
|
| 93 |
-
r = requests.get(f"https://api.pexels.com/videos/search?query={NICHO}&per_page=15", headers=h)
|
| 94 |
-
vids = r.json().get("videos", [])
|
| 95 |
fondos = []
|
| 96 |
-
|
| 97 |
-
|
| 98 |
-
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 104 |
log(f"Fondos listos: {len(fondos)}")
|
| 105 |
STATUS = "Renderizando video..."
|
| 106 |
from moviepy.editor import AudioFileClip as AC, VideoFileClip as VC, concatenate_videoclips
|
|
|
|
| 39 |
GROQ_KEY = "GROQ_PLACEHOLDER"
|
| 40 |
TIPO_VIDEO = "TIPO_PLACEHOLDER"
|
| 41 |
PEXELS_KEY = "PEXELS_PLACEHOLDER"
|
| 42 |
+
os.makedirs("media_cliente", exist_ok=True)
|
| 43 |
LOGS = []
|
| 44 |
STATUS = "Iniciando..."
|
| 45 |
|
|
|
|
| 89 |
import subprocess
|
| 90 |
subprocess.run(["ffmpeg","-y","-f","lavfi","-i","anullsrc=r=44100:cl=mono","-t","60","voz.mp3"], capture_output=True)
|
| 91 |
log("Voz lista")
|
| 92 |
+
STATUS = "Preparando fondos..."
|
|
|
|
|
|
|
|
|
|
| 93 |
fondos = []
|
| 94 |
+
# Revisar si hay media propia del cliente
|
| 95 |
+
archivos_propios = []
|
| 96 |
+
if os.path.exists("media_cliente"):
|
| 97 |
+
for f in sorted(os.listdir("media_cliente")):
|
| 98 |
+
if f.lower().endswith((".mp4", ".mov", ".jpg", ".jpeg", ".png", ".webp")):
|
| 99 |
+
archivos_propios.append(f"media_cliente/{f}")
|
| 100 |
+
if archivos_propios:
|
| 101 |
+
random.shuffle(archivos_propios)
|
| 102 |
+
fondos = archivos_propios[:6]
|
| 103 |
+
log(f"Usando {len(fondos)} archivos del cliente")
|
| 104 |
+
else:
|
| 105 |
+
STATUS = "Descargando fondo..."
|
| 106 |
+
h = {"Authorization": PEXELS_KEY}
|
| 107 |
+
r = requests.get(f"https://api.pexels.com/videos/search?query={NICHO}&per_page=15", headers=h)
|
| 108 |
+
vids = r.json().get("videos", [])
|
| 109 |
+
if vids:
|
| 110 |
+
random.shuffle(vids)
|
| 111 |
+
for i, v in enumerate(vids[:6]):
|
| 112 |
+
try:
|
| 113 |
+
u = v["video_files"][0]["link"]
|
| 114 |
+
with open(f"fondo{i}.mp4","wb") as f: f.write(requests.get(u, timeout=30).content)
|
| 115 |
+
fondos.append(f"fondo{i}.mp4")
|
| 116 |
+
except: pass
|
| 117 |
log(f"Fondos listos: {len(fondos)}")
|
| 118 |
STATUS = "Renderizando video..."
|
| 119 |
from moviepy.editor import AudioFileClip as AC, VideoFileClip as VC, concatenate_videoclips
|
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", 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")),
|
|
@@ -167,14 +167,22 @@ RUN pip install -r requirements.txt
|
|
| 167 |
COPY main.py .
|
| 168 |
EXPOSE 7860
|
| 169 |
CMD [\"uvicorn\", \"main:app\", \"--host\", \"0.0.0.0\", \"--port\", \"7860\"]"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 170 |
commit_payload = {
|
| 171 |
"summary": "TubeBot init",
|
| 172 |
-
"files":
|
| 173 |
-
{"path": "main.py", "content": b64(main_code), "encoding": "base64"},
|
| 174 |
-
{"path": "requirements.txt", "content": b64(req), "encoding": "base64"},
|
| 175 |
-
{"path": "README.md", "content": b64(readme), "encoding": "base64"},
|
| 176 |
-
{"path": "Dockerfile", "content": b64(dockerfile), "encoding": "base64"}
|
| 177 |
-
]
|
| 178 |
}
|
| 179 |
r2 = await client.post(
|
| 180 |
f"https://huggingface.co/api/spaces/{repo_name}/commit/main",
|
|
@@ -503,6 +511,9 @@ input:focus,select:focus{border-color:#ff2d2d;}
|
|
| 503 |
</select>
|
| 504 |
<label style="font-size:.85rem;color:#aaa;margin-top:12px;display:block">β¨ ΒΏTienes alguna preferencia? <span style="color:#666">(opcional)</span></label>
|
| 505 |
<textarea id="config${i}" rows="4" placeholder="Ej: voz femenina en ingles, subtitulos grandes arriba, tono motivacional, sin musica..." style="width:100%;padding:12px;background:#080808;color:#fff;border:1px solid #333;border-radius:8px;resize:vertical;font-family:system-ui;margin-top:6px"></textarea>
|
|
|
|
|
|
|
|
|
|
| 506 |
`;
|
| 507 |
container.appendChild(div);
|
| 508 |
}
|
|
@@ -547,6 +558,26 @@ async function activar(){
|
|
| 547 |
const conf = document.getElementById('config'+i);
|
| 548 |
if(n && t) canales.push({nicho: n.value, tipo: t.value, config: conf ? conf.value : ""});
|
| 549 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 550 |
document.getElementById('btn').disabled = true;
|
| 551 |
document.getElementById('loading').style.display = 'block';
|
| 552 |
try{
|
|
@@ -556,7 +587,7 @@ async function activar(){
|
|
| 556 |
method:'POST',
|
| 557 |
signal: ctrl.signal,
|
| 558 |
headers:{'Content-Type':'application/json'},
|
| 559 |
-
body: JSON.stringify({email, canales, token: "TOKEN_PLACEHOLDER"})
|
| 560 |
});
|
| 561 |
const d = await r.json();
|
| 562 |
if(d.url){
|
|
@@ -644,6 +675,7 @@ async def crear(request: Request):
|
|
| 644 |
data = await request.json()
|
| 645 |
email = data.get("email","").strip().lower()
|
| 646 |
canales_data = data.get("canales", [])
|
|
|
|
| 647 |
if canales_data:
|
| 648 |
nicho = canales_data[0].get("nicho","tecnologia")
|
| 649 |
tipo = canales_data[0].get("tipo","largo")
|
|
@@ -669,7 +701,7 @@ async def crear(request: Request):
|
|
| 669 |
# Parsear preferencias del cliente con Groq ANTES de crear
|
| 670 |
config_parsed = await parsear_config_groq(config_libre)
|
| 671 |
# Crear el canal pasando la config
|
| 672 |
-
resultado = await crear_space(nicho, email, tipo, config_parsed)
|
| 673 |
if not resultado:
|
| 674 |
return JSONResponse({"error": "No se pudo crear el canal"}, status_code=500)
|
| 675 |
u = resultado["url"]
|
|
|
|
| 114 |
# ββββββββββββββββββββββββββββββββββββββββββ
|
| 115 |
# CREAR SPACE EN HUGGING FACE
|
| 116 |
# ββββββββββββββββββββββββββββββββββββββββββ
|
| 117 |
+
async def crear_space(nicho: str, email: str, tipo: str = "largo", config_parsed: dict = None, archivos_subidos: list = 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")),
|
|
|
|
| 167 |
COPY main.py .
|
| 168 |
EXPOSE 7860
|
| 169 |
CMD [\"uvicorn\", \"main:app\", \"--host\", \"0.0.0.0\", \"--port\", \"7860\"]"""
|
| 170 |
+
files_lista = [
|
| 171 |
+
{"path": "main.py", "content": b64(main_code), "encoding": "base64"},
|
| 172 |
+
{"path": "requirements.txt", "content": b64(req), "encoding": "base64"},
|
| 173 |
+
{"path": "README.md", "content": b64(readme), "encoding": "base64"},
|
| 174 |
+
{"path": "Dockerfile", "content": b64(dockerfile), "encoding": "base64"}
|
| 175 |
+
]
|
| 176 |
+
# AΓ±adir archivos del cliente si los subiΓ³
|
| 177 |
+
if archivos_subidos:
|
| 178 |
+
for i, arc in enumerate(archivos_subidos[:20]):
|
| 179 |
+
nombre = arc.get("nombre", f"media_{i}.jpg").replace("/","_").replace("\\","_")
|
| 180 |
+
contenido = arc.get("contenido", "")
|
| 181 |
+
if contenido:
|
| 182 |
+
files_lista.append({"path": f"media_cliente/{nombre}", "content": contenido, "encoding": "base64"})
|
| 183 |
commit_payload = {
|
| 184 |
"summary": "TubeBot init",
|
| 185 |
+
"files": files_lista
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 186 |
}
|
| 187 |
r2 = await client.post(
|
| 188 |
f"https://huggingface.co/api/spaces/{repo_name}/commit/main",
|
|
|
|
| 511 |
</select>
|
| 512 |
<label style="font-size:.85rem;color:#aaa;margin-top:12px;display:block">β¨ ΒΏTienes alguna preferencia? <span style="color:#666">(opcional)</span></label>
|
| 513 |
<textarea id="config${i}" rows="4" placeholder="Ej: voz femenina en ingles, subtitulos grandes arriba, tono motivacional, sin musica..." style="width:100%;padding:12px;background:#080808;color:#fff;border:1px solid #333;border-radius:8px;resize:vertical;font-family:system-ui;margin-top:6px"></textarea>
|
| 514 |
+
<label style="font-size:.85rem;color:#aaa;margin-top:12px;display:block">πΈ Sube tus imagenes o videos <span style="color:#666">(opcional, max 20)</span></label>
|
| 515 |
+
<input type="file" id="media${i}" multiple accept="image/*,video/*" style="margin-top:6px;width:100%;padding:10px;background:#080808;color:#fff;border:1px solid #333;border-radius:8px"/>
|
| 516 |
+
<div id="mediainfo${i}" style="color:#888;font-size:.8rem;margin-top:4px"></div>
|
| 517 |
`;
|
| 518 |
container.appendChild(div);
|
| 519 |
}
|
|
|
|
| 558 |
const conf = document.getElementById('config'+i);
|
| 559 |
if(n && t) canales.push({nicho: n.value, tipo: t.value, config: conf ? conf.value : ""});
|
| 560 |
}
|
| 561 |
+
|
| 562 |
+
// Recoger archivos y convertir a base64
|
| 563 |
+
const archivos = [];
|
| 564 |
+
const fileInput = document.getElementById('media1');
|
| 565 |
+
if (fileInput && fileInput.files && fileInput.files.length > 0) {
|
| 566 |
+
document.getElementById('mediainfo1').textContent = "Procesando archivos...";
|
| 567 |
+
const files = Array.from(fileInput.files).slice(0, 20);
|
| 568 |
+
for (const f of files) {
|
| 569 |
+
try {
|
| 570 |
+
const b64 = await new Promise((resolve, reject) => {
|
| 571 |
+
const reader = new FileReader();
|
| 572 |
+
reader.onload = () => resolve(reader.result.split(',')[1]);
|
| 573 |
+
reader.onerror = reject;
|
| 574 |
+
reader.readAsDataURL(f);
|
| 575 |
+
});
|
| 576 |
+
archivos.push({nombre: f.name, contenido: b64});
|
| 577 |
+
} catch(e) { console.log("Error archivo", f.name, e); }
|
| 578 |
+
}
|
| 579 |
+
document.getElementById('mediainfo1').textContent = archivos.length + " archivos listos";
|
| 580 |
+
}
|
| 581 |
document.getElementById('btn').disabled = true;
|
| 582 |
document.getElementById('loading').style.display = 'block';
|
| 583 |
try{
|
|
|
|
| 587 |
method:'POST',
|
| 588 |
signal: ctrl.signal,
|
| 589 |
headers:{'Content-Type':'application/json'},
|
| 590 |
+
body: JSON.stringify({email, canales, archivos, token: "TOKEN_PLACEHOLDER"})
|
| 591 |
});
|
| 592 |
const d = await r.json();
|
| 593 |
if(d.url){
|
|
|
|
| 675 |
data = await request.json()
|
| 676 |
email = data.get("email","").strip().lower()
|
| 677 |
canales_data = data.get("canales", [])
|
| 678 |
+
archivos_subidos = data.get("archivos", [])
|
| 679 |
if canales_data:
|
| 680 |
nicho = canales_data[0].get("nicho","tecnologia")
|
| 681 |
tipo = canales_data[0].get("tipo","largo")
|
|
|
|
| 701 |
# Parsear preferencias del cliente con Groq ANTES de crear
|
| 702 |
config_parsed = await parsear_config_groq(config_libre)
|
| 703 |
# Crear el canal pasando la config
|
| 704 |
+
resultado = await crear_space(nicho, email, tipo, config_parsed, archivos_subidos)
|
| 705 |
if not resultado:
|
| 706 |
return JSONResponse({"error": "No se pudo crear el canal"}, status_code=500)
|
| 707 |
u = resultado["url"]
|