File size: 10,591 Bytes
1719e8e
578da72
1719e8e
 
 
 
 
578da72
 
 
 
 
 
 
1719e8e
 
 
 
578da72
1719e8e
 
 
 
 
 
f252547
 
1719e8e
578da72
f252547
1719e8e
f252547
 
 
 
 
 
 
 
 
 
 
 
 
 
1719e8e
 
 
f252547
1719e8e
578da72
 
1719e8e
f252547
 
 
 
 
 
1719e8e
f252547
 
 
 
 
 
 
1719e8e
 
578da72
 
 
 
 
1719e8e
 
 
 
 
 
 
 
f252547
 
 
 
 
 
578da72
 
1719e8e
f252547
 
578da72
f252547
 
 
 
 
1719e8e
f252547
 
1719e8e
f252547
 
 
 
 
 
 
 
 
 
 
 
1719e8e
578da72
 
1719e8e
 
 
 
 
 
 
 
 
578da72
1719e8e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
578da72
1719e8e
 
 
 
 
 
 
 
 
 
 
 
578da72
 
1719e8e
578da72
 
1719e8e
 
 
 
 
 
 
 
 
578da72
1719e8e
 
 
 
 
 
 
578da72
1719e8e
 
 
 
 
578da72
1719e8e
578da72
 
 
1719e8e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
from fastapi import APIRouter, Request, HTTPException, Depends
from app.core.session_manager import get_session_manager
from app.api.utils import get_or_create_session_for_request_async
from app.core.auth import get_current_active_user
from app.models.user import User
from pydantic import BaseModel
from typing import Optional
import logging

logger = logging.getLogger(__name__)

router = APIRouter()
session_manager = get_session_manager()

class ResetSessionRequest(BaseModel):
    chat_session_id: Optional[str] = None
    force_new: bool = False

@router.get("/context")
async def get_context(
    request: Request,
    chat_session_id: Optional[str] = None,
    current_user: User = Depends(get_current_active_user)
):
    """
    Get context for current session - ENHANCED with document access fix
    Now properly handles different chat sessions and ensures document access
    """
    try:
        # Determine which session to get context for with consistent session ID format
        if chat_session_id:
            # Getting context for a specific chat session - use consistent format
            session_id = f"chat_{chat_session_id}"
            logger.info(f"Getting context for specific chat session: {session_id}")
            
            # Ensure session is loaded in memory
            if session_id not in session_manager.sessions:
                logger.info(f"Chat session {session_id} not in memory, loading from database")
                loaded_session_id = await get_or_create_session_for_request_async(
                    request,
                    chat_session_id=chat_session_id,
                    user_id=str(current_user.id)
                )
                session_id = loaded_session_id
                logger.info(f"Loaded session ID: {session_id}")
        else:
            # Getting context for current session
            session_id = await get_or_create_session_for_request_async(request)
            logger.info(f"Getting context for current session: {session_id}")
        
        session = session_manager.get_session(session_id)
        rag_stats = session.get_rag_stats()
        
        #  Enhanced logging for document access debugging
        logger.info(f"Retrieved context for session {session_id}:")
        logger.info(f"  - Messages: {len(session.messages)}")
        logger.info(f"  - Documents: {rag_stats.get('total_documents', 0)}")
        logger.info(f"  - Chunks: {rag_stats.get('total_chunks', 0)}")
        logger.info(f"  - Uploaded files: {len(session.uploaded_files)}")
        
        # Log document details if available
        if rag_stats.get('documents'):
            for doc in rag_stats['documents']:
                logger.info(f"  - Available document: {doc.get('filename', 'unknown')} ({doc.get('chunks', 0)} chunks)")
        
        # Include session debugging info in response
        context_response = {
            "session_id": session_id,
            "chat_session_id": chat_session_id,
            "messages": session.messages,
            "rag_info": {
                "total_documents": rag_stats.get("total_documents", 0),
                "total_chunks": rag_stats.get("total_chunks", 0),
                "documents": rag_stats.get("documents", [])
            },
            "context_stats": {
                "message_count": len(session.messages),
                "user_messages": len([m for m in session.messages if m.get('role') == 'user']),
                "uploaded_files": session.uploaded_files,
                "total_upload_size": session.total_upload_size,
                "created_at": session.created_at.isoformat(),
                "last_accessed": session.last_accessed.isoformat()
            },
            # Add debugging info
            "debug_info": {
                "session_format": "chat_session" if chat_session_id else "new_session",
                "session_in_memory": session_id in session_manager.sessions,
                "document_access_working": rag_stats.get("total_documents", 0) > 0
            }
        }
        
        return context_response
        
    except Exception as e:
        logger.error(f"Error getting context for session_id {session_id if 'session_id' in locals() else 'unknown'}: {str(e)}")
        logger.error(f"Chat session ID: {chat_session_id}")
        import traceback
        logger.error(f"Full traceback: {traceback.format_exc()}")
        
        return {
            "session_id": session_id if 'session_id' in locals() else None,
            "chat_session_id": chat_session_id,
            "messages": [], 
            "rag_info": {"total_documents": 0, "total_chunks": 0, "documents": []},
            "context_stats": {
                "message_count": 0,
                "user_messages": 0,
                "uploaded_files": [],
                "total_upload_size": 0
            },
            "error": str(e),
            "debug_info": {
                "error_occurred": True,
                "error_type": type(e).__name__
            }
        }

