Moibe commited on
Commit
153e3fb
·
1 Parent(s): 7f5084c
Files changed (3) hide show
  1. app.py +8 -216
  2. main.py +220 -0
  3. requirements.txt +2 -1
app.py CHANGED
@@ -1,220 +1,12 @@
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("/echo-video/",
36
- tags=["Monitoreo Server"],
37
- description="Test endpoint para prueba de envío de videos. Recibe un video y lo devuelve tal cual.",
38
- summary="Mirror test para envío de videos"
39
- )
40
- async def echo_video(video: UploadFile = File(...)):
41
- """
42
- Recibe un archivo de video y lo devuelve sin modificaciones.
43
- Útil para probar la conectividad y el manejo de archivos de video en la API.
44
- """
45
- # Validar que el archivo subido es un video
46
- if not video.content_type.startswith("video/"):
47
- raise HTTPException(
48
- status_code=status.HTTP_400_BAD_REQUEST,
49
- detail="El archivo no es un video. Por favor, suba un archivo de video."
50
- )
51
-
52
- try:
53
- # Lee el contenido binario del video
54
- contents = await video.read()
55
-
56
- # Envuelve los bytes en un buffer en memoria
57
- buffer = BytesIO(contents)
58
- buffer.seek(0) # Asegúrate de que el puntero esté al inicio para la lectura
59
-
60
- # Devuelve el video utilizando StreamingResponse con el tipo MIME correcto
61
- return StreamingResponse(buffer, media_type=video.content_type)
62
-
63
- except Exception as e:
64
- # Captura cualquier error inesperado durante la lectura o la respuesta
65
- print(f"Error inesperado en /echo-video/: {e}")
66
- raise HTTPException(
67
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
68
- detail="Ha ocurrido un error inesperado al procesar el video."
69
- )
70
-
71
-
72
- @app.post("/motion-image/")
73
- async def motion_image(image: UploadFile = File(...), background_tasks: BackgroundTasks = BackgroundTasks()):
74
- """
75
- Recibe una imagen, la procesa con motion(), le da movimiento y devuelve el resultado.
76
- """
77
- if not image.content_type.startswith("image/"):
78
- raise HTTPException(
79
- status_code=status.HTTP_400_BAD_REQUEST,
80
- detail="El archivo no es una imagen. Por favor, suba una imagen."
81
- )
82
-
83
- temp_image_path = None # Inicializamos la variable para el bloque finally
84
- output_file_generated = False # Flag para saber si monomotion generó un archivo
85
-
86
- try:
87
- # 1. Guardar la imagen subida en un archivo temporal
88
- with tempfile.NamedTemporaryFile(delete=False, suffix=f"_{image.filename}") as tmp_file:
89
- contents = await image.read()
90
- tmp_file.write(contents)
91
- temp_image_path = tmp_file.name
92
-
93
- print(f"Imagen subida guardada temporalmente en: {temp_image_path}")
94
-
95
- # 2. Ejecutar motion()
96
- # Asumimos que motion devuelve la ruta a un archivo de salida
97
- path_archivo = await motion.motion(temp_image_path)
98
- print("Salí de monomotion con resultado: ", path_archivo)
99
- output_file_generated = True # Si llegamos aquí, asumimos que se generó un archivo
100
-
101
- # 3. Determinar el tipo MIME del archivo de salida (si es diferente al de entrada)
102
- # Esto es importante si motion cambia el formato (ej. de JPG a MP4)
103
- import mimetypes
104
- mimetypes.add_type("video/mp4", ".mp4") # Asegúrate de añadir tipos si esperas video
105
- mime_type, _ = mimetypes.guess_type(path_archivo)
106
- print("Myme type es: ", mime_type)
107
- if not mime_type:
108
- print("Entró a not mime_type")
109
- mime_type = "application/octet-stream" # Tipo genérico si no se puede adivinar
110
-
111
- # 4.5 Programar la eliminación de AMBOS archivos después de que la respuesta sea enviada
112
- # El archivo de entrada se borrará sí o sí.
113
- background_tasks.add_task(herramientas.delete_file_on_complete, temp_image_path)
114
- # El archivo de salida también se borrará, asumiendo que es temporal y solo para esta respuesta.
115
- background_tasks.add_task(herramientas.delete_file_on_complete, path_archivo)
116
-
117
- # 4. Devolver el archivo procesado al cliente
118
- return FileResponse(
119
- path=path_archivo,
120
- media_type=mime_type,
121
- filename=os.path.basename(path_archivo)
122
- )
123
-
124
- except HTTPException:
125
- # Re-lanza cualquier HTTPException ya creada (ej. el 400 inicial)
126
- raise
127
- except Exception as e:
128
- # Captura cualquier otro error inesperado durante el proceso
129
- print(f"Error inesperado en /generate-monomotion-image/: {e}")
130
- raise HTTPException(
131
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
132
- detail=f"Ha ocurrido un error interno al procesar la imagen con monomotion: {e}"
133
- )
134
- finally:
135
- # 5. Limpieza: Eliminar archivos temporales
136
- # Eliminar la imagen de entrada temporal
137
- if temp_image_path and os.path.exists(temp_image_path):
138
- try:
139
- os.remove(temp_image_path)
140
- print(f"Archivo temporal de entrada eliminado: {temp_image_path}")
141
- except Exception as cleanup_e:
142
- print(f"Error al eliminar el archivo temporal de entrada {temp_image_path}: {cleanup_e}")
143
-
144
- @app.post("/echo-random-file/")
145
- async def echo_random_file(files: List[UploadFile] = File(...)):
146
- """
147
- Recibe múltiples archivos, selecciona uno al azar y lo devuelve.
148
- """
149
- if not files:
150
- raise HTTPException(
151
- status_code=status.HTTP_400_BAD_REQUEST,
152
- detail="No se enviaron archivos."
153
- )
154
 
