|
#!/bin/bash |
|
|
|
|
|
set -e |
|
|
|
|
|
RED='\033[0;31m' |
|
GREEN='\033[0;32m' |
|
YELLOW='\033[1;33m' |
|
BLUE='\033[0;34m' |
|
NC='\033[0m' |
|
|
|
|
|
log() { |
|
echo -e "${GREEN}[$(date +'%Y-%m-%d %H:%M:%S')]${NC} $1" |
|
} |
|
|
|
error() { |
|
echo -e "${RED}[$(date +'%Y-%m-%d %H:%M:%S')] ERROR:${NC} $1" >&2 |
|
} |
|
|
|
warning() { |
|
echo -e "${YELLOW}[$(date +'%Y-%m-%d %H:%M:%S')] WARNING:${NC} $1" |
|
} |
|
|
|
info() { |
|
echo -e "${BLUE}[$(date +'%Y-%m-%d %H:%M:%S')] INFO:${NC} $1" |
|
} |
|
|
|
|
|
detect_environment() { |
|
if [ -n "$SPACE_ID" ] || [ -f "/app/app.py" ] || [ -f "/app/streamlit_app.py" ]; then |
|
echo "huggingface_spaces" |
|
elif [ -f "/.dockerenv" ] || [ -n "$DOCKER_CONTAINER" ]; then |
|
echo "docker" |
|
elif [[ "$PWD" == /app* ]]; then |
|
echo "container" |
|
else |
|
echo "local" |
|
fi |
|
} |
|
|
|
|
|
check_port() { |
|
local port=$1 |
|
if command -v netstat >/dev/null 2>&1; then |
|
if netstat -tuln | grep -q ":$port "; then |
|
warning "Port $port is already in use" |
|
return 1 |
|
fi |
|
elif command -v ss >/dev/null 2>&1; then |
|
if ss -tuln | grep -q ":$port "; then |
|
warning "Port $port is already in use" |
|
return 1 |
|
fi |
|
fi |
|
return 0 |
|
} |
|
|
|
|
|
wait_for_service() { |
|
local service_name=$1 |
|
local url=$2 |
|
local max_attempts=30 |
|
local attempt=1 |
|
|
|
log "Waiting for $service_name to be ready..." |
|
|
|
while [ $attempt -le $max_attempts ]; do |
|
if curl -s -f "$url" > /dev/null 2>&1; then |
|
log "$service_name is ready!" |
|
return 0 |
|
fi |
|
|
|
info "Attempt $attempt/$max_attempts: $service_name not ready yet..." |
|
sleep 2 |
|
((attempt++)) |
|
done |
|
|
|
error "$service_name failed to start within expected time" |
|
return 1 |
|
} |
|
|
|
|
|
test_python_imports() { |
|
log "Testing Python imports..." |
|
|
|
python3 -c " |
|
import sys |
|
import os |
|
sys.path.append('/app') |
|
|
|
try: |
|
from path_config import path_manager |
|
print(f'β
Path manager loaded: {path_manager.environment}') |
|
|
|
import pandas as pd |
|
print('β
Pandas imported') |
|
|
|
import sklearn |
|
print('β
Scikit-learn imported') |
|
|
|
import streamlit |
|
print('β
Streamlit imported') |
|
|
|
import fastapi |
|
print('β
FastAPI imported') |
|
|
|
print('β
All imports successful') |
|
except Exception as e: |
|
print(f'β Import failed: {e}') |
|
sys.exit(1) |
|
" |
|
|
|
if [ $? -ne 0 ]; then |
|
error "Python import test failed" |
|
return 1 |
|
fi |
|
|
|
return 0 |
|
} |
|
|
|
|
|
check_system_initialization() { |
|
log "Checking system initialization..." |
|
|
|
python3 -c " |
|
import sys |
|
import os |
|
sys.path.append('/app') |
|
|
|
try: |
|
from path_config import path_manager |
|
|
|
# Check critical files |
|
critical_files = [ |
|
path_manager.get_combined_dataset_path(), |
|
path_manager.get_model_file_path(), |
|
path_manager.get_vectorizer_path(), |
|
] |
|
|
|
missing_files = [] |
|
for file_path in critical_files: |
|
if not file_path.exists(): |
|
missing_files.append(str(file_path)) |
|
|
|
if missing_files: |
|
print(f'Missing files: {missing_files}') |
|
sys.exit(1) |
|
else: |
|
print('β
All critical files present') |
|
|
|
except Exception as e: |
|
print(f'β System check failed: {e}') |
|
sys.exit(1) |
|
" |
|
|
|
return $? |
|
} |
|
|
|
|
|
cleanup() { |
|
log "Shutting down services gracefully..." |
|
|
|
|
|
if [ ! -z "$SCHEDULER_PID" ]; then |
|
kill $SCHEDULER_PID 2>/dev/null || true |
|
wait $SCHEDULER_PID 2>/dev/null || true |
|
fi |
|
|
|
if [ ! -z "$MONITOR_PID" ]; then |
|
kill $MONITOR_PID 2>/dev/null || true |
|
wait $MONITOR_PID 2>/dev/null || true |
|
fi |
|
|
|
if [ ! -z "$FASTAPI_PID" ]; then |
|
kill $FASTAPI_PID 2>/dev/null || true |
|
wait $FASTAPI_PID 2>/dev/null || true |
|
fi |
|
|
|
log "Cleanup complete" |
|
exit 0 |
|
} |
|
|
|
|
|
trap cleanup SIGTERM SIGINT |
|
|
|
|
|
main() { |
|
local environment=$(detect_environment) |
|
|
|
log "π Starting Fake News Detection System" |
|
log "π Environment: $environment" |
|
log "π Working directory: $(pwd)" |
|
log "π Python path: $(which python3)" |
|
|
|
|
|
if ! test_python_imports; then |
|
error "Python environment check failed" |
|
exit 1 |
|
fi |
|
|
|
|
|
if ! check_system_initialization; then |
|
log "System not initialized, running initialization..." |
|
python3 /app/initialize_system.py |
|
|
|
if [ $? -ne 0 ]; then |
|
error "System initialization failed" |
|
exit 1 |
|
fi |
|
|
|
|
|
if ! check_system_initialization; then |
|
error "System initialization verification failed" |
|
exit 1 |
|
fi |
|
else |
|
log "β
System already initialized" |
|
fi |
|
|
|
|
|
export PYTHONPATH="/app:$PYTHONPATH" |
|
|
|
|
|
log "π Starting FastAPI server..." |
|
|
|
|
|
if [ "$environment" = "huggingface_spaces" ]; then |
|
FASTAPI_HOST="0.0.0.0" |
|
else |
|
FASTAPI_HOST="127.0.0.1" |
|
fi |
|
|
|
uvicorn app.fastapi_server:app \ |
|
--host $FASTAPI_HOST \ |
|
--port 8000 \ |
|
--log-level info \ |
|
--access-log \ |
|
--workers 1 & |
|
|
|
FASTAPI_PID=$! |
|
|
|
|
|
if ! wait_for_service "FastAPI" "http://127.0.0.1:8000/health"; then |
|
error "FastAPI failed to start" |
|
exit 1 |
|
fi |
|
|
|
|
|
if [ "$environment" != "huggingface_spaces" ]; then |
|
log "π Starting background services..." |
|
|
|
|
|
log "Starting scheduler..." |
|
python3 scheduler/schedule_tasks.py &> /app/logs/scheduler.log & |
|
SCHEDULER_PID=$! |
|
|
|
|
|
log "Starting drift monitor..." |
|
python3 monitor/monitor_drift.py &> /app/logs/monitor.log & |
|
MONITOR_PID=$! |
|
else |
|
log "βΉοΈ Skipping background services in HuggingFace Spaces environment" |
|
fi |
|
|
|
|
|
log "π₯ Performing final health check..." |
|
python3 -c " |
|
import sys |
|
import requests |
|
sys.path.append('/app') |
|
|
|
try: |
|
response = requests.get('http://127.0.0.1:8000/health', timeout=10) |
|
if response.status_code == 200: |
|
data = response.json() |
|
print(f'β
API Health: {data.get(\"status\", \"unknown\")}') |
|
print(f'β
Environment: {data.get(\"environment_info\", {}).get(\"environment\", \"unknown\")}') |
|
print(f'β
Model Available: {data.get(\"model_health\", {}).get(\"model_available\", False)}') |
|
else: |
|
print(f'β Health check failed: {response.status_code}') |
|
sys.exit(1) |
|
except Exception as e: |
|
print(f'β Health check error: {e}') |
|
sys.exit(1) |
|
" |
|
|
|
if [ $? -ne 0 ]; then |
|
error "Health check failed" |
|
exit 1 |
|
fi |
|
|
|
|
|
log "π¨ Starting Streamlit interface..." |
|
|
|
|
|
if [ "$environment" = "huggingface_spaces" ]; then |
|
|
|
exec streamlit run app/streamlit_app.py \ |
|
--server.port=7860 \ |
|
--server.address=0.0.0.0 \ |
|
--server.enableCORS false \ |
|
--server.enableXsrfProtection false \ |
|
--server.maxUploadSize 200 \ |
|
--server.enableStaticServing true \ |
|
--logger.level info \ |
|
--server.headless true |
|
else |
|
|
|
exec streamlit run app/streamlit_app.py \ |
|
--server.port=7860 \ |
|
--server.address=0.0.0.0 \ |
|
--server.enableCORS false \ |
|
--server.enableXsrfProtection false \ |
|
--server.maxUploadSize 200 \ |
|
--server.enableStaticServing true \ |
|
--logger.level info |
|
fi |
|
} |
|
|
|
|
|
preliminary_checks() { |
|
log "π Running preliminary checks..." |
|
|
|
|
|
if [ ! -f "/app/requirements.txt" ] && [ ! -f "requirements.txt" ]; then |
|
error "requirements.txt not found. Are we in the right directory?" |
|
exit 1 |
|
fi |
|
|
|
|
|
python_version=$(python3 --version 2>&1) |
|
log "π Python version: $python_version" |
|
|
|
|
|
if ! python3 -c "import sys, os, json, pathlib" 2>/dev/null; then |
|
error "Basic Python modules not available" |
|
exit 1 |
|
fi |
|
|
|
|
|
if [ "$(pwd)" != "/app" ] && [ -d "/app" ]; then |
|
log "π Changing to /app directory" |
|
cd /app |
|
fi |
|
|
|
log "β
Preliminary checks passed" |
|
} |
|
|
|
|
|
setup_environment() { |
|
local environment=$(detect_environment) |
|
|
|
log "βοΈ Setting up environment: $environment" |
|
|
|
case $environment in |
|
"huggingface_spaces") |
|
log "π€ Configuring for HuggingFace Spaces" |
|
export STREAMLIT_SERVER_ADDRESS="0.0.0.0" |
|
export STREAMLIT_SERVER_PORT="7860" |
|
export FASTAPI_HOST="0.0.0.0" |
|
|
|
export DISABLE_BACKGROUND_SERVICES="true" |
|
;; |
|
"docker"|"container") |
|
log "π³ Configuring for Docker/Container" |
|
export STREAMLIT_SERVER_ADDRESS="0.0.0.0" |
|
export STREAMLIT_SERVER_PORT="7860" |
|
export FASTAPI_HOST="127.0.0.1" |
|
;; |
|
"local") |
|
log "π» Configuring for Local Development" |
|
export STREAMLIT_SERVER_ADDRESS="127.0.0.1" |
|
export STREAMLIT_SERVER_PORT="7860" |
|
export FASTAPI_HOST="127.0.0.1" |
|
;; |
|
esac |
|
|
|
|
|
export PYTHONUNBUFFERED=1 |
|
export PYTHONPATH="/app:$PYTHONPATH" |
|
|
|
log "β
Environment setup complete" |
|
} |
|
|
|
|
|
if [ "${BASH_SOURCE[0]}" == "${0}" ]; then |
|
|
|
preliminary_checks |
|
setup_environment |
|
main "$@" |
|
fi |