Hjgugugjhuhjggg commited on
Commit
2058dee
1 Parent(s): f7ca3aa

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +184 -95
app.py CHANGED
@@ -1,15 +1,18 @@
1
  import os
2
  import json
 
 
3
  import threading
4
  import logging
5
- from google.cloud import storage
6
- from transformers import AutoModelForCausalLM, AutoTokenizer, pipeline
7
- from pydantic import BaseModel
8
  from fastapi import FastAPI, HTTPException
9
- import requests
10
- import uvicorn
 
 
11
  from dotenv import load_dotenv
 
12
 
 
13
  load_dotenv()
14
 
15
  API_KEY = os.getenv("API_KEY")
@@ -17,12 +20,19 @@ GCS_BUCKET_NAME = os.getenv("GCS_BUCKET_NAME")
17
  GOOGLE_APPLICATION_CREDENTIALS_JSON = os.getenv("GOOGLE_APPLICATION_CREDENTIALS_JSON")
18
  HF_API_TOKEN = os.getenv("HF_API_TOKEN")
19
 
 
20
  logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
21
  logger = logging.getLogger(__name__)
22
 
23
- credentials_info = json.loads(GOOGLE_APPLICATION_CREDENTIALS_JSON)
24
- storage_client = storage.Client.from_service_account_info(credentials_info)
25
- bucket = storage_client.bucket(GCS_BUCKET_NAME)
 
 
 
 
 
 
26
 
27
  app = FastAPI()
28
 
@@ -36,120 +46,199 @@ class GCSHandler:
36
  self.bucket = storage_client.bucket(bucket_name)
37
 
38
  def file_exists(self, blob_name):
39
- return self.bucket.blob(blob_name).exists()
40
-
41
- def create_folder_if_not_exists(self, folder_name):
42
- if not self.file_exists(folder_name):
43
- self.bucket.blob(folder_name + "/").upload_from_string("")
44
 
45
  def upload_file(self, blob_name, file_stream):
46
- self.create_folder_if_not_exists(os.path.dirname(blob_name))
47
  blob = self.bucket.blob(blob_name)
48
- blob.upload_from_file(file_stream)
 
 
 
 
 
49
 
50
  def download_file(self, blob_name):
51
  blob = self.bucket.blob(blob_name)
52
  if not blob.exists():
 
53
  raise HTTPException(status_code=404, detail=f"File '{blob_name}' not found.")
54
- return blob.open("rb")
 
55
 
56
  def generate_signed_url(self, blob_name, expiration=3600):
57
  blob = self.bucket.blob(blob_name)
58
- return blob.generate_signed_url(expiration=expiration)
 
 
59
 
60
  def download_model_from_huggingface(model_name):
61
  url = f"https://huggingface.co/{model_name}/tree/main"
62
  headers = {"Authorization": f"Bearer {HF_API_TOKEN}"}
63
- response = requests.get(url, headers=headers)
64
- if response.status_code == 200:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  model_files = [
66
  "pytorch_model.bin",
67
  "config.json",
68
  "tokenizer.json",
69
  "model.safetensors",
70
  ]
