|
|
"""
|
|
|
ORYNXML Complete Backend with AI Agents
|
|
|
FastAPI REST API + Manus Agent + SWE Agent + Browser Agent + HuggingFace Agent
|
|
|
"""
|
|
|
|
|
|
from fastapi import FastAPI, HTTPException, BackgroundTasks
|
|
|
from fastapi.middleware.cors import CORSMiddleware
|
|
|
from pydantic import BaseModel
|
|
|
from typing import Optional, List, Dict, Any
|
|
|
import os
|
|
|
import sys
|
|
|
import sqlite3
|
|
|
import hashlib
|
|
|
import asyncio
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
|
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
|
|
|
|
|
|
|
|
|
from app.agent.manus import Manus
|
|
|
from app.agent.swe import SWEAgent
|
|
|
from app.agent.browser import BrowserAgent
|
|
|
from app.agent.data_analysis import DataAnalysis
|
|
|
from app.llm import get_llm
|
|
|
from app.tool.tool_collection import ToolCollection
|
|
|
|
|
|
|
|
|
HF_TOKEN = os.getenv("HF_TOKEN", "")
|
|
|
|
|
|
|
|
|
CLOUDFLARE_CONFIG = {
|
|
|
"api_token": os.getenv("CLOUDFLARE_API_TOKEN", ""),
|
|
|
"account_id": os.getenv("CLOUDFLARE_ACCOUNT_ID", "62af59a7ac82b29543577ee6800735ee"),
|
|
|
"d1_database_id": os.getenv("CLOUDFLARE_D1_DATABASE_ID", "6d887f74-98ac-4db7-bfed-8061903d1f6c"),
|
|
|
"r2_bucket_name": os.getenv("CLOUDFLARE_R2_BUCKET_NAME", "openmanus-storage"),
|
|
|
"kv_namespace_id": os.getenv("CLOUDFLARE_KV_NAMESPACE_ID", "87f4aa01410d4fb19821f61006f94441"),
|
|
|
"kv_namespace_cache": os.getenv("CLOUDFLARE_KV_CACHE_ID", "7b58c88292c847d1a82c8e0dd5129f37"),
|
|
|
}
|
|
|
|
|
|
|
|
|
manus_agent = None
|
|
|
swe_agent = None
|
|
|
browser_agent = None
|
|
|
data_agent = None
|
|
|
|
|
|
|
|
|
app = FastAPI(
|
|
|
title="ORYNXML AI Platform with Agents",
|
|
|
description="Complete AI backend with Manus, SWE, Browser, and Data Analysis agents",
|
|
|
version="2.0.0",
|
|
|
)
|
|
|
|
|
|
|
|
|
app.add_middleware(
|
|
|
CORSMiddleware,
|
|
|
allow_origins=["*"],
|
|
|
allow_credentials=True,
|
|
|
allow_methods=["*"],
|
|
|
allow_headers=["*"],
|
|
|
)
|
|
|
|
|
|
|
|
|
def init_database():
|
|
|
conn = sqlite3.connect("openmanus.db")
|
|
|
cursor = conn.cursor()
|
|
|
cursor.execute("""
|
|
|
CREATE TABLE IF NOT EXISTS users (
|
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
|
mobile TEXT UNIQUE NOT NULL,
|
|
|
name TEXT NOT NULL,
|
|
|
password_hash TEXT NOT NULL,
|
|
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
|
)
|
|
|
""")
|
|
|
conn.commit()
|
|
|
conn.close()
|
|
|
|
|
|
init_database()
|
|
|
|
|
|
|
|
|
class SignupRequest(BaseModel):
|
|
|
mobile: str
|
|
|
name: str
|
|
|
password: str
|
|
|
|
|
|
class LoginRequest(BaseModel):
|
|
|
mobile: str
|
|
|
password: str
|
|
|
|
|
|
class AgentRequest(BaseModel):
|
|
|
prompt: str
|
|
|
agent: Optional[str] = "manus"
|
|
|
|
|
|
class CodeRequest(BaseModel):
|
|
|
task: str
|
|
|
language: Optional[str] = "python"
|
|
|
|
|
|
class BrowserRequest(BaseModel):
|
|
|
task: str
|
|
|
url: Optional[str] = None
|
|
|
|
|
|
class DataRequest(BaseModel):
|
|
|
data: Any
|
|
|
task: str
|
|
|
|
|
|
|
|
|
def hash_password(password: str) -> str:
|
|
|
return hashlib.sha256(password.encode()).hexdigest()
|
|
|
|
|
|
def verify_password(password: str, password_hash: str) -> bool:
|
|
|
return hash_password(password) == password_hash
|
|
|
|
|
|
|
|
|
@app.on_event("startup")
|
|
|
async def startup_event():
|
|
|
global manus_agent, swe_agent, browser_agent, data_agent
|
|
|
|
|
|
print("π Initializing AI Agents...")
|
|
|
|
|
|
try:
|
|
|
|
|
|
manus_agent = await Manus.create()
|
|
|
print("β
Manus Agent initialized")
|
|
|
|
|
|
|
|
|
swe_agent = await SWEAgent.create()
|
|
|
print("β
SWE Agent initialized")
|
|
|
|
|
|
|
|
|
browser_agent = await BrowserAgent.create()
|
|
|
print("β
Browser Agent initialized")
|
|
|
|
|
|
|
|
|
data_agent = await DataAnalysis.create()
|
|
|
print("β
Data Analysis Agent initialized")
|
|
|
|
|
|
print("π All agents ready!")
|
|
|
|
|
|
except Exception as e:
|
|
|
print(f"β οΈ Warning: Could not initialize all agents: {e}")
|
|
|
print("API will still work with limited functionality")
|
|
|
|
|
|
|
|
|
|
|
|
@app.get("/")
|
|
|
async def root():
|
|
|
return {
|
|
|
"message": "ORYNXML AI Platform with Agents",
|
|
|
"version": "2.0.0",
|
|
|
"agents": {
|
|
|
"manus": "Main agent with all capabilities" if manus_agent else "Not initialized",
|
|
|
"swe": "Software Engineer agent" if swe_agent else "Not initialized",
|
|
|
"browser": "Browser automation agent" if browser_agent else "Not initialized",
|
|
|
"data": "Data analysis agent" if data_agent else "Not initialized",
|
|
|
},
|
|
|
"endpoints": {
|
|
|
"health": "/health",
|
|
|
"auth": "/auth/signup, /auth/login",
|
|
|
"agents": "/agent/run, /agent/code, /agent/browser, /agent/data",
|
|
|
}
|
|
|
}
|
|
|
|
|
|
@app.get("/health")
|
|
|
async def health_check():
|
|
|
return {
|
|
|
"status": "healthy",
|
|
|
"timestamp": datetime.now().isoformat(),
|
|
|
"agents_initialized": {
|
|
|
"manus": manus_agent is not None,
|
|
|
"swe": swe_agent is not None,
|
|
|
"browser": browser_agent is not None,
|
|
|
"data": data_agent is not None,
|
|
|
},
|
|
|
"cloudflare_configured": bool(CLOUDFLARE_CONFIG["api_token"]),
|
|
|
}
|
|
|
|
|
|
@app.post("/auth/signup")
|
|
|
async def signup(request: SignupRequest):
|
|
|
try:
|
|
|
if len(request.password) < 6:
|
|
|
raise HTTPException(status_code=400, detail="Password must be at least 6 characters")
|
|
|
|
|
|
conn = sqlite3.connect("openmanus.db")
|
|
|
cursor = conn.cursor()
|
|
|
|
|
|
cursor.execute("SELECT mobile FROM users WHERE mobile = ?", (request.mobile,))
|
|
|
if cursor.fetchone():
|
|
|
conn.close()
|
|
|
raise HTTPException(status_code=400, detail="Mobile number already registered")
|
|
|
|
|
|
password_hash = hash_password(request.password)
|
|
|
cursor.execute(
|
|
|
"INSERT INTO users (mobile, name, password_hash) VALUES (?, ?, ?)",
|
|
|
(request.mobile, request.name, password_hash)
|
|
|
)
|
|
|
conn.commit()
|
|
|
conn.close()
|
|
|
|
|
|
return {
|
|
|
"success": True,
|
|
|
"message": "Account created successfully",
|
|
|
"mobile": request.mobile,
|
|
|
"name": request.name
|
|
|
}
|
|
|
|
|
|
except HTTPException:
|
|
|
raise
|
|
|
except Exception as e:
|
|
|
raise HTTPException(status_code=500, detail=f"Registration failed: {str(e)}")
|
|
|
|
|
|
@app.post("/auth/login")
|
|
|
async def login(request: LoginRequest):
|
|
|
try:
|
|
|
conn = sqlite3.connect("openmanus.db")
|
|
|
cursor = conn.cursor()
|
|
|
|
|
|
cursor.execute(
|
|
|
"SELECT name, password_hash FROM users WHERE mobile = ?",
|
|
|
(request.mobile,)
|
|
|
)
|
|
|
result = cursor.fetchone()
|
|
|
conn.close()
|
|
|
|
|
|
if not result:
|
|
|
raise HTTPException(status_code=401, detail="Invalid mobile number or password")
|
|
|
|
|
|
name, password_hash = result
|
|
|
|
|
|
if not verify_password(request.password, password_hash):
|
|
|
raise HTTPException(status_code=401, detail="Invalid mobile number or password")
|
|
|
|
|
|
return {
|
|
|
"success": True,
|
|
|
"message": "Login successful",
|
|
|
"user": {
|
|
|
"mobile": request.mobile,
|
|
|
"name": name
|
|
|
},
|
|
|
"token": f"session_{hash_password(request.mobile + str(datetime.now()))[:32]}"
|
|
|
}
|
|
|
|
|
|
except HTTPException:
|
|
|
raise
|
|
|
except Exception as e:
|
|
|
raise HTTPException(status_code=500, detail=f"Login failed: {str(e)}")
|
|
|
|
|
|
@app.post("/agent/run")
|
|
|
async def run_agent(request: AgentRequest):
|
|
|
"""Run any agent with a prompt"""
|
|
|
try:
|
|
|
agent_name = request.agent.lower()
|
|
|
|
|
|
|
|
|
if agent_name == "manus":
|
|
|
if not manus_agent:
|
|
|
raise HTTPException(status_code=503, detail="Manus agent not initialized")
|
|
|
agent = manus_agent
|
|
|
elif agent_name == "swe":
|
|
|
if not swe_agent:
|
|
|
raise HTTPException(status_code=503, detail="SWE agent not initialized")
|
|
|
agent = swe_agent
|
|
|
elif agent_name == "browser":
|
|
|
if not browser_agent:
|
|
|
raise HTTPException(status_code=503, detail="Browser agent not initialized")
|
|
|
agent = browser_agent
|
|
|
elif agent_name == "data":
|
|
|
if not data_agent:
|
|
|
raise HTTPException(status_code=503, detail="Data agent not initialized")
|
|
|
agent = data_agent
|
|
|
else:
|
|
|
raise HTTPException(status_code=400, detail=f"Unknown agent: {agent_name}")
|
|
|
|
|
|
|
|
|
result = await agent.run(request.prompt)
|
|
|
|
|
|
return {
|
|
|
"success": True,
|
|
|
"agent": agent_name,
|
|
|
"prompt": request.prompt,
|
|
|
"result": str(result),
|
|
|
"timestamp": datetime.now().isoformat()
|
|
|
}
|
|
|
|
|
|
except HTTPException:
|
|
|
raise
|
|
|
except Exception as e:
|
|
|
raise HTTPException(status_code=500, detail=f"Agent execution failed: {str(e)}")
|
|
|
|
|
|
@app.post("/agent/code")
|
|
|
async def generate_code(request: CodeRequest):
|
|
|
"""Software Engineer Agent - Generate code"""
|
|
|
try:
|
|
|
if not swe_agent:
|
|
|
raise HTTPException(status_code=503, detail="SWE agent not initialized")
|
|
|
|
|
|
prompt = f"Generate {request.language} code for: {request.task}"
|
|
|
result = await swe_agent.run(prompt)
|
|
|
|
|
|
return {
|
|
|
"success": True,
|
|
|
"task": request.task,
|
|
|
"language": request.language,
|
|
|
"code": str(result),
|
|
|
"timestamp": datetime.now().isoformat()
|
|
|
}
|
|
|
|
|
|
except HTTPException:
|
|
|
raise
|
|
|
except Exception as e:
|
|
|
raise HTTPException(status_code=500, detail=f"Code generation failed: {str(e)}")
|
|
|
|
|
|
@app.post("/agent/browser")
|
|
|
async def browser_automation(request: BrowserRequest):
|
|
|
"""Browser Agent - Automate web tasks"""
|
|
|
try:
|
|
|
if not browser_agent:
|
|
|
raise HTTPException(status_code=503, detail="Browser agent not initialized")
|
|
|
|
|
|
prompt = f"{request.task}"
|
|
|
if request.url:
|
|
|
prompt += f" on {request.url}"
|
|
|
|
|
|
result = await browser_agent.run(prompt)
|
|
|
|
|
|
return {
|
|
|
"success": True,
|
|
|
"task": request.task,
|
|
|
"url": request.url,
|
|
|
"result": str(result),
|
|
|
"timestamp": datetime.now().isoformat()
|
|
|
}
|
|
|
|
|
|
except HTTPException:
|
|
|
raise
|
|
|
except Exception as e:
|
|
|
raise HTTPException(status_code=500, detail=f"Browser automation failed: {str(e)}")
|
|
|
|
|
|
@app.post("/agent/data")
|
|
|
async def analyze_data(request: DataRequest):
|
|
|
"""Data Analysis Agent - Analyze and visualize data"""
|
|
|
try:
|
|
|
if not data_agent:
|
|
|
raise HTTPException(status_code=503, detail="Data agent not initialized")
|
|
|
|
|
|
prompt = f"Analyze this data: {request.data}. Task: {request.task}"
|
|
|
result = await data_agent.run(prompt)
|
|
|
|
|
|
return {
|
|
|
"success": True,
|
|
|
"task": request.task,
|
|
|
"result": str(result),
|
|
|
"timestamp": datetime.now().isoformat()
|
|
|
}
|
|
|
|
|
|
except HTTPException:
|
|
|
raise
|
|
|
except Exception as e:
|
|
|
raise HTTPException(status_code=500, detail=f"Data analysis failed: {str(e)}")
|
|
|
|
|
|
@app.get("/agents/list")
|
|
|
async def list_agents():
|
|
|
"""List all available agents and their status"""
|
|
|
return {
|
|
|
"agents": [
|
|
|
{
|
|
|
"name": "manus",
|
|
|
"description": "Main agent with all capabilities (chat, coding, browsing, data analysis)",
|
|
|
"status": "initialized" if manus_agent else "not initialized",
|
|
|
"endpoint": "/agent/run"
|
|
|
},
|
|
|
{
|
|
|
"name": "swe",
|
|
|
"description": "Software Engineer agent (code generation, debugging, refactoring)",
|
|
|
"status": "initialized" if swe_agent else "not initialized",
|
|
|
"endpoint": "/agent/code"
|
|
|
},
|
|
|
{
|
|
|
"name": "browser",
|
|
|
"description": "Browser automation agent (web scraping, form filling, navigation)",
|
|
|
"status": "initialized" if browser_agent else "not initialized",
|
|
|
"endpoint": "/agent/browser"
|
|
|
},
|
|
|
{
|
|
|
"name": "data",
|
|
|
"description": "Data analysis agent (charts, visualization, statistics)",
|
|
|
"status": "initialized" if data_agent else "not initialized",
|
|
|
"endpoint": "/agent/data"
|
|
|
}
|
|
|
]
|
|
|
}
|
|
|
|
|
|
@app.get("/cloudflare/status")
|
|
|
async def cloudflare_status():
|
|
|
services = []
|
|
|
if CLOUDFLARE_CONFIG["api_token"]:
|
|
|
services.append("β
API Token Configured")
|
|
|
if CLOUDFLARE_CONFIG["d1_database_id"]:
|
|
|
services.append("β
D1 Database Connected")
|
|
|
if CLOUDFLARE_CONFIG["r2_bucket_name"]:
|
|
|
services.append("β
R2 Storage Connected")
|
|
|
if CLOUDFLARE_CONFIG["kv_namespace_id"]:
|
|
|
services.append("β
KV Sessions Connected")
|
|
|
if CLOUDFLARE_CONFIG["kv_namespace_cache"]:
|
|
|
services.append("β
KV Cache Connected")
|
|
|
|
|
|
return {
|
|
|
"configured": len(services) > 0,
|
|
|
"services": services,
|
|
|
"account_id": CLOUDFLARE_CONFIG["account_id"]
|
|
|
}
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
uvicorn.run(
|
|
|
app,
|
|
|
host="0.0.0.0",
|
|
|
port=7860,
|
|
|
log_level="info"
|
|
|
)
|
|
|
|