-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathapp.py
More file actions
145 lines (111 loc) · 4.16 KB
/
app.py
File metadata and controls
145 lines (111 loc) · 4.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import os
import logging
from contextlib import asynccontextmanager
from typing import Optional
from fastapi import FastAPI, HTTPException, Request, status
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from pydantic import BaseModel, Field
from dotenv import load_dotenv
from src import db_connection
from src.agent import create_clickup_agent
load_dotenv()
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
class ChatRequest(BaseModel):
user_input: str = Field(..., description="User's message to the agent")
user_id: str = Field(..., description="Unique user identifier")
class ChatResponse(BaseModel):
success: bool = Field(..., description="Whether the request was successful")
message: Optional[str] = Field(None, description="Response message")
error: Optional[str] = Field(None, description="Error message if any")
class HealthResponse(BaseModel):
status: str = Field(..., description="Service health status")
database: str = Field(..., description="Database connection status")
@asynccontextmanager
async def lifespan(app: FastAPI):
logger.info("Starting up FastAPI application...")
try:
await db_connection.connect()
logger.info("Database connection established")
except Exception as e:
logger.error(f"Failed to connect to database: {e}")
raise
yield
logger.info("Shutting down FastAPI application...")
await db_connection.disconnect()
logger.info("Database connection closed")
app = FastAPI(
title="ClickUp Agent API",
description="Production-ready API for interacting with ClickUp agent",
version="1.0.0",
lifespan=lifespan
)
app.add_middleware(
CORSMiddleware,
allow_origins=os.getenv("ALLOWED_ORIGINS", "*").split(","),
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
logger.error(f"Unhandled exception: {exc}", exc_info=True)
return JSONResponse(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
content={
"success": False,
"error": "Internal server error occurred"
}
)
@app.get("/health", response_model=HealthResponse)
async def health_check():
"""Check the health status of the API and its dependencies."""
try:
db_status = "connected" if db_connection._client else "disconnected"
except Exception:
db_status = "error"
return HealthResponse(
status="healthy",
database=db_status
)
@app.post("/chat", response_model=ChatResponse)
async def chat(request: ChatRequest):
"""
Process a chat message using the ClickUp agent.
Args:
request: ChatRequest containing user_input and user_id
Returns:
ChatResponse with the agent's response or error message
"""
logger.info(f"Chat request from user {request.user_id}: {request.user_input[:50]}...")
try:
clickup_agent = create_clickup_agent()
result = await clickup_agent.run(
user_input=request.user_input,
user_id=request.user_id
)
response = await clickup_agent.get_agent_response(result)
logger.info(f"Successfully processed chat request for user {request.user_id}")
return ChatResponse(
success=True,
message=str(response) if result else "Agent processed the request successfully"
)
except Exception as e:
logger.error(f"Error processing chat request for user {request.user_id}: {e}", exc_info=True)
return ChatResponse(
success=False,
error=f"Failed to process chat request: {str(e)}"
)
if __name__ == "__main__":
import uvicorn
uvicorn.run(
"app:app",
host=os.getenv("HOST", "0.0.0.0"),
port=int(os.getenv("PORT", 8000)),
reload=os.getenv("ENVIRONMENT", "production") == "development",
log_level=os.getenv("LOG_LEVEL", "info").lower()
)