File size: 6,328 Bytes
d3d8124 227fa34 d3d8124 227fa34 d3d8124 227fa34 d3d8124 227fa34 d3d8124 227fa34 d3d8124 227fa34 d3d8124 227fa34 d3d8124 227fa34 d3d8124 227fa34 d3d8124 227fa34 d3d8124 227fa34 d3d8124 227fa34 d3d8124 227fa34 d3d8124 227fa34 d3d8124 227fa34 d3d8124 227fa34 d3d8124 227fa34 d3d8124 227fa34 d3d8124 227fa34 d3d8124 227fa34 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
# modal_app.py
import modal
import sys
from pathlib import Path
import os
import traceback # Para imprimir traceback detallado
# --- Configuraci贸n ---
PYTHON_VERSION = "3.10"
APP_NAME = "bioprocess-custom-eq-agent-modal"
LOCAL_APP_DIR = Path(__file__).parent
REMOTE_APP_DIR = "/app"
stub = modal.Stub(APP_NAME)
app_image = (
modal.Image.debian_slim(python_version=PYTHON_VERSION)
.pip_install_from_requirements(LOCAL_APP_DIR / "requirements.txt")
.copy_mount(
modal.Mount.from_local_dir(LOCAL_APP_DIR, remote_path=REMOTE_APP_DIR)
)
.env({
"PYTHONPATH": REMOTE_APP_DIR,
"HF_HOME": "/cache/huggingface",
"HF_HUB_CACHE": "/cache/huggingface/hub",
"TRANSFORMERS_CACHE": "/cache/huggingface/hub",
"MPLCONFIGDIR": "/tmp/matplotlib_cache"
})
.run_commands(
"apt-get update && apt-get install -y git git-lfs && rm -rf /var/lib/apt/lists/*",
"mkdir -p /cache/huggingface/hub /tmp/matplotlib_cache"
)
)
# --- Funci贸n Modal para LLM (sin cambios respecto a la anterior respuesta) ---
@stub.function(
image=app_image,
gpu="any",
secrets=[modal.Secret.from_name("huggingface-read-token", optional=True)],
timeout=600,
volumes={"/cache/huggingface": modal.Volume.persisted(f"{APP_NAME}-hf-cache-vol")}
)
def generate_analysis_llm_modal_remote(prompt: str, model_path_config: str, max_new_tokens_config: int) -> str:
import torch # Mover importaciones pesadas dentro de la funci贸n Modal
from transformers import AutoTokenizer, AutoModelForCausalLM
hf_token = os.environ.get("HUGGING_FACE_TOKEN")
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"LLM Modal Func: Usando dispositivo: {device}")
print(f"LLM Modal Func: Cargando modelo: {model_path_config} con token: {'S铆' if hf_token else 'No'}")
try:
tokenizer = AutoTokenizer.from_pretrained(model_path_config, cache_dir="/cache/huggingface/hub", token=hf_token)
model = AutoModelForCausalLM.from_pretrained(
model_path_config,
torch_dtype="auto",
device_map="auto",
cache_dir="/cache/huggingface/hub",
token=hf_token,
)
# Ajustar longitud de truncamiento para el prompt para dejar espacio a max_new_tokens
# La longitud total (prompt + generado) no debe exceder el context window del modelo.
# Asumamos un context window conservador de 4096 si no se conoce.
model_context_window = getattr(model.config, 'max_position_embeddings', 4096)
max_prompt_len = model_context_window - max_new_tokens_config - 50 # 50 tokens de buffer
inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=max_prompt_len).to(model.device)
with torch.no_grad():
outputs = model.generate(
**inputs,
max_new_tokens=max_new_tokens_config,
eos_token_id=tokenizer.eos_token_id,
pad_token_id=tokenizer.pad_token_id if tokenizer.pad_token_id is not None else tokenizer.eos_token_id,
do_sample=True,
temperature=0.6,
top_p=0.9,
)
input_length = inputs.input_ids.shape[1]
generated_ids = outputs[0][input_length:]
analysis = tokenizer.decode(generated_ids, skip_special_tokens=True)
print(f"LLM Modal Func: Longitud del an谩lisis generado: {len(analysis)} caracteres.")
return analysis.strip()
except Exception as e:
error_traceback = traceback.format_exc()
print(f"Error en generate_analysis_llm_modal_remote: {e}\n{error_traceback}")
return f"Error al generar an谩lisis con el modelo LLM: {str(e)}"
# --- Servidor Gradio ---
@stub.asgi_app()
def serve_gradio_app_asgi():
# Estas importaciones ocurren DENTRO del contenedor Modal
import gradio as gr
# sys.path ya est谩 configurado por la imagen, pero por si acaso:
if REMOTE_APP_DIR not in sys.path:
sys.path.insert(0, REMOTE_APP_DIR)
from UI import create_interface # De tu UI.py
import interface as app_interface_module # El m贸dulo interface.py
from config import MODEL_PATH as cfg_MODEL_PATH, MAX_LENGTH as cfg_MAX_LENGTH
# Wrapper para llamar a la funci贸n Modal remota
def analysis_func_wrapper_for_interface(prompt: str) -> str:
print("Gradio Backend: Llamando a generate_analysis_llm_modal_remote.remote...")
return generate_analysis_llm_modal_remote.remote(prompt, cfg_MODEL_PATH, cfg_MAX_LENGTH)
# Inyectar esta funci贸n wrapper en el m贸dulo `interface`
app_interface_module.generate_analysis_from_modal = analysis_func_wrapper_for_interface
app_interface_module.USE_MODAL_FOR_LLM_ANALYSIS = True
# Crear la app Gradio, pas谩ndole la funci贸n de procesamiento que ahora est谩 en app_interface_module
# create_interface ahora toma la funci贸n de callback como argumento.
gradio_ui = create_interface(process_function_for_button=app_interface_module.process_and_plot)
return gr.routes.App.create_app(gradio_ui)
@stub.local_entrypoint()
def test_llm():
print("Probando la generaci贸n de LLM con Modal (localmente)...")
# Necesitas importar config para que MODEL_PATH y MAX_LENGTH est茅n definidos
# Esto debe hacerse dentro de un contexto donde los m贸dulos de la app sean accesibles.
# Es mejor llamar a la funci贸n stub desde aqu铆.
if REMOTE_APP_DIR not in sys.path: # Asegurar path para pruebas locales tambi茅n
sys.path.insert(0, str(LOCAL_APP_DIR))
from config import MODEL_PATH, MAX_LENGTH
sample_prompt = "Explica brevemente el concepto de R cuadrado (R虏) en el ajuste de modelos."
# Ejecuta la funci贸n Modal directamente (no .remote() para prueba local de l贸gica)
# Para probar la ejecuci贸n remota real, necesitar铆as `modal run modal_app.py test_llm`
# o que test_llm llame a .remote().
# Aqu铆 vamos a probar la llamada remota.
try:
analysis = generate_analysis_llm_modal_remote.remote(sample_prompt, MODEL_PATH, MAX_LENGTH)
print("\nRespuesta del LLM:")
print(analysis)
except Exception as e:
print(f"Error durante test_llm: {e}")
traceback.print_exc() |