LiamKhoaLe commited on
Commit
e117df5
·
1 Parent(s): 55f463c

Refactor new namer agent

Browse files
helpers/models.py CHANGED
@@ -43,6 +43,8 @@ class ChatAnswerResponse(BaseModel):
43
  answer: str
44
  sources: List[Dict[str, Any]]
45
  relevant_files: Optional[List[str]] = None
 
 
46
 
47
  class HealthResponse(BaseModel):
48
  ok: bool
 
43
  answer: str
44
  sources: List[Dict[str, Any]]
45
  relevant_files: Optional[List[str]] = None
46
+ session_name: Optional[str] = None
47
+ session_id: Optional[str] = None
48
 
49
  class HealthResponse(BaseModel):
50
  ok: bool
helpers/namer.py ADDED
@@ -0,0 +1,152 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Session Auto-Naming Module
3
+
4
+ This module handles automatic naming of chat sessions based on the first user query.
5
+ Uses NVIDIA_SMALL API to generate concise, descriptive session names.
6
+ """
7
+
8
+ import asyncio
9
+ from typing import Optional
10
+ from utils.logger import get_logger
11
+
12
+ logger = get_logger("SESSION_NAMER", __name__)
13
+
14
+
15
+ async def auto_name_session(
16
+ user_id: str,
17
+ project_id: str,
18
+ session_id: str,
19
+ first_query: str,
20
+ nvidia_rotator=None,
21
+ rag_db=None
22
+ ) -> Optional[str]:
23
+ """
24
+ Automatically name a session based on the first query using NVIDIA_SMALL API.
25
+
26
+ Args:
27
+ user_id: User identifier
28
+ project_id: Project identifier
29
+ session_id: Session identifier
30
+ first_query: The first user query in the session
31
+ nvidia_rotator: NVIDIA API rotator instance
32
+ rag_db: Database connection
33
+
34
+ Returns:
35
+ Generated session name or None if failed
36
+ """
37
+ try:
38
+ if not nvidia_rotator:
39
+ logger.warning("[NAMER] NVIDIA rotator not available")
40
+ return None
41
+
42
+ # Use NVIDIA_SMALL to generate a 2-3 word session name
43
+ sys_prompt = """You are an expert at creating concise, descriptive session names.
44
+
45
+ Given a user's first query in a chat session, create a 2-3 word session name that captures the main topic or intent.
46
+
47
+ Rules:
48
+ - Use 2-3 words maximum
49
+ - Be descriptive but concise
50
+ - Use title case (capitalize first letter of each word)
51
+ - Focus on the main topic or question type
52
+ - Avoid generic terms like "Question" or "Chat"
53
+
54
+ Examples:
55
+ - "Machine Learning Basics" for "What is machine learning?"
56
+ - "Python Functions" for "How do I create functions in Python?"
57
+ - "Data Analysis" for "Can you help me analyze this dataset?"
58
+
59
+ Return only the session name, nothing else."""
60
+
61
+ user_prompt = f"First query: {first_query}\n\nCreate a 2-3 word session name:"
62
+
63
+ try:
64
+ from utils.api.router import generate_answer_with_model
65
+ selection = {"provider": "nvidia", "model": "meta/llama-3.1-8b-instruct"}
66
+
67
+ response = await generate_answer_with_model(
68
+ selection=selection,
69
+ system_prompt=sys_prompt,
70
+ user_prompt=user_prompt,
71
+ gemini_rotator=None,
72
+ nvidia_rotator=nvidia_rotator
73
+ )
74
+
75
+ # Clean up the response
76
+ session_name = response.strip()
77
+ # Remove quotes if present
78
+ if session_name.startswith('"') and session_name.endswith('"'):
79
+ session_name = session_name[1:-1]
80
+ if session_name.startswith("'") and session_name.endswith("'"):
81
+ session_name = session_name[1:-1]
82
+
83
+ # Truncate if too long (safety measure)
84
+ if len(session_name) > 50:
85
+ session_name = session_name[:47] + "..."
86
+
87
+ # Update the session with the auto-generated name in database
88
+ if rag_db:
89
+ result = rag_db["chat_sessions"].update_many(
90
+ {"user_id": user_id, "project_id": project_id, "session_id": session_id},
91
+ {"$set": {"session_name": session_name, "is_auto_named": True}}
92
+ )
93
+
94
+ if result.modified_count > 0:
95
+ logger.info(f"[NAMER] Auto-named session '{session_id}' to '{session_name}'")
96
+ return session_name
97
+ else:
98
+ logger.warning(f"[NAMER] Session not found for auto-naming: {session_id}")
99
+ return None
100
+ else:
101
+ logger.warning("[NAMER] Database connection not provided")
102
+ return session_name
103
+
104
+ except Exception as e:
105
+ logger.warning(f"[NAMER] Auto-naming failed: {e}")
106
+ return None
107
+
108
+ except Exception as e:
109
+ logger.error(f"[NAMER] Failed to auto-name session: {e}")
110
+ return None
111
+
112
+
113
+ async def auto_name_session_immediate(
114
+ user_id: str,
115
+ project_id: str,
116
+ session_id: str,
117
+ first_query: str,
118
+ nvidia_rotator=None,
119
+ rag_db=None
120
+ ) -> Optional[str]:
121
+ """
122
+ Immediately auto-name a session and return the name for UI update.
123
+ This function is designed to be called synchronously during chat processing.
124
+
125
+ Args:
126
+ user_id: User identifier
127
+ project_id: Project identifier
128
+ session_id: Session identifier
129
+ first_query: The first user query in the session
130
+ nvidia_rotator: NVIDIA API rotator instance
131
+ rag_db: Database connection
132
+
133
+ Returns:
134
+ Generated session name or None if failed
135
+ """
136
+ try:
137
+ # Run auto-naming in a separate task to avoid blocking
138
+ task = asyncio.create_task(
139
+ auto_name_session(user_id, project_id, session_id, first_query, nvidia_rotator, rag_db)
140
+ )
141
+
142
+ # Wait for completion with a timeout
143
+ try:
144
+ session_name = await asyncio.wait_for(task, timeout=10.0)
145
+ return session_name
146
+ except asyncio.TimeoutError:
147
+ logger.warning(f"[NAMER] Auto-naming timed out for session {session_id}")
148
+ return None
149
+
150
+ except Exception as e:
151
+ logger.error(f"[NAMER] Immediate auto-naming failed: {e}")
152
+ return None
routes/chats.py CHANGED
@@ -316,6 +316,7 @@ async def chat(
316
 
317
  try:
318
  # Check if this is the first message in the session for auto-naming
 
319
  if session_id:
320
  existing_messages = rag.db["chat_sessions"].count_documents({
321
  "user_id": user_id,
@@ -323,7 +324,7 @@ async def chat(
323
  "session_id": session_id
324
  })
325
 
326
- # If this is the first user message, create session and trigger auto-naming
327
  if existing_messages == 0:
328
  # Create session record first
329
  session_data = {
@@ -331,20 +332,34 @@ async def chat(
331
  "project_id": project_id,
332
  "session_id": session_id,
333
  "session_name": "New Chat",
334
- "is_auto_named": True,
335
  "created_at": datetime.now(timezone.utc),
336
  "timestamp": time.time()
337
  }
338
  rag.db["chat_sessions"].insert_one(session_data)
339
 
340
- # Now trigger auto-naming
341
  try:
342
- await _auto_name_session(user_id, project_id, session_id, question)
343
- logger.info(f"[CHAT] Auto-named session {session_id}")
 
 
 
 
 
 
344
  except Exception as e:
345
  logger.warning(f"[CHAT] Auto-naming failed: {e}")
346
 
347
- return await asyncio.wait_for(_chat_impl(user_id, project_id, question, k, use_web=use_web, max_web=max_web, session_id=session_id), timeout=120.0)
 
 
 
 
 
 
 
 
348
  except asyncio.TimeoutError:
349
  logger.error("[CHAT] Chat request timed out after 120 seconds")
350
  update_chat_status(session_id, "error", "Request timed out", 0)
@@ -830,64 +845,3 @@ async def chat_with_search(
830
  return ChatAnswerResponse(answer=answer, sources=merged_sources, relevant_files=merged_files)
831
 
832
 
833
- async def _auto_name_session(user_id: str, project_id: str, session_id: str, first_query: str):
834
- """Helper function to auto-name a session based on the first query"""
835
- try:
836
- if not nvidia_rotator:
837
- return
838
-
839
- # Use NVIDIA_SMALL to generate a 2-3 word session name
840
- sys_prompt = """You are an expert at creating concise, descriptive session names.
841
-
842
- Given a user's first query in a chat session, create a 2-3 word session name that captures the main topic or intent.
843
-
844
- Rules:
845
- - Use 2-3 words maximum
846
- - Be descriptive but concise
847
- - Use title case (capitalize first letter of each word)
848
- - Focus on the main topic or question type
849
- - Avoid generic terms like "Question" or "Chat"
850
-
851
- Examples:
852
- - "Machine Learning Basics" for "What is machine learning?"
853
- - "Python Functions" for "How do I create functions in Python?"
854
- - "Data Analysis" for "Can you help me analyze this dataset?"
855
-
856
- Return only the session name, nothing else."""
857
-
858
- user_prompt = f"First query: {first_query}\n\nCreate a 2-3 word session name:"
859
-
860
- from utils.api.router import generate_answer_with_model
861
- selection = {"provider": "nvidia", "model": "meta/llama-3.1-8b-instruct"}
862
-
863
- response = await generate_answer_with_model(
864
- selection=selection,
865
- system_prompt=sys_prompt,
866
- user_prompt=user_prompt,
867
- gemini_rotator=None,
868
- nvidia_rotator=nvidia_rotator
869
- )
870
-
871
- # Clean up the response
872
- session_name = response.strip()
873
- # Remove quotes if present
874
- if session_name.startswith('"') and session_name.endswith('"'):
875
- session_name = session_name[1:-1]
876
- if session_name.startswith("'") and session_name.endswith("'"):
877
- session_name = session_name[1:-1]
878
-
879
- # Truncate if too long (safety measure)
880
- if len(session_name) > 50:
881
- session_name = session_name[:47] + "..."
882
-
883
- # Update the session with the auto-generated name
884
- rag.db["chat_sessions"].update_many(
885
- {"user_id": user_id, "project_id": project_id, "session_id": session_id},
886
- {"$set": {"session_name": session_name, "is_auto_named": True}}
887
- )
888
-
889
- logger.info(f"[CHAT] Auto-named session '{session_id}' to '{session_name}'")
890
-
891
- except Exception as e:
892
- logger.warning(f"[CHAT] Auto-naming failed: {e}")
893
- # Don't raise the exception to avoid breaking the chat flow
 
316
 
317
  try:
318
  # Check if this is the first message in the session for auto-naming
319
+ session_name = None
320
  if session_id:
321
  existing_messages = rag.db["chat_sessions"].count_documents({
322
  "user_id": user_id,
 
324
  "session_id": session_id
325
  })
326
 
327
+ # If this is the first user message, create session and trigger immediate auto-naming
328
  if existing_messages == 0:
329
  # Create session record first
330
  session_data = {
 
332
  "project_id": project_id,
333
  "session_id": session_id,
334
  "session_name": "New Chat",
335
+ "is_auto_named": False, # Will be updated by auto-naming
336
  "created_at": datetime.now(timezone.utc),
337
  "timestamp": time.time()
338
  }
339
  rag.db["chat_sessions"].insert_one(session_data)
340
 
341
+ # Trigger immediate auto-naming
342
  try:
343
+ from helpers.namer import auto_name_session_immediate
344
+ session_name = await auto_name_session_immediate(
345
+ user_id, project_id, session_id, question, nvidia_rotator, rag.db
346
+ )
347
+ if session_name:
348
+ logger.info(f"[CHAT] Auto-named session {session_id} to '{session_name}'")
349
+ else:
350
+ logger.warning(f"[CHAT] Auto-naming failed for session {session_id}")
351
  except Exception as e:
352
  logger.warning(f"[CHAT] Auto-naming failed: {e}")
353
 
354
+ # Get the chat response
355
+ chat_response = await asyncio.wait_for(_chat_impl(user_id, project_id, question, k, use_web=use_web, max_web=max_web, session_id=session_id), timeout=120.0)
356
+
357
+ # Add session information to the response if auto-naming occurred
358
+ if session_name:
359
+ chat_response.session_name = session_name
360
+ chat_response.session_id = session_id
361
+
362
+ return chat_response
363
  except asyncio.TimeoutError:
364
  logger.error("[CHAT] Chat request timed out after 120 seconds")
365
  update_chat_status(session_id, "error", "Request timed out", 0)
 
845
  return ChatAnswerResponse(answer=answer, sources=merged_sources, relevant_files=merged_files)
846
 
847
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
routes/sessions.py CHANGED
@@ -157,67 +157,15 @@ async def auto_name_session(
157
  ):
158
  """Automatically name a session based on the first query using NVIDIA_SMALL API"""
159
  try:
160
- if not nvidia_rotator:
161
- return MessageResponse(message="Auto-naming not available")
162
 
163
- # Use NVIDIA_SMALL to generate a 2-3 word session name
164
- sys_prompt = """You are an expert at creating concise, descriptive session names.
165
-
166
- Given a user's first query in a chat session, create a 2-3 word session name that captures the main topic or intent.
167
-
168
- Rules:
169
- - Use 2-3 words maximum
170
- - Be descriptive but concise
171
- - Use title case (capitalize first letter of each word)
172
- - Focus on the main topic or question type
173
- - Avoid generic terms like "Question" or "Chat"
174
-
175
- Examples:
176
- - "Machine Learning Basics" for "What is machine learning?"
177
- - "Python Functions" for "How do I create functions in Python?"
178
- - "Data Analysis" for "Can you help me analyze this dataset?"
179
-
180
- Return only the session name, nothing else."""
181
-
182
- user_prompt = f"First query: {first_query}\n\nCreate a 2-3 word session name:"
183
 
184
- try:
185
- from utils.api.router import generate_answer_with_model
186
- selection = {"provider": "nvidia", "model": "meta/llama-3.1-8b-instruct"}
187
-
188
- response = await generate_answer_with_model(
189
- selection=selection,
190
- system_prompt=sys_prompt,
191
- user_prompt=user_prompt,
192
- gemini_rotator=None,
193
- nvidia_rotator=nvidia_rotator
194
- )
195
-
196
- # Clean up the response
197
- session_name = response.strip()
198
- # Remove quotes if present
199
- if session_name.startswith('"') and session_name.endswith('"'):
200
- session_name = session_name[1:-1]
201
- if session_name.startswith("'") and session_name.endswith("'"):
202
- session_name = session_name[1:-1]
203
-
204
- # Truncate if too long (safety measure)
205
- if len(session_name) > 50:
206
- session_name = session_name[:47] + "..."
207
-
208
- # Update the session with the auto-generated name
209
- result = rag.db["chat_sessions"].update_many(
210
- {"user_id": user_id, "project_id": project_id, "session_id": session_id},
211
- {"$set": {"session_name": session_name, "is_auto_named": True}}
212
- )
213
-
214
- if result.modified_count > 0:
215
- return MessageResponse(message=f"Session auto-named: {session_name}")
216
- else:
217
- return MessageResponse(message="Session not found for auto-naming")
218
-
219
- except Exception as e:
220
- logger.warning(f"[SESSIONS] Auto-naming failed: {e}")
221
  return MessageResponse(message="Auto-naming failed, keeping default name")
222
 
223
  except Exception as e:
 
157
  ):
158
  """Automatically name a session based on the first query using NVIDIA_SMALL API"""
159
  try:
160
+ from helpers.namer import auto_name_session_immediate
 
161
 
162
+ session_name = await auto_name_session_immediate(
163
+ user_id, project_id, session_id, first_query, nvidia_rotator, rag.db
164
+ )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
165
 
166
+ if session_name:
167
+ return MessageResponse(message=f"Session auto-named: {session_name}")
168
+ else:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
169
  return MessageResponse(message="Auto-naming failed, keeping default name")
170
 
171
  except Exception as e:
static/script.js CHANGED
@@ -583,6 +583,15 @@
583
  if (data.sources && data.sources.length > 0) {
584
  appendSources(data.sources);
585
  }
 
 
 
 
 
 
 
 
 
586
  await saveChatMessage(
587
  user.user_id,
588
  currentProject.project_id,
 
583
  if (data.sources && data.sources.length > 0) {
584
  appendSources(data.sources);
585
  }
586
+
587
+ // Handle session auto-naming if returned
588
+ if (data.session_name && data.session_id) {
589
+ // Update the session name in the UI immediately
590
+ if (window.__sb_update_session_name) {
591
+ window.__sb_update_session_name(data.session_id, data.session_name);
592
+ }
593
+ }
594
+
595
  await saveChatMessage(
596
  user.user_id,
597
  currentProject.project_id,
static/sessions.js CHANGED
@@ -331,11 +331,32 @@
331
  messages.scrollTop = messages.scrollHeight;
332
  }
333
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
334
  // Expose functions for external use
335
  window.__sb_get_current_session = () => currentSessionId;
336
  window.__sb_set_current_session = (sessionId) => selectSession(sessionId);
337
  window.__sb_append_message = appendMessage;
338
  window.__sb_load_sessions = loadSessions;
 
339
 
340
  // Initialize when DOM is ready
341
  if (document.readyState === 'loading') {
 
331
  messages.scrollTop = messages.scrollHeight;
332
  }
333
 
334
+ // Function to update session name in UI immediately
335
+ function updateSessionName(sessionId, newName) {
336
+ // Update the session in our local sessions array
337
+ const sessionIndex = sessions.findIndex(s => s.session_id === sessionId);
338
+ if (sessionIndex !== -1) {
339
+ sessions[sessionIndex].name = newName;
340
+ sessions[sessionIndex].is_auto_named = true;
341
+
342
+ // Update the dropdown to reflect the new name
343
+ updateSessionDropdown();
344
+
345
+ // If this is the currently selected session, update the dropdown value
346
+ if (currentSessionId === sessionId) {
347
+ sessionDropdown.value = sessionId;
348
+ }
349
+
350
+ console.log(`[SESSIONS] Updated session name to: ${newName}`);
351
+ }
352
+ }
353
+
354
  // Expose functions for external use
355
  window.__sb_get_current_session = () => currentSessionId;
356
  window.__sb_set_current_session = (sessionId) => selectSession(sessionId);
357
  window.__sb_append_message = appendMessage;
358
  window.__sb_load_sessions = loadSessions;
359
+ window.__sb_update_session_name = updateSessionName;
360
 
361
  // Initialize when DOM is ready
362
  if (document.readyState === 'loading') {