m-ahmad-official commited on
Commit
52ab762
·
1 Parent(s): 4dd8465
Files changed (2) hide show
  1. agent.py +12 -7
  2. api.py +34 -19
agent.py CHANGED
@@ -41,16 +41,21 @@ if backend_parent not in sys.path:
41
 
42
  # Import backend modules (support both module and script execution)
43
  try:
44
- from .config import get_config
45
- from .retrieve import search as retrieve_search
46
- from .logging_config import setup_logging
47
  except ImportError as e:
48
  try:
49
- from backend.config import get_config
50
- from backend.retrieve import search as retrieve_search
51
- from backend.logging_config import setup_logging
52
  except ImportError as e2:
53
- raise ImportError(f"Failed to import backend modules: {e2}")
 
 
 
 
 
54
 
55
  # Import OpenAI Agents SDK (must be installed separately)
56
  try:
 
41
 
42
  # Import backend modules (support both module and script execution)
43
  try:
44
+ from config import get_config
45
+ from retrieve import search as retrieve_search
46
+ from logging_config import setup_logging
47
  except ImportError as e:
48
  try:
49
+ from .config import get_config
50
+ from .retrieve import search as retrieve_search
51
+ from .logging_config import setup_logging
52
  except ImportError as e2:
53
+ try:
54
+ from backend.config import get_config
55
+ from backend.retrieve import search as retrieve_search
56
+ from backend.logging_config import setup_logging
57
+ except ImportError as e3:
58
+ raise ImportError(f"Failed to import backend modules: {e3}")
59
 
60
  # Import OpenAI Agents SDK (must be installed separately)
61
  try:
api.py CHANGED
@@ -38,7 +38,7 @@ except ImportError as e:
38
  app = FastAPI(
39
  title="RAG Chatbot API",
40
  version="1.0.0",
41
- description="FastAPI wrapper for RAG Book Assistant"
42
  )
43
 
44
  # ============ CORS Configuration ============
