ranilmukesh commited on
Commit
ec40ef6
·
1 Parent(s): 15697f2
Files changed (3) hide show
  1. Dockerfile +15 -5
  2. main.py +59 -5
  3. requirements.txt +2 -1
Dockerfile CHANGED
@@ -1,20 +1,32 @@
1
  # Use official Python 3.11 as base image
2
  FROM python:3.11-slim
3
 
4
- # Install system dependencies
5
  RUN apt-get update && apt-get install -y \
6
  build-essential \
7
  curl \
8
  git \
 
9
  && rm -rf /var/lib/apt/lists/*
10
 
 
 
 
 
11
  # Set up non-root user (HF Standard)
12
  RUN useradd -m -u 1000 user
13
  ENV HOME=/home/user \
14
- PATH=/home/user/.local/bin:$PATH
 
 
 
 
15
 
16
  WORKDIR $HOME/app
17
 
 
 
 
18
  # Copy and install basic deps
19
  COPY --chown=user requirements.txt requirements.txt
20
  RUN pip install --no-cache-dir --upgrade pip && \
@@ -31,9 +43,7 @@ RUN mkdir -p /tmp/tmp && chown -R user:user /tmp/tmp
31
  RUN ln -s /tmp/tmp tmp
32
 
33
  # Hugging Face PORT is 7860
34
- ENV PORT=7860 \
35
- PYTHONUNBUFFERED=1 \
36
- PYTHONDONTWRITEBYTECODE=1
37
 
38
  USER user
39
  EXPOSE 7860
 
1
  # Use official Python 3.11 as base image
2
  FROM python:3.11-slim
3
 
4
+ # Install system dependencies including timezone data
5
  RUN apt-get update && apt-get install -y \
6
  build-essential \
7
  curl \
8
  git \
9
+ tzdata \
10
  && rm -rf /var/lib/apt/lists/*
11
 
12
+ # Set timezone to Asia/Kolkata (IST)
13
+ ENV TZ=Asia/Kolkata
14
+ RUN ln -snf /usr/share/zoneinfo/Asia/Kolkata /etc/localtime && echo Asia/Kolkata > /etc/timezone
15
+
16
  # Set up non-root user (HF Standard)
17
  RUN useradd -m -u 1000 user
18
  ENV HOME=/home/user \
19
+ PATH=/home/user/.local/bin:$PATH \
20
+ MPLCONFIGDIR=/tmp/.matplotlib \
21
+ PYTHONUNBUFFERED=1 \
22
+ PYTHONDONTWRITEBYTECODE=1 \
23
+ TZ=Asia/Kolkata
24
 
25
  WORKDIR $HOME/app
26
 
27
+ # Create matplotlib config directory
28
+ RUN mkdir -p /tmp/.matplotlib && chown -R user:user /tmp/.matplotlib
29
+
30
  # Copy and install basic deps
31
  COPY --chown=user requirements.txt requirements.txt
32
  RUN pip install --no-cache-dir --upgrade pip && \
 
43
  RUN ln -s /tmp/tmp tmp
44
 
45
  # Hugging Face PORT is 7860
46
+ ENV PORT=7860
 
 
47
 
48
  USER user
49
  EXPOSE 7860
main.py CHANGED
@@ -2,21 +2,72 @@ import pandas as pd
2
  import numpy as np
3
  import joblib
4
  import shap
5
- from fastapi import FastAPI, HTTPException
6
  from fastapi.middleware.cors import CORSMiddleware
7
  from fastapi.staticfiles import StaticFiles
8
  from fastapi.responses import FileResponse
9
  from pydantic import BaseModel, Field
10
  from typing import Optional, List
11
  import os
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
  try:
14
  from llm import start_chat_session, get_chat_response
15
  CHAT_AVAILABLE = True
16
- print("[OK] LLM Chat module loaded")
17
  except Exception as _llm_err:
18
  CHAT_AVAILABLE = False
19
- print(f"[!] LLM Chat unavailable: {_llm_err}")
20
 
21
  app = FastAPI(
22
  title="PlacementPredictor+",
@@ -24,6 +75,9 @@ app = FastAPI(
24
  version="1.0.0"
25
  )
26
 
 
 
 
27
  app.add_middleware(
28
  CORSMiddleware,
29
  allow_origins=["*"],
@@ -55,14 +109,14 @@ def load_artifacts():
55
  feature_names = artifacts['feature_names']
56
  routing_engine = artifacts.get('routing_engine')
57
  explainer = shap.TreeExplainer(model)
58
- print("[OK] All artifacts loaded successfully!")
59
 
60
  @app.on_event("startup")
61
  async def startup_event():
62
  try:
63
  load_artifacts()
64
  except Exception as e:
65
- print(f"[!] Warning: {e}")
66
 
67
  class StudentData(BaseModel):
68
  Age: int = Field(..., ge=15, le=40)
 
2
  import numpy as np
3
  import joblib
4
  import shap
5
+ from fastapi import FastAPI, HTTPException, Request
6
  from fastapi.middleware.cors import CORSMiddleware
7
  from fastapi.staticfiles import StaticFiles
8
  from fastapi.responses import FileResponse
9
  from pydantic import BaseModel, Field
10
  from typing import Optional, List
11
  import os
12
+ import logging
13
+ from datetime import datetime
14
+ from pytz import timezone
15
+ from starlette.middleware.base import BaseHTTPMiddleware
16
+
17
+ # Setup IST timezone logging
18
+ IST = timezone('Asia/Kolkata')
19
+
20
+ # Configure logging with IST timezone
21
+ class ISTFormatter(logging.Formatter):
22
+ """Custom formatter for IST timestamps"""
23
+ def formatTime(self, record, datefmt=None):
24
+ dt = datetime.fromtimestamp(record.created, tz=IST)
25
+ if datefmt:
26
+ return dt.strftime(datefmt)
27
+ else:
28
+ return dt.strftime("%Y-%m-%d %H:%M:%S %Z")
29
+
30
+ # Only configure logs from main, not uvicorn multiple times
31
+ if not logging.getLogger("uvicorn").handlers:
32
+ logging.basicConfig(
33
+ level=logging.INFO,
34
+ format='[%(asctime)s] %(levelname)s - %(name)s - %(message)s',
35
+ datefmt='%Y-%m-%d %H:%M:%S %Z'
36
+ )
37
+ # Apply IST formatter
38
+ for handler in logging.root.handlers:
39
+ handler.setFormatter(ISTFormatter('[%(asctime)s] %(levelname)s - %(message)s'))
40
+
41
+ logger = logging.getLogger(__name__)
42
+
43
+ def get_client_ip(request: Request) -> str:
44
+ """Extract client IP from request headers or socket"""
45
+ if 'x-forwarded-for' in request.headers:
46
+ return request.headers['x-forwarded-for'].split(',')[0].strip()
47
+ elif 'x-real-ip' in request.headers:
48
+ return request.headers['x-real-ip']
49
+ else:
50
+ return request.client.host if request.client else "0.0.0.0"
51
+
52
+ class LoggingMiddleware(BaseHTTPMiddleware):
53
+ async def dispatch(self, request: Request, call_next):
54
+ client_ip = get_client_ip(request)
55
+ method = request.method
56
+ path = request.url.path
57
+ logger.info(f"📨 Incoming | IP: {client_ip} | {method} {path}")
58
+
59
+ response = await call_next(request)
60
+
61
+ logger.info(f"✅ Response | IP: {client_ip} | {method} {path} | Status: {response.status_code}")
62
+ return response
63
 
64
  try:
65
  from llm import start_chat_session, get_chat_response
66
  CHAT_AVAILABLE = True
67
+ logger.info("[OK] LLM Chat module loaded")
68
  except Exception as _llm_err:
69
  CHAT_AVAILABLE = False
70
+ logger.warning(f"[!] LLM Chat unavailable: {_llm_err}")
71
 
72
  app = FastAPI(
73
  title="PlacementPredictor+",
 
75
  version="1.0.0"
76
  )
77
 
78
+ # Add logging middleware first
79
+ app.add_middleware(LoggingMiddleware)
80
+
81
  app.add_middleware(
82
  CORSMiddleware,
83
  allow_origins=["*"],
 
109
  feature_names = artifacts['feature_names']
110
  routing_engine = artifacts.get('routing_engine')
111
  explainer = shap.TreeExplainer(model)
112
+ logger.info("[OK] All artifacts loaded successfully!")
113
 
114
  @app.on_event("startup")
115
  async def startup_event():
116
  try:
117
  load_artifacts()
118
  except Exception as e:
119
+ logger.error(f"[!] Warning: {e}")
120
 
121
  class StudentData(BaseModel):
122
  Age: int = Field(..., ge=15, le=40)
requirements.txt CHANGED
@@ -22,4 +22,5 @@ python-multipart
22
  sh
23
  jinja2
24
  python-slugify
25
- sqlalchemy
 
 
22
  sh
23
  jinja2
24
  python-slugify
25
+ sqlalchemy
26
+ pytz