abhiraj12 commited on
Commit
de92ddc
·
1 Parent(s): c5887d5

Fix 403 error: Unify deployment on port 7860 using FastAPI reverse proxy for Streamlit

Browse files
backend/main.py CHANGED
@@ -9,6 +9,9 @@ from fastapi.responses import FileResponse
9
  from fastapi.staticfiles import StaticFiles
10
  from contextlib import asynccontextmanager
11
  from infra.logger import get_logger
 
 
 
12
 
13
  log = get_logger(__name__)
14
  WEB_DIR = Path(__file__).resolve().parent.parent / "frontend" / "web"
@@ -162,6 +165,44 @@ def health_check():
162
  return {"status": "ok", "version": "4.0.0"}
163
 
164
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
  if __name__ == "__main__":
166
  try:
167
  import uvicorn
 
9
  from fastapi.staticfiles import StaticFiles
10
  from contextlib import asynccontextmanager
11
  from infra.logger import get_logger
12
+ import httpx
13
+ from fastapi import Request
14
+ from fastapi.responses import StreamingResponse
15
 
16
  log = get_logger(__name__)
17
  WEB_DIR = Path(__file__).resolve().parent.parent / "frontend" / "web"
 
165
  return {"status": "ok", "version": "4.0.0"}
166
 
167
 
168
+ # ── Streamlit Reverse Proxy ──────────────────────────────────────────────────
169
+ # This catch-all route forwards any non-API requests to the Streamlit port (8001).
170
+ STREAMLIT_URL = "http://localhost:8001"
171
+
172
+ @app.api_route("/{path_name:path}", include_in_schema=False)
173
+ async def _proxy_to_streamlit(request: Request, path_name: str):
174
+ # Skip if the path is explicitly an API route (though FastAPI should have caught it)
175
+ if path_name.startswith("api/") or path_name.startswith("docs") or path_name.startswith("redoc") or path_name.startswith("openapi.json"):
176
+ return {"error": "Not Found"}
177
+
178
+ target_url = f"{STREAMLIT_URL}/{path_name}"
179
+ if request.query_params:
180
+ target_url += f"?{request.query_params}"
181
+
182
+ async with httpx.AsyncClient() as client:
183
+ # Standard proxy logic
184
+ method = request.method
185
+ headers = dict(request.headers)
186
+ # We must remove host and adjust for the internal service
187
+ headers.pop("host", None)
188
+
189
+ # Handle Streamlit's specific requirements (like websockets if needed, but simple HTTP first)
190
+ response = await client.request(
191
+ method,
192
+ target_url,
193
+ content=await request.body(),
194
+ headers=headers,
195
+ timeout=60.0,
196
+ follow_redirects=True,
197
+ )
198
+
199
+ return StreamingResponse(
200
+ response.aiter_bytes(),
201
+ status_code=response.status_code,
202
+ headers=dict(response.headers),
203
+ )
204
+
205
+
206
  if __name__ == "__main__":
207
  try:
208
  import uvicorn
frontend/pages/1_Home.py CHANGED
@@ -9,7 +9,7 @@ from ui_shell import (
9
  render_workspace_banner,
10
  )
11
 
12
- API_URL = "http://localhost:8000/api"
13
 
14
  st.set_page_config(page_title="Home - AutoML Studio", page_icon="🏠", layout="wide")
15
 
 
9
  render_workspace_banner,
10
  )
11
 
12
+ API_URL = "http://localhost:7860/api"
13
 
14
  st.set_page_config(page_title="Home - AutoML Studio", page_icon="🏠", layout="wide")
15
 
frontend/pages/2_Dataset_DNA.py CHANGED
@@ -10,7 +10,7 @@ from ui_shell import (
10
  render_workspace_banner,
11
  )
12
 
13
- API_URL = "http://localhost:8000/api"
14
 
15
  st.set_page_config(page_title="Dataset DNA", page_icon="🧬", layout="wide")
16
 
 
10
  render_workspace_banner,
11
  )
12
 
13
+ API_URL = "http://localhost:7860/api"
14
 
15
  st.set_page_config(page_title="Dataset DNA", page_icon="🧬", layout="wide")
16
 
frontend/pages/3_Training_Lab.py CHANGED
@@ -10,7 +10,7 @@ from ui_shell import (
10
  render_workspace_banner,
11
  )
12
 
13
- API_URL = "http://localhost:8000/api"
14
 
15
  st.set_page_config(page_title="Live Training & Results", page_icon="⚡", layout="wide")
16
 
 
10
  render_workspace_banner,
11
  )
12
 
13
+ API_URL = "http://localhost:7860/api"
14
 
15
  st.set_page_config(page_title="Live Training & Results", page_icon="⚡", layout="wide")
16
 
frontend/pages/4_Results_Console.py CHANGED
@@ -14,7 +14,7 @@ from ui_shell import (
14
  render_workspace_banner,
15
  )
16
 
17
- API_URL = "http://localhost:8000/api"
18
 
19
  st.set_page_config(page_title="Results Console - AutoML Studio", page_icon="📊", layout="wide")
20
 
 
14
  render_workspace_banner,
15
  )
16
 
17
+ API_URL = "http://localhost:7860/api"
18
 
19
  st.set_page_config(page_title="Results Console - AutoML Studio", page_icon="📊", layout="wide")
20
 
