Spaces:
Sleeping
Sleeping
File size: 8,230 Bytes
5854e13 71ad4a3 18c9405 5854e13 341d7ef 5854e13 18c9405 7bac7c5 5854e13 18c9405 341d7ef 18c9405 5854e13 341d7ef 5854e13 18c9405 f6249c8 341d7ef 18c9405 341d7ef 18c9405 341d7ef 087b518 341d7ef 087b518 341d7ef 18c9405 e681062 f658de1 e681062 341d7ef 5854e13 341d7ef 7bac7c5 341d7ef 5854e13 71ad4a3 341d7ef 71ad4a3 341d7ef 5854e13 341d7ef 5854e13 341d7ef 5854e13 71ad4a3 341d7ef 71ad4a3 341d7ef 71ad4a3 5854e13 341d7ef 5854e13 341d7ef 5854e13 341d7ef 18c9405 341d7ef 5854e13 341d7ef 5854e13 341d7ef | 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 | import os
from flask import Flask, jsonify, request
from flask_cors import CORS
from dotenv import load_dotenv
import logging
from logging.handlers import RotatingFileHandler
import pymongo
import datetime
import secrets
# Import Database early for logging connection
from db import Database
# Import routes
from routes.department_routes import department_bp
from routes.auth_routes import auth_bp
from routes.workflow_routes import workflow_bp
from routes.log_routes import log_bp
from routes.incident_routes import incident_bp
from routes.user_routes import user_bp
# Load environment variables
load_dotenv()
# Create Flask app
app = Flask(__name__)
# Setup basic logging configuration first
log_dir = '/tmp/logs'
log_file = f"{log_dir}/app.log"
try:
if not os.path.exists(log_dir):
os.makedirs(log_dir)
handler = RotatingFileHandler(log_file, maxBytes=100000, backupCount=5)
log_level = logging.INFO
handler.setLevel(log_level)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
app.logger.addHandler(handler)
# Also add console logging
console_handler = logging.StreamHandler()
console_handler.setLevel(log_level)
console_handler.setFormatter(formatter)
app.logger.addHandler(console_handler)
app.logger.setLevel(log_level)
app.logger.info('File logging configured successfully.')
except Exception as e:
# If file logging fails, ensure console logging is set up
if not any(isinstance(h, logging.StreamHandler) for h in app.logger.handlers):
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
console_handler.setFormatter(formatter)
app.logger.addHandler(console_handler)
app.logger.setLevel(logging.INFO)
app.logger.warning(f"Could not set up file logging to {log_file}: {str(e)}. Logging to console.")
app.logger.info('Flask app created.')
# Configure secrets with fallbacks for development
app.config['SECRET_KEY'] = os.environ.get('JWT_SECRET') or secrets.token_hex(32)
app.config['MONGO_URI'] = os.environ.get('MONGO_URI')
app.logger.info('App secrets configured.')
# Verify essential environment variables
missing_vars = []
required_env_vars = ['MONGO_URI', 'OPENAI_API_KEY']
for var in required_env_vars:
if not os.environ.get(var):
missing_vars.append(var)
if missing_vars:
app.logger.warning(f"Missing essential environment variables: {', '.join(missing_vars)}")
app.logger.warning("Please create a .env file or set Space secrets.")
else:
app.logger.info("All essential environment variables are present.")
# Database Connection Test
try:
db_instance = Database.get_instance()
db = db_instance.get_db()
db.command('ping')
app.logger.info("Successfully connected to MongoDB.")
except Exception as e:
app.logger.error(f"Failed to connect to MongoDB: {str(e)}")
# Depending on severity, you might want to exit or prevent app run
# Configure OpenAI API key
if 'OPENAI_API_KEY' in os.environ:
try:
# We don't need to initialize the client globally
# It will be initialized in each function that needs it
app.logger.info("OpenAI API key available.")
except Exception as e:
app.logger.error(f"Failed to import OpenAI: {str(e)}")
else:
app.logger.warning("OPENAI_API_KEY not found in environment variables.")
# Enable CORS with specific origins
origins = [
"http://localhost:3000", # Development frontend
"https://www.tryenflow.com", # Production frontend
"https://droov-enflow-api.hf.space" # Add the Hugging Face Space URL
]
try:
CORS(app, resources={r"/api/*": {"origins": origins}}, supports_credentials=True)
app.logger.info(f"CORS configured for origins: {origins}")
except Exception as e:
app.logger.error(f"Failed to configure CORS: {str(e)}")
# Register blueprints
try:
app.register_blueprint(auth_bp, url_prefix='/api/auth')
app.register_blueprint(department_bp, url_prefix='/api/departments')
app.register_blueprint(workflow_bp, url_prefix='/api/workflows')
app.register_blueprint(log_bp, url_prefix='/api/logs')
app.register_blueprint(incident_bp, url_prefix='/api/incidents')
app.register_blueprint(user_bp, url_prefix='/api/users')
app.logger.info("All API blueprints registered successfully.")
except Exception as e:
app.logger.error(f"Failed to register blueprints: {str(e)}")
# Set up uploads directory in /tmp (which should be writable)
app.config['UPLOAD_FOLDER'] = '/tmp/uploads'
if not os.path.exists(app.config['UPLOAD_FOLDER']):
try:
os.makedirs(app.config['UPLOAD_FOLDER'])
app.logger.info(f"Uploads directory created at {app.config['UPLOAD_FOLDER']}")
except PermissionError:
app.logger.warning(f"Permission denied creating {app.config['UPLOAD_FOLDER']}. Using /tmp fallback.")
app.config['UPLOAD_FOLDER'] = '/tmp'
except Exception as e:
app.logger.error(f"Error creating uploads directory {app.config['UPLOAD_FOLDER']}: {str(e)}")
# Error handler
@app.errorhandler(Exception)
def handle_exception(e):
# Log the actual exception trace
app.logger.exception(f"Unhandled exception: {str(e)}")
return jsonify({"error": "An unexpected internal error occurred"}), 500
# Root route
@app.route('/')
def index():
app.logger.debug("Root route / accessed")
return jsonify({
"message": "Enflow API is running",
"version": "1.0.0"
})
# Test route that doesn't require authentication
@app.route('/api/test')
def test_route():
app.logger.info("/api/test route accessed")
return jsonify({
"message": "API test successful",
"timestamp": datetime.datetime.now().isoformat(),
"environment": os.environ.get('FLASK_DEBUG', '0') # Use FLASK_DEBUG now
})
# Health check route
@app.route('/health')
def health_check():
app.logger.info("Health check requested")
db_status = "unknown"
env_status = "ok"
error_details = ""
status_code = 200
try:
# Check MongoDB connection
db = Database.get_instance().get_db()
db.command('ping')
db_status = "connected"
app.logger.info("Health Check: MongoDB connection successful.")
except Exception as e:
db_status = "disconnected"
error_details += f"MongoDB Error: {str(e)}; "
app.logger.error(f"Health Check: MongoDB connection failed: {str(e)}")
status_code = 503 # Service Unavailable
# Check environment variables
if missing_vars:
env_status = f"Missing: {', '.join(missing_vars)}"
if status_code == 200: # Don't downgrade status if DB already failed
status_code = 500 # Internal Server Error for config issue
error_details += f"Missing environment variables: {', '.join(missing_vars)}; "
app.logger.warning(f"Health Check: Missing environment variables: {', '.join(missing_vars)}")
response = {
"status": "healthy" if status_code == 200 else "unhealthy",
"mongo": db_status,
"env_vars": env_status,
"upload_dir_exists": os.path.exists(app.config.get('UPLOAD_FOLDER', '/tmp')),
"log_dir_exists": os.path.exists(log_dir)
}
if error_details:
response["errors"] = error_details.strip()
return jsonify(response), status_code
# Logging setup moved to the top
if __name__ == '__main__':
# Use FLASK_DEBUG instead of FLASK_ENV for debug mode control
debug_mode = os.environ.get('FLASK_DEBUG', '0') == '1'
# Port configuration - Hugging Face might override this via its execution environment
port = int(os.environ.get('PORT', 7860)) # Default to 7860 if PORT env var not set
app.logger.info(f"Starting Flask app. Debug mode: {debug_mode}. Port: {port}")
# Note: When running via gunicorn (common in HF), gunicorn command sets the port,
# and this app.run() is not executed directly.
# The port setting here is mainly for local `python app.py` execution.
app.run(host='0.0.0.0', port=port, debug=debug_mode) |