71
- for file_name in model_files:
72
- file_url = f"https://huggingface.co/{model_name}/resolve/main/{file_name}"
73
- file_content = requests.get(file_url).content
74
- blob_name = f"models/{model_name}/{file_name}"
75
- bucket.blob(blob_name).upload_from_string(file_content)
76
- else:
77
- raise HTTPException(status_code=404, detail="Error accessing Hugging Face model files.")
78
-
79
- def download_and_verify_model(model_name):
80
- model_files = [
81
- "pytorch_model.bin",
82
- "config.json",
83
- "tokenizer.json",
84
- "model.safetensors",
85
- ]
86
- gcs_handler = GCSHandler(GCS_BUCKET_NAME)
87
- if not all(gcs_handler.file_exists(f"models/{model_name}/{file}") for file in model_files):
88
- download_model_from_huggingface(model_name)
89
-
90
- def load_model_from_gcs(model_name):
91
- model_files = [
92
- "pytorch_model.bin",
93
- "config.json",
94
- "tokenizer.json",
95
- "model.safetensors",
96
- ]
97
- gcs_handler = GCSHandler(GCS_BUCKET_NAME)
98
- model_files_streams = {
99
- file: gcs_handler.download_file(f"models/{model_name}/{file}")
100
- for file in model_files if gcs_handler.file_exists(f"models/{model_name}/{file}")
101
- }
102
- model_stream = model_files_streams.get("pytorch_model.bin") or model_files_streams.get("model.safetensors")
103
- tokenizer_stream = model_files_streams.get("tokenizer.json")
104
- config_stream = model_files_streams.get("config.json")
105
- model = AutoModelForCausalLM.from_pretrained(model_stream, config=config_stream)
106
- tokenizer = AutoTokenizer.from_pretrained(tokenizer_stream)
107
- return model, tokenizer
108
-
109
- def load_model(model_name):
110
- gcs_handler = GCSHandler(GCS_BUCKET_NAME)
111
- try:
112
- return load_model_from_gcs(model_name)
113
- except HTTPException:
114
- download_and_verify_model(model_name)
115
- return load_model_from_gcs(model_name)
116
-
117
- @app.on_event("startup")
118
- async def startup():
119
- gcs_handler = GCSHandler(GCS_BUCKET_NAME)
120
- blobs = list(bucket.list_blobs(prefix="models/"))
121
- model_names = set(blob.name.split("/")[1] for blob in blobs)
122
- def download_model_thread(model_name):
123
- try:
124
- download_and_verify_model(model_name)
125
- except Exception as e:
126
- logger.error(f"Error downloading model '{model_name}': {e}")
127
- threads = [threading.Thread(target=download_model_thread, args=(model_name,)) for model_name in model_names]
128
- for thread in threads:
129
- thread.start()
130
- for thread in threads:
131
- thread.join()
132
-
133
- @app.post("/predict/")
134
- async def predict(request: DownloadModelRequest):
135
- model_name = request.model_name
136
- pipeline_task = request.pipeline_task
137
- input_text = request.input_text
138
- model, tokenizer = load_model(model_name)
139
- pipe = pipeline(pipeline_task, model=model, tokenizer=tokenizer)
140
- result = pipe(input_text)
141
- return {"result": result}
142
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
143
  def download_all_models_in_background():
144
  models_url = "https://huggingface.co/api/models"
145
- response = requests.get(models_url)
146
- if response.status_code == 200:
 
 
 
 
 
147
  models = response.json()
148
  for model in models:
149
- download_model_from_huggingface(model["id"])
150
-
 
 
 
 
 
 
151
  def run_in_background():
 
152
  threading.Thread(target=download_all_models_in_background, daemon=True).start()
153
 
 
 
 
 
154
  if __name__ == "__main__":
155
  uvicorn.run(app, host="0.0.0.0", port=7860)
 
1
  import os
2
  import json
3
+ import uuid
4
+ import requests
5
  import threading
6
  import logging
 
 
 
7
  from fastapi import FastAPI, HTTPException
8
+ from pydantic import BaseModel
9
+ from google.cloud import storage
10
+ from google.auth import exceptions
11
+ from transformers import pipeline
12
  from dotenv import load_dotenv
13
+ import uvicorn
14
 
15
+ # Configuración de carga de variables de entorno
16
  load_dotenv()
17
 
18
  API_KEY = os.getenv("API_KEY")
 
20
  GOOGLE_APPLICATION_CREDENTIALS_JSON = os.getenv("GOOGLE_APPLICATION_CREDENTIALS_JSON")
21
  HF_API_TOKEN = os.getenv("HF_API_TOKEN")
22
 
23
+ # Configuración del logger
24
  logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
