Spaces:
Sleeping
Sleeping
| """ | |
| Modal deployment script for Hue Portal Backend (Django) | |
| Based on flux-modal pattern: https://github.com/omarkortam/flux-modal | |
| """ | |
| import os | |
| import subprocess | |
| from pathlib import Path | |
| import modal | |
| # Build Docker image with all dependencies | |
| hue_backend_image = ( | |
| modal.Image.debian_slim(python_version="3.11") | |
| .apt_install( | |
| "git", | |
| "build-essential", | |
| "tesseract-ocr", | |
| "tesseract-ocr-eng", | |
| "tesseract-ocr-vie", | |
| "libpoppler-cpp-dev", | |
| "pkg-config", | |
| "libgl1", | |
| ) | |
| .pip_install( | |
| "Django==5.0.6", | |
| "djangorestframework==3.15.2", | |
| "django-cors-headers==4.4.0", | |
| "psycopg2-binary==2.9.9", | |
| "django-environ==0.11.2", | |
| "gunicorn==22.0.0", | |
| "whitenoise==6.6.0", | |
| "redis==5.0.6", | |
| "celery==5.4.0", | |
| "scikit-learn==1.3.2", | |
| "numpy==1.24.3", | |
| "scipy==1.11.4", | |
| "pydantic>=2.0.0,<3.0.0", | |
| "sentence-transformers>=2.2.0", | |
| "torch>=2.0.0", | |
| "faiss-cpu>=1.7.4", | |
| "python-docx==0.8.11", | |
| "PyMuPDF==1.24.3", | |
| "Pillow>=8.0.0,<12.0", | |
| "pytesseract==0.3.13", | |
| "requests>=2.31.0", | |
| ) | |
| # Copy backend code | |
| .copy_local_dir("backend", "/app") | |
| .run_commands( | |
| "mkdir -p /app/hue_portal/static /app/hue_portal/media", | |
| "chmod +x /app/hue_portal/manage.py", | |
| ) | |
| ) | |
| app = modal.App(name="hue-portal-backend", image=hue_backend_image) | |
| # Mount backend directory | |
| backend_mount = modal.Mount.from_local_dir("backend", remote_path="/app") | |
| def web(): | |
| """Start Django application with Gunicorn.""" | |
| import os | |
| # Set working directory | |
| os.chdir("/app/hue_portal") | |
| # Run migrations | |
| print("[Modal] Running migrations...") | |
| migrate_result = subprocess.run( | |
| ["python", "manage.py", "migrate", "--noinput"], | |
| capture_output=True, | |
| text=True, | |
| check=False, | |
| ) | |
| if migrate_result.returncode != 0: | |
| print(f"[Modal] Migration warning: {migrate_result.stderr[:200]}") | |
| else: | |
| print("[Modal] Migrations completed") | |
| # Collect static files | |
| print("[Modal] Collecting static files...") | |
| collect_result = subprocess.run( | |
| ["python", "manage.py", "collectstatic", "--noinput"], | |
| capture_output=True, | |
| text=True, | |
| check=False, | |
| ) | |
| if collect_result.returncode != 0: | |
| print(f"[Modal] Collectstatic warning: {collect_result.stderr[:200]}") | |
| else: | |
| print("[Modal] Static files collected") | |
| # Start Gunicorn | |
| print("[Modal] Starting Gunicorn on 0.0.0.0:8000...") | |
| gunicorn_process = subprocess.Popen( | |
| [ | |
| "gunicorn", | |
| "-b", "0.0.0.0:8000", | |
| "--workers", "2", # Reduced for Modal | |
| "--timeout", "120", | |
| "--access-logfile", "-", | |
| "--error-logfile", "-", | |
| "hue_portal.wsgi:application", | |
| ], | |
| cwd="/app/hue_portal", | |
| ) | |
| print("[Modal] Gunicorn started, waiting...") | |
| # Keep process alive and monitor | |
| import time | |
| try: | |
| while True: | |
| # Check if gunicorn is still running | |
| if gunicorn_process.poll() is not None: | |
| print(f"[Modal] Gunicorn exited with code {gunicorn_process.returncode}") | |
| break | |
| time.sleep(1) | |
| except KeyboardInterrupt: | |
| print("[Modal] Shutting down...") | |
| gunicorn_process.terminate() | |
| gunicorn_process.wait() | |