File size: 10,645 Bytes
80a9345
 
dddb97d
80a9345
 
dddb97d
80a9345
 
 
6b044ce
80a9345
 
dddb97d
80a9345
 
 
 
 
 
 
 
 
 
 
 
6b044ce
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dddb97d
80a9345
 
6b044ce
 
 
 
 
 
 
 
 
 
80a9345
 
 
 
dddb97d
80a9345
 
 
 
 
 
dddb97d
80a9345
 
 
 
 
 
 
6b044ce
80a9345
 
 
 
 
 
 
 
6b044ce
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
dddb97d
 
 
d6bd6d1
dddb97d
 
 
6b044ce
d6bd6d1
 
dddb97d
 
6b044ce
d6bd6d1
 
dddb97d
 
6b044ce
d6bd6d1
 
 
 
 
 
dddb97d
 
d6bd6d1
dddb97d
d6bd6d1
6b044ce
 
 
 
 
 
d6bd6d1
6b044ce
 
 
 
 
d6bd6d1
6b044ce
 
 
 
 
dddb97d
 
 
 
6b044ce
 
 
 
 
 
 
 
d6bd6d1
 
6b044ce
 
d6bd6d1
dddb97d
6b044ce
80a9345
4f522b1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
a588ef4
4f522b1
 
 
 
 
 
 
 
 
 
a588ef4
4f522b1
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
#!/bin/bash

# Robust startup script with error handling and health checks
set -e  # Exit on any error

# Color codes for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

# Logging function
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"
}

# Function to detect environment
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
}

# Function to check if port is available
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
}

# Function to wait for service to be ready
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
}

# Function to test Python imports
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
}

# Function to check system initialization 
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 $?
}

# Function to handle shutdown gracefully
cleanup() {
    log "Shutting down services gracefully..."
    
    # Kill background processes
    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
}

# Set up signal handlers
trap cleanup SIGTERM SIGINT

# Main startup sequence
main() {
    local environment=$(detect_environment)
    
    log "πŸš€ Starting Fake News Detection System"
    log "🌍 Environment: $environment"
    log "πŸ“ Working directory: $(pwd)"
    log "🐍 Python path: $(which python3)"
    
    # Test Python imports first
    if ! test_python_imports; then
        error "Python environment check failed"
        exit 1
    fi
    
    # Check and initialize system if needed
    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
        
        # Verify initialization
        if ! check_system_initialization; then
            error "System initialization verification failed"
            exit 1
        fi
    else
        log "βœ… System already initialized"
    fi
    
    # Set PYTHONPATH to ensure imports work
    export PYTHONPATH="/app:$PYTHONPATH"
    
    # Start FastAPI server
    log "πŸš€ Starting FastAPI server..."
    
    # Choose appropriate host based on environment
    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=$!
    
    # Wait for FastAPI to be ready
    if ! wait_for_service "FastAPI" "http://127.0.0.1:8000/health"; then
        error "FastAPI failed to start"
        exit 1
    fi
    
    # Start background services only if not in HuggingFace Spaces
    if [ "$environment" != "huggingface_spaces" ]; then
        log "πŸ”„ Starting background services..."
        
        # Start scheduler
        log "Starting scheduler..."
        python3 scheduler/schedule_tasks.py &> /app/logs/scheduler.log &
        SCHEDULER_PID=$!
        
        # Start drift monitor
        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
    
    # Verify system health before starting Streamlit
    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
    
    # Start Streamlit (foreground)
    log "🎨 Starting Streamlit interface..."
    
    # Choose appropriate Streamlit configuration based on environment
    if [ "$environment" = "huggingface_spaces" ]; then
        # HuggingFace Spaces configuration
        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
        # Local/Docker configuration
        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
preliminary_checks() {
    log "πŸ” Running preliminary checks..."
    
    # Check if we're in the right directory
    if [ ! -f "/app/requirements.txt" ] && [ ! -f "requirements.txt" ]; then
        error "requirements.txt not found. Are we in the right directory?"
        exit 1
    fi
    
    # Check Python version
    python_version=$(python3 --version 2>&1)
    log "🐍 Python version: $python_version"
    
    # Check if we can import basic modules
    if ! python3 -c "import sys, os, json, pathlib" 2>/dev/null; then
        error "Basic Python modules not available"
        exit 1
    fi
    
    # Change to /app directory if we're not already there
    if [ "$(pwd)" != "/app" ] && [ -d "/app" ]; then
        log "πŸ“ Changing to /app directory"
        cd /app
    fi
    
    log "βœ… Preliminary checks passed"
}

# Environment-specific setup
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"
            # Disable background services for HF Spaces
            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
    
    # Set up logging
    export PYTHONUNBUFFERED=1
    export PYTHONPATH="/app:$PYTHONPATH"
    
    log "βœ… Environment setup complete"
}

# Entry point
if [ "${BASH_SOURCE[0]}" == "${0}" ]; then
    # Script is being executed directly
    preliminary_checks
    setup_environment
    main "$@"
fi