25
  logger = logging.getLogger(__name__)
26
 
27
+ # Inicializar el cliente de Google Cloud Storage
28
+ try:
29
+ credentials_info = json.loads(GOOGLE_APPLICATION_CREDENTIALS_JSON)
30
+ storage_client = storage.Client.from_service_account_info(credentials_info)
31
+ bucket = storage_client.bucket(GCS_BUCKET_NAME)
32
+ logger.info(f"Conexión con Google Cloud Storage exitosa. Bucket: {GCS_BUCKET_NAME}")
33
+ except (exceptions.DefaultCredentialsError, json.JSONDecodeError, KeyError, ValueError) as e:
34
+ logger.error(f"Error al cargar las credenciales o bucket: {e}")
35
+ raise RuntimeError(f"Error al cargar las credenciales o bucket: {e}")
36
 
37
  app = FastAPI()
38
 
 
46
  self.bucket = storage_client.bucket(bucket_name)
47
 
48
  def file_exists(self, blob_name):
49
+ exists = self.bucket.blob(blob_name).exists()
50
+ logger.debug(f"Comprobando existencia de archivo '{blob_name}': {exists}")
51
+ return exists
 
 
52
 
53
  def upload_file(self, blob_name, file_stream):
 
54
  blob = self.bucket.blob(blob_name)
55
+ try:
56
+ blob.upload_from_file(file_stream)
57
+ logger.info(f"Archivo '{blob_name}' subido exitosamente a GCS.")
58
+ except Exception as e:
59
+ logger.error(f"Error subiendo el archivo '{blob_name}' a GCS: {e}")
60
+ raise HTTPException(status_code=500, detail=f"Error subiendo archivo '{blob_name}' a GCS")
61
 
62
  def download_file(self, blob_name):
63
  blob = self.bucket.blob(blob_name)
64
  if not blob.exists():
65
+ logger.error(f"Archivo '{blob_name}' no encontrado en GCS.")
66
  raise HTTPException(status_code=404, detail=f"File '{blob_name}' not found.")
67
+ logger.debug(f"Descargando archivo '{blob_name}' de GCS.")
68
+ return blob.open("rb") # Abre el archivo en modo lectura de bytes
69
 
70
  def generate_signed_url(self, blob_name, expiration=3600):
71
  blob = self.bucket.blob(blob_name)
72
+ url = blob.generate_signed_url(expiration=expiration)
73
+ logger.debug(f"Generada URL firmada para '{blob_name}': {url}")
74
+ return url
75
 
76
  def download_model_from_huggingface(model_name):
77
  url = f"https://huggingface.co/{model_name}/tree/main"
78
  headers = {"Authorization": f"Bearer {HF_API_TOKEN}"}
79
+
80
+ try:
81
+ logger.info(f"Descargando el modelo '{model_name}' desde Hugging Face...")
82
+ response = requests.get(url, headers=headers)
83
+ if response.status_code == 200:
84
+ model_files = [
85
+ "pytorch_model.bin",
86
+ "config.json",
87
+ "tokenizer.json",
88
+ "model.safetensors",
89
+ ]
90
+ for file_name in model_files:
91
+ file_url = f"https://huggingface.co/{model_name}/resolve/main/{file_name}"
92
+ file_content = requests.get(file_url).content
93
+ # Subir el archivo directamente desde el contenido
94
+ blob_name = f"{model_name}/{file_name}"
95
+ blob = bucket.blob(blob_name)
96
+ blob.upload_from_string(file_content)
97
+ logger.info(f"Archivo '{file_name}' subido exitosamente al bucket GCS.")
98
+ else:
99
+ logger.error(f"Error al acceder al árbol de archivos de Hugging Face para '{model_name}'.")
100
+ raise HTTPException(status_code=404, detail="Error al acceder al árbol de archivos de Hugging Face.")
101
+ except Exception as e:
102
+ logger.error(f"Error descargando archivos de Hugging Face: {e}")
103
+ raise HTTPException(status_code=500, detail=f"Error descargando archivos de Hugging Face: {e}")
104
+
105
+ @app.post("/predict/")
106
+ async def predict(request: DownloadModelRequest):
107
+ logger.info(f"Iniciando predicción para el modelo '{request.model_name}' con tarea '{request.pipeline_task}'...")
108
+ try:
109
+ gcs_handler = GCSHandler(GCS_BUCKET_NAME)
110
+ model_prefix = request.model_name
111
  model_files = [
112
  "pytorch_model.bin",
113
  "config.json",
114
  "tokenizer.json",
115
  "model.safetensors",
116
  ]