frontend/pages/5_Experiment_Tracker.py CHANGED
@@ -9,7 +9,7 @@ from ui_shell import (
9
  render_workspace_banner,
10
  )
11
 
12
- API_URL = "http://localhost:8000/api"
13
 
14
 
15
  def api_json(path: str, timeout: int = 10):
 
9
  render_workspace_banner,
10
  )
11
 
12
+ API_URL = "http://localhost:7860/api"
13
 
14
 
15
  def api_json(path: str, timeout: int = 10):
frontend/pages/6_Drift_Monitor.py CHANGED
@@ -9,7 +9,7 @@ from ui_shell import (
9
  render_workspace_banner,
10
  )
11
 
12
- API_URL = "http://localhost:8000/api"
13
 
14
  st.set_page_config(page_title="Drift Monitor", page_icon="📉", layout="wide")
15
 
 
9
  render_workspace_banner,
10
  )
11
 
12
+ API_URL = "http://localhost:7860/api"
13
 
14
  st.set_page_config(page_title="Drift Monitor", page_icon="📉", layout="wide")
15
 
frontend/pages/7_Smart_AI_Hub.py CHANGED
@@ -10,7 +10,7 @@ from ui_shell import (
10
  render_workspace_banner,
11
  )
12
 
13
- API_URL = "http://localhost:8000/api"
14
 
15
  st.set_page_config(page_title="Smart AI Hub - AutoML Studio", page_icon="🤖", layout="wide")
16
 
 
10
  render_workspace_banner,
11
  )
12
 
13
+ API_URL = "http://localhost:7860/api"
14
 
15
  st.set_page_config(page_title="Smart AI Hub - AutoML Studio", page_icon="🤖", layout="wide")
16
 
frontend/ui_shell.py CHANGED
@@ -4,7 +4,7 @@ from typing import Iterable, Optional
4
  import requests
5
  import streamlit as st
6
 
7
- API_URL = "http://localhost:8000/api"
8
 
9
  SESSION_DEFAULTS = {
10
  "dataset_id": None,
 
4
  import requests
5
  import streamlit as st
6
 
7
+ API_URL = "http://localhost:7860/api"
8
 
9
  SESSION_DEFAULTS = {
10
  "dataset_id": None,
requirements.txt CHANGED
@@ -30,6 +30,7 @@ Pillow>=10.3.0
30
  # ── Async / Background Jobs ─────────────────────────────
31
  celery==5.4.0
32
  redis==5.0.4
 
33
 
34
  # ── Database ────────────────────────────────────────────
35
  sqlalchemy==2.0.30
 
30
  # ── Async / Background Jobs ─────────────────────────────
31
  celery==5.4.0
32
  redis==5.0.4
33
+ httpx>=0.27.0
34
 
35
  # ── Database ────────────────────────────────────────────
36
  sqlalchemy==2.0.30
start.sh CHANGED
@@ -15,22 +15,23 @@ echo "Starting Redis..."
15
  redis-server --port 6379 --dir /tmp --dbfilename dump.rdb --daemonize no &
16
  REDIS_PID=$!
17
 
18
- # 2. Start FastAPI Backend (Internal API)
19
- echo "Starting FastAPI Backend..."
20
  cd "$SCRIPT_DIR/backend"
21
- python -m uvicorn main:app --host 0.0.0.0 --port 8000 --timeout-keep-alive 600 &
22
  BACKEND_PID=$!
23
 
24
  # 3. Start Celery Worker (Task Processor)
25
  echo "Starting Celery Worker..."
26
- # We run this from the backend directory where core.worker is accessible
27
  python -m celery -A core.worker.celery_app worker --loglevel=info --concurrency=1 &
28
  WORKER_PID=$!
29
 
30
- # 4. Start Streamlit Frontend (Public UI)
31
- echo "Starting Streamlit Frontend on port ${PORT:-7860}..."
 
32
  cd "$SCRIPT_DIR/frontend"
33
- python -m streamlit run app.py --server.port "${PORT:-7860}" --server.headless true --server.address 0.0.0.0 &
34
  FRONTEND_PID=$!
35
 
36
  echo "🚀 All services launched!"
 
15
  redis-server --port 6379 --dir /tmp --dbfilename dump.rdb --daemonize no &
16
  REDIS_PID=$!
17
 
18
+ # 2. Start FastAPI Backend (Public Gateway)
19
+ echo "Starting FastAPI Backend on port ${PORT:-7860}..."
20
  cd "$SCRIPT_DIR/backend"
21
+ python -m uvicorn main:app --host 0.0.0.0 --port "${PORT:-7860}" --timeout-keep-alive 600 &
22
  BACKEND_PID=$!
23
 
24
  # 3. Start Celery Worker (Task Processor)
25
  echo "Starting Celery Worker..."
26
+ cd "$SCRIPT_DIR/backend"
27
  python -m celery -A core.worker.celery_app worker --loglevel=info --concurrency=1 &
28
  WORKER_PID=$!
29
 
30
+ # 4. Start Streamlit Frontend (Internal Service)
31
+ # This port (8001) will be proxied by FastAPI.
32
+ echo "Starting Streamlit Frontend on internal port 8001..."
33
  cd "$SCRIPT_DIR/frontend"
34
+ python -m streamlit run app.py --server.port 8001 --server.headless true --server.address 127.0.0.1 &
35
  FRONTEND_PID=$!
36
 
37
  echo "🚀 All services launched!"