Upload 3 files
Browse files- app.py +33 -29
- decorators.py +39 -23
- model_app.py +42 -49
app.py
CHANGED
@@ -1,44 +1,48 @@
|
|
1 |
# app.py
|
2 |
-
|
3 |
-
import interface as app_interface_module # Necesitamos la funci贸n process_and_plot
|
4 |
-
import sys # Para manipulaci贸n de path si es necesario
|
5 |
from pathlib import Path
|
6 |
|
7 |
-
#
|
8 |
-
#
|
|
|
|
|
|
|
|
|
|
|
9 |
try:
|
10 |
-
# Intentar importar el m贸dulo 'decorators' de tu proyecto
|
11 |
-
# Asume que app.py est谩 en la ra铆z del proyecto y decorators.py tambi茅n
|
12 |
-
current_dir = Path(__file__).parent
|
13 |
-
if str(current_dir) not in sys.path:
|
14 |
-
sys.path.insert(0, str(current_dir))
|
15 |
import decorators
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
# Sobrescribir si existen para que no causen error
|
22 |
-
if hasattr(decorators, 'GPU'):
|
23 |
-
decorators.GPU = _GPUNeutralizerLocal
|
24 |
-
print("INFO (app.py): 'decorators.GPU' neutralizado para ejecuci贸n local.")
|
25 |
-
if hasattr(decorators, 'gpu_decorator'):
|
26 |
-
decorators.gpu_decorator = lambda duration=0: lambda func: func
|
27 |
-
print("INFO (app.py): 'decorators.gpu_decorator' neutralizado para ejecuci贸n local.")
|
28 |
-
|
29 |
-
except ImportError:
|
30 |
-
print("ADVERTENCIA (app.py): M贸dulo 'decorators' no encontrado, no se pudo neutralizar GPU. Puede que no sea necesario.")
|
31 |
-
except Exception as e_dec:
|
32 |
-
print(f"ADVERTENCIA (app.py): Error al intentar neutralizar decoradores: {e_dec}")
|
33 |
-
# --- Fin de la neutralizaci贸n ---
|
34 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
|
36 |
def main():
|
37 |
# Pasa la funci贸n de procesamiento real (process_and_plot) a create_interface
|
38 |
# app_interface_module.process_and_plot es la funci贸n que queremos que el bot贸n llame.
|
|
|
|
|
39 |
demo_instance = create_interface(process_function_for_button=app_interface_module.process_and_plot)
|
40 |
|
41 |
-
print("Lanzando interfaz Gradio localmente...")
|
|
|
|
|
42 |
demo_instance.launch()
|
43 |
|
44 |
if __name__ == "__main__":
|
|
|
1 |
# app.py
|
2 |
+
import sys
|
|
|
|
|
3 |
from pathlib import Path
|
4 |
|
5 |
+
# A帽adir el directorio actual al path para asegurar que se encuentran los m贸dulos locales
|
6 |
+
# como UI, interface, decorators, config, models.
|
7 |
+
CURRENT_DIR = Path(__file__).parent
|
8 |
+
if str(CURRENT_DIR) not in sys.path:
|
9 |
+
sys.path.insert(0, str(CURRENT_DIR))
|
10 |
+
|
11 |
+
# Ahora que el path est谩 configurado, podemos importar los m贸dulos locales.
|
12 |
try:
|
|
|
|
|
|
|
|
|
|
|
13 |
import decorators
|
14 |
+
from UI import create_interface
|
15 |
+
import interface as app_interface_module
|
16 |
+
except ImportError as e:
|
17 |
+
print(f"Error cr铆tico de importaci贸n en app.py: {e}. Aseg煤rate de que todos los archivos .py est茅n en el mismo directorio.")
|
18 |
+
sys.exit(1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
|
20 |
+
# --- Manejo del decorador GPU para el arranque de Gradio local ---
|
21 |
+
# Si el decorador real de HF Spaces fue importado (incluso si es un stub de una lib),
|
22 |
+
# Gradio podr铆a esperar que una funci贸n est茅 decorada.
|
23 |
+
if decorators.was_real_spaces_gpu_imported():
|
24 |
+
print("INFO (app.py): El decorador GPU de 'spaces' parece estar disponible (o es un stub).")
|
25 |
+
print("INFO (app.py): Se definir谩 una funci贸n dummy decorada para satisfacer el chequeo de Gradio.")
|
26 |
+
|
27 |
+
@decorators.gpu_decorator(duration=1) # Usa TU gpu_decorator
|
28 |
+
def _app_py_dummy_gpu_function_for_gradio_startup():
|
29 |
+
"""Esta funci贸n es solo para satisfacer el chequeo de Gradio."""
|
30 |
+
# print("Funci贸n dummy GPU de app.py ejecutada (no deber铆a hacer nada).")
|
31 |
+
pass
|
32 |
+
else:
|
33 |
+
print("INFO (app.py): El decorador GPU real de 'spaces' no fue importado. No se necesita funci贸n dummy para GPU.")
|
34 |
+
# --- Fin del manejo del decorador GPU ---
|
35 |
|
36 |
def main():
|
37 |
# Pasa la funci贸n de procesamiento real (process_and_plot) a create_interface
|
38 |
# app_interface_module.process_and_plot es la funci贸n que queremos que el bot贸n llame.
|
39 |
+
|
40 |
+
print("INFO (app.py): Creando la interfaz Gradio...")
|
41 |
demo_instance = create_interface(process_function_for_button=app_interface_module.process_and_plot)
|
42 |
|
43 |
+
print("INFO (app.py): Lanzando la interfaz Gradio localmente...")
|
44 |
+
# Para desarrollo, puedes habilitar debug y share si es necesario.
|
45 |
+
# demo_instance.launch(debug=True, share=True)
|
46 |
demo_instance.launch()
|
47 |
|
48 |
if __name__ == "__main__":
|
decorators.py
CHANGED
@@ -1,32 +1,48 @@
|
|
1 |
# decorators.py
|
2 |
from functools import wraps
|
3 |
-
# La importaci贸n original 'from spaces import GPU' es espec铆fica de Hugging Face Spaces.
|
4 |
-
# Para un uso general o con Modal, este decorador necesitar铆a ser adaptado o
|
5 |
-
# la gesti贸n de GPU se har铆a directamente a trav茅s de la configuraci贸n de la funci贸n Modal.
|
6 |
|
7 |
-
|
8 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
9 |
|
10 |
-
class GPU: # Placeholder para simular la estructura si no se ejecuta en HF Spaces
|
11 |
-
def __init__(self, duration=100):
|
12 |
-
self.duration = duration
|
13 |
-
def __call__(self, func):
|
14 |
-
@wraps(func)
|
15 |
-
def wrapper(*args, **kwargs):
|
16 |
-
# print(f"Simulando ejecuci贸n con GPU (duraci贸n: {self.duration}s) para: {func.__name__}")
|
17 |
-
return func(*args, **kwargs)
|
18 |
-
return wrapper
|
19 |
|
20 |
def gpu_decorator(duration=100):
|
21 |
"""
|
22 |
-
Decorador
|
23 |
-
|
24 |
-
el decorador `spaces.GPU` real se encargar铆a de la gesti贸n.
|
25 |
"""
|
26 |
def decorator(func):
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
|
|
|
|
|
|
|
|
|
1 |
# decorators.py
|
2 |
from functools import wraps
|
|
|
|
|
|
|
3 |
|
4 |
+
_actual_spaces_GPU_imported = False
|
5 |
+
_GPU_decorator_target = None
|
6 |
+
|
7 |
+
try:
|
8 |
+
from spaces import GPU as ActualSpacesGPU_real # Intentar importar el real
|
9 |
+
_GPU_decorator_target = ActualSpacesGPU_real
|
10 |
+
_actual_spaces_GPU_imported = True
|
11 |
+
print("INFO (decorators.py): Se import贸 'GPU' correctamente desde 'spaces'.")
|
12 |
+
except ImportError:
|
13 |
+
print("ADVERTENCIA (decorators.py): No se pudo importar 'GPU' desde 'spaces'. Se usar谩 un placeholder. "
|
14 |
+
"Esto es normal si no se ejecuta en un Hugging Face Space con GPU habilitada.")
|
15 |
+
class PlaceholderGPU:
|
16 |
+
def __init__(self, duration=100, **kwargs): # Aceptar kwargs comunes como sdk_version
|
17 |
+
self.duration = duration
|
18 |
+
# print(f"PlaceholderGPU inicializado (duraci贸n: {self.duration}s)")
|
19 |
+
|
20 |
+
def __call__(self, func):
|
21 |
+
@wraps(func)
|
22 |
+
def wrapper(*args, **kwargs):
|
23 |
+
# print(f"PlaceholderGPU: Ejecutando funci贸n decorada '{func.__name__}'")
|
24 |
+
return func(*args, **kwargs)
|
25 |
+
return wrapper
|
26 |
+
_GPU_decorator_target = PlaceholderGPU
|
27 |
+
except Exception as e:
|
28 |
+
print(f"ERROR (decorators.py): Error inesperado al intentar importar/definir GPU: {e}")
|
29 |
+
# Fallback a un decorador que no hace absolutamente nada si todo lo dem谩s falla
|
30 |
+
_GPU_decorator_target = lambda duration=100, **kwargs: lambda func: func
|
31 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
|
33 |
def gpu_decorator(duration=100):
|
34 |
"""
|
35 |
+
Decorador que aplica el @spaces.GPU real si est谩 disponible,
|
36 |
+
o un placeholder funcional en otros casos.
|
|
|
37 |
"""
|
38 |
def decorator(func):
|
39 |
+
# Usar _GPU_decorator_target que es o el real o el placeholder
|
40 |
+
decorated_func = _GPU_decorator_target(duration=duration)(func)
|
41 |
+
return decorated_func
|
42 |
+
return decorator
|
43 |
+
|
44 |
+
def was_real_spaces_gpu_imported():
|
45 |
+
"""
|
46 |
+
Permite a otros m贸dulos verificar si el decorador GPU real de HF Spaces fue importado.
|
47 |
+
"""
|
48 |
+
return _actual_spaces_GPU_imported
|
model_app.py
CHANGED
@@ -9,39 +9,39 @@ import traceback
|
|
9 |
PYTHON_VERSION = "3.10"
|
10 |
APP_NAME = "bioprocess-custom-eq-agent-modal"
|
11 |
LOCAL_APP_DIR = Path(__file__).parent
|
12 |
-
REMOTE_APP_DIR = "/app"
|
13 |
|
14 |
stub = modal.Stub(APP_NAME)
|
15 |
|
16 |
app_image = (
|
17 |
modal.Image.debian_slim(python_version=PYTHON_VERSION)
|
18 |
-
.pip_install_from_requirements(LOCAL_APP_DIR / "requirements.txt")
|
19 |
-
.copy_mount(
|
20 |
modal.Mount.from_local_dir(LOCAL_APP_DIR, remote_path=REMOTE_APP_DIR)
|
21 |
)
|
22 |
-
.env({
|
23 |
-
"PYTHONPATH": REMOTE_APP_DIR,
|
24 |
"HF_HOME": "/cache/huggingface",
|
25 |
"HF_HUB_CACHE": "/cache/huggingface/hub",
|
26 |
"TRANSFORMERS_CACHE": "/cache/huggingface/hub",
|
27 |
-
"MPLCONFIGDIR": "/tmp/matplotlib_cache"
|
28 |
})
|
29 |
-
.run_commands(
|
30 |
"apt-get update && apt-get install -y git git-lfs && rm -rf /var/lib/apt/lists/*",
|
31 |
-
"mkdir -p /cache/huggingface/hub /tmp/matplotlib_cache"
|
32 |
)
|
33 |
)
|
34 |
|
35 |
-
# --- Funci贸n Modal para LLM (sin cambios respecto a la
|
36 |
@stub.function(
|
37 |
-
image=app_image,
|
38 |
-
gpu="any",
|
39 |
secrets=[modal.Secret.from_name("huggingface-read-token", optional=True)],
|
40 |
-
timeout=600,
|
41 |
volumes={"/cache/huggingface": modal.Volume.persisted(f"{APP_NAME}-hf-cache-vol")}
|
42 |
)
|
43 |
def generate_analysis_llm_modal_remote(prompt: str, model_path_config: str, max_new_tokens_config: int) -> str:
|
44 |
-
import torch
|
45 |
from transformers import AutoTokenizer, AutoModelForCausalLM
|
46 |
|
47 |
hf_token = os.environ.get("HUGGING_FACE_TOKEN")
|
@@ -57,14 +57,14 @@ def generate_analysis_llm_modal_remote(prompt: str, model_path_config: str, max_
|
|
57 |
device_map="auto",
|
58 |
cache_dir="/cache/huggingface/hub",
|
59 |
token=hf_token,
|
60 |
-
trust_remote_code=True
|
61 |
)
|
62 |
|
63 |
-
model_context_window = getattr(model.config, 'max_position_embeddings', getattr(model.config, 'sliding_window', 4096))
|
64 |
-
if model_context_window is None : model_context_window = 4096
|
65 |
|
66 |
-
max_prompt_len = model_context_window - max_new_tokens_config - 50
|
67 |
-
if max_prompt_len <=0 : max_prompt_len = model_context_window // 2
|
68 |
|
69 |
inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=max_prompt_len).to(model.device)
|
70 |
|
@@ -74,9 +74,7 @@ def generate_analysis_llm_modal_remote(prompt: str, model_path_config: str, max_
|
|
74 |
max_new_tokens=max_new_tokens_config,
|
75 |
eos_token_id=tokenizer.eos_token_id,
|
76 |
pad_token_id=tokenizer.pad_token_id if tokenizer.pad_token_id is not None else tokenizer.eos_token_id,
|
77 |
-
do_sample=True,
|
78 |
-
temperature=0.6,
|
79 |
-
top_p=0.9,
|
80 |
)
|
81 |
|
82 |
input_length = inputs.input_ids.shape[1]
|
@@ -91,69 +89,64 @@ def generate_analysis_llm_modal_remote(prompt: str, model_path_config: str, max_
|
|
91 |
return f"Error al generar an谩lisis con el modelo LLM: {str(e)}"
|
92 |
|
93 |
# --- Servidor Gradio ---
|
94 |
-
@stub.asgi_app(image=app_image)
|
95 |
def serve_gradio_app_asgi():
|
96 |
import gradio as gr
|
97 |
|
98 |
-
#
|
99 |
-
# y .copy_mount(... remote_path=REMOTE_APP_DIR)
|
100 |
-
# No obstante, una comprobaci贸n o inserci贸n expl铆cita no da帽a:
|
101 |
if REMOTE_APP_DIR not in sys.path:
|
102 |
sys.path.insert(0, REMOTE_APP_DIR)
|
103 |
-
print(f"INFO (modal_app.py): A帽adido {REMOTE_APP_DIR} a sys.path")
|
104 |
|
105 |
-
# ---
|
106 |
-
# Esto
|
|
|
107 |
try:
|
108 |
-
import decorators #
|
109 |
-
class
|
110 |
def __init__(self, *args, **kwargs): pass
|
111 |
def __call__(self, func): return func
|
112 |
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
except ImportError:
|
120 |
-
print("ADVERTENCIA (modal_app.py): M贸dulo 'decorators' no encontrado durante la neutralizaci贸n.
|
121 |
-
except Exception as
|
122 |
-
print(f"ADVERTENCIA (modal_app.py): Error durante la neutralizaci贸n de decoradores: {
|
123 |
# --- Fin de la neutralizaci贸n ---
|
124 |
|
125 |
-
# Importar los m贸dulos de la aplicaci贸n
|
126 |
from UI import create_interface
|
127 |
import interface as app_interface_module
|
128 |
from config import MODEL_PATH as cfg_MODEL_PATH, MAX_LENGTH as cfg_MAX_LENGTH
|
129 |
|
130 |
-
# Wrapper para llamar a la funci贸n Modal remota
|
131 |
def analysis_func_wrapper_for_interface_modal(prompt: str) -> str:
|
132 |
print("Gradio Backend (Modal): Llamando a generate_analysis_llm_modal_remote.remote...")
|
133 |
return generate_analysis_llm_modal_remote.remote(prompt, cfg_MODEL_PATH, cfg_MAX_LENGTH)
|
134 |
|
135 |
-
# Inyectar esta funci贸n wrapper en el m贸dulo `interface` que usa Gradio
|
136 |
app_interface_module.generate_analysis_from_modal = analysis_func_wrapper_for_interface_modal
|
137 |
app_interface_module.USE_MODAL_FOR_LLM_ANALYSIS = True
|
138 |
-
print("INFO (modal_app.py): Runner de LLM Modal inyectado en el m贸dulo 'interface'.")
|
139 |
|
140 |
-
# Crear la app Gradio, pas谩ndole la funci贸n de procesamiento real
|
141 |
gradio_ui_instance = create_interface(process_function_for_button=app_interface_module.process_and_plot)
|
142 |
|
143 |
-
print("INFO (modal_app.py): Interfaz Gradio creada y lista para ser servida.")
|
144 |
return gr.routes.App.create_app(gradio_ui_instance)
|
145 |
|
146 |
@stub.local_entrypoint()
|
147 |
-
def test_llm_local_entry():
|
148 |
print("Probando la generaci贸n de LLM con Modal (local_entrypoint)...")
|
149 |
-
if
|
150 |
sys.path.insert(0, str(LOCAL_APP_DIR))
|
151 |
from config import MODEL_PATH, MAX_LENGTH
|
152 |
|
153 |
sample_prompt = "Explica brevemente el concepto de R cuadrado (R虏) en el ajuste de modelos."
|
154 |
try:
|
155 |
-
# Para ejecutar esto, necesitar铆as que el stub est茅 activo.
|
156 |
-
# `modal run modal_app.py test_llm_local_entry`
|
157 |
analysis = generate_analysis_llm_modal_remote.remote(sample_prompt, MODEL_PATH, MAX_LENGTH)
|
158 |
print("\nRespuesta del LLM:")
|
159 |
print(analysis)
|
|
|
9 |
PYTHON_VERSION = "3.10"
|
10 |
APP_NAME = "bioprocess-custom-eq-agent-modal"
|
11 |
LOCAL_APP_DIR = Path(__file__).parent
|
12 |
+
REMOTE_APP_DIR = "/app" # Directorio donde se copiar谩n los archivos en el contenedor Modal
|
13 |
|
14 |
stub = modal.Stub(APP_NAME)
|
15 |
|
16 |
app_image = (
|
17 |
modal.Image.debian_slim(python_version=PYTHON_VERSION)
|
18 |
+
.pip_install_from_requirements(LOCAL_APP_DIR / "requirements.txt") # Lee desde tu requirements.txt
|
19 |
+
.copy_mount( # Copia todos los archivos de la app
|
20 |
modal.Mount.from_local_dir(LOCAL_APP_DIR, remote_path=REMOTE_APP_DIR)
|
21 |
)
|
22 |
+
.env({ # Configura variables de entorno dentro del contenedor
|
23 |
+
"PYTHONPATH": REMOTE_APP_DIR, # Permite importar m贸dulos desde /app
|
24 |
"HF_HOME": "/cache/huggingface",
|
25 |
"HF_HUB_CACHE": "/cache/huggingface/hub",
|
26 |
"TRANSFORMERS_CACHE": "/cache/huggingface/hub",
|
27 |
+
"MPLCONFIGDIR": "/tmp/matplotlib_cache" # Evita warnings de matplotlib
|
28 |
})
|
29 |
+
.run_commands( # Comandos a ejecutar durante la construcci贸n de la imagen
|
30 |
"apt-get update && apt-get install -y git git-lfs && rm -rf /var/lib/apt/lists/*",
|
31 |
+
"mkdir -p /cache/huggingface/hub /tmp/matplotlib_cache" # Crea directorios de cach茅
|
32 |
)
|
33 |
)
|
34 |
|
35 |
+
# --- Funci贸n Modal para LLM (sin cambios significativos respecto a la respuesta completa anterior) ---
|
36 |
@stub.function(
|
37 |
+
image=app_image,
|
38 |
+
gpu="any",
|
39 |
secrets=[modal.Secret.from_name("huggingface-read-token", optional=True)],
|
40 |
+
timeout=600,
|
41 |
volumes={"/cache/huggingface": modal.Volume.persisted(f"{APP_NAME}-hf-cache-vol")}
|
42 |
)
|
43 |
def generate_analysis_llm_modal_remote(prompt: str, model_path_config: str, max_new_tokens_config: int) -> str:
|
44 |
+
import torch
|
45 |
from transformers import AutoTokenizer, AutoModelForCausalLM
|
46 |
|
47 |
hf_token = os.environ.get("HUGGING_FACE_TOKEN")
|
|
|
57 |
device_map="auto",
|
58 |
cache_dir="/cache/huggingface/hub",
|
59 |
token=hf_token,
|
60 |
+
trust_remote_code=True
|
61 |
)
|
62 |
|
63 |
+
model_context_window = getattr(model.config, 'max_position_embeddings', getattr(model.config, 'sliding_window', 4096))
|
64 |
+
if model_context_window is None : model_context_window = 4096
|
65 |
|
66 |
+
max_prompt_len = model_context_window - max_new_tokens_config - 50
|
67 |
+
if max_prompt_len <=0 : max_prompt_len = model_context_window // 2
|
68 |
|
69 |
inputs = tokenizer(prompt, return_tensors="pt", truncation=True, max_length=max_prompt_len).to(model.device)
|
70 |
|
|
|
74 |
max_new_tokens=max_new_tokens_config,
|
75 |
eos_token_id=tokenizer.eos_token_id,
|
76 |
pad_token_id=tokenizer.pad_token_id if tokenizer.pad_token_id is not None else tokenizer.eos_token_id,
|
77 |
+
do_sample=True, temperature=0.6, top_p=0.9,
|
|
|
|
|
78 |
)
|
79 |
|
80 |
input_length = inputs.input_ids.shape[1]
|
|
|
89 |
return f"Error al generar an谩lisis con el modelo LLM: {str(e)}"
|
90 |
|
91 |
# --- Servidor Gradio ---
|
92 |
+
@stub.asgi_app(image=app_image)
|
93 |
def serve_gradio_app_asgi():
|
94 |
import gradio as gr
|
95 |
|
96 |
+
# El PYTHONPATH ya est谩 configurado en la imagen, pero una verificaci贸n no da帽a.
|
|
|
|
|
97 |
if REMOTE_APP_DIR not in sys.path:
|
98 |
sys.path.insert(0, REMOTE_APP_DIR)
|
99 |
+
print(f"INFO (modal_app.py @asgi): A帽adido {REMOTE_APP_DIR} a sys.path")
|
100 |
|
101 |
+
# --- Neutralizaci贸n del decorador GPU de Spaces, DENTRO del contexto Modal ---
|
102 |
+
# Esto asegura que cualquier importaci贸n de `gradio` o `decorators`
|
103 |
+
# no cause problemas con el chequeo de `@spaces.GPU`.
|
104 |
try:
|
105 |
+
import decorators # Importa TU decorators.py
|
106 |
+
class _GPUNeutralizerInModal:
|
107 |
def __init__(self, *args, **kwargs): pass
|
108 |
def __call__(self, func): return func
|
109 |
|
110 |
+
# Sobrescribir la clase GPU y el decorador en el m贸dulo 'decorators'
|
111 |
+
# para esta instancia del servidor ASGI.
|
112 |
+
decorators.ActualSpacesGPU = _GPUNeutralizerInModal # Si decorators.py usa este nombre
|
113 |
+
decorators._GPU_decorator_target = _GPUNeutralizerInModal # Si decorators.py usa este
|
114 |
+
decorators.gpu_decorator = lambda duration=0: lambda func: func # Neutralizar el decorador
|
115 |
+
print("INFO (modal_app.py @asgi): Decoradores GPU de 'spaces' neutralizados para el entorno Modal.")
|
116 |
except ImportError:
|
117 |
+
print("ADVERTENCIA (modal_app.py @asgi): M贸dulo 'decorators' no encontrado durante la neutralizaci贸n. Puede ser OK.")
|
118 |
+
except Exception as e_neut_modal:
|
119 |
+
print(f"ADVERTENCIA (modal_app.py @asgi): Error durante la neutralizaci贸n de decoradores en Modal: {e_neut_modal}")
|
120 |
# --- Fin de la neutralizaci贸n ---
|
121 |
|
122 |
+
# Importar los m贸dulos de la aplicaci贸n DESPU脡S de la neutralizaci贸n y config de path
|
123 |
from UI import create_interface
|
124 |
import interface as app_interface_module
|
125 |
from config import MODEL_PATH as cfg_MODEL_PATH, MAX_LENGTH as cfg_MAX_LENGTH
|
126 |
|
127 |
+
# Wrapper para llamar a la funci贸n Modal remota
|
128 |
def analysis_func_wrapper_for_interface_modal(prompt: str) -> str:
|
129 |
print("Gradio Backend (Modal): Llamando a generate_analysis_llm_modal_remote.remote...")
|
130 |
return generate_analysis_llm_modal_remote.remote(prompt, cfg_MODEL_PATH, cfg_MAX_LENGTH)
|
131 |
|
|
|
132 |
app_interface_module.generate_analysis_from_modal = analysis_func_wrapper_for_interface_modal
|
133 |
app_interface_module.USE_MODAL_FOR_LLM_ANALYSIS = True
|
134 |
+
print("INFO (modal_app.py @asgi): Runner de LLM Modal inyectado en el m贸dulo 'interface'.")
|
135 |
|
|
|
136 |
gradio_ui_instance = create_interface(process_function_for_button=app_interface_module.process_and_plot)
|
137 |
|
138 |
+
print("INFO (modal_app.py @asgi): Interfaz Gradio creada y lista para ser servida por Modal.")
|
139 |
return gr.routes.App.create_app(gradio_ui_instance)
|
140 |
|
141 |
@stub.local_entrypoint()
|
142 |
+
def test_llm_local_entry():
|
143 |
print("Probando la generaci贸n de LLM con Modal (local_entrypoint)...")
|
144 |
+
if str(LOCAL_APP_DIR) not in sys.path:
|
145 |
sys.path.insert(0, str(LOCAL_APP_DIR))
|
146 |
from config import MODEL_PATH, MAX_LENGTH
|
147 |
|
148 |
sample_prompt = "Explica brevemente el concepto de R cuadrado (R虏) en el ajuste de modelos."
|
149 |
try:
|
|
|
|
|
150 |
analysis = generate_analysis_llm_modal_remote.remote(sample_prompt, MODEL_PATH, MAX_LENGTH)
|
151 |
print("\nRespuesta del LLM:")
|
152 |
print(analysis)
|