diff --git a/api.py b/api.py index bc35cf7aec..158474e440 100644 --- a/api.py +++ b/api.py @@ -111,45 +111,3 @@ async def get_task_status(task_id: str): log_error(logger, f"Error getting task status: {str(e)}") await send_error_to_webhook(str(e), "get_task_status", task_id) raise HTTPException(status_code=500, detail=str(e)) - -@router.get("/metrics") -async def get_metrics(): - """Return system metrics""" - try: - with get_db() as db: - # Get database statistics - total_tasks = db.query(Task).count() - completed_tasks = db.query(Task).filter(Task.status == "completed").count() - failed_tasks = db.query(Task).filter(Task.status == "failed").count() - running_tasks = db.query(Task).filter(Task.status == "running").count() - - # Get system metrics - cpu_percent = psutil.cpu_percent() - memory = psutil.virtual_memory() - disk = psutil.disk_usage('/') - - metrics = { - "system": { - "cpu_percent": cpu_percent, - "memory_percent": memory.percent, - "disk_percent": disk.percent - }, - "tasks": { - "total": total_tasks, - "completed": completed_tasks, - "failed": failed_tasks, - "running": running_tasks, - # "queued": task_queue.qsize(), - "available_slots": MAX_CONCURRENT_TASKS - running_tasks - } - } - - # Send metrics to webhook - await send_metrics_to_webhook(metrics) - - return metrics - - except Exception as e: - log_error(logger, f"Error getting metrics: {str(e)}") - await send_error_to_webhook(str(e), "get_metrics") - raise HTTPException(status_code=500, detail=str(e)) \ No newline at end of file diff --git a/browser.py b/browser.py index afa8ef94bf..83eb57dfba 100644 --- a/browser.py +++ b/browser.py @@ -87,7 +87,7 @@ async def execute_task(self, task: str, config: Dict[str, Any], task_id: str) -> async def onStepEnd(self: Agent): self.save_history(history_path) - if run_history == True: + if run_history: log_info(logger, f"TASK {task_id} run history {str(history)}") with open(history_path, "w") as f: json.dump(history, f) diff --git a/compose.yml b/compose.yml index 33c13f7fa6..12875f3261 100644 --- a/compose.yml +++ b/compose.yml @@ -19,7 +19,7 @@ services: depends_on: - db # scale: 2 - image: browseruser/browser-user:pr-4 + image: browseruser/browser-user environment: - OLLAMA_HOST=${OLLAMA_HOST} - ERROR_WEBHOOK_URL=http://localhost:3000 @@ -59,6 +59,7 @@ services: - STATUS_WEBHOOK_URL=http://localhost:3000 - DEEPSEEK_API_KEY=${DEEPSEEK_API_KEY} - OPENAI_API_KEY=${OPENAI_API_KEY} + - GOOGLE_API_KEY=${GOOGLE_API_KEY} - DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@db:5432/browser-use - PYTHONUNBUFFERED=1 - BROWSER_USE_LOGGING_LEVEL=info diff --git a/crud.py b/crud.py deleted file mode 100644 index 85b09b05a1..0000000000 --- a/crud.py +++ /dev/null @@ -1,68 +0,0 @@ -from sqlalchemy.orm import Session -from typing import List, Optional -from models import Task, BrowserSession -from schemas import TaskCreate, TaskUpdate, BrowserSessionCreate - -async def create_task(db: Session, task: TaskCreate) -> Task: - db_task = Task( - task=task.task, - config=task.config, - status="pending", - priority=task.priority, - max_retries=task.max_retries, - timeout=task.timeout, - tags=task.tags, - metadata=task.metadata - ) - db.add(db_task) - await db.commit() - await db.refresh(db_task) - return db_task - -async def get_tasks(db: Session, skip: int = 0, limit: int = 100) -> List[Task]: - return db.query(Task).order_by(Task.created_at.desc()).offset(skip).limit(limit).all() - -async def get_task(db: Session, task_id: int) -> Optional[Task]: - return db.query(Task).filter(Task.id == task_id).first() - -async def update_task(db: Session, task_id: int, task: TaskUpdate) -> Task: - db_task = db.query(Task).filter(Task.id == task_id).first() - if not db_task: - return None - - for key, value in task.dict(exclude_unset=True).items(): - setattr(db_task, key, value) - - await db.commit() - await db.refresh(db_task) - return db_task - -async def delete_task(db: Session, task_id: int) -> bool: - db_task = db.query(Task).filter(Task.id == task_id).first() - if not db_task: - return False - - db.delete(db_task) - await db.commit() - return True - -async def create_browser_session(db: Session, session: BrowserSessionCreate) -> BrowserSession: - db_session = BrowserSession( - task_id=session.task_id, - status="active", - config=session.config, - metadata=session.metadata - ) - db.add(db_session) - await db.commit() - await db.refresh(db_session) - return db_session - -async def get_browser_sessions(db: Session, skip: int = 0, limit: int = 100) -> List[BrowserSession]: - return db.query(BrowserSession).order_by(BrowserSession.created_at.desc()).offset(skip).limit(limit).all() - -async def get_browser_session(db: Session, session_id: int) -> Optional[BrowserSession]: - return db.query(BrowserSession).filter(BrowserSession.id == session_id).first() - -async def get_browser_sessions_by_task(db: Session, task_id: int) -> List[BrowserSession]: - return db.query(BrowserSession).filter(BrowserSession.task_id == task_id).all() \ No newline at end of file diff --git a/database.py b/database.py index c879a0eb4d..e5cbb4e9df 100644 --- a/database.py +++ b/database.py @@ -63,25 +63,6 @@ class Task(Base): started_at = Column(DateTime, nullable=True) completed_at = Column(DateTime, nullable=True) -class Metric(Base): - __tablename__ = "metrics" - - id = Column(Integer, primary_key=True, index=True) - name = Column(String, nullable=False) - value = Column(Float, nullable=False) - created_at = Column(DateTime, nullable=False) - -class Session(Base): - __tablename__ = "sessions" - - id = Column(Integer, primary_key=True, index=True) - task_id = Column(Integer, nullable=False) - start_time = Column(DateTime, nullable=False) - end_time = Column(DateTime, nullable=True) - status = Column(String, nullable=False) - error = Column(String, nullable=True) - created_at = Column(DateTime, nullable=False) - # Function to get database session @contextmanager def get_db(): @@ -170,40 +151,6 @@ def get_pending_tasks(db: Session, skip: int = 0, limit: int = 100) -> list[Task }, exc_info=True) raise -# Functions for Session -def get_sessions(db: Session, skip: int = 0, limit: int = 100) -> list[Session]: - """List all sessions with pagination""" - try: - result = db.query(Session).offset(skip).limit(limit).all() - return result - except Exception as e: - log_error(logger, "Error listing sessions", { - "error": str(e) - }, exc_info=True) - raise - -def get_session(db: Session, session_id: int) -> Session: - """Get a session by ID""" - try: - return db.query(Session).filter(Session.id == session_id).first() - except Exception as e: - log_error(logger, "Error getting session", { - "session_id": session_id, - "error": str(e) - }, exc_info=True) - raise - -def get_task_sessions(db: Session, task_id: int) -> list[Session]: - """Get all sessions for a task""" - try: - result = db.query(Session).filter(Session.task_id == task_id).all() - return result - except Exception as e: - log_error(logger, "Error getting task sessions", { - "task_id": task_id, - "error": str(e) - }, exc_info=True) - raise def delete_task(db: Session, task_id: int) -> bool: """Remove a task from database""" diff --git a/diagnose.py b/diagnose.py deleted file mode 100644 index d037a4a383..0000000000 --- a/diagnose.py +++ /dev/null @@ -1,128 +0,0 @@ -#!/usr/bin/env python3 -""" -Diagnóstico do ambiente Browser-use API -Este script verifica se todas as dependências necessárias estão disponíveis -e se o ambiente está corretamente configurado. -""" - -import sys -import os -import importlib.util -import subprocess -import platform -import json - -print("Iniciando diagnóstico do Browser-use API...\n") - -# Versão do Python -print(f"Versão do Python: {platform.python_version()}") -if sys.version_info < (3, 11): - print("⚠️ AVISO: Versão mínima do Python requerida é 3.11!") -else: - print("✅ Versão do Python OK") - -# Verificar dependências obrigatórias -required_packages = [ - "fastapi", - "uvicorn", - "playwright", - "langchain_google_genai", - "browser_use", -] - -missing_packages = [] -for package in required_packages: - spec = importlib.util.find_spec(package) - if spec is None: - missing_packages.append(package) - print(f"❌ Pacote '{package}' não encontrado") - else: - try: - module = importlib.import_module(package) - version = getattr(module, "__version__", "versão desconhecida") - print(f"✅ {package} instalado (versão {version})") - except ImportError as e: - print(f"⚠️ {package} encontrado mas não pode ser importado: {e}") - -# Verificar variáveis de ambiente -env_vars = [ - "PLAYWRIGHT_BROWSERS_PATH", - "BROWSER_USE_DEBUG", - "BROWSER_USE_HEADLESS", - "OPENAI_API_KEY", - "ANTHROPIC_API_KEY", - "GOOGLE_API_KEY", -] - -print("\nVariáveis de ambiente:") -for var in env_vars: - if var in os.environ: - value = "***" if "KEY" in var or "TOKEN" in var else os.environ[var] - print(f"✅ {var} = {value}") - else: - print(f"⚠️ {var} não definida") - -# Verificar disponibilidade do Xvfb -print("\nVerificando disponibilidade do Xvfb:") -try: - xvfb_version = subprocess.run( - ["Xvfb", "-version"], - capture_output=True, - text=True, - check=False - ) - if xvfb_version.returncode == 0: - print(f"✅ Xvfb disponível: {xvfb_version.stderr.strip()}") - else: - print(f"❌ Xvfb não disponível (código {xvfb_version.returncode})") -except FileNotFoundError: - print("❌ Xvfb não encontrado no PATH") - -# Verificar navegadores do Playwright -print("\nVerificando navegadores do Playwright:") -try: - from playwright.sync_api import sync_playwright - - with sync_playwright() as p: - browsers = { - "chromium": False, - "firefox": False, - "webkit": False - } - - try: - browser = p.chromium.launch() - browsers["chromium"] = True - browser.close() - except Exception as e: - print(f"❌ Erro ao iniciar Chromium: {e}") - - for name, available in browsers.items(): - if available: - print(f"✅ {name.capitalize()} disponível") - else: - print(f"⚠️ {name.capitalize()} não verificado") -except Exception as e: - print(f"❌ Erro ao inicializar Playwright: {e}") - -# Verificar arquivo server.py -print("\nVerificando arquivo server.py:") -if os.path.exists("server.py"): - print(f"✅ Arquivo server.py encontrado") - with open("server.py", "r") as f: - content = f.read() - if "langchain_google_genai" in content: - print("✅ server.py utiliza langchain_google_genai") - else: - print("ℹ️ server.py não parece utilizar langchain_google_genai diretamente") -else: - print("❌ Arquivo server.py não encontrado no diretório atual") - -print("\nDiagnóstico concluído!") - -if missing_packages: - print(f"\n⚠️ Os seguintes pacotes necessários estão faltando: {', '.join(missing_packages)}") - print("Execute o seguinte comando para instalar os pacotes faltantes:") - print(f"pip install {' '.join(missing_packages)}") -else: - print("\n✅ Todas as dependências requeridas estão instaladas") \ No newline at end of file diff --git a/main.py b/main.py deleted file mode 100644 index 80eb71bed0..0000000000 --- a/main.py +++ /dev/null @@ -1,544 +0,0 @@ -from fastapi import FastAPI, HTTPException, Depends, Request, Query -from fastapi.middleware.cors import CORSMiddleware -from fastapi.responses import JSONResponse -from sqlalchemy.orm import Session -from typing import Optional, List -import json -import time -import psutil -from datetime import datetime, timedelta -import asyncio -from queue import PriorityQueue -import threading -import logging -import uvicorn -from logging_config import setup_logging, log_info, log_error - -from config import settings -from database import get_db -from models import Task, Base -from browser import BrowserManager -from schemas import TaskCreate, TaskResponse, TaskUpdate, BrowserSessionResponse -from crud import ( - create_task, get_tasks, get_task, update_task, delete_task, - get_browser_sessions, get_browser_session, - get_browser_sessions_by_task -) -from notifications import webhook_manager -from api import router as api_router -from metrics import collect_metrics_periodically - -# Logging configuration -logger = logging.getLogger('browser-use.main') - -app = FastAPI( - title="Browser Automation API", - description="API for browser automation with session management", - version="1.0.0" -) - -# CORS configuration -app.add_middleware( - CORSMiddleware, - allow_origins=["*"], - allow_credentials=True, - allow_methods=["*"], - allow_headers=["*"], -) - -# Include API router -app.include_router(api_router) - -# Database initialization -Base.metadata.create_all(bind=settings.engine) - -# Global BrowserManager instance -browser_manager = BrowserManager() - -# Priority queue for tasks -task_queue = PriorityQueue() -task_lock = threading.Lock() - -# Running tasks -active_tasks = {} - -async def process_task_queue(): - """Processes the task queue in priority order""" - while True: - try: - with task_lock: - if not task_queue.empty(): - priority, task_id = task_queue.get() - task = await get_task_from_db(task_id) - - if task and task.status == "pending": - await execute_task(task) - - except Exception as e: - log_error(logger, "Error processing task queue", { - "error": str(e) - }, exc_info=True) - - await asyncio.sleep(1) - -async def get_task_from_db(task_id: int) -> Optional[Task]: - """Gets a task from the database""" - async with get_db() as db: - return await db.query(Task).filter(Task.id == task_id).first() - -async def execute_task(task: Task): - """Executes a task""" - try: - # Update status to running - async with get_db() as db: - task.status = "running" - task.started_at = datetime.utcnow() - await db.commit() - - # Notify execution start - await webhook_manager.notify_run( - task_id=task.id, - task_data={ - "task": task.task, - "config": task.config, - "priority": task.priority - } - ) - - # Execute task with timeout - try: - result = await asyncio.wait_for( - browser_manager.execute_task(task.task, task.config or {}), - timeout=task.timeout - ) - - # Update result - async with get_db() as db: - task.status = "completed" - task.result = json.dumps(result) - task.completed_at = datetime.utcnow() - await db.commit() - - except asyncio.TimeoutError: - error_msg = "Task timeout" - async with get_db() as db: - task.status = "failed" - task.error = error_msg - task.completed_at = datetime.utcnow() - await db.commit() - - # Notify error - await webhook_manager.notify_error( - task_id=task.id, - error=error_msg, - task_data={ - "task": task.task, - "config": task.config, - "priority": task.priority - } - ) - - except Exception as e: - log_error(logger, "Error executing task", { - "task_id": task.id, - "error": str(e) - }, exc_info=True) - async with get_db() as db: - task.status = "failed" - task.error = str(e) - task.completed_at = datetime.utcnow() - await db.commit() - - # Notify error - await webhook_manager.notify_error( - task_id=task.id, - error=str(e), - task_data={ - "task": task.task, - "config": task.config, - "priority": task.priority - } - ) - -async def collect_metrics(): - """Collects and sends metrics periodically""" - while True: - try: - # Collect system metrics - metrics = { - "cpu_percent": psutil.cpu_percent(), - "memory_percent": psutil.virtual_memory().percent, - "disk_percent": psutil.disk_usage('/').percent, - "active_tasks": len(active_tasks), - "browser_metrics": browser_manager.get_metrics() - } - - # Send metrics via webhook - await webhook_manager.send_status(metrics) - - except Exception as e: - log_error(logger, "Error collecting metrics", { - "error": str(e) - }, exc_info=True) - - await asyncio.sleep(3600) # Collect every hour - -@app.on_event("startup") -async def startup_event(): - """Initializes the browser manager on application startup""" - try: - await browser_manager.initialize() - log_info(logger, "BrowserManager initialized successfully") - except Exception as e: - log_error(logger, "Error initializing BrowserManager", { - "error": str(e) - }, exc_info=True) - raise - -@app.on_event("shutdown") -async def shutdown_event(): - """Closes the browser manager on application shutdown""" - try: - await browser_manager.close() - log_info(logger, "BrowserManager closed successfully") - except Exception as e: - log_error(logger, "Error closing BrowserManager", { - "error": str(e) - }, exc_info=True) - -@app.post("/run") -async def run_task(task: TaskCreate, db: Session = Depends(get_db)): - """Executes a new automation task""" - try: - # Create task in database - db_task = await create_task(db, task) - log_info(logger, "Task created successfully", { - "task_id": db_task.id - }) - - # Execute task using session pool - result = await browser_manager.execute_task(task.task, task.config) - log_info(logger, "Task executed successfully", { - "task_id": db_task.id - }) - - # Update task status and result - db_task.status = "completed" - db_task.result = str(result) - db_task.completed_at = datetime.utcnow() - await db.commit() - - return TaskResponse( - id=db_task.id, - status=db_task.status, - priority=db_task.priority, - result=db_task.result, - error=db_task.error, - created_at=db_task.created_at, - completed_at=db_task.completed_at - ) - except Exception as e: - log_error(logger, "Error executing task", { - "error": str(e) - }, exc_info=True) - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/metrics") -async def get_metrics(): - """Returns system and browser metrics""" - try: - return await browser_manager.get_metrics() - except Exception as e: - log_error(logger, "Error getting metrics", { - "error": str(e) - }, exc_info=True) - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/tasks", response_model=List[TaskResponse]) -async def list_tasks( - skip: int = Query(0, ge=0), - limit: int = Query(100, ge=1, le=100), - db: Session = Depends(get_db) -): - """Lists all tasks with pagination""" - try: - tasks = await get_tasks(db, skip=skip, limit=limit) - return [ - TaskResponse( - id=task.id, - status=task.status, - priority=task.priority, - result=task.result, - error=task.error, - created_at=task.created_at, - completed_at=task.completed_at - ) - for task in tasks - ] - except Exception as e: - log_error(logger, "Error listing tasks", { - "error": str(e) - }, exc_info=True) - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/tasks/{task_id}", response_model=TaskResponse) -async def get_task_by_id(task_id: int, db: Session = Depends(get_db)): - """Gets details of a specific task""" - try: - task = await get_task(db, task_id) - if not task: - raise HTTPException(status_code=404, detail="Task not found") - return TaskResponse( - id=task.id, - status=task.status, - priority=task.priority, - result=task.result, - error=task.error, - created_at=task.created_at, - completed_at=task.completed_at - ) - except HTTPException: - raise - except Exception as e: - log_error(logger, "Error getting task", { - "task_id": task_id, - "error": str(e) - }, exc_info=True) - raise HTTPException(status_code=500, detail=str(e)) - -@app.post("/tasks", response_model=TaskResponse) -async def create_new_task(task: TaskCreate, db: Session = Depends(get_db)): - """Creates a new task""" - try: - db_task = await create_task(db, task) - log_info(logger, "Task created successfully", { - "task_id": db_task.id - }) - return TaskResponse( - id=db_task.id, - status=db_task.status, - priority=db_task.priority, - result=db_task.result, - error=db_task.error, - created_at=db_task.created_at, - completed_at=db_task.completed_at - ) - except Exception as e: - log_error(logger, "Error creating task", { - "error": str(e) - }, exc_info=True) - raise HTTPException(status_code=500, detail=str(e)) - -@app.put("/tasks/{task_id}", response_model=TaskResponse) -async def update_existing_task(task_id: int, task: TaskUpdate, db: Session = Depends(get_db)): - """Updates an existing task""" - try: - db_task = await update_task(db, task_id, task) - if not db_task: - raise HTTPException(status_code=404, detail="Task not found") - log_info(logger, "Task updated successfully", { - "task_id": task_id - }) - return TaskResponse( - id=db_task.id, - status=db_task.status, - priority=db_task.priority, - result=db_task.result, - error=db_task.error, - created_at=db_task.created_at, - completed_at=db_task.completed_at - ) - except HTTPException: - raise - except Exception as e: - log_error(logger, "Error updating task", { - "task_id": task_id, - "error": str(e) - }, exc_info=True) - raise HTTPException(status_code=500, detail=str(e)) - -@app.delete("/tasks/{task_id}") -async def delete_existing_task(task_id: int, db: Session = Depends(get_db)): - """Deletes a task""" - try: - success = await delete_task(db, task_id) - if not success: - raise HTTPException(status_code=404, detail="Task not found") - log_info(logger, "Task deleted successfully", { - "task_id": task_id - }) - return {"status": "success"} - except HTTPException: - raise - except Exception as e: - log_error(logger, "Error deleting task", { - "task_id": task_id, - "error": str(e) - }, exc_info=True) - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/browser-sessions", response_model=List[BrowserSessionResponse]) -async def list_browser_sessions( - skip: int = Query(0, ge=0), - limit: int = Query(100, ge=1, le=100), - db: Session = Depends(get_db) -): - """Lists all browser sessions with pagination""" - try: - sessions = await get_browser_sessions(db, skip=skip, limit=limit) - return [ - BrowserSessionResponse( - id=session.id, - task_id=session.task_id, - status=session.status, - config=session.config, - metadata=session.metadata, - created_at=session.created_at, - updated_at=session.updated_at - ) - for session in sessions - ] - except Exception as e: - log_error(logger, "Error listing sessions", { - "error": str(e) - }, exc_info=True) - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/browser-sessions/{session_id}", response_model=BrowserSessionResponse) -async def get_browser_session_by_id(session_id: int, db: Session = Depends(get_db)): - """Gets details of a specific session""" - try: - session = await get_browser_session(db, session_id) - if not session: - raise HTTPException(status_code=404, detail="Browser session not found") - return BrowserSessionResponse( - id=session.id, - task_id=session.task_id, - status=session.status, - config=session.config, - metadata=session.metadata, - created_at=session.created_at, - updated_at=session.updated_at - ) - except HTTPException: - raise - except Exception as e: - log_error(logger, "Error getting session", { - "session_id": session_id, - "error": str(e) - }, exc_info=True) - raise HTTPException(status_code=500, detail=str(e)) - -@app.get("/tasks/{task_id}/browser-sessions", response_model=List[BrowserSessionResponse]) -async def get_task_browser_sessions(task_id: int, db: Session = Depends(get_db)): - """Lists all sessions associated with a task""" - try: - sessions = await get_browser_sessions_by_task(db, task_id) - return [ - BrowserSessionResponse( - id=session.id, - task_id=session.task_id, - status=session.status, - config=session.config, - metadata=session.metadata, - created_at=session.created_at, - updated_at=session.updated_at - ) - for session in sessions - ] - except Exception as e: - log_error(logger, "Error getting task sessions", { - "task_id": task_id, - "error": str(e) - }, exc_info=True) - raise HTTPException(status_code=500, detail=str(e)) - -@app.exception_handler(Exception) -async def global_exception_handler(request: Request, exc: Exception): - """Global exception handler""" - log_error(logger, "Unhandled error", { - "error": str(exc) - }, exc_info=True) - return JSONResponse( - status_code=500, - content={"detail": "Internal server error"} - ) - -@app.get("/health") -async def health_check(): - """Application health check endpoint""" - return {"status": "healthy"} - -@app.get("/tasks/", response_model=List[TaskResponse]) -async def list_tasks( - skip: int = Query(0, ge=0), - limit: int = Query(100, ge=1, le=100), - db: Session = Depends(get_db) -): - tasks = await get_tasks(db, skip=skip, limit=limit) - return [ - TaskResponse( - id=task.id, - status=task.status, - priority=task.priority, - result=task.result, - error=task.error, - created_at=task.created_at, - completed_at=task.completed_at - ) - for task in tasks - ] - -@app.get("/metrics/errors") -async def get_error_metrics(db: Session = Depends(get_db)): - """Returns error metrics""" - try: - last_hour = datetime.utcnow() - timedelta(hours=1) - error_tasks = db.query(Task).filter( - Task.status == "failed", - Task.created_at >= last_hour - ).all() - - return { - "total_errors": len(error_tasks), - "errors": [ - { - "task_id": task.id, - "error": task.error, - "timestamp": task.created_at.isoformat() - } for task in error_tasks - ] - } - except Exception as e: - log_error(logger, "Error getting error metrics", { - "error": str(e) - }, exc_info=True) - raise HTTPException(status_code=500, detail=str(e)) - -async def main(): - """Main function that starts the server and metrics collector""" - try: - log_info(logger, "Starting application") - - # Start metrics collector in background - log_info(logger, "Starting metrics collector") - asyncio.create_task(collect_metrics_periodically()) - - # Start FastAPI server - log_info(logger, "Starting FastAPI server") - config = uvicorn.Config(app, host="0.0.0.0", port=8000, log_level="info") - server = uvicorn.Server(config) - await server.serve() - - except Exception as e: - log_error(logger, "Error starting application", { - "error": str(e) - }, exc_info=True) - raise - -if __name__ == "__main__": - # Configure logging - setup_logging() - - # Run the application - asyncio.run(main()) \ No newline at end of file diff --git a/metrics.py b/metrics.py deleted file mode 100644 index 1139b6349b..0000000000 --- a/metrics.py +++ /dev/null @@ -1,60 +0,0 @@ -import asyncio -import psutil -import logging -from database import get_db, Task -from logging_config import log_info, log_error -# Logging configuration -logger = logging.getLogger('browser-use.api') -from settings import MAX_CONCURRENT_TASKS -from telemetry import send_metrics_to_webhook, send_error_to_webhook -# Function to collect metrics periodically -async def collect_metrics_periodically(): - """Collect system metrics periodically and adjust concurrent task limit""" - while True: - try: - - # Collect metrics - with get_db() as db: - # Get database statistics - total_tasks = db.query(Task).count() - completed_tasks = db.query(Task).filter(Task.status == "completed").count() - failed_tasks = db.query(Task).filter(Task.status == "failed").count() - running_tasks = db.query(Task).filter(Task.status == "running").count() - - # Get system metrics - cpu_percent = psutil.cpu_percent() - memory = psutil.virtual_memory() - disk = psutil.disk_usage('/') - - metrics = { - "system": { - "cpu_percent": cpu_percent, - "memory_percent": memory.percent, - "disk_percent": disk.percent - }, - "tasks": { - "total": total_tasks, - "completed": completed_tasks, - "failed": failed_tasks, - "running": running_tasks, - # "queued": task_queue.qsize(), - "available_slots": MAX_CONCURRENT_TASKS - running_tasks - } - } - - # Log current metrics - log_info(logger, "Updated system metrics", metrics) - - # Send metrics to webhook - await send_metrics_to_webhook(metrics) - - # Wait 30 seconds before next collection - await asyncio.sleep(30) - - except Exception as e: - log_error(logger, f"Error collecting metrics: {str(e)}") - await send_error_to_webhook(str(e), "collect_metrics_periodically") - await asyncio.sleep(30) # Wait even if error occurs - -# Start periodic metrics collection -asyncio.create_task(collect_metrics_periodically()) \ No newline at end of file diff --git a/migration.sql b/migration.sql deleted file mode 100644 index 12977302d9..0000000000 --- a/migration.sql +++ /dev/null @@ -1,71 +0,0 @@ --- Migration script that checks for existing tables before creating - -DO $$ -BEGIN - -- Check if tables already exist - IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'tasks') THEN - -- Create tasks table - CREATE TABLE tasks ( - id SERIAL PRIMARY KEY, - task VARCHAR NOT NULL, - config JSONB, - status VARCHAR NOT NULL, - result JSONB, - error VARCHAR, - created_at TIMESTAMP WITH TIME ZONE NOT NULL, - started_at TIMESTAMP WITH TIME ZONE, - completed_at TIMESTAMP WITH TIME ZONE - ); - - -- Create index for tasks - CREATE INDEX idx_tasks_status ON tasks(status); - CREATE INDEX idx_tasks_created_at ON tasks(created_at); - - RAISE NOTICE 'Created tasks table'; - ELSE - RAISE NOTICE 'tasks table already exists, skipping creation'; - END IF; - - IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'metrics') THEN - -- Create metrics table - CREATE TABLE metrics ( - id SERIAL PRIMARY KEY, - name VARCHAR NOT NULL, - value DOUBLE PRECISION NOT NULL, - created_at TIMESTAMP WITH TIME ZONE NOT NULL - ); - - -- Create index for metrics - CREATE INDEX idx_metrics_name ON metrics(name); - CREATE INDEX idx_metrics_created_at ON metrics(created_at); - - RAISE NOTICE 'Created metrics table'; - ELSE - RAISE NOTICE 'metrics table already exists, skipping creation'; - END IF; - - IF NOT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'sessions') THEN - -- Create sessions table - CREATE TABLE sessions ( - id SERIAL PRIMARY KEY, - task_id INTEGER NOT NULL, - start_time TIMESTAMP WITH TIME ZONE NOT NULL, - end_time TIMESTAMP WITH TIME ZONE, - status VARCHAR NOT NULL, - error VARCHAR, - created_at TIMESTAMP WITH TIME ZONE NOT NULL - ); - - -- Create index for sessions - CREATE INDEX idx_sessions_task_id ON sessions(task_id); - CREATE INDEX idx_sessions_status ON sessions(status); - CREATE INDEX idx_sessions_start_time ON sessions(start_time); - - RAISE NOTICE 'Created sessions table'; - ELSE - RAISE NOTICE 'sessions table already exists, skipping creation'; - END IF; -END $$; - --- Output the results -SELECT 'Migration completed with existence checks' AS result; \ No newline at end of file diff --git a/nixpacks.toml b/nixpacks.toml deleted file mode 100644 index 713184a697..0000000000 --- a/nixpacks.toml +++ /dev/null @@ -1,32 +0,0 @@ -[variables] -PYTHON_VERSION = "3.11" - -[phases.setup] -nixPkgs = [ - "python311", - "python311Packages.pip", - "python311Packages.virtualenv", - "gcc", - "python3-dev", - "libpq-dev", - "chromium", - "chromedriver", - "postgresql" -] - -[phases.install] -cmds = [ - "pip install --no-cache-dir -r requirements.txt", - "playwright install chromium", - "playwright install-deps", - "chmod +x start.sh" -] - -[phases.build] -cmds = [ - "python3 -m playwright install chromium", - "echo 'Build phase completed'" -] - -[start] -cmd = "./start.sh" \ No newline at end of file diff --git a/nixpacks.toml.alternative b/nixpacks.toml.alternative deleted file mode 100644 index 06a71c0eab..0000000000 --- a/nixpacks.toml.alternative +++ /dev/null @@ -1,23 +0,0 @@ -# Versão alternativa e simplificada do nixpacks.toml -# Use este arquivo se a versão original não funcionar -# Renomeie para nixpacks.toml antes de fazer deploy - -[phases.setup] -nixPkgs = ["chromium", "wget", "gnumake", "gcc", "git"] - -[phases.install] -cmds = [ - "apt-get update", - "apt-get install -y xvfb-run xvfb", - "python -m pip install -e .", - "chmod +x start.sh" -] - -[phases.build] -cmds = [ - "python -m playwright install chromium", - "echo 'Build phase completed'" -] - -[start] -cmd = "./start.sh" \ No newline at end of file diff --git a/notifications.py b/notifications.py deleted file mode 100644 index 08b72b72a3..0000000000 --- a/notifications.py +++ /dev/null @@ -1,72 +0,0 @@ -import aiohttp -import logging -from typing import Dict, Any -from datetime import datetime -import json -import os - -logger = logging.getLogger(__name__) - -class WebhookManager: - def __init__(self): - self.notify_run_url = os.getenv("NOTIFY_WEBHOOK_URL","https://vrautomatize-n8n.snrhk1.easypanel.host/webhook/notify-run") - self.error_handler_url = os.getenv("ERROR_WEBHOOK_URL","https://vrautomatize-n8n.snrhk1.easypanel.host/webhook/browser-use-vra-handler") - self.status_url = os.getenv("STATUS_WEBHOOK_URL","https://vrautomatize-n8n.snrhk1.easypanel.host/webhook/status") - self.session = None - - async def init_session(self): - if not self.session: - self.session = aiohttp.ClientSession() - - async def close(self): - if self.session: - await self.session.close() - self.session = None - - async def notify_run(self, task_id: int, task_data: Dict[str, Any]): - """Notifica sobre uma nova execução de tarefa""" - try: - await self.init_session() - payload = { - "task_id": task_id, - "task_data": task_data, - "timestamp": datetime.utcnow().isoformat() - } - async with self.session.post(self.notify_run_url, json=payload) as response: - if response.status != 200: - logger.error(f"Erro ao notificar run: {await response.text()}") - except Exception as e: - logger.error(f"Erro ao enviar notificação de run: {str(e)}") - - async def notify_error(self, task_id: int, error: str, task_data: Dict[str, Any]): - """Notifica sobre um erro na execução""" - try: - await self.init_session() - payload = { - "task_id": task_id, - "error": error, - "task_data": task_data, - "timestamp": datetime.utcnow().isoformat() - } - async with self.session.post(self.error_handler_url, json=payload) as response: - if response.status != 200: - logger.error(f"Erro ao notificar erro: {await response.text()}") - except Exception as e: - logger.error(f"Erro ao enviar notificação de erro: {str(e)}") - - async def send_status(self, metrics: Dict[str, Any]): - """Envia status e métricas do sistema""" - try: - await self.init_session() - payload = { - "metrics": metrics, - "timestamp": datetime.utcnow().isoformat() - } - async with self.session.post(self.status_url, json=payload) as response: - if response.status != 200: - logger.error(f"Erro ao enviar status: {await response.text()}") - except Exception as e: - logger.error(f"Erro ao enviar status: {str(e)}") - -# Instância global do WebhookManager -webhook_manager = WebhookManager() \ No newline at end of file