ever-brain / web /backend /main.py
AlexKurian's picture
feat: implement FastAPI backend and frontend proxy configuration for brain management services
37f2357
Raw
History Blame Contribute Delete
4.58 kB
import os
import sys
from pathlib import Path
from typing import List, Optional
from fastapi import FastAPI, HTTPException, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import FileResponse
from pydantic import BaseModel
# Add parent directory to sys.path to allow importing the brain package
sys.path.append(str(Path(__file__).resolve().parents[2]))
from brain.paths import get_brains_dir, get_brain_path
from brain.config import load_config, save_config
from brain.templates.brain_instance import scaffold_brain_instance
app = FastAPI(title="Ever Brain API")
# Configure CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # In production, specify the actual frontend URL
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
class BrainCreateRequest(BaseModel):
name: str
class BrainUseRequest(BaseModel):
name: str
class BrainStatusResponse(BaseModel):
active_brain: Optional[str]
brains_path: str
brain_count: int
@app.get("/status", response_model=BrainStatusResponse)
async def get_status():
config = load_config()
brains_dir = get_brains_dir()
brains = [d.name for d in brains_dir.iterdir() if d.is_dir()]
active_path_str = config.get("active_brain")
active_brain_name = Path(active_path_str).name if active_path_str else None
return {
"active_brain": active_brain_name,
"brains_path": str(brains_dir),
"brain_count": len(brains)
}
@app.get("/brains", response_model=List[str])
async def list_brains():
brains_dir = get_brains_dir()
return [d.name for d in brains_dir.iterdir() if d.is_dir()]
@app.post("/brains")
async def create_brain(request: BrainCreateRequest):
brain_path = get_brain_path(request.name)
if brain_path.exists():
raise HTTPException(status_code=400, detail=f"Brain instance '{request.name}' already exists.")
try:
scaffold_brain_instance(brain_path)
return {"message": f"Brain '{request.name}' created successfully.", "path": str(brain_path)}
except Exception as e:
raise HTTPException(status_code=500, detail=str(e))
@app.post("/brains/use")
async def use_brain(request: BrainUseRequest):
brain_path = get_brain_path(request.name)
if not brain_path.exists():
raise HTTPException(status_code=404, detail=f"Brain instance '{request.name}' not found.")
from brain.config import set_active_brain
set_active_brain(brain_path)
return {"message": f"Active brain set to '{request.name}'."}
@app.get("/download")
async def download_cli():
# Path to the pre-packaged binary
binary_path = Path(__file__).resolve().parents[2] / "dist" / "ever-brain.exe"
if not binary_path.exists():
raise HTTPException(status_code=404, detail="CLI binary not found. Please run the packaging script.")
return FileResponse(
path=binary_path,
filename="ever-brain.exe",
media_type="application/octet-stream"
)
@app.get("/download/setup")
async def download_setup():
# Path to the GUI installer
setup_path = Path(__file__).resolve().parents[2] / "dist" / "EverBrainSetup.exe"
if not setup_path.exists():
raise HTTPException(status_code=404, detail="GUI Setup installer not found. Please compile the .iss script.")
return FileResponse(
path=setup_path,
filename="EverBrainSetup.exe",
media_type="application/octet-stream"
)
@app.get("/install.ps1")
async def download_install_script(request: Request):
# Path to the web installation script
script_path = Path(__file__).resolve().parents[2] / "scripts" / "web_install.ps1"
if not script_path.exists():
raise HTTPException(status_code=404, detail="Installation script not found.")
# Read script and inject the current host URL
content = script_path.read_text(encoding="utf-8")
# Hugging Face usually has 'x-forwarded-proto' and 'host' headers
protocol = request.headers.get("x-forwarded-proto", "http")
host = request.headers.get("host", "localhost:8000")
base_url = f"{protocol}://{host}"
content = content.replace('http://localhost:8000', base_url)
from fastapi.responses import Response
return Response(
content=content,
media_type="text/plain",
headers={"Content-Disposition": "attachment; filename=install.ps1"}
)
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)