from fastapi import FastAPI, Request, WebSocket, WebSocketDisconnect from fastapi.staticfiles import StaticFiles from fastapi.responses import HTMLResponse, JSONResponse from app.core.storage import ensure_storage_dirs from app.core.config import Settings # Page renderers from app.pages.landing import render_landing from app.pages.phone import render_phone_page from app.pages.gbridge import render_gbridge_page from app.pages.windsurf import render_windsurf_page from app.pages.receipts import render_receipts_page from app.pages.chat import render_chat_page # API routes from app.api.routes_sessions import router as sessions_router from app.api.routes_jobs import router as jobs_router from app.api.routes_receipts import router as receipts_router from app.api.routes_gbridge import router as gbridge_router from app.api.routes_windsurf import router as windsurf_router from app.api.routes_health import router as health_router from app.api.routes_chat import router as chat_router from app.api.routes_mesh import router as mesh_router # Phone relay from app.phone.relay import ( connect_worker_websocket, connect_client_websocket, disconnect_worker, disconnect_client, handle_worker_message, handle_client_message, handle_mac_node_message, ) from app.mac_relay import connect_mac_node, disconnect_mac_node from app.phone.sessions import verify_worker_join_token # gbridge router from app.gbridge.router import route_capability_call app = FastAPI(title="GBridge PhoneGPU", version="0.1.0") # Mount static assets app.mount("/static", StaticFiles(directory="app/static", html=True), name="static") # Include API routes app.include_router(sessions_router) app.include_router(jobs_router) app.include_router(receipts_router) app.include_router(gbridge_router) app.include_router(windsurf_router) app.include_router(health_router) app.include_router(chat_router) app.include_router(mesh_router) @app.on_event("startup") async def startup_event(): ensure_storage_dirs() @app.on_event("shutdown") async def shutdown_event(): pass # Page routes @app.get("/", response_class=HTMLResponse) async def root(): return render_landing() @app.get("/phone", response_class=HTMLResponse) async def phone_page(request: Request): return render_phone_page(request) @app.get("/gbridge", response_class=HTMLResponse) async def gbridge_page(request: Request): return render_gbridge_page(request) @app.get("/windsurf", response_class=HTMLResponse) async def windsurf_page(request: Request): return render_windsurf_page(request) @app.get("/chat", response_class=HTMLResponse) async def chat_page(request: Request): return render_chat_page(request) @app.get("/receipts", response_class=HTMLResponse) async def receipts_page(request: Request): return render_receipts_page(request) @app.get("/dashboard", response_class=HTMLResponse) async def dashboard_page(): with open("app/static/dashboard.html", "r") as f: return f.read() @app.get("/worker") async def worker_page(request: Request, session_id: str, token: str): if not verify_worker_join_token(session_id, token): return HTMLResponse(content="