182 lines
No EOL
5.8 KiB
Python
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) |