HF Readme
Browse files- .gitattributes +2 -0
- .gitignore +6 -1
- Dockerfile +11 -0
- README.MD +11 -0
- app.py +178 -0
- audio_tests/audioHF.py +29 -0
- audio_tests/audioMELO.py +15 -0
- audio_tests/audioMS.py +14 -0
- audio_tests/audioOpen.py +14 -0
- audio_tests/audioOpenAI.py +24 -0
- busqueda.py +68 -0
- funciones/__pycache__/motion.cpython-311.pyc +0 -0
- funciones/motion.py +66 -0
- funciones_old.py +186 -0
- guardaImagenes.py +74 -0
- herramientas.py +46 -0
- requirements.txt +10 -0
- run.py +0 -19
- stitcher.py +86 -0
- test.py +7 -0
.gitattributes
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
|
|
1 |
+
*.wav filter=lfs diff=lfs merge=lfs -text
|
2 |
+
*.mp4 filter=lfs diff=lfs merge=lfs -text
|
.gitignore
CHANGED
@@ -1,3 +1,8 @@
|
|
1 |
/venv/
|
2 |
/media/
|
3 |
-
/resultados/
|
|
|
|
|
|
|
|
|
|
|
|
1 |
/venv/
|
2 |
/media/
|
3 |
+
/resultados/
|
4 |
+
bridges.py
|
5 |
+
/__pycache__/
|
6 |
+
*.mp4
|
7 |
+
/audio_tests/
|
8 |
+
*.wav
|
Dockerfile
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
FROM python:3.11
|
2 |
+
|
3 |
+
WORKDIR /code
|
4 |
+
|
5 |
+
COPY ./requirements.txt /code/requirements.txt
|
6 |
+
|
7 |
+
RUN pip install --no-cache-dir -r /code/requirements.txt
|
8 |
+
|
9 |
+
COPY . .
|
10 |
+
|
11 |
+
CMD ["uvicorn", "app:app", "--host", "0.0.0.0", "--port", "7860"]
|
README.MD
ADDED
@@ -0,0 +1,11 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
---
|
2 |
+
title: GenVid
|
3 |
+
emoji: 📽️
|
4 |
+
colorFrom: blue
|
5 |
+
colorTo: indigo
|
6 |
+
sdk: docker
|
7 |
+
pinned: true
|
8 |
+
license: mit
|
9 |
+
---
|
10 |
+
|
11 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
app.py
ADDED
@@ -0,0 +1,178 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
from io import BytesIO
|
3 |
+
from typing import List
|
4 |
+
import funciones.motion as motion
|
5 |
+
import tempfile
|
6 |
+
from fastapi import FastAPI, Form
|
7 |
+
from fastapi import FastAPI, File, UploadFile, HTTPException, status, BackgroundTasks
|
8 |
+
from fastapi.responses import StreamingResponse, FileResponse, JSONResponse
|
9 |
+
import herramientas
|
10 |
+
|
11 |
+
app = FastAPI()
|
12 |
+
|
13 |
+
@app.get("/health",
|
14 |
+
tags=["Monitoreo Server"],
|
15 |
+
description="Verifica el estado de salud de la API.",
|
16 |
+
summary="Health Check"
|
17 |
+
)
|
18 |
+
async def health_check():
|
19 |
+
"""
|
20 |
+
Este endpoint devuelve una respuesta 200 OK para indicar que la API está funcionando.
|
21 |
+
"""
|
22 |
+
return JSONResponse(content={"status": "ok"}, status_code=200)
|
23 |
+
|
24 |
+
@app.post("/echo-image/",
|
25 |
+
tags=["Monitoreo Server"],
|
26 |
+
description="Test endpoint para prueba de envío de imagenes.",
|
27 |
+
summary="Mirror test para envío de imagenes"
|
28 |
+
)
|
29 |
+
async def echo_image(image: UploadFile = File(...)):
|
30 |
+
if not image.content_type.startswith("image/"):
|
31 |
+
return {"error": "El archivo no es una imagen"}
|
32 |
+
contents = await image.read()
|
33 |
+
return StreamingResponse(BytesIO(contents), media_type=image.content_type)
|
34 |
+
|
35 |
+
@app.post("/motion-image/")
|
36 |
+
async def motion_image(image: UploadFile = File(...), background_tasks: BackgroundTasks = BackgroundTasks()):
|
37 |
+
"""
|
38 |
+
Recibe una imagen, la procesa con motion(), le da movimiento y devuelve el resultado.
|
39 |
+
"""
|
40 |
+
if not image.content_type.startswith("image/"):
|
41 |
+
raise HTTPException(
|
42 |
+
status_code=status.HTTP_400_BAD_REQUEST,
|
43 |
+
detail="El archivo no es una imagen. Por favor, suba una imagen."
|
44 |
+
)
|
45 |
+
|
46 |
+
temp_image_path = None # Inicializamos la variable para el bloque finally
|
47 |
+
output_file_generated = False # Flag para saber si monomotion generó un archivo
|
48 |
+
|
49 |
+
try:
|
50 |
+
# 1. Guardar la imagen subida en un archivo temporal
|
51 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=f"_{image.filename}") as tmp_file:
|
52 |
+
contents = await image.read()
|
53 |
+
tmp_file.write(contents)
|
54 |
+
temp_image_path = tmp_file.name
|
55 |
+
|
56 |
+
print(f"Imagen subida guardada temporalmente en: {temp_image_path}")
|
57 |
+
|
58 |
+
# 2. Ejecutar motion()
|
59 |
+
# Asumimos que motion devuelve la ruta a un archivo de salida
|
60 |
+
path_archivo = await motion.motion(temp_image_path)
|
61 |
+
print("Salí de monomotion con resultado: ", path_archivo)
|
62 |
+
output_file_generated = True # Si llegamos aquí, asumimos que se generó un archivo
|
63 |
+
|
64 |
+
# 3. Determinar el tipo MIME del archivo de salida (si es diferente al de entrada)
|
65 |
+
# Esto es importante si motion cambia el formato (ej. de JPG a MP4)
|
66 |
+
import mimetypes
|
67 |
+
mimetypes.add_type("video/mp4", ".mp4") # Asegúrate de añadir tipos si esperas video
|
68 |
+
mime_type, _ = mimetypes.guess_type(path_archivo)
|
69 |
+
if not mime_type:
|
70 |
+
mime_type = "application/octet-stream" # Tipo genérico si no se puede adivinar
|
71 |
+
|
72 |
+
# 4.5 Programar la eliminación de AMBOS archivos después de que la respuesta sea enviada
|
73 |
+
# El archivo de entrada se borrará sí o sí.
|
74 |
+
background_tasks.add_task(herramientas.delete_file_on_complete, temp_image_path)
|
75 |
+
# El archivo de salida también se borrará, asumiendo que es temporal y solo para esta respuesta.
|
76 |
+
background_tasks.add_task(herramientas.delete_file_on_complete, path_archivo)
|
77 |
+
|
78 |
+
# 4. Devolver el archivo procesado al cliente
|
79 |
+
return FileResponse(
|
80 |
+
path=path_archivo,
|
81 |
+
media_type=mime_type,
|
82 |
+
filename=os.path.basename(path_archivo)
|
83 |
+
)
|
84 |
+
|
85 |
+
except HTTPException:
|
86 |
+
# Re-lanza cualquier HTTPException ya creada (ej. el 400 inicial)
|
87 |
+
raise
|
88 |
+
except Exception as e:
|
89 |
+
# Captura cualquier otro error inesperado durante el proceso
|
90 |
+
print(f"Error inesperado en /generate-monomotion-image/: {e}")
|
91 |
+
raise HTTPException(
|
92 |
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
93 |
+
detail=f"Ha ocurrido un error interno al procesar la imagen con monomotion: {e}"
|
94 |
+
)
|
95 |
+
finally:
|
96 |
+
# 5. Limpieza: Eliminar archivos temporales
|
97 |
+
# Eliminar la imagen de entrada temporal
|
98 |
+
if temp_image_path and os.path.exists(temp_image_path):
|
99 |
+
try:
|
100 |
+
os.remove(temp_image_path)
|
101 |
+
print(f"Archivo temporal de entrada eliminado: {temp_image_path}")
|
102 |
+
except Exception as cleanup_e:
|
103 |
+
print(f"Error al eliminar el archivo temporal de entrada {temp_image_path}: {cleanup_e}")
|
104 |
+
|
105 |
+
@app.post("/echo-random-file/")
|
106 |
+
async def echo_random_file(files: List[UploadFile] = File(...)):
|
107 |
+
"""
|
108 |
+
Recibe múltiples archivos, selecciona uno al azar y lo devuelve.
|
109 |
+
"""
|
110 |
+
if not files:
|
111 |
+
raise HTTPException(
|
112 |
+
status_code=status.HTTP_400_BAD_REQUEST,
|
113 |
+
detail="No se enviaron archivos."
|
114 |
+
)
|
115 |
+
|
116 |
+
temp_file_paths = [] # Lista para guardar las rutas de los archivos temporales
|
117 |
+
try:
|
118 |
+
# 1. Guardar cada UploadFile en un archivo temporal en disco
|
119 |
+
for uploaded_file in files:
|
120 |
+
# Creamos un archivo temporal con un sufijo para mantener la extensión
|
121 |
+
# delete=False para que no se elimine inmediatamente al cerrar el archivo.
|
122 |
+
# Lo eliminaremos explícitamente en el bloque finally.
|
123 |
+
with tempfile.NamedTemporaryFile(delete=False, suffix=f"_{uploaded_file.filename}") as tmp_file:
|
124 |
+
contents = await uploaded_file.read()
|
125 |
+
tmp_file.write(contents)
|
126 |
+
current_temp_path = tmp_file.name
|
127 |
+
temp_file_paths.append(current_temp_path)
|
128 |
+
print(f"Guardado temporalmente: {current_temp_path}")
|
129 |
+
|
130 |
+
# 2. Pasar la lista de rutas de archivos temporales a tu función 'cinema'
|
131 |
+
# ¡Ahora 'lista_rutas_archivos' es la "lista" que tu función cinema espera!
|
132 |
+
resultado_cinema = await motion.cinema(temp_file_paths)
|
133 |
+
|
134 |
+
# 3. Manejar el resultado de la función 'cinema'
|
135 |
+
if isinstance(resultado_cinema, str):
|
136 |
+
# Si cinema devuelve una ruta a un archivo (ej. un video generado)
|
137 |
+
# Determinar el tipo MIME del archivo de salida
|
138 |
+
import mimetypes
|
139 |
+
mime_type, _ = mimetypes.guess_type(resultado_cinema)
|
140 |
+
if not mime_type:
|
141 |
+
mime_type = "application/octet-stream" # Tipo genérico si no se puede adivinar
|
142 |
+
|
143 |
+
# Devolver el archivo generado por cinema
|
144 |
+
# Asegúrate de que este archivo también se gestione y elimine si es temporal
|
145 |
+
return FileResponse(
|
146 |
+
path=resultado_cinema,
|
147 |
+
media_type=mime_type,
|
148 |
+
filename=os.path.basename(resultado_cinema)
|
149 |
+
)
|
150 |
+
elif isinstance(resultado_cinema, dict) and "error" in resultado_cinema:
|
151 |
+
# Si cinema devuelve un diccionario de error
|
152 |
+
raise HTTPException(
|
153 |
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
154 |
+
detail=f"Error en la función cinema: {resultado_cinema['error']}"
|
155 |
+
)
|
156 |
+
else:
|
157 |
+
# Si cinema devuelve otra cosa (ej. un JSON de éxito sin archivo)
|
158 |
+
return resultado_cinema # Asume que es un diccionario JSON serializable
|
159 |
+
|
160 |
+
except HTTPException:
|
161 |
+
# Re-lanza cualquier HTTPException que ya se haya levantado (ej. por validación de entrada)
|
162 |
+
raise
|
163 |
+
except Exception as e:
|
164 |
+
# Captura cualquier otro error inesperado
|
165 |
+
print(f"Error inesperado en /process-files-with-cinema/: {e}")
|
166 |
+
raise HTTPException(
|
167 |
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
168 |
+
detail=f"Ha ocurrido un error interno al procesar los archivos con cinema: {e}"
|
169 |
+
)
|
170 |
+
finally:
|
171 |
+
# 4. Limpiar los archivos temporales creados
|
172 |
+
for path in temp_file_paths:
|
173 |
+
if os.path.exists(path):
|
174 |
+
try:
|
175 |
+
os.remove(path)
|
176 |
+
print(f"Archivo temporal eliminado: {path}")
|
177 |
+
except Exception as cleanup_e:
|
178 |
+
print(f"Error al eliminar el archivo temporal {path}: {cleanup_e}")
|
audio_tests/audioHF.py
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from transformers import pipeline
|
2 |
+
from datasets import load_dataset
|
3 |
+
import soundfile as sf
|
4 |
+
import torch
|
5 |
+
import time
|
6 |
+
|
7 |
+
synthesiser = pipeline("text-to-speech", "microsoft/speecht5_tts")
|
8 |
+
#synthesiser = pipeline("text-to-speech", "Sandiago21/speecht5_finetuned_facebook_voxpopuli_spanish")
|
9 |
+
#synthesiser = pipeline("text-to-speech", "jjyaoao/speecht5_voxpopuli_spanish")
|
10 |
+
|
11 |
+
embeddings_dataset = load_dataset("Matthijs/cmu-arctic-xvectors", split="validation")
|
12 |
+
speaker_embedding = torch.tensor(embeddings_dataset[7306]["xvector"]).unsqueeze(0)
|
13 |
+
# You can replace this embedding with your own as well.
|
14 |
+
|
15 |
+
dialogo = """
|
16 |
+
Las piedras preciosas son, en esencia, minerales, rocas o materiales orgánicos que han sido seleccionados por su
|
17 |
+
belleza, durabilidad y rareza, lo que les confiere un gran valor. Son objetos de deseo y admiración desde hace milenios,
|
18 |
+
utilizados en joyería, objetos de arte y como símbolos de estatus o poder.
|
19 |
+
"""
|
20 |
+
|
21 |
+
unix_timestamp_float = time.time()
|
22 |
+
start_time = time.time() # Registra el tiempo de inicio
|
23 |
+
speech = synthesiser("Lo del puto perro", forward_params={"speaker_embeddings": speaker_embedding})
|
24 |
+
end_time = time.time() # Registra el tiempo de finalización
|
25 |
+
|
26 |
+
# Calcula la duración
|
27 |
+
duration = end_time - start_time
|
28 |
+
|
29 |
+
sf.write(f"audioHF_ms_{unix_timestamp_float}_{duration}s.wav", speech["audio"], samplerate=speech["sampling_rate"])
|
audio_tests/audioMELO.py
ADDED
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from melo.api import TTS
|
2 |
+
|
3 |
+
# Speed is adjustable
|
4 |
+
speed = 1.0
|
5 |
+
|
6 |
+
# CPU is sufficient for real-time inference.
|
7 |
+
# You can also change to cuda:0
|
8 |
+
device = 'cpu'
|
9 |
+
|
10 |
+
text = "El resplandor del sol acaricia las olas, pintando el cielo con una paleta deslumbrante."
|
11 |
+
model = TTS(language='ES', device=device)
|
12 |
+
speaker_ids = model.hps.data.spk2id
|
13 |
+
|
14 |
+
output_path = 'es.wav'
|
15 |
+
model.tts_to_file(text, speaker_ids['ES'], output_path, speed=speed)
|
audio_tests/audioMS.py
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from transformers import pipeline
|
2 |
+
from datasets import load_dataset
|
3 |
+
import soundfile as sf
|
4 |
+
import torch
|
5 |
+
|
6 |
+
synthesiser = pipeline(task="text-to-speech", model="microsoft/speecht5_tts")
|
7 |
+
|
8 |
+
embeddings_dataset = load_dataset("Matthijs/cmu-arctic-xvectors", split="validation")
|
9 |
+
speaker_embedding = torch.tensor(embeddings_dataset[7306]["xvector"]).unsqueeze(0)
|
10 |
+
# You can replace this embedding with your own as well.
|
11 |
+
|
12 |
+
speech = synthesiser("Hello, my dog is cooler than you!", forward_params={"speaker_embeddings": speaker_embedding})
|
13 |
+
|
14 |
+
sf.write("speech.wav", speech["audio"], samplerate=speech["sampling_rate"])
|
audio_tests/audioOpen.py
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pathlib import Path
|
2 |
+
from openai import OpenAI
|
3 |
+
import bridges
|
4 |
+
|
5 |
+
client = OpenAI(api_key=bridges.llave) #Usa Buzzword (buzz) o Moibe (llave).
|
6 |
+
speech_file_path = Path(__file__).parent / "speech.mp3"
|
7 |
+
|
8 |
+
with client.audio.speech.with_streaming_response.create(
|
9 |
+
model="gpt-4o-mini-tts",
|
10 |
+
voice="coral",
|
11 |
+
input="Today is a wonderful day to build something people love!",
|
12 |
+
instructions="Speak in a cheerful and positive tone.",
|
13 |
+
) as response:
|
14 |
+
response.stream_to_file(speech_file_path)
|
audio_tests/audioOpenAI.py
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import asyncio
|
2 |
+
|
3 |
+
from openai import AsyncOpenAI
|
4 |
+
from openai.helpers import LocalAudioPlayer
|
5 |
+
|
6 |
+
openai = AsyncOpenAI()
|
7 |
+
|
8 |
+
input = """Yeah, yeah, ya got Big Apple Insurance, whaddaya need? Let's make this quick, I got places to be.\n\nIf ya gotta file a claim, press 1—lemme guess, someone cut ya off? Figures.\n\nWanna check the status? Press 2, I know, I know, hurry it up, right?\n\nIf ya just wanna hold, press 3—hey, your call, but don't say I didn't warn ya.\n\nNeed a real person? Press 4, and I'll get ya through—just don't start yellin' at 'em, they're doin' their best.\n\nAlright, let's move it along, time is money, buddy!"""
|
9 |
+
|
10 |
+
instructions = """Voice: Gruff, fast-talking, and a little worn-out, like a New York cabbie who's seen it all but still keeps things moving.\n\nTone: Slightly exasperated but still functional, with a mix of sarcasm and no-nonsense efficiency.\n\nDialect: Strong New York accent, with dropped \"r\"s, sharp consonants, and classic phrases like whaddaya and lemme guess.\n\nPronunciation: Quick and clipped, with a rhythm that mimics the natural hustle of a busy city conversation.\n\nFeatures: Uses informal, straight-to-the-point language, throws in some dry humor, and keeps the energy just on the edge of impatience but still helpful."""
|
11 |
+
|
12 |
+
async def main() -> None:
|
13 |
+
|
14 |
+
async with openai.audio.speech.with_streaming_response.create(
|
15 |
+
model="gpt-4o-mini-tts",
|
16 |
+
voice="echo",
|
17 |
+
input=input,
|
18 |
+
instructions=instructions,
|
19 |
+
response_format="pcm",
|
20 |
+
) as response:
|
21 |
+
await LocalAudioPlayer().play(response)
|
22 |
+
|
23 |
+
if __name__ == "__main__":
|
24 |
+
asyncio.run(main())
|
busqueda.py
ADDED
@@ -0,0 +1,68 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from googleapiclient.discovery import build
|
2 |
+
|
3 |
+
# --- Configura tus credenciales y ID de Motor de Búsqueda ---
|
4 |
+
API_KEY = "AIzaSyDjsiJLlUwtHaCCBQUwcFCqlN5Nu5wJluw" # Reemplaza con tu Clave de API de Google Cloud
|
5 |
+
CX = "90556d12415d84063" # Reemplaza con el ID de tu Custom Search Engine
|
6 |
+
|
7 |
+
def buscar_imagenes_google(query, num_results=5):
|
8 |
+
"""
|
9 |
+
Realiza una búsqueda de imágenes en Google usando la Custom Search API.
|
10 |
+
|
11 |
+
Args:
|
12 |
+
query (str): El término de búsqueda.
|
13 |
+
num_results (int): El número máximo de resultados a devolver (máx. 10 por solicitud).
|
14 |
+
|
15 |
+
Returns:
|
16 |
+
list: Una lista de diccionarios, donde cada diccionario representa una imagen
|
17 |
+
y contiene su URL, título, etc.
|
18 |
+
"""
|
19 |
+
try:
|
20 |
+
# Construye el servicio de la API de Custom Search
|
21 |
+
# 'customsearch' es el nombre del servicio, 'v1' es la versión
|
22 |
+
service = build("customsearch", "v1", developerKey=API_KEY)
|
23 |
+
|
24 |
+
# Ejecuta la búsqueda.
|
25 |
+
# 'q': el término de búsqueda
|
26 |
+
# 'cx': el ID de tu Custom Search Engine
|
27 |
+
# 'searchType': MUY IMPORTANTE, para especificar que buscas imágenes
|
28 |
+
# 'num': número de resultados (máx. 10 por solicitud, aunque puedes paginar)
|
29 |
+
res = service.cse().list(
|
30 |
+
q=query,
|
31 |
+
cx=CX,
|
32 |
+
searchType='image',
|
33 |
+
num=num_results
|
34 |
+
).execute()
|
35 |
+
|
36 |
+
# Extrae los resultados
|
37 |
+
items = res.get('items', [])
|
38 |
+
|
39 |
+
resultados_imagenes = []
|
40 |
+
for item in items:
|
41 |
+
resultados_imagenes.append({
|
42 |
+
'title': item.get('title'),
|
43 |
+
'link': item.get('link'), # URL directa de la imagen
|
44 |
+
'displayLink': item.get('displayLink'), # URL del sitio donde se encontró
|
45 |
+
'thumbnailLink': item['image'].get('thumbnailLink') if 'image' in item else None # URL de la miniatura
|
46 |
+
})
|
47 |
+
|
48 |
+
return resultados_imagenes
|
49 |
+
|
50 |
+
except Exception as e:
|
51 |
+
print(f"Ocurrió un error: {e}")
|
52 |
+
return []
|
53 |
+
|
54 |
+
# --- Ejemplo de uso ---
|
55 |
+
if __name__ == "__main__":
|
56 |
+
termino_busqueda = "Japan Mt Fuji"
|
57 |
+
imagenes_encontradas = buscar_imagenes_google(termino_busqueda, num_results=3)
|
58 |
+
|
59 |
+
if imagenes_encontradas:
|
60 |
+
print(f"Imágenes encontradas para '{termino_busqueda}':")
|
61 |
+
for i, imagen in enumerate(imagenes_encontradas):
|
62 |
+
print(f"--- Imagen {i+1} ---")
|
63 |
+
print(f"Título: {imagen.get('title')}")
|
64 |
+
print(f"URL: {imagen.get('link')}")
|
65 |
+
print(f"URL Miniatura: {imagen.get('thumbnailLink')}")
|
66 |
+
print("-" * 20)
|
67 |
+
else:
|
68 |
+
print("No se encontraron imágenes o hubo un error.")
|
funciones/__pycache__/motion.cpython-311.pyc
ADDED
Binary file (2.18 kB). View file
|
|
funciones/motion.py
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import time
|
2 |
+
import subprocess
|
3 |
+
import herramientas
|
4 |
+
|
5 |
+
|
6 |
+
async def motion(imagen):
|
7 |
+
|
8 |
+
current_timestamp_int = int(time.time())
|
9 |
+
print("Ésto es current time stamp: ", current_timestamp_int)
|
10 |
+
|
11 |
+
print("Esto es imagen en monomotion: ", imagen)
|
12 |
+
|
13 |
+
ffmpeg_command = [
|
14 |
+
'ffmpeg', '-y',
|
15 |
+
'-loop', '1',
|
16 |
+
'-i',
|
17 |
+
f'{imagen}',
|
18 |
+
'-t', str(3),
|
19 |
+
'-vf',
|
20 |
+
f"scale=1280:720:force_original_aspect_ratio=increase,"
|
21 |
+
f"crop=1280:720,"
|
22 |
+
f"zoompan=z='zoom+0.0005':d=1500", #al zoom actual le vas a aumentar
|
23 |
+
'-r', str(25),
|
24 |
+
'-pix_fmt', 'yuv420p',
|
25 |
+
'-c:v', 'libx264',
|
26 |
+
'-preset', 'fast',
|
27 |
+
'-movflags', '+faststart', # Agregar esta línea
|
28 |
+
f'resultados/{current_timestamp_int}.mp4'
|
29 |
+
]
|
30 |
+
|
31 |
+
print("Comando:")
|
32 |
+
print(ffmpeg_command)
|
33 |
+
|
34 |
+
subprocess.run(ffmpeg_command, check=True)
|
35 |
+
|
36 |
+
return f'resultados/{current_timestamp_int}.mp4'
|
37 |
+
|
38 |
+
async def cinema(lista):
|
39 |
+
|
40 |
+
lista = herramientas.lista_archivos('media')
|
41 |
+
print("Ésto es lista:", lista)
|
42 |
+
|
43 |
+
for elemento in lista:
|
44 |
+
|
45 |
+
ffmpeg_command = [
|
46 |
+
'ffmpeg', '-y',
|
47 |
+
'-loop', '1',
|
48 |
+
'-i',
|
49 |
+
f'media/{elemento}',
|
50 |
+
'-t', str(3),
|
51 |
+
'-vf',
|
52 |
+
f"scale=1280:720:force_original_aspect_ratio=increase,"
|
53 |
+
f"crop=1280:720,"
|
54 |
+
f"zoompan=z='zoom+0.0005':d=1500", #al zoom actual le vas a aumentar
|
55 |
+
'-r', str(25),
|
56 |
+
'-pix_fmt', 'yuv420p',
|
57 |
+
'-c:v', 'libx264',
|
58 |
+
'-preset', 'fast',
|
59 |
+
'-movflags', '+faststart', # Agregar esta línea
|
60 |
+
f'resultados1/{elemento}.mp4'
|
61 |
+
]
|
62 |
+
|
63 |
+
print("Comando:")
|
64 |
+
print(ffmpeg_command)
|
65 |
+
|
66 |
+
subprocess.run(ffmpeg_command, check=True)
|
funciones_old.py
ADDED
@@ -0,0 +1,186 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import io
|
2 |
+
import time
|
3 |
+
import globales
|
4 |
+
import random
|
5 |
+
import herramientas
|
6 |
+
import gradio_client
|
7 |
+
from fastapi import HTTPException, status
|
8 |
+
from huggingface_hub import InferenceClient
|
9 |
+
|
10 |
+
|
11 |
+
servidor = globales.servidor
|
12 |
+
|
13 |
+
def procesa_dni(platillo):
|
14 |
+
|
15 |
+
print("Estoy en procesa DNI...")
|
16 |
+
|
17 |
+
print("Y esto es contents: ", platillo)
|
18 |
+
|
19 |
+
time.sleep(18)
|
20 |
+
|
21 |
+
prompt = globales.previo + platillo
|
22 |
+
print("Platillo enviado:", platillo)
|
23 |
+
|
24 |
+
try:
|
25 |
+
|
26 |
+
dict_espacios = conexion_firebase.obtenDato('nowme', servidor, 'espacios')
|
27 |
+
|
28 |
+
espacios_habilitados = [
|
29 |
+
nombre for nombre, config in dict_espacios.items()
|
30 |
+
if config.get("habilitado", False) # Usamos .get() para evitar KeyError si 'habilitado' no existe
|
31 |
+
]
|
32 |
+
|
33 |
+
print(f"Espacios habilitados: {espacios_habilitados}")
|
34 |
+
|
35 |
+
espacio_aleatorio_elegido = random.choice(espacios_habilitados)
|
36 |
+
configuracion_espacio = dict_espacios[espacio_aleatorio_elegido]
|
37 |
+
print(f"La configuración completa para '{espacio_aleatorio_elegido}' es: {configuracion_espacio}")
|
38 |
+
|
39 |
+
client = gradio_client.Client(configuracion_espacio['ruta'], hf_token=globales.llave)
|
40 |
+
#kwargs = selected_space_config['static_kwargs']
|
41 |
+
|
42 |
+
result = client.predict(
|
43 |
+
#**kwargs,
|
44 |
+
prompt=prompt,
|
45 |
+
#negative_prompt="live animals",
|
46 |
+
# seed=42,
|
47 |
+
# randomize_seed=True,
|
48 |
+
width=786,
|
49 |
+
height=568,
|
50 |
+
# guidance_scale=3.5,
|
51 |
+
# num_inference_steps=28,
|
52 |
+
api_name=configuracion_espacio['api_name']
|
53 |
+
)
|
54 |
+
|
55 |
+
#Cuando es GPU, debe de restar segundos disponibles de HF
|
56 |
+
herramientas.restaSegundosGPU(globales.work_cost)
|
57 |
+
|
58 |
+
print("Platillo generado:", platillo)
|
59 |
+
return result[0]
|
60 |
+
|
61 |
+
except Exception as e:
|
62 |
+
print("Excepción: ", e)
|
63 |
+
# Opción para regresar imagen genérica. (ya no porque se envía desde backend.)
|
64 |
+
# return "default.png"
|
65 |
+
raise HTTPException(
|
66 |
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
67 |
+
detail=e
|
68 |
+
)
|
69 |
+
|
70 |
+
def genera_platillo_gpu(platillo):
|
71 |
+
|
72 |
+
prompt = globales.previo + platillo
|
73 |
+
print("Platillo enviado:", platillo)
|
74 |
+
|
75 |
+
try:
|
76 |
+
|
77 |
+
dict_espacios = conexion_firebase.obtenDato('nowme', servidor, 'espacios')
|
78 |
+
|
79 |
+
espacios_habilitados = [
|
80 |
+
nombre for nombre, config in dict_espacios.items()
|
81 |
+
if config.get("habilitado", False) # Usamos .get() para evitar KeyError si 'habilitado' no existe
|
82 |
+
]
|
83 |
+
|
84 |
+
print(f"Espacios habilitados: {espacios_habilitados}")
|
85 |
+
|
86 |
+
espacio_aleatorio_elegido = random.choice(espacios_habilitados)
|
87 |
+
configuracion_espacio = dict_espacios[espacio_aleatorio_elegido]
|
88 |
+
print(f"La configuración completa para '{espacio_aleatorio_elegido}' es: {configuracion_espacio}")
|
89 |
+
|
90 |
+
client = gradio_client.Client(configuracion_espacio['ruta'], hf_token=globales.llave)
|
91 |
+
#kwargs = selected_space_config['static_kwargs']
|
92 |
+
|
93 |
+
result = client.predict(
|
94 |
+
#**kwargs,
|
95 |
+
prompt=prompt,
|
96 |
+
#negative_prompt="live animals",
|
97 |
+
# seed=42,
|
98 |
+
# randomize_seed=True,
|
99 |
+
width=786,
|
100 |
+
height=568,
|
101 |
+
# guidance_scale=3.5,
|
102 |
+
# num_inference_steps=28,
|
103 |
+
api_name=configuracion_espacio['api_name']
|
104 |
+
)
|
105 |
+
|
106 |
+
#Cuando es GPU, debe de restar segundos disponibles de HF
|
107 |
+
herramientas.restaSegundosGPU(globales.work_cost)
|
108 |
+
|
109 |
+
print("Platillo generado:", platillo)
|
110 |
+
return result[0]
|
111 |
+
|
112 |
+
except Exception as e:
|
113 |
+
print("Excepción: ", e)
|
114 |
+
# Opción para regresar imagen genérica. (ya no porque se envía desde backend.)
|
115 |
+
# return "default.png"
|
116 |
+
raise HTTPException(
|
117 |
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
118 |
+
detail=e
|
119 |
+
)
|
120 |
+
|
121 |
+
def genera_platillo_inference(platillo):
|
122 |
+
|
123 |
+
dict_modelos = conexion_firebase.obtenDato('nowme', servidor, 'modelos')
|
124 |
+
|
125 |
+
modelos_habilitados = [
|
126 |
+
nombre for nombre, config in dict_modelos.items()
|
127 |
+
if config.get("habilitado", False) # Usamos .get() para evitar KeyError si 'habilitado' no existe
|
128 |
+
]
|
129 |
+
|
130 |
+
print(f"Modelos habilitados: {modelos_habilitados}")
|
131 |
+
|
132 |
+
modelo_aleatorio_elegido = random.choice(modelos_habilitados)
|
133 |
+
configuracion_modelo = dict_modelos[modelo_aleatorio_elegido]
|
134 |
+
print(f"La configuración completa para '{modelo_aleatorio_elegido}' es: {configuracion_modelo}")
|
135 |
+
|
136 |
+
|
137 |
+
creditos_restantes_inference = conexion_firebase.obtenDato('nowme', servidor, 'inferencias')
|
138 |
+
|
139 |
+
#print("Los créditos restantes de hf-inference que tienes son: ", creditos_restantes_inference)
|
140 |
+
if creditos_restantes_inference > 0:
|
141 |
+
provedor_seleccionado = globales.proveedor
|
142 |
+
else:
|
143 |
+
provedor_seleccionado = globales.proveedor_back
|
144 |
+
|
145 |
+
prompt = globales.previo + platillo
|
146 |
+
print("Platillo enviado:", platillo)
|
147 |
+
|
148 |
+
client = InferenceClient(
|
149 |
+
provider= provedor_seleccionado,
|
150 |
+
model=configuracion_modelo['ruta'],
|
151 |
+
api_key=globales.llave
|
152 |
+
)
|
153 |
+
|
154 |
+
print("Cree cliente: ", client)
|
155 |
+
time.sleep(0)
|
156 |
+
|
157 |
+
try:
|
158 |
+
image = client.text_to_image(
|
159 |
+
prompt,
|
160 |
+
#negative_prompt="live animals",
|
161 |
+
width=784, #786
|
162 |
+
height=560, #568
|
163 |
+
num_inference_steps=16
|
164 |
+
)
|
165 |
+
|
166 |
+
#Detenido momentaneamente por cambio a firebase.
|
167 |
+
herramientas.restaSegundosInference(globales.inference_cost)
|
168 |
+
|
169 |
+
except Exception as e:
|
170 |
+
print("Excepción: ", e)
|
171 |
+
if "Gateway Time-out" in str(e):
|
172 |
+
print("GATEWAY TIME-OUT 💀")
|
173 |
+
#modelo=globales.inferencia_backup #Con el nuevo paradigma ya no hay cambio de modelo.
|
174 |
+
#Escribe en txt el nuevo modelo.
|
175 |
+
#herramientas.modificaModeloActual(modelo)
|
176 |
+
error_impreso = f"Error: {e}"
|
177 |
+
print(error_impreso)
|
178 |
+
raise HTTPException(
|
179 |
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
180 |
+
)
|
181 |
+
|
182 |
+
img_io = io.BytesIO()
|
183 |
+
image.save(img_io, "PNG")
|
184 |
+
img_io.seek(0)
|
185 |
+
print("Platillo generado:", platillo)
|
186 |
+
return img_io
|
guardaImagenes.py
ADDED
@@ -0,0 +1,74 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from googleapiclient.discovery import build
|
2 |
+
import bridges
|
3 |
+
import time
|
4 |
+
|
5 |
+
# --- Configura tus credenciales y ID de Motor de Búsqueda ---
|
6 |
+
API_KEY = bridges.google_api # Reemplaza con tu Clave de API de Google Cloud
|
7 |
+
CX = "90556d12415d84063" # Reemplaza con el ID de tu Custom Search Engine
|
8 |
+
|
9 |
+
def buscar_imagenes_google(query, num_results=5):
|
10 |
+
"""
|
11 |
+
Realiza una búsqueda de imágenes en Google usando la Custom Search API.
|
12 |
+
|
13 |
+
Args:
|
14 |
+
query (str): El término de búsqueda.
|
15 |
+
num_results (int): El número máximo de resultados a devolver (máx. 10 por solicitud).
|
16 |
+
|
17 |
+
Returns:
|
18 |
+
list: Una lista de diccionarios, donde cada diccionario representa una imagen
|
19 |
+
y contiene su URL, título, etc.
|
20 |
+
"""
|
21 |
+
try:
|
22 |
+
# Construye el servicio de la API de Custom Search
|
23 |
+
# 'customsearch' es el nombre del servicio, 'v1' es la versión
|
24 |
+
service = build("customsearch", "v1", developerKey=API_KEY)
|
25 |
+
|
26 |
+
# Ejecuta la búsqueda.
|
27 |
+
# 'q': el término de búsqueda
|
28 |
+
# 'cx': el ID de tu Custom Search Engine
|
29 |
+
# 'searchType': MUY IMPORTANTE, para especificar que buscas imágenes
|
30 |
+
# 'num': número de resultados (máx. 10 por solicitud, aunque puedes paginar)
|
31 |
+
res = service.cse().list(
|
32 |
+
q=query,
|
33 |
+
cx=CX,
|
34 |
+
searchType='image',
|
35 |
+
num=num_results
|
36 |
+
).execute()
|
37 |
+
|
38 |
+
print("Esto es res:")
|
39 |
+
print(res)
|
40 |
+
time.sleep(18)
|
41 |
+
|
42 |
+
# Extrae los resultados
|
43 |
+
items = res.get('items', [])
|
44 |
+
|
45 |
+
resultados_imagenes = []
|
46 |
+
for item in items:
|
47 |
+
resultados_imagenes.append({
|
48 |
+
'title': item.get('title'),
|
49 |
+
'link': item.get('link'), # URL directa de la imagen
|
50 |
+
'displayLink': item.get('displayLink'), # URL del sitio donde se encontró
|
51 |
+
'thumbnailLink': item['image'].get('thumbnailLink') if 'image' in item else None # URL de la miniatura
|
52 |
+
})
|
53 |
+
|
54 |
+
return resultados_imagenes
|
55 |
+
|
56 |
+
except Exception as e:
|
57 |
+
print(f"Ocurrió un error: {e}")
|
58 |
+
return []
|
59 |
+
|
60 |
+
# --- Ejemplo de uso ---
|
61 |
+
if __name__ == "__main__":
|
62 |
+
termino_busqueda = "Mexico Day of the Dead"
|
63 |
+
imagenes_encontradas = buscar_imagenes_google(termino_busqueda, num_results=3)
|
64 |
+
|
65 |
+
if imagenes_encontradas:
|
66 |
+
print(f"Imágenes encontradas para '{termino_busqueda}':")
|
67 |
+
for i, imagen in enumerate(imagenes_encontradas):
|
68 |
+
print(f"--- Imagen {i+1} ---")
|
69 |
+
print(f"Título: {imagen.get('title')}")
|
70 |
+
print(f"URL: {imagen.get('link')}")
|
71 |
+
print(f"URL Miniatura: {imagen.get('thumbnailLink')}")
|
72 |
+
print("-" * 20)
|
73 |
+
else:
|
74 |
+
print("No se encontraron imágenes o hubo un error.")
|
herramientas.py
ADDED
@@ -0,0 +1,46 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
def lista_archivos(directorio):
|
4 |
+
nombres_archivos = [] # Inicializamos una lista vacía para guardar los nombres
|
5 |
+
|
6 |
+
try:
|
7 |
+
# Verificar si la carpeta existe
|
8 |
+
if os.path.exists(directorio) and os.path.isdir(directorio):
|
9 |
+
# Listar todos los elementos dentro de la carpeta
|
10 |
+
elementos = os.listdir(directorio)
|
11 |
+
|
12 |
+
print(f"Archivos encontrados en la carpeta '{directorio}':")
|
13 |
+
for elemento in elementos:
|
14 |
+
ruta_completa = os.path.join(directorio, elemento)
|
15 |
+
# Verificar si el elemento es un archivo
|
16 |
+
if os.path.isfile(ruta_completa):
|
17 |
+
nombres_archivos.append(elemento) # Añadir el nombre del archivo a la lista
|
18 |
+
print(elemento) # Opcional: imprimir el nombre mientras se guarda
|
19 |
+
|
20 |
+
print("\nLista de nombres de archivos guardada en la variable 'nombres_archivos'.")
|
21 |
+
# Ahora la variable 'nombres_archivos' contiene todos los nombres de los archivos
|
22 |
+
# que puedes usar en el resto de tu código.
|
23 |
+
# Ejemplo de cómo podrías acceder a los nombres:
|
24 |
+
# for nombre in nombres_archivos:
|
25 |
+
# print(f"Procesando archivo: {nombre}")
|
26 |
+
|
27 |
+
return nombres_archivos
|
28 |
+
|
29 |
+
else:
|
30 |
+
print(f"La carpeta '{directorio}' no existe o no es un directorio.")
|
31 |
+
nombres_archivos = [] # Asegurarse de que la lista esté vacía en caso de error
|
32 |
+
return nombres_archivos
|
33 |
+
|
34 |
+
except Exception as e:
|
35 |
+
print(f"Ocurrió un error al acceder a la carpeta: {e}")
|
36 |
+
nombres_archivos = [] # Asegurarse de que la lista esté vacía en caso de error
|
37 |
+
return nombres_archivos
|
38 |
+
|
39 |
+
def delete_file_on_complete(path: str):
|
40 |
+
"""Callback para borrar un archivo después de que la respuesta se haya enviado."""
|
41 |
+
if os.path.exists(path):
|
42 |
+
try:
|
43 |
+
os.remove(path)
|
44 |
+
print(f"Archivo eliminado correctamente en BackgroundTasks: {path}")
|
45 |
+
except Exception as e:
|
46 |
+
print(f"ERROR: No se pudo eliminar el archivo {path} en BackgroundTasks: {e}")
|
requirements.txt
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
openai
|
2 |
+
datasets
|
3 |
+
openai[voice_helpers]
|
4 |
+
transformers
|
5 |
+
torch
|
6 |
+
soundfile
|
7 |
+
sentencepiece
|
8 |
+
#melo.api
|
9 |
+
google-api-python-client
|
10 |
+
fastapi
|
run.py
DELETED
@@ -1,19 +0,0 @@
|
|
1 |
-
import subprocess
|
2 |
-
|
3 |
-
ffmpeg_command = [
|
4 |
-
'ffmpeg', '-y',
|
5 |
-
'-loop', '1',
|
6 |
-
'-i', 'media/tp.jpg',
|
7 |
-
'-t', str(3),
|
8 |
-
'-vf',
|
9 |
-
# f"scale=16:9:force_original_aspect_ratio=increase,"
|
10 |
-
# f"crop=16:9,"
|
11 |
-
f"zoompan=z='zoom+0.0005':d=25*60",
|
12 |
-
'-r', str(25),
|
13 |
-
'-pix_fmt', 'yuv420p',
|
14 |
-
'-c:v', 'libx264',
|
15 |
-
'-preset', 'fast',
|
16 |
-
'resultados/resultado.mp4'
|
17 |
-
]
|
18 |
-
|
19 |
-
subprocess.run(ffmpeg_command, check=True)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
stitcher.py
ADDED
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import subprocess
|
2 |
+
import herramientas
|
3 |
+
import os
|
4 |
+
|
5 |
+
def remux_video(input_path, output_path):
|
6 |
+
"""Re-muxea un archivo de video MP4."""
|
7 |
+
ffmpeg_command_remux = [
|
8 |
+
'ffmpeg',
|
9 |
+
'-i', input_path,
|
10 |
+
'-c', 'copy',
|
11 |
+
'-movflags', '+faststart',
|
12 |
+
output_path
|
13 |
+
]
|
14 |
+
try:
|
15 |
+
subprocess.run(ffmpeg_command_remux, check=True, capture_output=True)
|
16 |
+
print(f"Re-muxing exitoso de: {input_path} a {output_path}")
|
17 |
+
return True
|
18 |
+
except subprocess.CalledProcessError as e:
|
19 |
+
print(f"Error al re-muxear {input_path}: {e}")
|
20 |
+
print(f"Salida de error de FFmpeg:\n{e.stderr.decode()}")
|
21 |
+
return False
|
22 |
+
except Exception as e:
|
23 |
+
print(f"Ocurrió un error durante el re-muxing: {e}")
|
24 |
+
return False
|
25 |
+
|
26 |
+
def unirVideos():
|
27 |
+
|
28 |
+
directorio_videos = 'resultados'
|
29 |
+
lista_nombres_archivos = herramientas.lista_archivos(directorio_videos)
|
30 |
+
archivos_remuxeados = []
|
31 |
+
lista_archivo_temporal = 'lista_concat.txt'
|
32 |
+
|
33 |
+
try:
|
34 |
+
with open(lista_archivo_temporal, 'w') as f_lista:
|
35 |
+
for nombre_archivo in lista_nombres_archivos:
|
36 |
+
ruta_completa = os.path.join(directorio_videos, nombre_archivo)
|
37 |
+
nombre_base, extension = os.path.splitext(nombre_archivo)
|
38 |
+
ruta_temporal = os.path.join(directorio_videos, f"temp_{nombre_base}{extension}")
|
39 |
+
if remux_video(ruta_completa, ruta_temporal):
|
40 |
+
archivos_remuxeados.append(ruta_temporal)
|
41 |
+
f_lista.write(f"file '{ruta_temporal}'\n")
|
42 |
+
else:
|
43 |
+
print("Error al re-muxear un archivo. Abortando la creación de la lista.")
|
44 |
+
archivos_remuxeados = []
|
45 |
+
break
|
46 |
+
except FileNotFoundError as e:
|
47 |
+
print(f"Error al abrir o crear el archivo de lista temporal: {e}")
|
48 |
+
archivos_remuxeados = []
|
49 |
+
except Exception as e:
|
50 |
+
print(f"Ocurrió un error al escribir en el archivo de lista temporal: {e}")
|
51 |
+
archivos_remuxeados = []
|
52 |
+
|
53 |
+
if archivos_remuxeados:
|
54 |
+
ffmpeg_command_concat = [
|
55 |
+
'ffmpeg',
|
56 |
+
'-f', 'concat',
|
57 |
+
'-safe', '0',
|
58 |
+
'-i', lista_archivo_temporal,
|
59 |
+
'-an',
|
60 |
+
'-c', 'copy',
|
61 |
+
'video_unido_sin_audio.mp4'
|
62 |
+
]
|
63 |
+
|
64 |
+
try:
|
65 |
+
subprocess.run(ffmpeg_command_concat, check=True, capture_output=True)
|
66 |
+
print("Los videos se han unido exitosamente (usando archivo de lista y archivos remuxeados).")
|
67 |
+
except subprocess.CalledProcessError as e:
|
68 |
+
print(f"Error al ejecutar FFmpeg para concatenar (archivo de lista): {e}")
|
69 |
+
print(f"Salida de error de FFmpeg:\n{e.stderr.decode()}")
|
70 |
+
except Exception as e:
|
71 |
+
print(f"Ocurrió un error durante la concatenación (archivo de lista): {e}")
|
72 |
+
finally:
|
73 |
+
# Limpiar los archivos temporales y el archivo de lista
|
74 |
+
for archivo_temporal in archivos_remuxeados:
|
75 |
+
try:
|
76 |
+
os.remove(archivo_temporal)
|
77 |
+
print(f"Archivo temporal eliminado: {archivo_temporal}")
|
78 |
+
except OSError as e:
|
79 |
+
print(f"Error al eliminar el archivo temporal {archivo_temporal}: {e}")
|
80 |
+
try:
|
81 |
+
os.remove(lista_archivo_temporal)
|
82 |
+
print(f"Archivo de lista eliminado: {lista_archivo_temporal}")
|
83 |
+
except OSError as e:
|
84 |
+
print(f"Error al eliminar el archivo de lista {lista_archivo_temporal}: {e}")
|
85 |
+
else:
|
86 |
+
print("No se pudieron re-muxear los archivos o hubo un error al crear la lista, no se intentó la concatenación.")
|
test.py
ADDED
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import herramientas
|
2 |
+
import stitcher
|
3 |
+
|
4 |
+
resultado = herramientas.lista_archivos('resultados')
|
5 |
+
print("Ésta es la lista de nombres 182: ", resultado)
|
6 |
+
|
7 |
+
stitcher.unirVideos()
|