105 lines
3.2 KiB
Python
105 lines
3.2 KiB
Python
|
|
"""FastAPI application for web interface."""
|
||
|
|
from src.api.routes import dashboard, chat, tasks, calendar, projects
|
||
|
|
from fastapi import FastAPI, Request, Depends, HTTPException, status
|
||
|
|
from fastapi.responses import HTMLResponse, StreamingResponse
|
||
|
|
from fastapi.staticfiles import StaticFiles
|
||
|
|
from fastapi.templating import Jinja2Templates
|
||
|
|
from fastapi.security import HTTPBasic, HTTPBasicCredentials
|
||
|
|
import secrets
|
||
|
|
from pathlib import Path
|
||
|
|
from src.config import settings
|
||
|
|
from src.api.agent_instance import agent
|
||
|
|
|
||
|
|
# Initialize FastAPI app
|
||
|
|
app = FastAPI(
|
||
|
|
title="MyOrg Assistant",
|
||
|
|
description="AI-powered personal assistant for GTD task management",
|
||
|
|
version="1.0.0",
|
||
|
|
)
|
||
|
|
|
||
|
|
# Set up templates and static files
|
||
|
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||
|
|
templates = Jinja2Templates(directory=str(BASE_DIR / "web" / "templates"))
|
||
|
|
app.mount("/static", StaticFiles(directory=str(BASE_DIR /
|
||
|
|
"web" / "static")), name="static")
|
||
|
|
|
||
|
|
# Security
|
||
|
|
security = HTTPBasic()
|
||
|
|
|
||
|
|
|
||
|
|
def verify_credentials(credentials: HTTPBasicCredentials = Depends(security)) -> bool:
|
||
|
|
"""Verify HTTP Basic Auth credentials.
|
||
|
|
|
||
|
|
Args:
|
||
|
|
credentials: HTTP Basic credentials
|
||
|
|
|
||
|
|
Returns:
|
||
|
|
True if valid
|
||
|
|
|
||
|
|
Raises:
|
||
|
|
HTTPException: If credentials are invalid
|
||
|
|
"""
|
||
|
|
if not settings.web_password:
|
||
|
|
# No password set, allow access
|
||
|
|
return True
|
||
|
|
|
||
|
|
correct_password = settings.web_password.encode("utf8")
|
||
|
|
provided_password = credentials.password.encode("utf8")
|
||
|
|
|
||
|
|
is_correct = secrets.compare_digest(provided_password, correct_password)
|
||
|
|
|
||
|
|
if not is_correct:
|
||
|
|
raise HTTPException(
|
||
|
|
status_code=status.HTTP_401_UNAUTHORIZED,
|
||
|
|
detail="Incorrect password",
|
||
|
|
headers={"WWW-Authenticate": "Basic"},
|
||
|
|
)
|
||
|
|
|
||
|
|
return True
|
||
|
|
|
||
|
|
|
||
|
|
# Import routes
|
||
|
|
|
||
|
|
# Include routers
|
||
|
|
app.include_router(dashboard.router, dependencies=[
|
||
|
|
Depends(verify_credentials)])
|
||
|
|
app.include_router(chat.router, dependencies=[Depends(verify_credentials)])
|
||
|
|
app.include_router(tasks.router, dependencies=[Depends(verify_credentials)])
|
||
|
|
app.include_router(calendar.router, dependencies=[Depends(verify_credentials)])
|
||
|
|
app.include_router(projects.router, dependencies=[Depends(verify_credentials)])
|
||
|
|
|
||
|
|
|
||
|
|
@app.get("/", response_class=HTMLResponse)
|
||
|
|
async def root(request: Request, _: bool = Depends(verify_credentials)):
|
||
|
|
"""Redirect to dashboard."""
|
||
|
|
from fastapi.responses import RedirectResponse
|
||
|
|
return RedirectResponse(url="/dashboard")
|
||
|
|
|
||
|
|
|
||
|
|
@app.get("/health")
|
||
|
|
async def health():
|
||
|
|
"""Health check endpoint."""
|
||
|
|
return {"status": "healthy", "service": "myorg-assistant"}
|
||
|
|
|
||
|
|
|
||
|
|
def run_web() -> None:
|
||
|
|
"""Run the web server."""
|
||
|
|
import uvicorn
|
||
|
|
|
||
|
|
print("🌐 Starting MyOrg Assistant Web Server...")
|
||
|
|
print(
|
||
|
|
f"📊 Dashboard: http://{settings.web_host}:{settings.web_port}/dashboard")
|
||
|
|
print(f"💬 Chat: http://{settings.web_host}:{settings.web_port}/chat")
|
||
|
|
|
||
|
|
if settings.web_password:
|
||
|
|
print("🔒 Authentication enabled")
|
||
|
|
else:
|
||
|
|
print("⚠️ Warning: No password set (WEB_PASSWORD not configured)")
|
||
|
|
|
||
|
|
uvicorn.run(
|
||
|
|
"src.api.app:app",
|
||
|
|
host=settings.web_host,
|
||
|
|
port=settings.web_port,
|
||
|
|
reload=False,
|
||
|
|
)
|