Skip to content

Commit dc744f8

Browse files
authored
Merge pull request browser-use#343 from browser-use/example/fast-api
Example to run agent with fast api and pause / stop run
2 parents 8669ad2 + e02b31c commit dc744f8

File tree

3 files changed

+437
-0
lines changed

3 files changed

+437
-0
lines changed

examples/fastapi/README.md

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
# FastAPI Browser Agent Example
2+
3+
This example demonstrates how to create a web interface for controlling a Browser Agent using FastAPI.
4+
5+
## Requirements
6+
7+
```bash
8+
uv pip install fastapi uvicorn sse-starlette langchain-openai
9+
```
10+
11+
## Running the Example
12+
13+
1. Navigate to the fastapi example directory:
14+
```bash
15+
cd examples/fastapi
16+
```
17+
18+
2. Run the FastAPI application:
19+
```bash
20+
python main.py
21+
```
22+
23+
3. Open your web browser and navigate to `http://localhost:8000`
24+
25+
26+
## API Endpoints
27+
28+
- `GET /` - Serves the web interface
29+
- `POST /agent/run` - Creates and runs an agent with the specified task
30+
- `POST /agent/pause` - Pauses the current agent
31+
- `POST /agent/resume` - Resumes the paused agent
32+
- `POST /agent/stop` - Stops the current agent
33+
- `GET /agent/status` - Gets the current status of the agent
34+
- `GET /logs` - Server-sent events endpoint for real-time logs

examples/fastapi/main.py

+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
import asyncio
2+
import logging
3+
import os
4+
from queue import Queue
5+
from threading import Lock
6+
from typing import Optional
7+
8+
from fastapi import FastAPI, HTTPException
9+
from fastapi.middleware.cors import CORSMiddleware
10+
from fastapi.responses import FileResponse, JSONResponse
11+
from fastapi.staticfiles import StaticFiles
12+
from langchain_openai import ChatOpenAI
13+
from pydantic import BaseModel
14+
from sse_starlette.sse import EventSourceResponse
15+
16+
from browser_use import Agent
17+
18+
# Configure logging
19+
logging.basicConfig(level=logging.INFO)
20+
logger = logging.getLogger(__name__)
21+
22+
# Create a queue for log messages
23+
log_queue = Queue()
24+
log_lock = Lock()
25+
26+
27+
class LogHandler(logging.Handler):
28+
def emit(self, record):
29+
log_entry = self.format(record)
30+
with log_lock:
31+
log_queue.put(log_entry)
32+
33+
34+
# Add custom handler to the root logger
35+
root_logger = logging.getLogger('browser_use')
36+
root_logger.addHandler(LogHandler())
37+
38+
app = FastAPI()
39+
40+
# Enable CORS
41+
app.add_middleware(
42+
CORSMiddleware,
43+
allow_origins=['*'], # Allows all origins
44+
allow_credentials=True,
45+
allow_methods=['*'], # Allows all methods
46+
allow_headers=['*'], # Allows all headers
47+
)
48+
49+
# Create static directory if it doesn't exist
50+
STATIC_DIR = os.path.join(os.path.dirname(__file__), 'static')
51+
os.makedirs(STATIC_DIR, exist_ok=True)
52+
53+
# Serve static files
54+
app.mount('/static', StaticFiles(directory=STATIC_DIR), name='static')
55+
56+
57+
class TaskRequest(BaseModel):
58+
task: str
59+
60+
61+
class AgentManager:
62+
def __init__(self):
63+
self.agent: Optional[Agent] = None
64+
self.task: Optional[str] = None
65+
self._running = False
66+
67+
def create_agent(self, task: str):
68+
llm = ChatOpenAI(model='gpt-4o')
69+
self.agent = Agent(task=task, llm=llm)
70+
self.task = task
71+
self._running = False
72+
73+
def get_agent(self) -> Agent:
74+
if not self.agent:
75+
raise ValueError('Agent not initialized')
76+
return self.agent
77+
78+
@property
79+
def is_running(self):
80+
return self._running
81+
82+
@is_running.setter
83+
def is_running(self, value: bool):
84+
self._running = value
85+
86+
87+
# Create a singleton instance
88+
agent_manager = AgentManager()
89+
90+
91+
@app.get('/')
92+
async def read_root():
93+
return FileResponse(os.path.join(STATIC_DIR, 'index.html'))
94+
95+
96+
@app.post('/agent/run')
97+
async def run_agent(request: TaskRequest):
98+
try:
99+
# Create new agent if task is different or agent doesn't exist
100+
if not agent_manager.agent or agent_manager.task != request.task:
101+
agent_manager.create_agent(request.task)
102+
103+
agent = agent_manager.get_agent()
104+
agent_manager.is_running = True
105+
106+
# Run in background task to not block
107+
asyncio.create_task(agent.run())
108+
return {'status': 'running', 'task': request.task}
109+
except Exception as e:
110+
raise HTTPException(status_code=400, detail=str(e))
111+
112+
113+
@app.post('/agent/pause')
114+
async def pause_agent():
115+
try:
116+
agent = agent_manager.get_agent()
117+
agent.pause()
118+
return {'status': 'paused'}
119+
except ValueError as e:
120+
raise HTTPException(status_code=400, detail=str(e))
121+
122+
123+
@app.post('/agent/resume')
124+
async def resume_agent():
125+
try:
126+
agent = agent_manager.get_agent()
127+
agent.resume()
128+
return {'status': 'resumed'}
129+
except ValueError as e:
130+
raise HTTPException(status_code=400, detail=str(e))
131+
132+
133+
@app.post('/agent/stop')
134+
async def stop_agent():
135+
try:
136+
agent = agent_manager.get_agent()
137+
agent.stop()
138+
agent_manager.is_running = False
139+
return {'status': 'stopped'}
140+
except ValueError as e:
141+
raise HTTPException(status_code=400, detail=str(e))
142+
143+
144+
@app.get('/agent/status')
145+
async def get_status():
146+
if not agent_manager.agent:
147+
return {'status': 'not_created'}
148+
149+
agent = agent_manager.get_agent()
150+
if agent._stopped:
151+
status = 'stopped'
152+
elif agent._paused:
153+
status = 'paused'
154+
elif agent_manager.is_running:
155+
status = 'running'
156+
else:
157+
status = 'ready'
158+
159+
return {'status': status, 'task': agent_manager.task}
160+
161+
162+
@app.get('/logs')
163+
async def event_stream():
164+
async def generate():
165+
while True:
166+
if not log_queue.empty():
167+
with log_lock:
168+
while not log_queue.empty():
169+
log_entry = log_queue.get()
170+
yield {'event': 'log', 'data': log_entry}
171+
await asyncio.sleep(0.1)
172+
173+
return EventSourceResponse(generate())
174+
175+
176+
if __name__ == '__main__':
177+
import uvicorn
178+
179+
uvicorn.run(app, host='0.0.0.0', port=8000)

0 commit comments

Comments
 (0)