@@ -62,7 +62,7 @@ app.add_middleware(
62
  class ChatRequest(BaseModel):
63
  question: str = Field(..., min_length=1, max_length=1000)
64
 
65
- @validator('question')
66
  def validate_question(cls, v):
67
  if not v or not v.strip():
68
  raise ValueError("Question cannot be empty")
@@ -91,10 +91,12 @@ class HealthStatus(BaseModel):
91
 
92
  # ============ Health Check ============
93
 
 
94
  def check_qdrant_health() -> str:
95
  try:
96
- from backend.config import get_config
97
  from qdrant_client import QdrantClient
 
98
  cfg = get_config()
99
  client = QdrantClient(url=cfg["qdrant_url"], api_key=cfg["qdrant_api_key"])
100
  client.get_collection(cfg["qdrant_collection"])
@@ -109,6 +111,7 @@ def check_openai_health() -> str:
109
  if not api_key:
110
  return "disconnected"
111
  import openai
 
112
  client = openai.OpenAI(api_key=api_key)
113
  client.models.list()
114
  return "connected"
@@ -120,17 +123,20 @@ def check_openai_health() -> str:
120
  async def health_check():
121
  qdrant = check_qdrant_health()
122
  openai = check_openai_health()
123
- status = "healthy" if qdrant == "connected" and openai == "connected" else "degraded"
 
 
124
  return HealthStatus(
125
  status=status,
126
  qdrant=qdrant,
127
  openai=openai,
128
- timestamp=datetime.utcnow().isoformat() + "Z"
129
  )
130
 
131
 
132
  # ============ Chat Endpoint ============
133
 
 
134
  @app.post("/chat")
135
  async def chat_endpoint(request: ChatRequest):
136
  request_id = str(uuid.uuid4())[:8]
@@ -140,10 +146,7 @@ async def chat_endpoint(request: ChatRequest):
140
  agent = get_agent()
141
 
142
  # Run agent with timeout (20s to accommodate full workflow)
143
- result = await asyncio.wait_for(
144
- Runner.run(agent, question),
145
- timeout=20.0
146
- )
147
 
148
  # Extract sources from tool call outputs
149
  sources = []
@@ -153,42 +156,54 @@ async def chat_endpoint(request: ChatRequest):
153
  output = item.output
154
  if isinstance(output, list):
155
  for chunk in output:
156
- sources.append(Source(
157
- url=chunk.get("url", ""),
158
- chunk_index=chunk.get("chunk_index", 0),
159
- text_snippet=chunk.get("text", "")[:200]
160
- ))
 
 
161
 
162
  # Get token usage
163
  tokens_used = 0
164
- if result.context_wrapper and hasattr(result.context_wrapper, 'usage'):
165
  tokens_used = result.context_wrapper.usage.total_tokens
166
 
167
  return ChatResponse(
168
  answer=result.final_output,
169
  sources=sources,
170
  tokens_used=tokens_used,
171
- agent_trace=f"{request_id}: completed"
172
  )
173
 
174
  except asyncio.TimeoutError:
175
  return JSONResponse(
176
  status_code=504,
177
- content={"error": "timeout", "message": "The chatbot is taking too long to respond. Please try a shorter question."}
 
 
 
178
  )
179
 
180
  except Exception as e:
181
  if "openai" in str(e).lower() or "rate limit" in str(e).lower():
182
  return JSONResponse(
183
  status_code=503,
184
- content={"error": "openai_failed", "message": "The AI service is currently unavailable. Please try again in a few minutes."}
 
 
 
185
  )
186
  return JSONResponse(
187
  status_code=500,
188
- content={"error": "internal_error", "message": "An unexpected error occurred. Please refresh the page and try again."}
 
 
 
189
  )
190
 
191
 
192
  if __name__ == "__main__":
193
  import uvicorn
 
194
  uvicorn.run(app, host="0.0.0.0", port=8000)
 
38
  app = FastAPI(
39
  title="RAG Chatbot API",
40
  version="1.0.0",
41
+ description="FastAPI wrapper for RAG Book Assistant",
42
  )
43
 
44
  # ============ CORS Configuration ============
 
62
  class ChatRequest(BaseModel):
63
  question: str = Field(..., min_length=1, max_length=1000)
64
 
65
+ @validator("question")
66
  def validate_question(cls, v):
67
  if not v or not v.strip():
68
  raise ValueError("Question cannot be empty")
 
91
 
92
  # ============ Health Check ============
93
 
94
+
95
  def check_qdrant_health() -> str:
96
  try:
97
+ from config import get_config
98
  from qdrant_client import QdrantClient
99
+
100
  cfg = get_config()
101
  client = QdrantClient(url=cfg["qdrant_url"], api_key=cfg["qdrant_api_key"])
102
  client.get_collection(cfg["qdrant_collection"])
 
111
  if not api_key:
112
  return "disconnected"
113
  import openai
114
+
115
  client = openai.OpenAI(api_key=api_key)
116
  client.models.list()
117
  return "connected"
 
123
  async def health_check():
124
  qdrant = check_qdrant_health()
125
  openai = check_openai_health()
126
+ status = (
127
+ "healthy" if qdrant == "connected" and openai == "connected" else "degraded"
128
+ )
129
  return HealthStatus(
130
  status=status,
131
  qdrant=qdrant,
132
  openai=openai,
133
+ timestamp=datetime.utcnow().isoformat() + "Z",
134
  )
135
 
136
 
137
  # ============ Chat Endpoint ============
138
 
139
+
140
  @app.post("/chat")
141
  async def chat_endpoint(request: ChatRequest):
142
  request_id = str(uuid.uuid4())[:8]
 
146
  agent = get_agent()
147
 
148
  # Run agent with timeout (20s to accommodate full workflow)
149
+ result = await asyncio.wait_for(Runner.run(agent, question), timeout=20.0)
 
 
 
150
 
151
  # Extract sources from tool call outputs
152
  sources = []
 
156
  output = item.output
157
  if isinstance(output, list):
158
  for chunk in output:
159
+ sources.append(
160
+ Source(
161
+ url=chunk.get("url", ""),
162
+ chunk_index=chunk.get("chunk_index", 0),
163
+ text_snippet=chunk.get("text", "")[:200],
164
+ )
165
+ )
166
 
167
  # Get token usage
168
  tokens_used = 0
169
+ if result.context_wrapper and hasattr(result.context_wrapper, "usage"):
170
  tokens_used = result.context_wrapper.usage.total_tokens
171
 
172
  return ChatResponse(
173
  answer=result.final_output,
174
  sources=sources,
175
  tokens_used=tokens_used,
176
+ agent_trace=f"{request_id}: completed",
177
  )
178
 
179
  except asyncio.TimeoutError:
180
  return JSONResponse(
181
  status_code=504,
182
+ content={
183
+ "error": "timeout",
184
+ "message": "The chatbot is taking too long to respond. Please try a shorter question.",
185
+ },
186
  )
187
 
188
  except Exception as e:
189
  if "openai" in str(e).lower() or "rate limit" in str(e).lower():
190
  return JSONResponse(
191
  status_code=503,
192
+ content={
193
+ "error": "openai_failed",
194
+ "message": "The AI service is currently unavailable. Please try again in a few minutes.",
195
+ },
196
  )
197
  return JSONResponse(
198
  status_code=500,
199
+ content={
200
+ "error": "internal_error",
201
+ "message": "An unexpected error occurred. Please refresh the page and try again.",
202
+ },
203
  )
204
 
205
 
206
  if __name__ == "__main__":
207
  import uvicorn
208
+
209
  uvicorn.run(app, host="0.0.0.0", port=8000)