deploy
Browse files- Dockerfile +3 -3
- app.py +17 -5
Dockerfile
CHANGED
@@ -24,8 +24,8 @@ COPY app.py .
|
|
24 |
# Set environment variable for Hugging Face cache
|
25 |
ENV HF_HOME=/app/cache
|
26 |
|
27 |
-
# Expose port
|
28 |
EXPOSE 8000
|
29 |
|
30 |
-
# Run the FastAPI app with uvicorn
|
31 |
-
CMD ["sh", "-c", "uvicorn app:app --host 0.0.0.0 --port ${PORT:-8000}"]
|
|
|
24 |
# Set environment variable for Hugging Face cache
|
25 |
ENV HF_HOME=/app/cache
|
26 |
|
27 |
+
# Expose default port (can be overridden by PORT env var)
|
28 |
EXPOSE 8000
|
29 |
|
30 |
+
# Run the FastAPI app with uvicorn, using PORT env var
|
31 |
+
CMD ["sh", "-c", "uvicorn app:app --host 0.0.0.0 --port ${PORT:-8000} --workers 1"]
|
app.py
CHANGED
@@ -10,6 +10,7 @@ import subprocess
|
|
10 |
import tempfile
|
11 |
from contextlib import contextmanager
|
12 |
|
|
|
13 |
logging.basicConfig(
|
14 |
level=logging.INFO,
|
15 |
format="%(asctime)s [%(levelname)s] %(message)s",
|
@@ -20,6 +21,7 @@ logging.basicConfig(
|
|
20 |
)
|
21 |
logger = logging.getLogger(__name__)
|
22 |
|
|
|
23 |
logger.info(f"Python version: {sys.version}")
|
24 |
try:
|
25 |
import transformers
|
@@ -30,26 +32,33 @@ except ImportError as e:
|
|
30 |
logger.error(f"Failed to import dependency: {str(e)}")
|
31 |
raise
|
32 |
|
|
|
33 |
os.makedirs("/app/cache", exist_ok=True)
|
34 |
os.environ["HF_HOME"] = "/app/cache"
|
35 |
logger.info(f"Set HF_HOME to /app/cache")
|
36 |
|
|
|
37 |
app = FastAPI(title="Quran Transcription API")
|
38 |
|
|
|
39 |
@app.get("/health", status_code=200)
|
40 |
async def health_check():
|
41 |
logger.info("Health check requested")
|
42 |
return {"status": "healthy", "model_loaded": model is not None}
|
43 |
|
|
|
44 |
@app.get("/debug")
|
45 |
async def debug():
|
|
|
46 |
return {
|
47 |
"cuda_available": torch.cuda.is_available(),
|
48 |
"model_loaded": model is not None,
|
49 |
"pipeline_initialized": asr is not None,
|
50 |
-
"cache_dir": os.getenv("HF_HOME")
|
|
|
51 |
}
|
52 |
|
|
|
53 |
try:
|
54 |
model_id = "tarteel-ai/whisper-base-ar-quran"
|
55 |
logger.info(f"Loading processor for model: {model_id}")
|
@@ -61,6 +70,7 @@ except Exception as e:
|
|
61 |
logger.error(f"Failed to load model: {str(e)}")
|
62 |
raise HTTPException(status_code=500, detail="Model loading failed")
|
63 |
|
|
|
64 |
try:
|
65 |
logger.info("Initializing ASR pipeline")
|
66 |
asr = pipeline(
|
@@ -68,7 +78,7 @@ try:
|
|
68 |
model=model,
|
69 |
tokenizer=processor.tokenizer,
|
70 |
feature_extractor=processor.feature_extractor,
|
71 |
-
device=-1 # Force CPU
|
72 |
)
|
73 |
except Exception as e:
|
74 |
logger.error(f"Failed to initialize ASR pipeline: {str(e)}")
|
@@ -111,7 +121,8 @@ async def transcribe_audio(file: UploadFile = File(...)):
|
|
111 |
["ffmpeg", "-i", temp_mp3.name, "-ar", "16000", "-ac", "1", "-y", temp_wav_path],
|
112 |
check=True,
|
113 |
capture_output=True,
|
114 |
-
text=True
|
|
|
115 |
)
|
116 |
logger.debug(f"ffmpeg output: {result.stdout}")
|
117 |
except subprocess.CalledProcessError as e:
|
@@ -145,11 +156,12 @@ async def startup_event():
|
|
145 |
logger.info(f"Memory allocated: {torch.cuda.memory_allocated() if torch.cuda.is_available() else 'N/A'}")
|
146 |
|
147 |
if __name__ == "__main__":
|
148 |
-
port = int(os.getenv("PORT", 8000))
|
149 |
logger.info(f"Starting Uvicorn server on port {port}")
|
150 |
uvicorn.run(
|
151 |
"app:app",
|
152 |
host="0.0.0.0",
|
153 |
port=port,
|
154 |
-
log_level="info"
|
|
|
155 |
)
|
|
|
10 |
import tempfile
|
11 |
from contextlib import contextmanager
|
12 |
|
13 |
+
# Configure logging
|
14 |
logging.basicConfig(
|
15 |
level=logging.INFO,
|
16 |
format="%(asctime)s [%(levelname)s] %(message)s",
|
|
|
21 |
)
|
22 |
logger = logging.getLogger(__name__)
|
23 |
|
24 |
+
# Log system information
|
25 |
logger.info(f"Python version: {sys.version}")
|
26 |
try:
|
27 |
import transformers
|
|
|
32 |
logger.error(f"Failed to import dependency: {str(e)}")
|
33 |
raise
|
34 |
|
35 |
+
# Set up cache directory
|
36 |
os.makedirs("/app/cache", exist_ok=True)
|
37 |
os.environ["HF_HOME"] = "/app/cache"
|
38 |
logger.info(f"Set HF_HOME to /app/cache")
|
39 |
|
40 |
+
# Initialize FastAPI app
|
41 |
app = FastAPI(title="Quran Transcription API")
|
42 |
|
43 |
+
# Health check endpoint
|
44 |
@app.get("/health", status_code=200)
|
45 |
async def health_check():
|
46 |
logger.info("Health check requested")
|
47 |
return {"status": "healthy", "model_loaded": model is not None}
|
48 |
|
49 |
+
# Debug endpoint
|
50 |
@app.get("/debug")
|
51 |
async def debug():
|
52 |
+
logger.info("Debug endpoint requested")
|
53 |
return {
|
54 |
"cuda_available": torch.cuda.is_available(),
|
55 |
"model_loaded": model is not None,
|
56 |
"pipeline_initialized": asr is not None,
|
57 |
+
"cache_dir": os.getenv("HF_HOME"),
|
58 |
+
"port": os.getenv("PORT", "8000")
|
59 |
}
|
60 |
|
61 |
+
# Load model and processor
|
62 |
try:
|
63 |
model_id = "tarteel-ai/whisper-base-ar-quran"
|
64 |
logger.info(f"Loading processor for model: {model_id}")
|
|
|
70 |
logger.error(f"Failed to load model: {str(e)}")
|
71 |
raise HTTPException(status_code=500, detail="Model loading failed")
|
72 |
|
73 |
+
# Initialize ASR pipeline
|
74 |
try:
|
75 |
logger.info("Initializing ASR pipeline")
|
76 |
asr = pipeline(
|
|
|
78 |
model=model,
|
79 |
tokenizer=processor.tokenizer,
|
80 |
feature_extractor=processor.feature_extractor,
|
81 |
+
device=-1 # Force CPU
|
82 |
)
|
83 |
except Exception as e:
|
84 |
logger.error(f"Failed to initialize ASR pipeline: {str(e)}")
|
|
|
121 |
["ffmpeg", "-i", temp_mp3.name, "-ar", "16000", "-ac", "1", "-y", temp_wav_path],
|
122 |
check=True,
|
123 |
capture_output=True,
|
124 |
+
text=True,
|
125 |
+
timeout=30
|
126 |
)
|
127 |
logger.debug(f"ffmpeg output: {result.stdout}")
|
128 |
except subprocess.CalledProcessError as e:
|
|
|
156 |
logger.info(f"Memory allocated: {torch.cuda.memory_allocated() if torch.cuda.is_available() else 'N/A'}")
|
157 |
|
158 |
if __name__ == "__main__":
|
159 |
+
port = int(os.getenv("PORT", 8000)) # Use PORT env var or default to 8000
|
160 |
logger.info(f"Starting Uvicorn server on port {port}")
|
161 |
uvicorn.run(
|
162 |
"app:app",
|
163 |
host="0.0.0.0",
|
164 |
port=port,
|
165 |
+
log_level="info",
|
166 |
+
workers=1 # Single worker to avoid resource issues
|
167 |
)
|