Robert Yaw Agyekum Addo commited on
Commit
8f61658
·
1 Parent(s): f38258d

Changes made

Browse files
Files changed (2) hide show
  1. Dockerfile +9 -7
  2. app/main.py +85 -6
Dockerfile CHANGED
@@ -24,7 +24,8 @@ RUN apt-get update && \
24
  libtesseract-dev \
25
  tesseract-ocr-eng \
26
  tesseract-ocr-fra \
27
- tesseract-ocr-spa && \
 
28
  rm -rf /var/lib/apt/lists/*
29
 
30
  # Copy Python dependencies from system locations
@@ -33,10 +34,6 @@ COPY --from=builder /usr/local/bin/gunicorn /usr/local/bin/
33
  COPY --from=builder /usr/local/bin/uvicorn /usr/local/bin/
34
  COPY . .
35
 
36
- # Health check endpoint
37
- HEALTHCHECK --interval=30s --timeout=30s --start-period=5s --retries=3 \
38
- CMD curl -f http://localhost:8000/health || exit 1
39
-
40
  # Create non-root user and set permissions
41
  RUN useradd -m appuser && \
42
  chown -R appuser:appuser /app && \
@@ -46,6 +43,11 @@ RUN useradd -m appuser && \
46
  # Switch to non-root user
47
  USER appuser
48
 
49
- EXPOSE 8000
 
 
 
 
50
 
51
- CMD ["gunicorn", "-k", "uvicorn.workers.UvicornWorker", "-b", "0.0.0.0:8000", "--timeout", "120", "app.main:app"]
 
 
24
  libtesseract-dev \
25
  tesseract-ocr-eng \
26
  tesseract-ocr-fra \
27
+ tesseract-ocr-spa \
28
+ curl && \
29
  rm -rf /var/lib/apt/lists/*
30
 
31
  # Copy Python dependencies from system locations
 
34
  COPY --from=builder /usr/local/bin/uvicorn /usr/local/bin/
35
  COPY . .
36
 
 
 
 
 
37
  # Create non-root user and set permissions
38
  RUN useradd -m appuser && \
39
  chown -R appuser:appuser /app && \
 
43
  # Switch to non-root user
44
  USER appuser
45
 
46
+ # Health check with longer intervals and start period for model loading
47
+ HEALTHCHECK --interval=60s --timeout=30s --start-period=300s --retries=5 \
48
+ CMD curl -f http://localhost:7860/health || exit 1
49
+
50
+ EXPOSE 7860
51
 
52
+ # Use port 7860 which is standard for Hugging Face Spaces
53
+ CMD ["gunicorn", "-k", "uvicorn.workers.UvicornWorker", "-b", "0.0.0.0:7860", "--timeout", "300", "--worker-connections", "10", "app.main:app"]
app/main.py CHANGED
@@ -1,18 +1,97 @@
1
  from fastapi import FastAPI
2
  from fastapi.middleware.cors import CORSMiddleware
 
 
3
  from fastapi import FastAPI
4
  from .api.v1.router import router as api_router
5
  from app.api.v1.endpoints import transcription, ocr, translation, tts
 
 
6
 
7
  app = FastAPI(generate_unique_id_function=lambda route: f"{route.tags[0]}_{route.name}")
8
 
9
- app.include_router(api_router)
 
 
10
 
11
- #app = FastAPI(
12
- # title="Polyglot API",
13
- # description="Multilingual Communication Suite",
14
- # version="1.0.0"
15
- #)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
  # CORS configuration
18
  app.add_middleware(
 
1
  from fastapi import FastAPI
2
  from fastapi.middleware.cors import CORSMiddleware
3
+ from fastapi.responses import JSONResponse
4
+ import asyncio
5
  from fastapi import FastAPI
6
  from .api.v1.router import router as api_router
7
  from app.api.v1.endpoints import transcription, ocr, translation, tts
8
+ import logging
9
+ logging.basicConfig(level=logging.INFO)
10
 
11
  app = FastAPI(generate_unique_id_function=lambda route: f"{route.tags[0]}_{route.name}")
12
 
13
+ # Global flag to track if models are loaded
14
+ models_loaded = False
15
+ loading_progress = {"status": "initializing", "message": "Starting model loading..."}
16
 
17
+ async def load_models():
18
+ """Load heavy models asynchronously during startup"""
19
+ global models_loaded, loading_progress
20
+
21
+ try:
22
+ loading_progress["status"] = "loading"
23
+ loading_progress["message"] = "Loading Whisper model..."
24
+
25
+ # Load your Whisper model here
26
+ # whisper_model = whisper.load_model("base")
27
+
28
+ loading_progress["message"] = "Loading TTS model..."
29
+ # Load your TTS model here
30
+
31
+ loading_progress["message"] = "Loading translator..."
32
+ # Initialize deep-translator
33
+
34
+ models_loaded = True
35
+ loading_progress["status"] = "ready"
36
+ loading_progress["message"] = "All models loaded successfully"
37
+ logging.info("All models loaded successfully")
38
+
39
+ except Exception as e:
40
+ loading_progress["status"] = "error"
41
+ loading_progress["message"] = f"Error loading models: {str(e)}"
42
+ logging.error(f"Error loading models: {str(e)}")
43
+
44
+ @app.on_event("startup")
45
+ async def startup_event():
46
+ """Start model loading in background during app startup"""
47
+ asyncio.create_task(load_models())
48
+
49
+ @app.get("/health")
50
+ async def health_check():
51
+ """
52
+ Health check endpoint that responds quickly
53
+ Returns different status based on model loading progress
54
+ """
55
+ if models_loaded:
56
+ return JSONResponse(
57
+ status_code=200,
58
+ content={
59
+ "status": "healthy",
60
+ "models_loaded": True,
61
+ "message": "Service is ready"
62
+ }
63
+ )
64
+ else:
65
+ # Return 200 even during loading to pass health checks
66
+ # But indicate that models are still loading
67
+ return JSONResponse(
68
+ status_code=200,
69
+ content={
70
+ "status": "loading",
71
+ "models_loaded": False,
72
+ "progress": loading_progress
73
+ }
74
+ )
75
+
76
+ @app.get("/ready")
77
+ async def readiness_check():
78
+ """
79
+ Separate readiness endpoint for when models are fully loaded
80
+ """
81
+ if models_loaded:
82
+ return JSONResponse(
83
+ status_code=200,
84
+ content={"status": "ready", "models_loaded": True}
85
+ )
86
+ else:
87
+ return JSONResponse(
88
+ status_code=503,
89
+ content={
90
+ "status": "not_ready",
91
+ "models_loaded": False,
92
+ "progress": loading_progress
93
+ }
94
+ )
95
 
96
  # CORS configuration
97
  app.add_middleware(