Girish Jeswani commited on
Commit
a85d17b
·
1 Parent(s): 74b0b4e

fix document upload to new chat

Browse files
multi_llm_chatbot_backend/app/api/routes/chat.py CHANGED
@@ -153,9 +153,13 @@ async def create_new_chat(
153
  raise HTTPException(status_code=500, detail="Failed to create new chat")
154
 
155
  @router.post("/chat-sequential")
156
- async def chat_sequential_enhanced(message: ChatMessage, request: Request):
 
 
 
 
157
  """
158
- Enhanced sequential chat with proper session management and document access
159
  """
160
  try:
161
  # Ensure consistent session ID for document retrieval
@@ -164,59 +168,36 @@ async def chat_sequential_enhanced(message: ChatMessage, request: Request):
164
  session_id = f"chat_{message.chat_session_id}"
165
  logger.info(f"Using chat session: {session_id}")
166
 
167
- # Ensure session exists in memory (load if needed)
168
  if session_id not in session_manager.sessions:
169
  logger.warning(f"Chat session {message.chat_session_id} not in memory, loading now")
170
- # Load the session using the async utility function
171
- memory_session_id = await get_or_create_session_for_request_async(
172
- request,
 
173
  chat_session_id=message.chat_session_id,
174
- user_id="system" # This might need proper user ID from auth
175
  )
176
- session_id = memory_session_id
 
 
 
177
  else:
178
- # This is a new chat or no specific chat session
179
- session_id = await get_or_create_session_for_request_async(
180
- request,
181
- session_id_override=message.session_id
182
- )
183
- logger.info(f"Using new/existing session: {session_id}")
184
-
185
- # Get the session
186
  session = session_manager.get_session(session_id)
187
 
188
- # Debug document access
189
  rag_stats = session.get_rag_stats()
190
  logger.info(f"Session {session_id} has {rag_stats.get('total_documents', 0)} documents available")
191
 
192
- # Debug logging
193
- user_messages_count = len([msg for msg in session.messages if msg.get('role') == 'user'])
194
- logger.info(f"Session {session_id} has {user_messages_count} user messages before processing")
195
- logger.info(f"Input to analyze: '{message.user_input}'")
196
-
197
- # Check if this needs clarification BEFORE adding the message
198
- needs_clarification = chat_orchestrator._needs_clarification(session, message.user_input)
199
-
200
- logger.info(f"Clarification needed: {needs_clarification}")
201
-
202
- # Add user message to session for context (after clarification check)
203
  session.append_message("user", message.user_input)
204
 
205
- if needs_clarification:
206
- # Generate clarification question
207
- clarification_question = await chat_orchestrator._generate_clarification_question(session)
208
-
209
- logger.info(f"Clarification needed for session {session_id}: '{message.user_input}'")
210
-
211
- return {
212
- "type": "clarification_needed",
213
- "message": clarification_question,
214
- "suggestions": chat_orchestrator._get_clarification_suggestions(),
215
- "session_id": session_id,
216
- "chat_session_id": message.chat_session_id # Include for frontend
217
- }
218
-
219
- # No clarification needed - proceed with intelligent persona ordering
220
  top_personas = await chat_orchestrator.get_top_personas(
221
  session_id=session_id,
222
  k=3 # Limit to top 3 most relevant personas
@@ -224,15 +205,14 @@ async def chat_sequential_enhanced(message: ChatMessage, request: Request):
224
 
225
  logger.info(f"Intelligent persona order for session {session_id}: {top_personas}")
226
 
227
- # Generate responses from ONLY the top 3 personas
228
  responses = []
229
 
230
  for persona_id in top_personas:
231
  try:
232
- # Pass the consistent session_id for document retrieval
233
  logger.info(f"Generating response for {persona_id} with session {session_id}")
234
 
235
- # Generate response from this persona
236
  persona_result = await chat_orchestrator.chat_with_persona(
237
  user_input=message.user_input,
238
  persona_id=persona_id,
@@ -240,19 +220,52 @@ async def chat_sequential_enhanced(message: ChatMessage, request: Request):
240
  response_length=message.response_length or "medium"
241
  )
242
 
243
- if "persona_name" in persona_result and "response" in persona_result:
244
- responses.append({
245
- "persona": persona_result["persona_name"],
246
- "persona_id": persona_result["persona_id"],
247
- "response": persona_result["response"],
248
- "used_documents": persona_result.get("used_documents", False),
249
- "document_chunks_used": persona_result.get("document_chunks_used", 0)
250
- })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
251
  else:
 
252
  responses.append({
253
- "persona": chat_orchestrator.personas[persona_id].name,
254
  "persona_id": persona_id,
255
- "response": "I'm having trouble processing your question right now. Please try again.",
 
256
  "used_documents": False,
257
  "document_chunks_used": 0
258
  })
@@ -260,39 +273,30 @@ async def chat_sequential_enhanced(message: ChatMessage, request: Request):
260
  except Exception as e:
261
  logger.error(f"Error generating response for persona {persona_id}: {str(e)}")
262
  responses.append({
263
- "persona": chat_orchestrator.personas[persona_id].name,
264
  "persona_id": persona_id,
265
- "response": "I encountered an error while processing your question. Please try again.",
 
266
  "used_documents": False,
267
  "document_chunks_used": 0
268
  })
269
 
270
- # Include document access info in response
271
  return {
272
- "type": "sequential_responses",
273
  "responses": responses,
274
- "session_id": session_id,
275
- "chat_session_id": message.chat_session_id,
276
- "document_info": {
277
- "total_documents": rag_stats.get('total_documents', 0),
278
- "total_chunks": rag_stats.get('total_chunks', 0),
279
- "documents": rag_stats.get('documents', [])
 
280
  }
281
  }
282
-
283
  except Exception as e:
284
- logger.error(f"Error in enhanced sequential chat: {str(e)}")
285
- return {
286
- "type": "error",
287
- "responses": [{
288
- "persona": "System",
289
- "response": "I'm having trouble processing your request. Could you please try again?",
290
- "used_documents": False,
291
- "document_chunks_used": 0
292
- }],
293
- "session_id": session_id if 'session_id' in locals() else None,
294
- "chat_session_id": message.chat_session_id if hasattr(message, 'chat_session_id') else None
295
- }
296
 
297
 
298
  @router.post("/chat/{persona_id}")
 
153
  raise HTTPException(status_code=500, detail="Failed to create new chat")
154
 
155
  @router.post("/chat-sequential")
156
+ async def chat_sequential_enhanced(
157
+ message: ChatMessage,
158
+ request: Request,
159
+ current_user: User = Depends(get_current_active_user)
160
+ ):
161
  """
162
+ Enhanced sequential chat with proper session management, document access, and intelligent persona ordering
163
  """
164
  try:
165
  # Ensure consistent session ID for document retrieval
 
168
  session_id = f"chat_{message.chat_session_id}"
169
  logger.info(f"Using chat session: {session_id}")
170
 
171
+ # FIXED: Ensure session exists in memory (load if needed)
172
  if session_id not in session_manager.sessions:
173
  logger.warning(f"Chat session {message.chat_session_id} not in memory, loading now")
174
+
175
+ # FIXED: Pass the user_id parameter to properly load existing session
176
+ loaded_session_id = await get_or_create_session_for_request_async(
177
+ request,
178
  chat_session_id=message.chat_session_id,
179
+ user_id=str(current_user.id)
180
  )
181
+
182
+ # Use the loaded session ID
183
+ session_id = loaded_session_id
184
+ logger.info(f"Loaded session from database: {session_id}")
185
  else:
186
+ # No specific chat session, create/use ephemeral session
187
+ session_id = await get_or_create_session_for_request_async(request)
188
+ logger.info(f"Using ephemeral session: {session_id}")
189
+
190
+ # Get session from memory
 
 
 
191
  session = session_manager.get_session(session_id)
192
 
193
+ # Log session debugging info
194
  rag_stats = session.get_rag_stats()
195
  logger.info(f"Session {session_id} has {rag_stats.get('total_documents', 0)} documents available")
196
 
197
+ # Add user message to session (needed for persona ranking)
 
 
 
 
 
 
 
 
 
 
198
  session.append_message("user", message.user_input)
199
 
200
+ # RESTORED: Get intelligently ordered personas based on context
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  top_personas = await chat_orchestrator.get_top_personas(
202
  session_id=session_id,
203
  k=3 # Limit to top 3 most relevant personas
 
205
 
206
  logger.info(f"Intelligent persona order for session {session_id}: {top_personas}")
207
 
208
+ # Generate responses from ONLY the top personas
209
  responses = []
210
 
211
  for persona_id in top_personas:
212
  try:
 
213
  logger.info(f"Generating response for {persona_id} with session {session_id}")
214
 
215
+ # Generate response from this specific persona
216
  persona_result = await chat_orchestrator.chat_with_persona(
217
  user_input=message.user_input,
218
  persona_id=persona_id,
 
220
  response_length=message.response_length or "medium"
221
  )
222
 
223
+ # FIXED: Safe response processing with proper error handling
224
+ if isinstance(persona_result, dict):
225
+ # Handle different response formats
226
+ if "persona_name" in persona_result and "response" in persona_result:
227
+ responses.append({
228
+ "persona_id": persona_result["persona_id"],
229
+ "persona_name": persona_result["persona_name"],
230
+ "content": persona_result["response"],
231
+ "used_documents": persona_result.get("used_documents", False),
232
+ "document_chunks_used": persona_result.get("document_chunks_used", 0)
233
+ })
234
+ elif persona_result.get("type") == "single_persona_response" and "persona" in persona_result:
235
+ persona_data = persona_result["persona"]
236
+ responses.append({
237
+ "persona_id": persona_data["persona_id"],
238
+ "persona_name": persona_data["persona_name"],
239
+ "content": persona_data["response"],
240
+ "used_documents": persona_data.get("used_documents", False),
241
+ "document_chunks_used": persona_data.get("document_chunks_used", 0)
242
+ })
243
+ elif "error" in persona_result:
244
+ # Handle error responses
245
+ responses.append({
246
+ "persona_id": persona_id,
247
+ "persona_name": chat_orchestrator.personas[persona_id].name,
248
+ "content": persona_result["response"],
249
+ "used_documents": False,
250
+ "document_chunks_used": 0
251
+ })
252
+ else:
253
+ # Generic dict response
254
+ content = persona_result.get("response") or persona_result.get("content", "")
255
+ if content.strip():
256
+ responses.append({
257
+ "persona_id": persona_id,
258
+ "persona_name": chat_orchestrator.personas[persona_id].name,
259
+ "content": content,
260
+ "used_documents": persona_result.get("used_documents", False),
261
+ "document_chunks_used": persona_result.get("document_chunks_used", 0)
262
+ })
263
  else:
264
+ # Fallback for non-dict responses
265
  responses.append({
 
266
  "persona_id": persona_id,
267
+ "persona_name": chat_orchestrator.personas[persona_id].name,
268
+ "content": "I'm having trouble processing your question right now. Please try again.",
269
  "used_documents": False,
270
  "document_chunks_used": 0
271
  })
 
273
  except Exception as e:
274
  logger.error(f"Error generating response for persona {persona_id}: {str(e)}")
275
  responses.append({
 
276
  "persona_id": persona_id,
277
+ "persona_name": chat_orchestrator.personas[persona_id].name,
278
+ "content": "I encountered an error while processing your question. Please try again.",
279
  "used_documents": False,
280
  "document_chunks_used": 0
281
  })
282
 
 
283
  return {
 
284
  "responses": responses,
285
+ "session_debug": {
286
+ "session_id": session_id,
287
+ "documents_available": rag_stats.get('total_documents', 0),
288
+ "chunks_available": rag_stats.get('total_chunks', 0),
289
+ "valid_responses": len(responses),
290
+ "selected_personas": top_personas,
291
+ "total_personas_available": len(chat_orchestrator.personas)
292
  }
293
  }
294
+
295
  except Exception as e:
296
+ logger.error(f"Error in chat_sequential_enhanced: {e}")
297
+ import traceback
298
+ logger.error(f"Full traceback: {traceback.format_exc()}")
299
+ raise HTTPException(status_code=500, detail=f"Chat processing failed: {str(e)}")
 
 
 
 
 
 
 
 
300
 
301
 
302
  @router.post("/chat/{persona_id}")
multi_llm_chatbot_backend/app/api/routes/documents.py CHANGED
@@ -157,7 +157,8 @@ def convert_messages_for_export(messages):
157
  async def upload_document(
158
  file: UploadFile = File(...),
159
  request: Request = None,
160
- chat_session_id: str = Query(None, description="Chat session ID if uploading to specific chat")
 
161
  ):
162
  try:
163
  if chat_session_id:
@@ -166,9 +167,14 @@ async def upload_document(
166
  logger.info(f"Uploading document to specific chat session: {session_id}")
167
  else:
168
  # For new/temporary chats, use regular session management
169
- session_id = await get_or_create_session_for_request_async(request) # FIXED: Added await
170
  logger.info(f"Uploading document to new session: {session_id}")
171
 
 
 
 
 
 
172
  session = session_manager.get_session(session_id)
173
 
174
  MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB
@@ -193,7 +199,7 @@ async def upload_document(
193
  rag_result = rag_manager.add_document(
194
  content=content,
195
  filename=file.filename,
196
- session_id=session_id, # This now uses the consistent format
197
  file_type=file_type
198
  )
199
 
@@ -220,8 +226,9 @@ async def upload_document(
220
  "total_tokens": rag_result['total_tokens'],
221
  "file_type": file_type,
222
  "can_reference_by_name": True,
223
- "session_id": session_id, # Include session ID for debugging
224
- "chat_session_id": chat_session_id # Include original chat session ID
 
225
  }
226
 
227
  except HTTPException:
 
157
  async def upload_document(
158
  file: UploadFile = File(...),
159
  request: Request = None,
160
+ chat_session_id: str = Query(None, description="Chat session ID if uploading to specific chat"),
161
+ current_user: User = Depends(get_current_active_user) # ADDED: Require authentication
162
  ):
163
  try:
164
  if chat_session_id:
 
167
  logger.info(f"Uploading document to specific chat session: {session_id}")
168
  else:
169
  # For new/temporary chats, use regular session management
170
+ session_id = await get_or_create_session_for_request_async(request)
171
  logger.info(f"Uploading document to new session: {session_id}")
172
 
173
+ # Add debug logging to track session IDs
174
+ logger.info(f"Document upload - chat_session_id parameter: {chat_session_id}")
175
+ logger.info(f"Document upload - final session_id: {session_id}")
176
+ logger.info(f"Document upload - user_id: {current_user.id}")
177
+
178
  session = session_manager.get_session(session_id)
179
 
180
  MAX_FILE_SIZE = 10 * 1024 * 1024 # 10MB
 
199
  rag_result = rag_manager.add_document(
200
  content=content,
201
  filename=file.filename,
202
+ session_id=session_id,
203
  file_type=file_type
204
  )
205
 
 
226
  "total_tokens": rag_result['total_tokens'],
227
  "file_type": file_type,
228
  "can_reference_by_name": True,
229
+ "session_id": session_id,
230
+ "chat_session_id": chat_session_id,
231
+ "user_id": str(current_user.id) # ADDED: Include user ID for debugging
232
  }
233
 
234
  except HTTPException:
multi_llm_chatbot_backend/app/api/utils.py CHANGED
@@ -8,78 +8,94 @@ import logging
8
  logger = logging.getLogger(__name__)
9
  session_manager = get_session_manager()
10
 
11
- async def load_chat_session_into_context(chat_session_id: str, user_id: str) -> Optional[str]:
12
  """
13
- Load a MongoDB chat session into in-memory context
14
- Returns the in-memory session_id to use
15
  """
16
  try:
17
  db = get_database()
18
 
19
- # Get the chat session from MongoDB
 
 
 
 
 
20
  chat_session = await db.chat_sessions.find_one({
21
  "_id": ObjectId(chat_session_id),
22
- "user_id": user_id,
23
- "is_active": True
24
  })
25
 
26
  if not chat_session:
27
  logger.warning(f"Chat session {chat_session_id} not found for user {user_id}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
  return None
 
 
 
29
 
30
- # Create or get in-memory session with a unique ID based on chat session
31
  memory_session_id = f"chat_{chat_session_id}"
 
 
 
 
32
  memory_session = session_manager.get_session(memory_session_id)
33
 
34
- # Clear existing messages and load from MongoDB
35
- memory_session.clear_messages()
36
 
37
- # Load all messages from the chat session with proper format conversion
38
- messages = chat_session.get("messages", [])
39
- for message in messages:
40
- # Convert MongoDB message format to session manager format
41
- # MongoDB format: {type: 'user'/'advisor', content: '', advisorId: '', ...}
42
- # Session format: {role: '', content: '', timestamp: ''}
43
-
44
- msg_type = message.get("type", "user")
45
- content = message.get("content", "")
46
- timestamp = message.get("timestamp", "")
47
-
48
- # Map message types to roles for session manager
49
- if msg_type == "user":
50
- role = "user"
51
- elif msg_type == "advisor":
52
- role = "assistant"
53
- # For advisor messages, include advisor info in content if needed
54
- advisor_name = message.get("advisorName", "")
55
- if advisor_name:
56
- # Store advisor info as metadata that can be retrieved
57
- role = f"advisor_{message.get('advisorId', 'unknown')}"
58
- elif msg_type == "system":
59
- role = "system"
60
- elif msg_type == "error":
61
- role = "system"
62
- elif msg_type == "document_upload":
63
- role = "system"
64
- elif msg_type == "clarification":
65
- role = "system"
66
- else:
67
- role = "user" # Default fallback
68
-
69
- # Add the message to session with original structure preserved
70
- memory_session.append_message(role, content)
71
-
72
- # Store original message metadata for frontend reconstruction
73
- if not hasattr(memory_session, 'original_messages'):
74
- memory_session.original_messages = []
75
-
76
- memory_session.original_messages.append(message)
77
 
78
  logger.info(f"Loaded {len(messages)} messages into session {memory_session_id}")
79
  return memory_session_id
80
 
81
  except Exception as e:
82
  logger.error(f"Error loading chat session into context: {e}")
 
 
83
  return None
84
 
85
  async def get_or_create_session_for_request_async(
 
8
  logger = logging.getLogger(__name__)
9
  session_manager = get_session_manager()
10
 
11
+ async def load_chat_session_into_context(chat_session_id: str, user_id: str) -> str:
12
  """
13
+ Load a chat session from MongoDB into memory context - ENHANCED DEBUG VERSION
 
14
  """
15
  try:
16
  db = get_database()
17
 
18
+ # Add enhanced debugging
19
+ logger.info(f"=== LOADING CHAT SESSION DEBUG ===")
20
+ logger.info(f"Attempting to load chat_session_id: {chat_session_id}")
21
+ logger.info(f"For user_id: {user_id}")
22
+
23
+ # Try to find the session with enhanced debugging
24
  chat_session = await db.chat_sessions.find_one({
25
  "_id": ObjectId(chat_session_id),
26
+ "user_id": ObjectId(user_id),
27
+ "deleted_at": {"$exists": False}
28
  })
29
 
30
  if not chat_session:
31
  logger.warning(f"Chat session {chat_session_id} not found for user {user_id}")
32
+
33
+ # Debug: Check if session exists for any user
34
+ try:
35
+ session_exists = await db.chat_sessions.find_one({"_id": ObjectId(chat_session_id)})
36
+ if session_exists:
37
+ logger.warning(f"Session exists but for different user: {session_exists.get('user_id')}")
38
+ logger.warning(f"Expected user: {user_id}")
39
+ logger.warning(f"Session user: {session_exists.get('user_id')}")
40
+ logger.warning(f"User ID types - Expected: {type(user_id)}, Found: {type(session_exists.get('user_id'))}")
41
+ else:
42
+ logger.warning(f"Session {chat_session_id} does not exist in database at all")
43
+ except Exception as debug_error:
44
+ logger.error(f"Error during session debug: {debug_error}")
45
+
46
+ # Debug: List recent sessions for this user
47
+ try:
48
+ recent_sessions = await db.chat_sessions.find(
49
+ {"user_id": ObjectId(user_id), "deleted_at": {"$exists": False}}
50
+ ).limit(5).to_list(5)
51
+ logger.info(f"Recent sessions for user {user_id}: {[str(s['_id']) for s in recent_sessions]}")
52
+ except Exception as debug_error:
53
+ logger.error(f"Error listing recent sessions: {debug_error}")
54
+
55
  return None
56
+
57
+ logger.info(f"✅ Found chat session: {chat_session.get('title', 'Untitled')}")
58
+ logger.info(f"✅ Message count: {len(chat_session.get('messages', []))}")
59
 
60
+ # Create consistent memory session ID
61
  memory_session_id = f"chat_{chat_session_id}"
62
+ logger.info(f"✅ Creating memory session: {memory_session_id}")
63
+
64
+ # Get session manager and create memory session
65
+ session_manager = get_session_manager()
66
  memory_session = session_manager.get_session(memory_session_id)
67
 
68
+ # Clear any existing data
69
+ memory_session.clear_all_data()
70
 
71
+ # Load messages into memory session
72
+ messages = chat_session.get('messages', [])
73
+ for msg_data in messages:
74
+ try:
75
+ message = {
76
+ 'id': msg_data.get('id', 'unknown'),
77
+ 'role': 'user' if msg_data.get('type') == 'user' else 'assistant',
78
+ 'content': msg_data.get('content', ''),
79
+ 'timestamp': msg_data.get('timestamp', '')
80
+ }
81
+ memory_session.append_message(message['role'], message['content'])
82
+
83
+ # Store original message for export
84
+ if not hasattr(memory_session, 'original_messages'):
85
+ memory_session.original_messages = []
86
+
87
+ memory_session.original_messages.append(message)
88
+ except Exception as msg_error:
89
+ logger.error(f"Error loading message: {msg_error}")
90
+ continue
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
 
92
  logger.info(f"Loaded {len(messages)} messages into session {memory_session_id}")
93
  return memory_session_id
94
 
95
  except Exception as e:
96
  logger.error(f"Error loading chat session into context: {e}")
97
+ import traceback
98
+ logger.error(f"Full traceback: {traceback.format_exc()}")
99
  return None
100
 
101
  async def get_or_create_session_for_request_async(