117
+
118
+ model_files_exist = all(gcs_handler.file_exists(f"{model_prefix}/{file}") for file in model_files)
119
+
120
+ if not model_files_exist:
121
+ logger.info(f"Modelos no encontrados en GCS, descargando '{model_prefix}' desde Hugging Face...")
122
+ download_model_from_huggingface(model_prefix)
123
+
124
+ model_files_streams = {file: gcs_handler.download_file(f"{model_prefix}/{file}") for file in model_files if gcs_handler.file_exists(f"{model_prefix}/{file}")}
125
+
126
+ config_stream = model_files_streams.get("config.json")
127
+ tokenizer_stream = model_files_streams.get("tokenizer.json")
128
+ model_stream = model_files_streams.get("pytorch_model.bin")
129
+
130
+ if not config_stream or not tokenizer_stream or not model_stream:
131
+ logger.error(f"Faltan archivos necesarios para el modelo '{model_prefix}'.")
132
+ raise HTTPException(status_code=500, detail="Required model files missing.")
133
+
134
+ # Tareas basadas en texto
135
+ if request.pipeline_task in ["text-generation", "translation", "summarization"]:
136
+ pipe = pipeline(request.pipeline_task, model=model_stream, tokenizer=tokenizer_stream)
137
+ result = pipe(request.input_text)
138
+ logger.info(f"Resultado generado para la tarea '{request.pipeline_task}': {result[0]}")
139
+ return {"response": result[0]}
140
+
141
+ # Tareas de imagen
142
+ elif request.pipeline_task == "image-generation":
143
+ try:
144
+ pipe = pipeline("image-generation", model=model_stream)
145
+ images = pipe(request.input_text)
146
+ image = images[0]
147
+ image_filename = f"{uuid.uuid4().hex}.png"
148
+ image_path = f"images/{image_filename}"
149
+ image.save(image_path)
150
+
151
+ # Subir la imagen generada a GCS
152
+ gcs_handler.upload_file(image_path, open(image_path, "rb"))
153
+ image_url = gcs_handler.generate_signed_url(image_path)
154
+ logger.info(f"Imagen generada y subida correctamente con URL: {image_url}")
155
+ return {"response": {"image_url": image_url}}
156
+ except Exception as e:
157
+ logger.error(f"Error generando la imagen: {e}")
158
+ raise HTTPException(status_code=400, detail="Error generando la imagen.")
159
+
160
+ elif request.pipeline_task == "image-editing":
161
+ try:
162
+ pipe = pipeline("image-editing", model=model_stream)
163
+ edited_images = pipe(request.input_text)
164
+ edited_image = edited_images[0]
165
+ edited_image_filename = f"{uuid.uuid4().hex}_edited.png"
166
+ edited_image.save(edited_image_filename)
167
+
168
+ gcs_handler.upload_file(f"images/{edited_image_filename}", open(edited_image_filename, "rb"))
169
+ edited_image_url = gcs_handler.generate_signed_url(f"images/{edited_image_filename}")
170
+ logger.info(f"Imagen editada y subida correctamente con URL: {edited_image_url}")
171
+ return {"response": {"edited_image_url": edited_image_url}}
172
+ except Exception as e:
173
+ logger.error(f"Error editando la imagen: {e}")
174
+ raise HTTPException(status_code=400, detail="Error editando la imagen.")
175
+
176
+ elif request.pipeline_task == "image-to-image":
177
+ try:
178
+ pipe = pipeline("image-to-image", model=model_stream)
179
+ transformed_images = pipe(request.input_text)
180
+ transformed_image = transformed_images[0]
181
+ transformed_image_filename = f"{uuid.uuid4().hex}_transformed.png"
182
+ transformed_image.save(transformed_image_filename)
183
+
184
+ gcs_handler.upload_file(f"images/{transformed_image_filename}", open(transformed_image_filename, "rb"))
185
+ transformed_image_url = gcs_handler.generate_signed_url(f"images/{transformed_image_filename}")
186
+ logger.info(f"Imagen transformada y subida correctamente con URL: {transformed_image_url}")
187
+ return {"response": {"transformed_image_url": transformed_image_url}}
188
+ except Exception as e:
189
+ logger.error(f"Error transformando la imagen: {e}")
190
+ raise HTTPException(status_code=400, detail="Error transformando la imagen.")
191
+
192
+ # Tarea de generación de modelo 3D (simulada)
193
+ elif request.pipeline_task == "text-to-3d":
194
+ try:
195
+ model_3d_filename = f"{uuid.uuid4().hex}.obj"
196
+ model_3d_path = f"3d-models/{model_3d_filename}"
197
+ with open(model_3d_path, "w") as f:
198
+ f.write("Simulated 3D model data")
199
+
200
+ gcs_handler.upload_file(f"3d-models/{model_3d_filename}", open(model_3d_path, "rb"))
201
+ model_3d_url = gcs_handler.generate_signed_url(f"3d-models/{model_3d_filename}")
202
+ logger.info(f"Modelo 3D generado y subido con URL: {model_3d_url}")
203
+ return {"response": {"model_3d_url": model_3d_url}}
204
+ except Exception as e:
205
+ logger.error(f"Error generando el modelo 3D: {e}")
206
+ raise HTTPException(status_code=400, detail="Error generando el modelo 3D.")
207
+
208
+ except HTTPException as e:
209
+ logger.error(f"HTTPException: {e.detail}")
210
+ raise e
211
+ except Exception as e:
212
+ logger.error(f"Error inesperado: {e}")
213
+ raise HTTPException(status_code=500, detail=f"Error: {e}")
214
+
215
+ # Función para ejecutar en segundo plano la descarga de modelos
216
  def download_all_models_in_background():
