Moibe commited on
Commit
993fe8a
·
1 Parent(s): 9cb9b46
.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()