"""Phone GUI Agent - Main Entry Point Web console for controlling the agent loop. """ import asyncio import json from pathlib import Path from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Request from fastapi.responses import HTMLResponse from fastapi.staticfiles import StaticFiles from fastapi.templating import Jinja2Templates from config import settings from src.capture import ADBCapture from src.planner.agent_loop import AgentLoop app = FastAPI(title="Phone GUI Agent", version="0.1.0") BASE_DIR = Path(__file__).parent.parent app.mount("/static", StaticFiles(directory=BASE_DIR / "web" / "static"), name="static") templates = Jinja2Templates(directory=BASE_DIR / "web" / "templates") # Global state capture = ADBCapture() agent = AgentLoop() @app.get("/", response_class=HTMLResponse) async def index(request: Request): return templates.TemplateResponse(request, "index.html") @app.get("/api/device") async def device_info(): """Check device connection status.""" try: info = capture.check_device() return info except Exception as e: return {"connected": False, "error": str(e)} @app.get("/api/screenshot") async def take_screenshot(): """Take a screenshot and return base64.""" try: b64 = capture.screenshot_base64() return {"ok": True, "image": b64} except Exception as e: return {"ok": False, "error": str(e)} @app.post("/api/stop") async def stop_task(): """Stop the current running task.""" agent.stop() return {"ok": True} @app.websocket("/ws/task") async def task_websocket(ws: WebSocket): """WebSocket endpoint for running tasks with real-time updates. Client sends: {"task": "打开微信搜索张三"} Server streams: StepResult objects as JSON """ await ws.accept() try: data = await ws.receive_json() task = data.get("task", "") if not task: await ws.send_json({"error": "No task provided"}) return await ws.send_json({"status": "started", "task": task}) def on_step(result): asyncio.get_event_loop().call_soon_threadsafe( asyncio.ensure_future, ws.send_json({ "status": "step", "step": result.step, "observation": result.observation, "thinking": result.thinking, "action_type": result.action_type, "action_desc": result.action_desc, "screenshot": result.screenshot_before[:100] + "..." if result.screenshot_before else None, "error": result.error, }) ) session = await agent.run_task(task, on_step=on_step) await ws.send_json({ "status": session.status, "total_steps": len(session.steps), "task": task, }) except WebSocketDisconnect: agent.stop() except Exception as e: try: await ws.send_json({"error": str(e)}) except Exception: pass def main(): import uvicorn uvicorn.run( "src.main:app", host=settings.host, port=settings.port, reload=True, ) if __name__ == "__main__": main()