217
  models_url = "https://huggingface.co/api/models"
218
+ try:
219
+ logger.info("Obteniendo lista de modelos desde Hugging Face...")
220
+ response = requests.get(models_url)
221
+ if response.status_code != 200:
222
+ logger.error("Error al obtener la lista de modelos de Hugging Face.")
223
+ raise HTTPException(status_code=500, detail="Error al obtener la lista de modelos.")
224
+
225
  models = response.json()
226
  for model in models:
227
+ model_name = model["id"]
228
+ logger.info(f"Descargando el modelo '{model_name}' desde Hugging Face...")
229
+ download_model_from_huggingface(model_name)
230
+ except Exception as e:
231
+ logger.error(f"Error al descargar modelos en segundo plano: {e}")
232
+ raise HTTPException(status_code=500, detail="Error al descargar modelos en segundo plano.")
233
+
234
+ # Iniciar la descarga de modelos en segundo plano
235
  def run_in_background():
236
+ logger.info("Iniciando la descarga de modelos en segundo plano...")
237
  threading.Thread(target=download_all_models_in_background, daemon=True).start()
238
 
239
+ @app.on_event("startup")
240
+ async def startup_event():
241
+ run_in_background()
242
+
243
  if __name__ == "__main__":
244
  uvicorn.run(app, host="0.0.0.0", port=7860)