MedAI_VLM / start.py
Jesteban247's picture
Upload 88 files
d5f2660 verified
"""
MedGemma AI Assistant - Unified Launcher
Handles both HF Spaces and Local deployment automatically
"""
import subprocess
import sys
import time
import signal
import os
from pathlib import Path
# Import logger
sys.path.append('src')
from logger import setup_logger
from config import IS_HF_SPACE
logger = setup_logger(__name__)
# ============================================================================
# HF SPACES MODE - Just run app.py directly
# ============================================================================
if IS_HF_SPACE:
logger.info("="*70)
logger.info("🌐 HF Spaces Mode Detected")
logger.info("="*70)
logger.info("Starting Gradio app with transformers inference...")
# In HF Spaces, just run app.py directly
# Model server for classification/detection/segmentation still needed
try:
# Start model server in background
logger.info("Starting Model Server (Classification/Detection/Segmentation)...")
model_server = subprocess.Popen(
[sys.executable, "src/server_models.py"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
time.sleep(3)
if model_server.poll() is None:
logger.info("βœ“ Model Server started")
else:
logger.warning("⚠️ Model Server may have failed to start")
# Run Gradio app (this will block)
logger.info("Starting Gradio UI...")
subprocess.run([sys.executable, "app.py"])
except KeyboardInterrupt:
logger.info("Shutting down...")
if model_server and model_server.poll() is None:
model_server.terminate()
model_server.wait(timeout=5)
sys.exit(0)
# ============================================================================
# LOCAL MODE - Start all services
# ============================================================================
logger.info("πŸ’» Running in local GGUF mode")
# Global list to track all processes
processes = []
def check_file_exists(path, description):
"""Check if a required file exists"""
if not Path(path).exists():
logger.error(f"{description} not found: {path}")
return False
return True
def check_requirements():
"""Check if all required files and dependencies exist"""
logger.info("Checking Requirements...")
all_good = True
# Check Python files
files_to_check = [
("src/server_models.py", "Model server script"),
("app.py", "Gradio app script"),
]
for file_path, description in files_to_check:
if check_file_exists(file_path, description):
logger.info(f"βœ“ {description} found")
else:
all_good = False
# Check GGUF requirements
all_good = _check_gguf_requirements() and all_good
return all_good
def _check_gguf_requirements():
"""Check GGUF mode requirements"""
logger.info("Checking local GGUF model requirements")
all_good = True
model_dirs = [
("Models/Medgemma_Base", "Base model directory"),
("Models/Medgemma_FT", "Fine-tuned model directory"),
]
for dir_path, description in model_dirs:
if Path(dir_path).exists():
logger.info(f"βœ“ {description} found")
else:
logger.warning(f"{description} not found: {dir_path}")
logger.warning(" β†’ Download models from Hugging Face")
# Check llama-server
try:
result = subprocess.run(["which", "llama-server"], capture_output=True, text=True)
if result.returncode == 0:
logger.info(f"βœ“ llama-server found: {result.stdout.strip()}")
else:
logger.warning("llama-server not found in PATH")
logger.warning(" β†’ Install from: https://github.com/ggerganov/llama.cpp")
all_good = False
except Exception as e:
logger.error(f"Could not check for llama-server: {e}")
all_good = False
return all_good
def cleanup(signum=None, frame=None):
"""Cleanup function to terminate all processes"""
logger.info("="*70)
logger.info("πŸ›‘ Shutting Down Services")
logger.info("="*70)
for name, process in processes:
if process and process.poll() is None:
logger.info(f"Terminating {name}...")
process.terminate()
try:
process.wait(timeout=5)
logger.info(f"βœ“ {name} stopped")
except subprocess.TimeoutExpired:
logger.warning(f"Force killing {name}...")
process.kill()
logger.info("All services stopped. Goodbye!")
sys.exit(0)
# Register signal handlers
signal.signal(signal.SIGINT, cleanup)
signal.signal(signal.SIGTERM, cleanup)
def start_service(name, command, wait_time=2, show_output=False):
"""Start a service and add it to the process list"""
logger.info(f"Starting {name}...")
logger.debug(f"Command: {' '.join(command)}")
try:
if show_output:
# Show output directly
process = subprocess.Popen(
command,
text=True
)
else:
# Capture output for silent services
process = subprocess.Popen(
command,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True,
bufsize=1
)
processes.append((name, process))
time.sleep(wait_time)
# Check if process is still running
if process.poll() is None:
logger.info(f"βœ“ {name} started successfully")
return True
else:
logger.error(f"{name} failed to start")
return False
except Exception as e:
logger.error(f"{name} error: {e}")
return False
def main():
logger.info("="*70)
logger.info("πŸ₯ MedGemma AI Assistant Launcher")
logger.info("="*70)
logger.info("πŸ”§ Running in Local GGUF mode")
# Check requirements
if not check_requirements():
logger.error("Some requirements are missing")
try:
response = input("\nContinue anyway? (y/N): ")
if response.lower() != 'y':
sys.exit(1)
except EOFError:
logger.error("Cannot prompt for input (non-interactive mode). Exiting.")
sys.exit(1)
logger.info("Starting Services...")
# Service 1: Model Server (Classification, Detection, Segmentation)
if not start_service(
"Model Server",
[sys.executable, "src/server_models.py"],
wait_time=3
):
logger.error("Failed to start model server. Exiting.")
cleanup()
return
# Service 2: GGUF llama-servers
logger.info("Starting llama-servers...")
llama_servers = [
("Base LLM (8080)", "Models/Medgemma_Base/medgemma-4b-it-Q5_K_M.gguf",
"Models/Medgemma_Base/mmproj-F16.gguf", "8080"),
("FT LLM (8081)", "Models/Medgemma_FT/brats_medgemma-q5_k_m.gguf",
"Models/Medgemma_FT/mmproj_model_f16.gguf", "8081")
]
for name, model_path, mmproj_path, port in llama_servers:
if Path(model_path).exists() and Path(mmproj_path).exists():
start_service(
name,
["llama-server", "--model", model_path, "--mmproj", mmproj_path,
"--port", port, "-np", "5", "-c", "16384"],
wait_time=5
)
else:
logger.warning(f"{name} skipped (model files not found)")
# Service 3: Gradio App
if not start_service(
"Gradio UI (7860)",
[sys.executable, "app.py"],
wait_time=5,
show_output=True
):
logger.error("Failed to start Gradio app. Exiting.")
cleanup()
return
# Wait for Gradio to print URLs
time.sleep(5)
logger.info("="*70)
logger.info("βœ… All Services Running")
logger.info("="*70)
logger.info("πŸ”§ Model Server: http://localhost:8000")
logger.info("πŸ€– Base LLM: http://localhost:8080")
logger.info("🧠 FT LLM: http://localhost:8081")
logger.info("🌐 Gradio UI: http://127.0.0.1:7860 (see URLs above)")
logger.info("="*70)
logger.info("⏸️ Press Ctrl+C to stop all services")
logger.info("="*70)
# Keep the script running and monitor processes
try:
while True:
time.sleep(1)
# Check if any process has died
for name, process in processes:
if process.poll() is not None:
logger.error(f"{name} died unexpectedly (exit code: {process.returncode})")
cleanup()
return
except KeyboardInterrupt:
cleanup()
if __name__ == "__main__":
main()