mfoud444 commited on
Commit
0b9ad55
·
verified ·
1 Parent(s): ca33059

Create api.py

Browse files
Files changed (1) hide show
  1. api.py +161 -0
api.py ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from fastapi import FastAPI, Request
2
+ from fastapi.middleware.cors import CORSMiddleware
3
+ from fastapi.responses import JSONResponse
4
+ from contextlib import asynccontextmanager
5
+ from agentpress.thread_manager import ThreadManager
6
+ from services.supabase import DBConnection
7
+ from datetime import datetime, timezone
8
+ from dotenv import load_dotenv
9
+ from utils.config import config, EnvMode
10
+ import asyncio
11
+ from utils.logger import logger
12
+ import uuid
13
+ import time
14
+ from collections import OrderedDict
15
+
16
+ # Import the agent API module
17
+ from agent import api as agent_api
18
+ from sandbox import api as sandbox_api
19
+ from services import billing as billing_api
20
+
21
+ # Load environment variables (these will be available through config)
22
+ load_dotenv()
23
+
24
+ # Initialize managers
25
+ db = DBConnection()
26
+ thread_manager = None
27
+ instance_id = "single"
28
+
29
+ # Rate limiter state
30
+ ip_tracker = OrderedDict()
31
+ MAX_CONCURRENT_IPS = 25
32
+
33
+ @asynccontextmanager
34
+ async def lifespan(app: FastAPI):
35
+ # Startup
36
+ global thread_manager
37
+ logger.info(f"Starting up FastAPI application with instance ID: {instance_id} in {config.ENV_MODE.value} mode")
38
+
39
+ try:
40
+ # Initialize database
41
+ await db.initialize()
42
+ thread_manager = ThreadManager()
43
+
44
+ # Initialize the agent API with shared resources
45
+ agent_api.initialize(
46
+ thread_manager,
47
+ db,
48
+ instance_id
49
+ )
50
+
51
+ # Initialize the sandbox API with shared resources
52
+ sandbox_api.initialize(db)
53
+
54
+ # Initialize Redis connection
55
+ from services import redis
56
+ try:
57
+ await redis.initialize_async()
58
+ logger.info("Redis connection initialized successfully")
59
+ except Exception as e:
60
+ logger.error(f"Failed to initialize Redis connection: {e}")
61
+ # Continue without Redis - the application will handle Redis failures gracefully
62
+
63
+ # Start background tasks
64
+ asyncio.create_task(agent_api.restore_running_agent_runs())
65
+
66
+ yield
67
+
68
+ # Clean up agent resources
69
+ logger.info("Cleaning up agent resources")
70
+ await agent_api.cleanup()
71
+
72
+ # Clean up Redis connection
73
+ try:
74
+ logger.info("Closing Redis connection")
75
+ await redis.close()
76
+ logger.info("Redis connection closed successfully")
77
+ except Exception as e:
78
+ logger.error(f"Error closing Redis connection: {e}")
79
+
80
+ # Clean up database connection
81
+ logger.info("Disconnecting from database")
82
+ await db.disconnect()
83
+ except Exception as e:
84
+ logger.error(f"Error during application startup: {e}")
85
+ raise
86
+
87
+ app = FastAPI(lifespan=lifespan)
88
+
89
+ @app.middleware("http")
90
+ async def log_requests_middleware(request: Request, call_next):
91
+ start_time = time.time()
92
+ client_ip = request.client.host
93
+ method = request.method
94
+ url = str(request.url)
95
+ path = request.url.path
96
+ query_params = str(request.query_params)
97
+
98
+ # Log the incoming request
99
+ logger.info(f"Request started: {method} {path} from {client_ip} | Query: {query_params}")
100
+
101
+ try:
102
+ response = await call_next(request)
103
+ process_time = time.time() - start_time
104
+ logger.debug(f"Request completed: {method} {path} | Status: {response.status_code} | Time: {process_time:.2f}s")
105
+ return response
106
+ except Exception as e:
107
+ process_time = time.time() - start_time
108
+ logger.error(f"Request failed: {method} {path} | Error: {str(e)} | Time: {process_time:.2f}s")
109
+ raise
110
+
111
+ # Define allowed origins based on environment
112
+ allowed_origins = ["https://www.suna.so","https://suna-gold.vercel.app", "https://suna.so", "https://staging.suna.so", "http://localhost:3000"]
113
+
114
+ # Add staging-specific origins
115
+ if config.ENV_MODE == EnvMode.STAGING:
116
+ allowed_origins.append("http://localhost:3006")
117
+
118
+ # Add local-specific origins
119
+ if config.ENV_MODE == EnvMode.LOCAL:
120
+ allowed_origins.append("http://localhost:3006")
121
+
122
+ app.add_middleware(
123
+ CORSMiddleware,
124
+ allow_origins=allowed_origins,
125
+ allow_credentials=True,
126
+ allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"],
127
+ allow_headers=["Content-Type", "Authorization"],
128
+ )
129
+
130
+ # Include the agent router with a prefix
131
+ app.include_router(agent_api.router, prefix="/api")
132
+
133
+ # Include the sandbox router with a prefix
134
+ app.include_router(sandbox_api.router, prefix="/api")
135
+
136
+ # Include the billing router with a prefix
137
+ app.include_router(billing_api.router, prefix="/api")
138
+
139
+ @app.get("/api/health")
140
+ async def health_check():
141
+ """Health check endpoint to verify API is working."""
142
+ logger.info("Health check endpoint called")
143
+ return {
144
+ "status": "ok",
145
+ "timestamp": datetime.now(timezone.utc).isoformat(),
146
+ "instance_id": instance_id
147
+ }
148
+
149
+ if __name__ == "__main__":
150
+ import uvicorn
151
+
152
+ workers = 2
153
+
154
+ logger.info(f"Starting server on 0.0.0.0:8000 with {workers} workers")
155
+ uvicorn.run(
156
+ "api:app",
157
+ host="0.0.0.0",
158
+ port=8000,
159
+ workers=workers,
160
+ # reload=True
161
+ )