davidtran999 commited on
Commit
89ed9c6
·
verified ·
1 Parent(s): d56ad3e

Upload backend/hue_portal/hue-portal-backendDocker/modal_app.py with huggingface_hub

Browse files
backend/hue_portal/hue-portal-backendDocker/modal_app.py ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Modal deployment script for Hue Portal Backend (Django)
3
+ Based on flux-modal pattern: https://github.com/omarkortam/flux-modal
4
+ """
5
+ import os
6
+ import subprocess
7
+ from pathlib import Path
8
+
9
+ import modal
10
+
11
+ # Build Docker image with all dependencies
12
+ hue_backend_image = (
13
+ modal.Image.debian_slim(python_version="3.11")
14
+ .apt_install(
15
+ "git",
16
+ "build-essential",
17
+ "tesseract-ocr",
18
+ "tesseract-ocr-eng",
19
+ "tesseract-ocr-vie",
20
+ "libpoppler-cpp-dev",
21
+ "pkg-config",
22
+ "libgl1",
23
+ )
24
+ .pip_install(
25
+ "Django==5.0.6",
26
+ "djangorestframework==3.15.2",
27
+ "django-cors-headers==4.4.0",
28
+ "psycopg2-binary==2.9.9",
29
+ "django-environ==0.11.2",
30
+ "gunicorn==22.0.0",
31
+ "whitenoise==6.6.0",
32
+ "redis==5.0.6",
33
+ "celery==5.4.0",
34
+ "scikit-learn==1.3.2",
35
+ "numpy==1.24.3",
36
+ "scipy==1.11.4",
37
+ "pydantic>=2.0.0,<3.0.0",
38
+ "sentence-transformers>=2.2.0",
39
+ "torch>=2.0.0",
40
+ "faiss-cpu>=1.7.4",
41
+ "python-docx==0.8.11",
42
+ "PyMuPDF==1.24.3",
43
+ "Pillow>=8.0.0,<12.0",
44
+ "pytesseract==0.3.13",
45
+ "requests>=2.31.0",
46
+ )
47
+ # Copy backend code
48
+ .copy_local_dir("backend", "/app")
49
+ .run_commands(
50
+ "mkdir -p /app/hue_portal/static /app/hue_portal/media",
51
+ "chmod +x /app/hue_portal/manage.py",
52
+ )
53
+ )
54
+
55
+ app = modal.App(name="hue-portal-backend", image=hue_backend_image)
56
+
57
+
58
+ # Mount backend directory
59
+ backend_mount = modal.Mount.from_local_dir("backend", remote_path="/app")
60
+
61
+ @app.function(
62
+ allow_concurrent_inputs=100,
63
+ concurrency_limit=10,
64
+ container_idle_timeout=300, # 5 minutes
65
+ timeout=600, # 10 minutes max request time
66
+ cpu=2, # 2 CPUs
67
+ memory=4096, # 4GB RAM
68
+ secrets=[
69
+ modal.Secret.from_name("hue-portal-secrets", required=False), # Optional for now
70
+ ],
71
+ mounts=[backend_mount],
72
+ )
73
+ @modal.web_server(8000, startup_timeout=180)
74
+ def web():
75
+ """Start Django application with Gunicorn."""
76
+ import os
77
+
78
+ # Set working directory
79
+ os.chdir("/app/hue_portal")
80
+
81
+ # Run migrations
82
+ print("[Modal] Running migrations...")
83
+ migrate_result = subprocess.run(
84
+ ["python", "manage.py", "migrate", "--noinput"],
85
+ capture_output=True,
86
+ text=True,
87
+ check=False,
88
+ )
89
+ if migrate_result.returncode != 0:
90
+ print(f"[Modal] Migration warning: {migrate_result.stderr[:200]}")
91
+ else:
92
+ print("[Modal] Migrations completed")
93
+
94
+ # Collect static files
95
+ print("[Modal] Collecting static files...")
96
+ collect_result = subprocess.run(
97
+ ["python", "manage.py", "collectstatic", "--noinput"],
98
+ capture_output=True,
99
+ text=True,
100
+ check=False,
101
+ )
102
+ if collect_result.returncode != 0:
103
+ print(f"[Modal] Collectstatic warning: {collect_result.stderr[:200]}")
104
+ else:
105
+ print("[Modal] Static files collected")
106
+
107
+ # Start Gunicorn
108
+ print("[Modal] Starting Gunicorn on 0.0.0.0:8000...")
109
+ gunicorn_process = subprocess.Popen(
110
+ [
111
+ "gunicorn",
112
+ "-b", "0.0.0.0:8000",
113
+ "--workers", "2", # Reduced for Modal
114
+ "--timeout", "120",
115
+ "--access-logfile", "-",
116
+ "--error-logfile", "-",
117
+ "hue_portal.wsgi:application",
118
+ ],
119
+ cwd="/app/hue_portal",
120
+ )
121
+
122
+ print("[Modal] Gunicorn started, waiting...")
123
+
124
+ # Keep process alive and monitor
125
+ import time
126
+ try:
127
+ while True:
128
+ # Check if gunicorn is still running
129
+ if gunicorn_process.poll() is not None:
130
+ print(f"[Modal] Gunicorn exited with code {gunicorn_process.returncode}")
131
+ break
132
+ time.sleep(1)
133
+ except KeyboardInterrupt:
134
+ print("[Modal] Shutting down...")
135
+ gunicorn_process.terminate()
136
+ gunicorn_process.wait()