128 lines
3.7 KiB
Python
128 lines
3.7 KiB
Python
"""
|
||
Browser Use REST API Server
|
||
Простой HTTP API для управления браузером из n8n
|
||
"""
|
||
import os
|
||
import asyncio
|
||
from typing import Optional
|
||
from fastapi import FastAPI, HTTPException
|
||
from pydantic import BaseModel
|
||
from browser_use import Agent, Browser, ChatOpenAI
|
||
from browser_use.agent.views import AgentHistoryList
|
||
import uvicorn
|
||
|
||
# Обход проверки API ключа browser-use
|
||
os.environ["OPENAI_API_KEY"] = os.environ.get("OPENAI_API_KEY", "dummy")
|
||
|
||
app = FastAPI(title="Browser Use API", version="1.0.0")
|
||
|
||
# Модели запросов
|
||
class TaskRequest(BaseModel):
|
||
task: str
|
||
max_steps: Optional[int] = 20
|
||
model: Optional[str] = "openai/gpt-4o-mini"
|
||
|
||
class TaskResponse(BaseModel):
|
||
task_id: str
|
||
status: str
|
||
result: Optional[str] = None
|
||
error: Optional[str] = None
|
||
|
||
# Хранилище задач
|
||
tasks = {}
|
||
|
||
@app.post("/api/tasks", response_model=TaskResponse)
|
||
async def create_task(request: TaskRequest):
|
||
"""Создать новую задачу браузера"""
|
||
import uuid
|
||
task_id = str(uuid.uuid4())[:8]
|
||
|
||
tasks[task_id] = {
|
||
"status": "pending",
|
||
"task": request.task,
|
||
"result": None
|
||
}
|
||
|
||
# Запускаем задачу в фоне
|
||
asyncio.create_task(run_browser_task(task_id, request.task, request.max_steps, request.model))
|
||
|
||
return TaskResponse(
|
||
task_id=task_id,
|
||
status="pending"
|
||
)
|
||
|
||
async def run_browser_task(task_id: str, task: str, max_steps: int, model: str):
|
||
"""Выполнение задачи браузера"""
|
||
browser = None
|
||
try:
|
||
tasks[task_id]["status"] = "running"
|
||
|
||
# Настройка LLM через OpenRouter
|
||
api_key = os.getenv("OPENROUTER_API_KEY", "")
|
||
if not api_key:
|
||
raise ValueError("OPENROUTER_API_KEY not set")
|
||
|
||
# Используем ChatOpenAI с base_url для OpenRouter
|
||
llm = ChatOpenAI(
|
||
model=model,
|
||
base_url="https://openrouter.ai/api/v1",
|
||
api_key=api_key
|
||
)
|
||
|
||
# Инициализация браузера
|
||
browser = Browser()
|
||
|
||
# Создание агента
|
||
agent = Agent(
|
||
task=task,
|
||
llm=llm,
|
||
browser=browser,
|
||
)
|
||
|
||
# Выполнение задачи
|
||
history: AgentHistoryList = await agent.run(max_steps=max_steps)
|
||
|
||
# Получение результата
|
||
result = history.final_result()
|
||
|
||
tasks[task_id]["status"] = "completed"
|
||
tasks[task_id]["result"] = result
|
||
|
||
except Exception as e:
|
||
tasks[task_id]["status"] = "failed"
|
||
tasks[task_id]["error"] = str(e)
|
||
finally:
|
||
# Закрытие браузера (правильный способ)
|
||
if browser:
|
||
try:
|
||
# browser_use сам управляет закрытием
|
||
pass
|
||
except:
|
||
pass
|
||
|
||
@app.get("/api/tasks/{task_id}", response_model=TaskResponse)
|
||
async def get_task(task_id: str):
|
||
"""Получить статус/результат задачи"""
|
||
if task_id not in tasks:
|
||
raise HTTPException(status_code=404, detail="Task not found")
|
||
|
||
task = tasks[task_id]
|
||
return TaskResponse(
|
||
task_id=task_id,
|
||
status=task["status"],
|
||
result=task.get("result"),
|
||
error=task.get("error")
|
||
)
|
||
|
||
@app.get("/api/health")
|
||
async def health_check():
|
||
"""Проверка здоровья сервера"""
|
||
return {
|
||
"status": "healthy",
|
||
"service": "browser-use-api",
|
||
"version": "1.0.0"
|
||
}
|
||
|
||
if __name__ == "__main__":
|
||
uvicorn.run(app, host="0.0.0.0", port=8383)
|