gateway/app.py
2025-04-23 09:01:52 +02:00

182 lines
No EOL
5.8 KiB
Python

import os
os.environ["NUMEXPR_MAX_THREADS"] = "12"
from fastapi import FastAPI, HTTPException, Depends, Body, status, Response
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse, FileResponse
from fastapi.staticfiles import StaticFiles
from fastapi.security import OAuth2PasswordRequestForm
from contextlib import asynccontextmanager
import uvicorn
from typing import Dict, Any
import logging
from logging.handlers import RotatingFileHandler
from datetime import timedelta
import pathlib
from modules.configuration import APP_CONFIG
from modules.gateway_interface import get_gateway_interface
# Import auth module
from modules.auth import (
create_access_token,
get_current_active_user,
get_user_context,
ACCESS_TOKEN_EXPIRE_MINUTES
)
# Import models - import generically for INITIALIZATION, even if dummy!
import modules.gateway_model as gateway_model
#from modules.lucydom_interface import get_lucydom_interface as dom_interface
def init_logging():
# Get log level from config (default to INFO if not found)
log_level_name = APP_CONFIG.get("APP_LOG_LEVEL", "INFO")
log_level = getattr(logging, log_level_name)
# Configure handlers based on config
handlers = []
# Add console handler if enabled
if APP_CONFIG.get("Logging_CONSOLE_ENABLED", True):
console_handler = logging.StreamHandler()
handlers.append(console_handler)
# Add file handler if enabled
if APP_CONFIG.get("Logging_FILE_ENABLED", True):
log_file = APP_CONFIG.get("APP_LOG_FILE", "app.log")
rotation_size = int(APP_CONFIG.get("Logging_ROTATION_SIZE", 10485760)) # Default: 10MB
backup_count = int(APP_CONFIG.get("Logging_BACKUP_COUNT", 5))
file_handler = RotatingFileHandler(
log_file,
maxBytes=rotation_size,
backupCount=backup_count
)
handlers.append(file_handler)
# Configure the logger
logging.basicConfig(
level=log_level,
format=APP_CONFIG.get("Logging_FORMAT", "%(asctime)s - %(levelname)s - %(name)s - %(message)s"),
datefmt=APP_CONFIG.get("Logging_DATE_FORMAT", "%Y-%m-%d %H:%M:%S"),
handlers=handlers
)
# Initialize logging
init_logging()
logger = logging.getLogger(__name__)
instance_label = APP_CONFIG.get("APP_ENV_LABEL")
# Define lifespan context manager for application startup/shutdown events
@asynccontextmanager
async def lifespan(app: FastAPI):
# Startup logic (if any)
logger.info("Application is starting up")
yield
# Shutdown logic
logger.info("Application has been shut down")
# START APP
app = FastAPI(
title="PowerOn | Data Platform API",
description=f"Backend API for the Multi-Agent Platform by ValueOn AG ({instance_label})",
lifespan=lifespan
)
# CORS configuration for frontend requests
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:8080","https://poweron-lucyagents-xxx.germanywestcentral-01.azurewebsites.net"],
allow_credentials=True,
allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
allow_headers=["*"],
expose_headers=["*"],
max_age=86400 # Increased caching for preflight requests
)
# Static folder for frontend - work with absolute path
base_dir = pathlib.Path(__file__).parent
static_folder = base_dir / "static"
os.makedirs(static_folder, exist_ok=True)
app.mount("/static", StaticFiles(directory=str(static_folder)), name="static")
# Add a specific route for favicon.ico
@app.get("/favicon.ico", include_in_schema=False)
async def favicon():
favicon_path = static_folder / "favicon.ico"
return FileResponse(str(favicon_path))
# General Elements
@app.get("/", tags=["General"])
async def root():
"""API status endpoint"""
return {"status": "online", "message": "Data Platform API is active"}
@app.get("/api/test", tags=["General"])
async def get_test():
return "OK 1.5"
@app.options("/{full_path:path}", tags=["General"])
async def options_route(full_path: str):
return Response(status_code=200)
# Token endpoint for login
@app.post("/api/token", response_model=gateway_model.Token, tags=["General"])
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends()):
# Initialize Gateway interface without context
gateway = get_gateway_interface()
# Authenticate user
user = gateway.authenticate_user(form_data.username, form_data.password)
if not user:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid username or password",
headers={"WWW-Authenticate": "Bearer"},
)
# Create token with tenant ID
access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
access_token = create_access_token(
data={
"sub": user["username"],
"mandate_id": user["mandate_id"]
},
expires_delta=access_token_expires
)
return {"access_token": access_token, "token_type": "bearer"}
# Get user info
@app.get("/api/user/me", response_model=Dict[str, Any], tags=["General"])
async def read_user_me(current_user: Dict[str, Any] = Depends(get_current_active_user)):
return current_user
# Include all routers
from routes.attributes import router as attributes_router
app.include_router(attributes_router)
from routes.mandates import router as mandate_router
app.include_router(mandate_router)
from routes.users import router as user_router
app.include_router(user_router)
from routes.files import router as file_router
app.include_router(file_router)
from routes.prompts import router as prompt_router
app.include_router(prompt_router)
from routes.workflows import router as workflow_router
app.include_router(workflow_router)
#if __name__ == "__main__":
# uvicorn.run("app:app", host="0.0.0.0", port=8000, reload=True)