C2MV commited on
Commit
e43df9f
verified
1 Parent(s): de3a711

Upload 3 files

Browse files
Files changed (3) hide show
  1. app.py +33 -29
  2. decorators.py +39 -23
  3. model_app.py +42 -49
app.py CHANGED
@@ -1,44 +1,48 @@
1
  # app.py
2
- from UI import create_interface
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
- # --- Intento de Neutralizar el decorador problem谩tico para ejecuci贸n local ---
8
- # Esto es un hack para evitar el error de 'No @spaces.GPU' si Gradio lo busca.
 
 
 
 
 
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
- class _GPUNeutralizerLocal:
18
- def __init__(self, *args, **kwargs): pass
19
- def __call__(self, func): return func
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
- # Por ahora, mantenemos la estructura, pero ten en cuenta que @GPU no funcionar谩
8
- # fuera del entorno de HF Spaces tal como est谩. Modal tiene su propia forma de asignar GPUs.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 personalizado que simula el uso de GPU.
23
- En un entorno de Hugging Face Spaces con GPU asignada,
24
- el decorador `spaces.GPU` real se encargar铆a de la gesti贸n.
25
  """
26
  def decorator(func):
27
- @GPU(duration=duration) # Usando nuestro placeholder o el real de `spaces`
28
- @wraps(func)
29
- def wrapper(*args, **kwargs):
30
- return func(*args, **kwargs)
31
- return wrapper
32
- return decorator
 
 
 
 
 
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 anterior respuesta completa) ---
36
  @stub.function(
37
- image=app_image, # Hereda la imagen base del stub si est谩 definida, o usa esta.
38
- gpu="any",
39
  secrets=[modal.Secret.from_name("huggingface-read-token", optional=True)],
40
- timeout=600, # 10 minutos
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 # Importaciones pesadas dentro de la funci贸n Modal
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 # Necesario para algunos modelos como Qwen
61
  )
62
 
63
- model_context_window = getattr(model.config, 'max_position_embeddings', getattr(model.config, 'sliding_window', 4096)) # Para Qwen2 sliding_window
64
- if model_context_window is None : model_context_window = 4096 # Fallback
65
 
66
- max_prompt_len = model_context_window - max_new_tokens_config - 50 # Buffer
67
- if max_prompt_len <=0 : max_prompt_len = model_context_window // 2 # Si max_new_tokens es muy grande
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) # Especificar la imagen para el endpoint ASGI tambi茅n
95
  def serve_gradio_app_asgi():
96
  import gradio as gr
97
 
98
- # sys.path ya est谩 configurado por la imagen de Modal debido a .env({"PYTHONPATH": REMOTE_APP_DIR})
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
- # --- Intento de Neutralizar el decorador problem谩tico ANTES de las importaciones de la app ---
106
- # Esto es para evitar el error "No @spaces.GPU function detected" si Gradio lo busca.
 
107
  try:
108
- import decorators # Intenta importar TU decorators.py
109
- class _GPUNeutralizerModal:
110
  def __init__(self, *args, **kwargs): pass
111
  def __call__(self, func): return func
112
 
113
- if hasattr(decorators, 'GPU'):
114
- decorators.GPU = _GPUNeutralizerModal
115
- print("INFO (modal_app.py): 'decorators.GPU' neutralizado para el entorno Modal.")
116
- if hasattr(decorators, 'gpu_decorator'):
117
- decorators.gpu_decorator = lambda duration=0: lambda func: func
118
- print("INFO (modal_app.py): 'decorators.gpu_decorator' neutralizado para el entorno Modal.")
119
  except ImportError:
120
- print("ADVERTENCIA (modal_app.py): M贸dulo 'decorators' no encontrado durante la neutralizaci贸n. Esto puede ser OK.")
121
- except Exception as e_neut:
122
- print(f"ADVERTENCIA (modal_app.py): Error durante la neutralizaci贸n de decoradores: {e_neut}")
123
  # --- Fin de la neutralizaci贸n ---
124
 
125
- # Importar los m贸dulos de la aplicaci贸n AHORA
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 desde tu interface.py
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(): # Renombrado para evitar conflicto con el `test_llm` de la respuesta anterior
148
  print("Probando la generaci贸n de LLM con Modal (local_entrypoint)...")
149
- if REMOTE_APP_DIR not in sys.path: # Asegurar path para pruebas locales tambi茅n
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)