heatmap / scripts /run_local.sh
Ndg07's picture
Feat: 24-hour cleanup for local SQLite
c293f7c
#!/bin/bash
# Local Development Setup Script
# Starts all services required for the misinformation heatmap application
set -e
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
NC='\033[0m' # No Color
# Configuration
PROJECT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
BACKEND_DIR="$PROJECT_ROOT/backend"
FRONTEND_DIR="$PROJECT_ROOT/frontend"
DATA_DIR="$PROJECT_ROOT/data"
LOGS_DIR="$PROJECT_ROOT/logs"
# Default configuration
MODE="local"
SKIP_DEPS=false
SKIP_DB_INIT=false
SKIP_FRONTEND=false
VERBOSE=false
DETACHED=false
# Function to print colored output
print_header() {
echo -e "${PURPLE}================================${NC}"
echo -e "${PURPLE}$1${NC}"
echo -e "${PURPLE}================================${NC}"
}
print_status() {
echo -e "${BLUE}[INFO]${NC} $1"
}
print_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
print_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
print_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Function to show usage
show_usage() {
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " -h, --help Show this help message"
echo " -m, --mode MODE Set deployment mode (local|cloud) [default: local]"
echo " -s, --skip-deps Skip dependency installation"
echo " -d, --skip-db Skip database initialization"
echo " -f, --skip-frontend Skip frontend serving"
echo " -v, --verbose Enable verbose output"
echo " -D, --detached Run services in detached mode"
echo " --stop Stop all running services"
echo " --status Show status of running services"
echo " --logs Show logs from all services"
echo ""
echo "Examples:"
echo " $0 Start all services in local mode"
echo " $0 --mode cloud Start with cloud configuration"
echo " $0 --skip-deps Start without installing dependencies"
echo " $0 --detached Start services in background"
echo " $0 --stop Stop all running services"
}
# Function to parse command line arguments
parse_args() {
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
show_usage
exit 0
;;
-m|--mode)
MODE="$2"
shift 2
;;
-s|--skip-deps)
SKIP_DEPS=true
shift
;;
-d|--skip-db)
SKIP_DB_INIT=true
shift
;;
-f|--skip-frontend)
SKIP_FRONTEND=true
shift
;;
-v|--verbose)
VERBOSE=true
shift
;;
-D|--detached)
DETACHED=true
shift
;;
--stop)
stop_services
exit 0
;;
--status)
show_status
exit 0
;;
--logs)
show_logs
exit 0
;;
*)
print_error "Unknown option: $1"
show_usage
exit 1
;;
esac
done
}
# Function to check prerequisites
check_prerequisites() {
print_status "Checking prerequisites..."
# Check Python
if ! command -v python3 &> /dev/null; then
print_error "Python 3 is not installed. Please install Python 3.8 or higher."
exit 1
fi
local python_version=$(python3 --version | cut -d' ' -f2)
print_status "Python version: $python_version"
# Check pip
if ! command -v pip3 &> /dev/null; then
print_error "pip3 is not installed. Please install pip3."
exit 1
fi
# Check Node.js (for frontend)
if [[ "$SKIP_FRONTEND" == false ]]; then
if ! command -v node &> /dev/null; then
print_warning "Node.js not found. Frontend serving will be disabled."
SKIP_FRONTEND=true
else
local node_version=$(node --version)
print_status "Node.js version: $node_version"
fi
fi
# Check required directories
for dir in "$BACKEND_DIR" "$FRONTEND_DIR" "$DATA_DIR"; do
if [[ ! -d "$dir" ]]; then
print_error "Required directory not found: $dir"
exit 1
fi
done
print_success "Prerequisites check completed"
}
# Function to create necessary directories
create_directories() {
print_status "Creating necessary directories..."
mkdir -p "$LOGS_DIR"
mkdir -p "$DATA_DIR"
mkdir -p "$PROJECT_ROOT/.env"
print_success "Directories created"
}
# Function to install dependencies
install_dependencies() {
if [[ "$SKIP_DEPS" == true ]]; then
print_warning "Skipping dependency installation"
return
fi
print_status "Installing Python dependencies..."
cd "$BACKEND_DIR"
# Create virtual environment if it doesn't exist
if [[ ! -d "venv" ]]; then
print_status "Creating Python virtual environment..."
python3 -m venv venv
fi
# Activate virtual environment
source venv/bin/activate
# Upgrade pip
pip install --upgrade pip
# Install requirements
if [[ -f "requirements.txt" ]]; then
pip install -r requirements.txt
else
print_error "requirements.txt not found in backend directory"
exit 1
fi
print_success "Python dependencies installed"
# Install frontend dependencies if needed
if [[ "$SKIP_FRONTEND" == false && -f "$FRONTEND_DIR/package.json" ]]; then
print_status "Installing frontend dependencies..."
cd "$FRONTEND_DIR"
npm install
print_success "Frontend dependencies installed"
fi
}
# Function to initialize database
initialize_database() {
if [[ "$SKIP_DB_INIT" == true ]]; then
print_warning "Skipping database initialization"
return
fi
print_status "Initializing database..."
cd "$BACKEND_DIR"
source venv/bin/activate
# Run database initialization script
if [[ -f "init_db.py" ]]; then
python init_db.py --mode "$MODE"
print_success "Database initialized"
else
print_warning "Database initialization script not found, skipping..."
fi
}
# Function to setup environment variables
setup_environment() {
print_status "Setting up environment variables..."
# Create .env file if it doesn't exist
local env_file="$PROJECT_ROOT/.env"
if [[ ! -f "$env_file" ]]; then
print_status "Creating .env file..."
cat > "$env_file" << EOF
# Misinformation Heatmap Configuration
MODE=$MODE
DEBUG=true
LOG_LEVEL=INFO
# Database Configuration
DATABASE_URL=sqlite:///./data/heatmap.db
# API Configuration
API_HOST=0.0.0.0
API_PORT=8000
CORS_ORIGINS=["http://localhost:3000", "http://localhost:8000"]
# NLP Configuration
HUGGINGFACE_TOKEN=
MODEL_CACHE_DIR=./models
# Pub/Sub Configuration (Local)
PUBSUB_EMULATOR_HOST=localhost:8085
PUBSUB_PROJECT_ID=misinformation-heatmap-local
# Google Cloud Configuration (for cloud mode)
GOOGLE_CLOUD_PROJECT=
GOOGLE_APPLICATION_CREDENTIALS=
# IBM Watson Configuration (for cloud mode)
WATSON_DISCOVERY_API_KEY=
WATSON_DISCOVERY_URL=
# Monitoring Configuration
ENABLE_METRICS=true
METRICS_PORT=9090
EOF
print_success ".env file created"
else
print_status ".env file already exists"
fi
}
# Function to start Pub/Sub emulator
start_pubsub_emulator() {
if [[ "$MODE" != "local" ]]; then
return
fi
print_status "Starting Pub/Sub emulator..."
# Check if gcloud is installed
if ! command -v gcloud &> /dev/null; then
print_warning "gcloud CLI not found. Installing Pub/Sub emulator..."
# Install using pip as fallback
pip install google-cloud-pubsub
fi
# Start emulator in background
local pubsub_log="$LOGS_DIR/pubsub-emulator.log"
if [[ "$DETACHED" == true ]]; then
nohup gcloud beta emulators pubsub start --host-port=localhost:8085 > "$pubsub_log" 2>&1 &
local pubsub_pid=$!
echo $pubsub_pid > "$LOGS_DIR/pubsub.pid"
print_success "Pub/Sub emulator started (PID: $pubsub_pid)"
else
print_status "Starting Pub/Sub emulator (press Ctrl+C to stop all services)"
gcloud beta emulators pubsub start --host-port=localhost:8085 &
local pubsub_pid=$!
echo $pubsub_pid > "$LOGS_DIR/pubsub.pid"
fi
# Wait for emulator to start
sleep 3
# Create topics and subscriptions
export PUBSUB_EMULATOR_HOST=localhost:8085
python3 -c "
import os
from google.cloud import pubsub_v1
os.environ['PUBSUB_EMULATOR_HOST'] = 'localhost:8085'
project_id = 'misinformation-heatmap-local'
publisher = pubsub_v1.PublisherClient()
subscriber = pubsub_v1.SubscriberClient()
# Create topics
topics = ['events-raw', 'events-processed', 'events-validated']
for topic_name in topics:
topic_path = publisher.topic_path(project_id, topic_name)
try:
publisher.create_topic(request={'name': topic_path})
print(f'Created topic: {topic_name}')
except Exception as e:
print(f'Topic {topic_name} may already exist: {e}')
# Create subscriptions
subscriptions = [
('events-raw', 'events-raw-sub'),
('events-processed', 'events-processed-sub'),
('events-validated', 'events-validated-sub')
]
for topic_name, sub_name in subscriptions:
topic_path = publisher.topic_path(project_id, topic_name)
subscription_path = subscriber.subscription_path(project_id, sub_name)
try:
subscriber.create_subscription(
request={'name': subscription_path, 'topic': topic_path}
)
print(f'Created subscription: {sub_name}')
except Exception as e:
print(f'Subscription {sub_name} may already exist: {e}')
"
}
# Function to start backend API
start_backend() {
print_status "Starting backend API server..."
cd "$BACKEND_DIR"
source venv/bin/activate
local api_log="$LOGS_DIR/api.log"
if [[ "$DETACHED" == true ]]; then
nohup python api.py > "$api_log" 2>&1 &
local api_pid=$!
echo $api_pid > "$LOGS_DIR/api.pid"
print_success "Backend API started (PID: $api_pid)"
else
print_status "Starting backend API (press Ctrl+C to stop all services)"
python api.py &
local api_pid=$!
echo $api_pid > "$LOGS_DIR/api.pid"
fi
}
# Function to start frontend server
start_frontend() {
if [[ "$SKIP_FRONTEND" == true ]]; then
print_warning "Skipping frontend server"
return
fi
print_status "Starting frontend server..."
cd "$FRONTEND_DIR"
local frontend_log="$LOGS_DIR/frontend.log"
# Use Python's built-in HTTP server for simplicity
if [[ "$DETACHED" == true ]]; then
nohup python3 -m http.server 3000 > "$frontend_log" 2>&1 &
local frontend_pid=$!
echo $frontend_pid > "$LOGS_DIR/frontend.pid"
print_success "Frontend server started (PID: $frontend_pid)"
else
print_status "Starting frontend server (press Ctrl+C to stop all services)"
python3 -m http.server 3000 &
local frontend_pid=$!
echo $frontend_pid > "$LOGS_DIR/frontend.pid"
fi
}
# Function to perform health checks
perform_health_checks() {
print_status "Performing health checks..."
# Wait a moment for services to start
sleep 5
# Check backend API
if curl -s http://localhost:8000/health > /dev/null; then
print_success "Backend API is healthy"
else
print_warning "Backend API health check failed"
fi
# Check frontend
if [[ "$SKIP_FRONTEND" == false ]]; then
if curl -s http://localhost:3000 > /dev/null; then
print_success "Frontend server is healthy"
else
print_warning "Frontend server health check failed"
fi
fi
# Check Pub/Sub emulator (local mode only)
if [[ "$MODE" == "local" ]]; then
if curl -s http://localhost:8085 > /dev/null; then
print_success "Pub/Sub emulator is healthy"
else
print_warning "Pub/Sub emulator health check failed"
fi
fi
}
# Function to show running services status
show_status() {
print_header "Service Status"
# Check API
if [[ -f "$LOGS_DIR/api.pid" ]]; then
local api_pid=$(cat "$LOGS_DIR/api.pid")
if ps -p $api_pid > /dev/null; then
print_success "Backend API running (PID: $api_pid)"
else
print_warning "Backend API not running (stale PID file)"
fi
else
print_warning "Backend API not started"
fi
# Check frontend
if [[ -f "$LOGS_DIR/frontend.pid" ]]; then
local frontend_pid=$(cat "$LOGS_DIR/frontend.pid")
if ps -p $frontend_pid > /dev/null; then
print_success "Frontend server running (PID: $frontend_pid)"
else
print_warning "Frontend server not running (stale PID file)"
fi
else
print_warning "Frontend server not started"
fi
# Check Pub/Sub emulator
if [[ -f "$LOGS_DIR/pubsub.pid" ]]; then
local pubsub_pid=$(cat "$LOGS_DIR/pubsub.pid")
if ps -p $pubsub_pid > /dev/null; then
print_success "Pub/Sub emulator running (PID: $pubsub_pid)"
else
print_warning "Pub/Sub emulator not running (stale PID file)"
fi
else
print_warning "Pub/Sub emulator not started"
fi
}
# Function to show logs
show_logs() {
print_header "Service Logs"
if [[ -f "$LOGS_DIR/api.log" ]]; then
echo -e "${BLUE}=== Backend API Logs ===${NC}"
tail -n 20 "$LOGS_DIR/api.log"
echo ""
fi
if [[ -f "$LOGS_DIR/frontend.log" ]]; then
echo -e "${BLUE}=== Frontend Server Logs ===${NC}"
tail -n 20 "$LOGS_DIR/frontend.log"
echo ""
fi
if [[ -f "$LOGS_DIR/pubsub-emulator.log" ]]; then
echo -e "${BLUE}=== Pub/Sub Emulator Logs ===${NC}"
tail -n 20 "$LOGS_DIR/pubsub-emulator.log"
echo ""
fi
}
# Function to stop all services
stop_services() {
print_header "Stopping Services"
# Stop API
if [[ -f "$LOGS_DIR/api.pid" ]]; then
local api_pid=$(cat "$LOGS_DIR/api.pid")
if ps -p $api_pid > /dev/null; then
kill $api_pid
print_success "Backend API stopped"
fi
rm -f "$LOGS_DIR/api.pid"
fi
# Stop frontend
if [[ -f "$LOGS_DIR/frontend.pid" ]]; then
local frontend_pid=$(cat "$LOGS_DIR/frontend.pid")
if ps -p $frontend_pid > /dev/null; then
kill $frontend_pid
print_success "Frontend server stopped"
fi
rm -f "$LOGS_DIR/frontend.pid"
fi
# Stop Pub/Sub emulator
if [[ -f "$LOGS_DIR/pubsub.pid" ]]; then
local pubsub_pid=$(cat "$LOGS_DIR/pubsub.pid")
if ps -p $pubsub_pid > /dev/null; then
kill $pubsub_pid
print_success "Pub/Sub emulator stopped"
fi
rm -f "$LOGS_DIR/pubsub.pid"
fi
print_success "All services stopped"
}
# Function to handle cleanup on exit
cleanup() {
if [[ "$DETACHED" == false ]]; then
print_status "Cleaning up..."
stop_services
fi
}
# Function to display service URLs
show_service_urls() {
print_header "Service URLs"
echo -e "${GREEN}Backend API:${NC} http://localhost:8000"
echo -e "${GREEN}API Documentation:${NC} http://localhost:8000/docs"
echo -e "${GREEN}Health Check:${NC} http://localhost:8000/health"
if [[ "$SKIP_FRONTEND" == false ]]; then
echo -e "${GREEN}Frontend:${NC} http://localhost:3000"
fi
if [[ "$MODE" == "local" ]]; then
echo -e "${GREEN}Pub/Sub Emulator:${NC} http://localhost:8085"
fi
echo ""
echo -e "${YELLOW}Logs Directory:${NC} $LOGS_DIR"
echo -e "${YELLOW}Data Directory:${NC} $DATA_DIR"
}
# Main execution function
main() {
print_header "Misinformation Heatmap - Local Development Setup"
parse_args "$@"
# Set up signal handlers for cleanup
trap cleanup EXIT INT TERM
check_prerequisites
create_directories
setup_environment
install_dependencies
initialize_database
# Start services
if [[ "$MODE" == "local" ]]; then
start_pubsub_emulator
fi
start_backend
start_frontend
# Perform health checks
perform_health_checks
# Show service information
show_service_urls
if [[ "$DETACHED" == true ]]; then
print_success "All services started in detached mode"
print_status "Use '$0 --status' to check service status"
print_status "Use '$0 --logs' to view service logs"
print_status "Use '$0 --stop' to stop all services"
else
print_success "All services started successfully!"
print_status "Press Ctrl+C to stop all services"
# Wait for user interrupt
while true; do
sleep 1
done
fi
}
# Run main function
main "$@"