Files
manus_ai_clone/main.py
T
2025-11-05 01:03:10 +01:00

175 lines
4.3 KiB
Python

"""
Manus AI Clone - AI-powered browser automation API
"""
import os
from contextlib import asynccontextmanager
from pathlib import Path
from typing import Optional
from dotenv import load_dotenv
from fastapi import FastAPI, HTTPException, Request
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from pydantic import BaseModel, ConfigDict
from pydantic_settings import BaseSettings
from browser_agent import BrowserAgent
# Load environment variables
load_dotenv()
# Get base directory
BASE_DIR = Path(__file__).resolve().parent
# Setup templates and static files
templates = Jinja2Templates(directory=str(BASE_DIR / "templates"))
class Settings(BaseSettings):
"""Application settings"""
model_config = ConfigDict(env_file=".env")
openai_api_key: str = os.getenv("OPENAI_API_KEY", "")
model: str = os.getenv("MODEL", "gpt-4o-mini")
headless: bool = os.getenv("HEADLESS", "false").lower() == "true"
# Global agent instance
agent: Optional[BrowserAgent] = None
settings = Settings()
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Manage application lifecycle"""
global agent
# Startup
if not settings.openai_api_key:
print("Warning: OPENAI_API_KEY not set. Please set it in .env file")
else:
print("Initializing browser agent...")
agent = BrowserAgent(
openai_api_key=settings.openai_api_key, model=settings.model
)
await agent.initialize(headless=settings.headless)
print("Browser agent ready!")
yield
# Shutdown
if agent:
print("Cleaning up browser agent...")
await agent.cleanup()
print("Cleanup complete")
# Create FastAPI app
app = FastAPI(
title="Manus AI Clone",
description="AI-powered browser automation using LangChain and Playwright",
version="0.1.0",
lifespan=lifespan,
)
# Mount static files
app.mount("/static", StaticFiles(directory=str(BASE_DIR / "static")), name="static")
# Pydantic models
class TaskRequest(BaseModel):
"""Request model for browser automation tasks"""
model_config = ConfigDict(
json_schema_extra={
"example": {
"prompt": "Go to google.com and search for 'LangChain tutorial'"
}
}
)
prompt: str
class TaskResponse(BaseModel):
"""Response model for browser automation tasks"""
success: bool
output: Optional[str] = None
error: Optional[str] = None
screenshot: Optional[str] = None
action_history: list = []
# API Routes
@app.get("/", response_class=HTMLResponse)
async def home(request: Request):
"""Serve the frontend interface"""
return templates.TemplateResponse("index.html", {"request": request})
@app.get("/health")
async def health_check():
"""Health check endpoint"""
return {
"status": "healthy",
"agent_initialized": agent is not None,
"model": settings.model,
}
@app.post("/execute", response_model=TaskResponse)
async def execute_task(request: TaskRequest):
"""Execute a browser automation task"""
if not agent:
raise HTTPException(
status_code=503,
detail="Browser agent not initialized. Please check OPENAI_API_KEY.",
)
if not request.prompt.strip():
raise HTTPException(status_code=400, detail="Prompt cannot be empty")
try:
result = await agent.execute_task(request.prompt)
return TaskResponse(**result)
except Exception as e:
raise HTTPException(status_code=500, detail=f"Error executing task: {str(e)}")
@app.get("/status")
async def get_status():
"""Get current browser status and action history"""
if not agent:
raise HTTPException(status_code=503, detail="Browser agent not initialized")
return {
"action_history": agent.browser.action_history,
"current_url": agent.browser.page.url if agent.browser.page else None,
}
def main():
"""Run the application"""
import uvicorn
port = int(os.getenv("PORT", "8000"))
host = os.getenv("HOST", "0.0.0.0")
print(f"""
🤖 Manus AI Clone Starting...
📝 Make sure to set OPENAI_API_KEY in your .env file
🌐 Server will be available at: http://localhost:{port}
""")
uvicorn.run(app, host=host, port=port)
if __name__ == "__main__":
main()