Update app.py
Browse files
app.py
CHANGED
@@ -1,108 +1,114 @@
|
|
1 |
import os
|
2 |
import logging
|
|
|
|
|
|
|
|
|
3 |
import json
|
4 |
-
from
|
5 |
-
from transformers import pipeline, AutoTokenizer, AutoModelForSequenceClassification
|
6 |
-
import requests
|
7 |
-
import uvicorn
|
8 |
-
import threading
|
9 |
-
from dotenv import load_dotenv
|
10 |
|
11 |
-
|
12 |
-
|
13 |
-
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
|
14 |
-
logger = logging.getLogger(__name__)
|
15 |
|
|
|
|
|
16 |
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 |
try:
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
|
|
26 |
logger.info(f"Conexi贸n con Google Cloud Storage exitosa. Bucket: {GCS_BUCKET_NAME}")
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
except (exceptions.DefaultCredentialsError, json.JSONDecodeError, KeyError, ValueError) as e:
|
31 |
logger.error(f"Error al cargar las credenciales o bucket: {e}")
|
32 |
raise RuntimeError(f"Error al cargar las credenciales o bucket: {e}")
|
33 |
|
|
|
34 |
app = FastAPI()
|
35 |
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
def
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
return
|
51 |
-
|
52 |
-
hf_base_url = f"https://huggingface.co/{model_name}/resolve/main/"
|
53 |
-
files = ["config.json", "pytorch_model.bin", "tokenizer.json"]
|
54 |
-
|
55 |
-
for file_name in files:
|
56 |
-
file_url = hf_base_url + file_name
|
57 |
-
blob = bucket.blob(f"{model_folder}{file_name}")
|
58 |
-
logger.info(f"Descargando {file_url} al bucket...")
|
59 |
-
|
60 |
-
response = requests.get(file_url, stream=True)
|
61 |
-
if response.status_code == 200:
|
62 |
-
blob.upload_from_string(response.content)
|
63 |
-
logger.info(f"Archivo {file_name} subido al bucket.")
|
64 |
-
else:
|
65 |
-
logger.error(f"No se pudo descargar el archivo {file_name}. HTTP {response.status_code}")
|
66 |
-
|
67 |
-
def load_model_from_bucket(model_name: str):
|
68 |
-
model_folder = f"{model_name}/"
|
69 |
-
model_blob = bucket.blob(f"{model_folder}pytorch_model.bin")
|
70 |
-
config_blob = bucket.blob(f"{model_folder}config.json")
|
71 |
-
tokenizer_blob = bucket.blob(f"{model_folder}tokenizer.json")
|
72 |
-
|
73 |
-
if not (model_blob.exists() and config_blob.exists() and tokenizer_blob.exists()):
|
74 |
-
logger.error(f"Modelo no encontrado en el bucket: {model_name}")
|
75 |
-
raise HTTPException(status_code=404, detail="Modelo no encontrado en el bucket. Aseg煤rese de haberlo descargado correctamente.")
|
76 |
-
|
77 |
-
tokenizer = AutoTokenizer.from_pretrained(tokenizer_blob.download_as_bytes())
|
78 |
-
model = AutoModelForSequenceClassification.from_pretrained(model_blob.download_as_bytes(), config=config_blob.download_as_bytes())
|
79 |
-
return tokenizer, model
|
80 |
-
|
81 |
-
def background_download_all_models():
|
82 |
-
logger.info("Iniciando descarga de modelos en segundo plano...")
|
83 |
try:
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
92 |
|
93 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
94 |
|
|
|
95 |
@app.post("/predict")
|
96 |
-
def predict(
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
):
|
101 |
try:
|
102 |
-
|
103 |
-
|
104 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
105 |
result = nlp_pipeline(input_text)
|
|
|
106 |
return {"response": result}
|
107 |
|
108 |
except HTTPException as e:
|
@@ -113,10 +119,5 @@ def predict(
|
|
113 |
raise HTTPException(status_code=500, detail=str(e))
|
114 |
|
115 |
if __name__ == "__main__":
|
116 |
-
|
117 |
-
|
118 |
-
ssl_context = ssl.create_default_context()
|
119 |
-
uvicorn.run(app, host="0.0.0.0", port=7860)
|
120 |
-
except ModuleNotFoundError as e:
|
121 |
-
logger.error(f"Falta el m贸dulo requerido: {str(e)}")
|
122 |
-
raise RuntimeError("El entorno no tiene instalado el paquete necesario para manejar conexiones seguras.")
|
|
|
1 |
import os
|
2 |
import logging
|
3 |
+
from fastapi import FastAPI, HTTPException
|
4 |
+
from pydantic import BaseModel
|
5 |
+
from google.cloud import storage
|
6 |
+
from transformers import pipeline
|
7 |
import json
|
8 |
+
from google.auth.exceptions import DefaultCredentialsError
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
+
# Configuraci贸n de GCS
|
|
|
|
|
|
|
11 |
|
12 |
+
# Cargar las variables de entorno
|
13 |
+
API_KEY = os.getenv("API_KEY")
|
14 |
GCS_BUCKET_NAME = os.getenv("GCS_BUCKET_NAME")
|
15 |
GOOGLE_APPLICATION_CREDENTIALS_JSON = os.getenv("GOOGLE_APPLICATION_CREDENTIALS_JSON")
|
16 |
HF_API_TOKEN = os.getenv("HF_API_TOKEN")
|
17 |
|
18 |
+
# Configuraci贸n de logs
|
19 |
+
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
|
20 |
+
logger = logging.getLogger(__name__)
|
21 |
+
|
22 |
try:
|
23 |
+
# Intentar cargar las credenciales de servicio de GCS desde la variable de entorno
|
24 |
+
credentials_info = json.loads(GOOGLE_APPLICATION_CREDENTIALS_JSON) # Cargar el JSON de credenciales
|
25 |
+
storage_client = storage.Client.from_service_account_info(credentials_info) # Crear cliente de GCS
|
26 |
+
bucket = storage_client.bucket(GCS_BUCKET_NAME) # Acceder al bucket
|
27 |
+
|
28 |
+
# Verificaci贸n exitosa
|
29 |
logger.info(f"Conexi贸n con Google Cloud Storage exitosa. Bucket: {GCS_BUCKET_NAME}")
|
30 |
+
|
31 |
+
except (DefaultCredentialsError, json.JSONDecodeError, KeyError, ValueError) as e:
|
32 |
+
# Manejo de errores en caso de que las credenciales sean incorrectas o faltantes
|
|
|
33 |
logger.error(f"Error al cargar las credenciales o bucket: {e}")
|
34 |
raise RuntimeError(f"Error al cargar las credenciales o bucket: {e}")
|
35 |
|
36 |
+
# Configurar la aplicaci贸n FastAPI
|
37 |
app = FastAPI()
|
38 |
|
39 |
+
# Configuraci贸n de logs
|
40 |
+
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(levelname)s - %(message)s')
|
41 |
+
logger = logging.getLogger(__name__)
|
42 |
+
|
43 |
+
class PredictionRequest(BaseModel):
|
44 |
+
model_name: str
|
45 |
+
pipeline_task: str
|
46 |
+
input_text: str
|
47 |
+
|
48 |
+
# Funci贸n para obtener la URL del modelo desde GCS
|
49 |
+
def get_gcs_model_url(bucket_name: str, model_name: str):
|
50 |
+
"""
|
51 |
+
Obtiene la URL del modelo desde GCS.
|
52 |
+
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
53 |
try:
|
54 |
+
model_dir = f"models/{model_name}/"
|
55 |
+
|
56 |
+
# Verificar si la carpeta del modelo existe en GCS
|
57 |
+
bucket = storage_client.get_bucket(bucket_name)
|
58 |
+
blobs = bucket.list_blobs(prefix=model_dir)
|
59 |
+
|
60 |
+
# Verificar si existen archivos en el directorio del modelo
|
61 |
+
file_list = [blob.name for blob in blobs]
|
62 |
+
if not file_list:
|
63 |
+
raise HTTPException(status_code=404, detail="No se encontraron los archivos del modelo en GCS.")
|
64 |
+
|
65 |
+
# Construir la URL GCS del modelo (en este caso solo la ruta del directorio)
|
66 |
+
gcs_url = f"gs://{bucket_name}/{model_dir}"
|
67 |
+
|
68 |
+
return gcs_url
|
69 |
|
70 |
+
except Exception as e:
|
71 |
+
logger.error(f"Error al obtener la URL del modelo desde GCS: {str(e)}")
|
72 |
+
raise HTTPException(status_code=500, detail="Error al obtener la URL del modelo desde GCS.")
|
73 |
+
|
74 |
+
# Funci贸n para cargar el pipeline directamente desde GCS como URL
|
75 |
+
def load_pipeline_from_gcs(model_name: str, pipeline_task: str):
|
76 |
+
"""
|
77 |
+
Carga el pipeline directamente desde la URL del modelo en GCS sin usar RAM ni almacenamiento temporal.
|
78 |
+
"""
|
79 |
+
try:
|
80 |
+
# Obtener la URL del modelo desde GCS
|
81 |
+
model_url = get_gcs_model_url(GCS_BUCKET_NAME, model_name)
|
82 |
+
|
83 |
+
# Cargar el pipeline directamente desde la URL del modelo
|
84 |
+
nlp_pipeline = pipeline(
|
85 |
+
task=pipeline_task,
|
86 |
+
model=model_url, # Usamos la URL de GCS como modelo
|
87 |
+
)
|
88 |
+
|
89 |
+
return nlp_pipeline
|
90 |
+
except Exception as e:
|
91 |
+
logger.error(f"Error al cargar el pipeline desde GCS: {str(e)}")
|
92 |
+
raise HTTPException(status_code=500, detail="Error al cargar el pipeline desde GCS.")
|
93 |
|
94 |
+
# Endpoint para realizar la predicci贸n
|
95 |
@app.post("/predict")
|
96 |
+
def predict(request: PredictionRequest):
|
97 |
+
"""
|
98 |
+
Endpoint para recibir solicitudes POST con datos JSON y realizar la predicci贸n.
|
99 |
+
"""
|
|
|
100 |
try:
|
101 |
+
# Extraer los par谩metros de la solicitud JSON
|
102 |
+
model_name = request.model_name
|
103 |
+
pipeline_task = request.pipeline_task
|
104 |
+
input_text = request.input_text
|
105 |
+
|
106 |
+
# Cargar el pipeline directamente desde GCS sin usar RAM ni almacenamiento temporal
|
107 |
+
nlp_pipeline = load_pipeline_from_gcs(model_name, pipeline_task)
|
108 |
+
|
109 |
+
# Realizar la predicci贸n
|
110 |
result = nlp_pipeline(input_text)
|
111 |
+
|
112 |
return {"response": result}
|
113 |
|
114 |
except HTTPException as e:
|
|
|
119 |
raise HTTPException(status_code=500, detail=str(e))
|
120 |
|
121 |
if __name__ == "__main__":
|
122 |
+
import uvicorn
|
123 |
+
uvicorn.run(app, host="0.0.0.0", port=7860)
|
|
|
|
|
|
|
|
|
|