@router.post("/reset-session")
async def reset_session(
    reset_request: ResetSessionRequest,
    request: Request,
    current_user: User = Depends(get_current_active_user)
):
    """
    Reset session - ENHANCED
    Now properly handles different reset scenarios
    """
    try:
        if reset_request.force_new:
            # Force create a completely new session
            session_id = session_manager.create_session()
            session = session_manager.get_session(session_id)
            session.clear_all_data()
            
            logger.info(f"Force created new session: {session_id}")
            
            return {
                "status": "reset", 
                "message": "New session created with fresh context",
                "session_id": session_id,
                "chat_session_id": None
            }
        
        elif reset_request.chat_session_id:
            # Reset a specific chat session context
            session_id = f"chat_{reset_request.chat_session_id}"
            
            if session_id in session_manager.sessions:
                success = session_manager.reset_session_completely(session_id)
                message = "Chat session context reset successfully" if success else "Failed to reset chat session context"
            else:
                # Create fresh context for this chat
                session = session_manager.get_session(session_id)
                session.clear_all_data()
                success = True
                message = "Fresh context created for chat session"
            
            logger.info(f"Reset chat session {reset_request.chat_session_id}, memory session: {session_id}")
            
            return {
                "status": "reset" if success else "error",
                "message": message,
                "session_id": session_id,
                "chat_session_id": reset_request.chat_session_id
            }
        
        else:
            # Reset current session
            session_id = await get_or_create_session_for_request_async(request)
            success = session_manager.reset_session_completely(session_id)
            
            logger.info(f"Reset current session: {session_id}")
            
            return {
                "status": "reset" if success else "error",
                "message": "Current session reset successfully" if success else "Failed to reset current session",
                "session_id": session_id
            }
            
    except Exception as e:
        logger.error(f"Error resetting session: {e}")
        return {"status": "error", "message": f"Failed to reset session: {str(e)}"}

@router.get("/session-stats")
async def get_session_stats(
    request: Request,
    chat_session_id: Optional[str] = None,
    current_user: User = Depends(get_current_active_user)
):
    """
    Get session statistics - ENHANCED
    Now provides detailed stats for different session types
    """
    try:
        if chat_session_id:
            # Stats for specific chat session
            session_id = f"chat_{chat_session_id}"
        else:
            # Stats for current session
            session_id = await get_or_create_session_for_request_async(request)
        
        stats = session_manager.get_session_stats(session_id)
        
        # Add additional context
        stats["session_type"] = "chat_session" if chat_session_id else "current_session"
        stats["chat_session_id"] = chat_session_id
        
        return stats
        
    except Exception as e:
        logger.error(f"Error getting session stats: {str(e)}")
        return {"error": str(e)}

@router.get("/active-sessions")
async def get_active_sessions(current_user: User = Depends(get_current_active_user)):
    """
    Get all active sessions for debugging
    """
    try:
        active_count = session_manager.get_active_session_count()
        
        # Get overview of sessions (don't return full content for privacy)
        session_overview = {}
        for session_id, session in session_manager.sessions.items():
            session_overview[session_id] = {
                "message_count": len(session.messages),
                "uploaded_files": len(session.uploaded_files),
                "created_at": session.created_at.isoformat(),
                "last_accessed": session.last_accessed.isoformat(),
                "is_chat_session": session_id.startswith("chat_")
            }
        
        return {
            "active_session_count": active_count,
            "sessions": session_overview
        }
        
    except Exception as e:
        logger.error(f"Error getting active sessions: {str(e)}")
        return {"error": str(e)}

@router.post("/cleanup-sessions")
async def cleanup_expired_sessions(current_user: User = Depends(get_current_active_user)):
    """
    Manually trigger session cleanup
    """
    try:
        initial_count = session_manager.get_active_session_count()
        
        # Force cleanup
        session_manager._cleanup_expired_sessions()
        
        final_count = session_manager.get_active_session_count()
        cleaned_count = initial_count - final_count
        
        return {
            "status": "success",
            "message": f"Cleaned up {cleaned_count} expired sessions",
            "sessions_before": initial_count,
            "sessions_after": final_count
        }
        
    except Exception as e:
        logger.error(f"Error during session cleanup: {str(e)}")
        return {"status": "error", "message": str(e)}