155
- temp_file_paths = [] # Lista para guardar las rutas de los archivos temporales
156
- try:
157
- # 1. Guardar cada UploadFile en un archivo temporal en disco
158
- for uploaded_file in files:
159
- # Creamos un archivo temporal con un sufijo para mantener la extensión
160
- # delete=False para que no se elimine inmediatamente al cerrar el archivo.
161
- # Lo eliminaremos explícitamente en el bloque finally.
162
- with tempfile.NamedTemporaryFile(delete=False, suffix=f"_{uploaded_file.filename}") as tmp_file:
163
- contents = await uploaded_file.read()
164
- tmp_file.write(contents)
165
- current_temp_path = tmp_file.name
166
- temp_file_paths.append(current_temp_path)
167
- print(f"Guardado temporalmente: {current_temp_path}")
168
-
169
- # 2. Pasar la lista de rutas de archivos temporales a tu función 'cinema'
170
- # ¡Ahora 'lista_rutas_archivos' es la "lista" que tu función cinema espera!
171
- resultado_cinema = await motion.cinema(temp_file_paths)
172
-
173
- print("182.- Resultado es: ", resultado_cinema)
174
- print("Y su tipo es: ", type(resultado_cinema))
175
-
176
- # 3. Manejar el resultado de la función 'cinema'
177
- if isinstance(resultado_cinema, str):
178
- # Si cinema devuelve una ruta a un archivo (ej. un video generado)
179
- # Determinar el tipo MIME del archivo de salida
180
- import mimetypes
181
- mime_type, _ = mimetypes.guess_type(resultado_cinema)
182
- if not mime_type:
183
- mime_type = "application/octet-stream" # Tipo genérico si no se puede adivinar
184
 
185
- # Devolver el archivo generado por cinema
186
- # Asegúrate de que este archivo también se gestione y elimine si es temporal
187
- return FileResponse(
188
- path=resultado_cinema,
189
- media_type=mime_type,
190
- filename=os.path.basename(resultado_cinema)
191
- )
192
- elif isinstance(resultado_cinema, dict) and "error" in resultado_cinema:
193
- # Si cinema devuelve un diccionario de error
194
- raise HTTPException(
195
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
196
- detail=f"Error en la función cinema: {resultado_cinema['error']}"
197
- )
198
- else:
199
- # Si cinema devuelve otra cosa (ej. un JSON de éxito sin archivo)
200
- return resultado_cinema # Asume que es un diccionario JSON serializable
201
 
202
- except HTTPException:
203
- # Re-lanza cualquier HTTPException que ya se haya levantado (ej. por validación de entrada)
204
- raise
205
- except Exception as e:
206
- # Captura cualquier otro error inesperado
207
- print(f"Error inesperado en /process-files-with-cinema/: {e}")
208
- raise HTTPException(
209
- status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
210
- detail=f"Ha ocurrido un error interno al procesar los archivos con cinema: {e}"
211
- )
212
- finally:
213
- # 4. Limpiar los archivos temporales creados
214
- for path in temp_file_paths:
215
- if os.path.exists(path):
216
- try:
217
- #os.remove(path)
218
- print(f"Archivo temporal eliminado: {path}")
219
- except Exception as cleanup_e:
220
- print(f"Error al eliminar el archivo temporal {path}: {cleanup_e}")
 
1
+ import gradio as gr
2
+ import funciones.motion
 
 
 
 
 
 
 
3
 
4
+ async def sepia(input_img):
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5
 
6
+ print("Hola")
7
+ resultado = await funciones.motion.motion(input_img)
8
+ return resultado
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
+ demo = gr.Interface(sepia, gr.Image(type='filepath'), gr.Video())
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
+ demo.launch()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
main.py ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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("/echo-video/",
36
+ tags=["Monitoreo Server"],
37
+ description="Test endpoint para prueba de envío de videos. Recibe un video y lo devuelve tal cual.",
38
+ summary="Mirror test para envío de videos"
39
+ )
40
+ async def echo_video(video: UploadFile = File(...)):
41
+ """
42
+ Recibe un archivo de video y lo devuelve sin modificaciones.
43
+ Útil para probar la conectividad y el manejo de archivos de video en la API.
44
+ """
45
+ # Validar que el archivo subido es un video
46
+ if not video.content_type.startswith("video/"):
47
+ raise HTTPException(
48
+ status_code=status.HTTP_400_BAD_REQUEST,
49
+ detail="El archivo no es un video. Por favor, suba un archivo de video."
50
+ )
51
+
52
+ try:
53
+ # Lee el contenido binario del video
54
+ contents = await video.read()
55
+
56
+ # Envuelve los bytes en un buffer en memoria
57
+ buffer = BytesIO(contents)
58
+ buffer.seek(0) # Asegúrate de que el puntero esté al inicio para la lectura
59
+
60
+ # Devuelve el video utilizando StreamingResponse con el tipo MIME correcto
61
+ return StreamingResponse(buffer, media_type=video.content_type)
62
+
63
+ except Exception as e:
64
+ # Captura cualquier error inesperado durante la lectura o la respuesta
65
+ print(f"Error inesperado en /echo-video/: {e}")
66
+ raise HTTPException(
67
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
68
+ detail="Ha ocurrido un error inesperado al procesar el video."
69
+ )
70
+
71
+
72
+ @app.post("/motion-image/")
73
+ async def motion_image(image: UploadFile = File(...), background_tasks: BackgroundTasks = BackgroundTasks()):
74
+ """
75
+ Recibe una imagen, la procesa con motion(), le da movimiento y devuelve el resultado.
76
+ """
77
+ if not image.content_type.startswith("image/"):
78
+ raise HTTPException(
79
+ status_code=status.HTTP_400_BAD_REQUEST,
80
+ detail="El archivo no es una imagen. Por favor, suba una imagen."
81
+ )
82
+
83
+ temp_image_path = None # Inicializamos la variable para el bloque finally
84
+ output_file_generated = False # Flag para saber si monomotion generó un archivo
85
+
86
+ try:
87
+ # 1. Guardar la imagen subida en un archivo temporal
88
+ with tempfile.NamedTemporaryFile(delete=False, suffix=f"_{image.filename}") as tmp_file:
89
+ contents = await image.read()
90
+ tmp_file.write(contents)
91
+ temp_image_path = tmp_file.name
92
+
93
+ print(f"Imagen subida guardada temporalmente en: {temp_image_path}")
94
+
95
+ # 2. Ejecutar motion()
96
+ # Asumimos que motion devuelve la ruta a un archivo de salida
97
+ path_archivo = await motion.motion(temp_image_path)
98
+ print("Salí de monomotion con resultado: ", path_archivo)
99
+ output_file_generated = True # Si llegamos aquí, asumimos que se generó un archivo
100
+
101
+ # 3. Determinar el tipo MIME del archivo de salida (si es diferente al de entrada)
102
+ # Esto es importante si motion cambia el formato (ej. de JPG a MP4)
103
+ import mimetypes
104
+ mimetypes.add_type("video/mp4", ".mp4") # Asegúrate de añadir tipos si esperas video
105
+ mime_type, _ = mimetypes.guess_type(path_archivo)
106
+ print("Myme type es: ", mime_type)
107
+ if not mime_type:
108
+ print("Entró a not mime_type")
109
+ mime_type = "application/octet-stream" # Tipo genérico si no se puede adivinar
110
+
111
+ # 4.5 Programar la eliminación de AMBOS archivos después de que la respuesta sea enviada
112
+ # El archivo de entrada se borrará sí o sí.
113
+ background_tasks.add_task(herramientas.delete_file_on_complete, temp_image_path)
114
+ # El archivo de salida también se borrará, asumiendo que es temporal y solo para esta respuesta.
115
+ background_tasks.add_task(herramientas.delete_file_on_complete, path_archivo)
116
+
117
+ # 4. Devolver el archivo procesado al cliente
118
+ return FileResponse(
119
+ path=path_archivo,
120
+ media_type=mime_type,
121
+ filename=os.path.basename(path_archivo)
122
+ )
123
+
124
+ except HTTPException:
125
+ # Re-lanza cualquier HTTPException ya creada (ej. el 400 inicial)
126
+ raise
127
+ except Exception as e:
128
+ # Captura cualquier otro error inesperado durante el proceso
129
+ print(f"Error inesperado en /generate-monomotion-image/: {e}")
130
+ raise HTTPException(
131
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
132
+ detail=f"Ha ocurrido un error interno al procesar la imagen con monomotion: {e}"
133
+ )
134
+ finally:
135
+ # 5. Limpieza: Eliminar archivos temporales
136
+ # Eliminar la imagen de entrada temporal
137
+ if temp_image_path and os.path.exists(temp_image_path):
138
+ try:
139
+ os.remove(temp_image_path)
140
+ print(f"Archivo temporal de entrada eliminado: {temp_image_path}")
141
+ except Exception as cleanup_e:
142
+ print(f"Error al eliminar el archivo temporal de entrada {temp_image_path}: {cleanup_e}")
143
+
144
+ @app.post("/echo-random-file/")
145
+ async def echo_random_file(files: List[UploadFile] = File(...)):
146
+ """
147
+ Recibe múltiples archivos, selecciona uno al azar y lo devuelve.
148
+ """
149
+ if not files:
150
+ raise HTTPException(
151
+ status_code=status.HTTP_400_BAD_REQUEST,
152
+ detail="No se enviaron archivos."
153
+ )
154
+
155
+ temp_file_paths = [] # Lista para guardar las rutas de los archivos temporales
156
+ try:
157
+ # 1. Guardar cada UploadFile en un archivo temporal en disco
158
+ for uploaded_file in files:
159
+ # Creamos un archivo temporal con un sufijo para mantener la extensión
160
+ # delete=False para que no se elimine inmediatamente al cerrar el archivo.
161
+ # Lo eliminaremos explícitamente en el bloque finally.
162
+ with tempfile.NamedTemporaryFile(delete=False, suffix=f"_{uploaded_file.filename}") as tmp_file:
163
+ contents = await uploaded_file.read()
164
+ tmp_file.write(contents)
165
+ current_temp_path = tmp_file.name
166
+ temp_file_paths.append(current_temp_path)
167
+ print(f"Guardado temporalmente: {current_temp_path}")
168
+
169
+ # 2. Pasar la lista de rutas de archivos temporales a tu función 'cinema'
170
+ # ¡Ahora 'lista_rutas_archivos' es la "lista" que tu función cinema espera!
171
+ resultado_cinema = await motion.cinema(temp_file_paths)
172
+
173
+ print("182.- Resultado es: ", resultado_cinema)
174
+ print("Y su tipo es: ", type(resultado_cinema))
175
+
176
+ # 3. Manejar el resultado de la función 'cinema'
177
+ if isinstance(resultado_cinema, str):
178
+ # Si cinema devuelve una ruta a un archivo (ej. un video generado)
179
+ # Determinar el tipo MIME del archivo de salida
180
+ import mimetypes
181
+ mime_type, _ = mimetypes.guess_type(resultado_cinema)
182
+ if not mime_type:
183
+ mime_type = "application/octet-stream" # Tipo genérico si no se puede adivinar
184
+
185
+ # Devolver el archivo generado por cinema
186
+ # Asegúrate de que este archivo también se gestione y elimine si es temporal
187
+ return FileResponse(
188
+ path=resultado_cinema,
189
+ media_type=mime_type,
190
+ filename=os.path.basename(resultado_cinema)
191
+ )
192
+ elif isinstance(resultado_cinema, dict) and "error" in resultado_cinema:
193
+ # Si cinema devuelve un diccionario de error
194
+ raise HTTPException(
195
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
196
+ detail=f"Error en la función cinema: {resultado_cinema['error']}"
197
+ )
198
+ else:
199
+ # Si cinema devuelve otra cosa (ej. un JSON de éxito sin archivo)
200
+ return resultado_cinema # Asume que es un diccionario JSON serializable
201
+
202
+ except HTTPException:
203
+ # Re-lanza cualquier HTTPException que ya se haya levantado (ej. por validación de entrada)
204
+ raise
205
+ except Exception as e:
206
+ # Captura cualquier otro error inesperado
207
+ print(f"Error inesperado en /process-files-with-cinema/: {e}")
208
+ raise HTTPException(
209
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
210
+ detail=f"Ha ocurrido un error interno al procesar los archivos con cinema: {e}"
211
+ )
212
+ finally:
213
+ # 4. Limpiar los archivos temporales creados
214
+ for path in temp_file_paths:
215
+ if os.path.exists(path):
216
+ try:
217
+ #os.remove(path)
218
+ print(f"Archivo temporal eliminado: {path}")
219
+ except Exception as cleanup_e:
220
+ print(f"Error al eliminar el archivo temporal {path}: {cleanup_e}")
requirements.txt CHANGED
@@ -10,4 +10,5 @@ google-api-python-client
10
  fastapi
11
  uvicorn
12
  python-multipart
13
- ffmpy
 
 
10
  fastapi
11
  uvicorn
12
  python-multipart
13
+ ffmpy
14
+ gradio