KURUPRASATH-J commited on
Commit
289e83d
·
verified ·
1 Parent(s): 67c407a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +103 -199
app.py CHANGED
@@ -45,7 +45,7 @@ import pytesseract
45
  from PIL import Image
46
 
47
  # Import Juno AI Prompts System
48
- from prompts import juno_prompts, get_main_conversation_prompt, get_document_summary_prompt, get_rag_prompt, get_streaming_prompt, get_fallback_responses, get_user_extraction_prompt, get_memory_consolidation_prompt
49
 
50
  # Load environment variables
51
  load_dotenv()
@@ -101,41 +101,49 @@ class ChatbotWithMemoryAndRAG:
101
  self.vectorstore = None
102
  self.chat_history = []
103
  self.memory = {}
104
- # NEWLY ADDED: User information storage for persistent memory
105
- self.user_info = {}
 
106
  self.session_id = str(uuid.uuid4())
107
  self.last_rate_limit = None
108
  self.consecutive_rate_limits = 0
109
  self.prompts = juno_prompts
110
- # NEWLY ADDED: Initialize user info storage
111
- self._initialize_user_storage()
112
  logging.info(f"🤖 Juno AI initialized with session ID: {self.session_id}")
113
 
114
- def _initialize_user_storage(self):
115
- """Initialize user information storage structure"""
116
- self.user_info = {
117
- "name": {
118
- "first_name": None,
119
- "last_name": None,
120
- "full_name": None,
121
- "nickname": None
122
- },
123
- "personal_details": {
124
- "age": None,
125
- "location": None,
126
- "occupation": None,
127
- "family": None
128
- },
129
- "preferences": {
130
- "interests": [],
131
- "likes": [],
132
- "dislikes": []
133
- },
134
- "goals": [],
135
- "context": [],
136
- "communication_preferences": None
137
- }
138
- logging.info("User information storage initialized.")
 
 
 
 
 
 
 
 
 
139
 
140
  def _retry_with_backoff(self, func, max_retries=5, base_delay=2):
141
  """Improved retry function with progressive backoff for rate limit handling"""
@@ -182,108 +190,18 @@ class ChatbotWithMemoryAndRAG:
182
  logging.warning(f"Generating fallback response for message: '{user_message[:50]}...'")
183
  fallback_templates = get_fallback_responses()
184
  template = random.choice(fallback_templates)
185
- # NEWLY ADDED: Include user name in fallback if available
186
- user_name = self._get_user_name()
187
- if user_name:
188
- response = template.format(user_message_preview=user_message[:50]).replace("Your", f"{user_name}'s")
 
 
189
  else:
190
  response = template.format(user_message_preview=user_message[:50])
 
191
  self.chat_history.append({"user": user_message, "bot": response, "timestamp": datetime.now().isoformat(), "fallback": True})
192
  return response
193
 
194
- def _get_user_name(self):
195
- """Get the user's preferred name from stored information"""
196
- if self.user_info.get("name"):
197
- name_info = self.user_info["name"]
198
- return (name_info.get("nickname") or
199
- name_info.get("first_name") or
200
- name_info.get("full_name") or
201
- None)
202
- return None
203
-
204
- def _extract_user_information(self, user_message, bot_response):
205
- """Extract user information from conversation using AI"""
206
- def _extract():
207
- model = genai.GenerativeModel(GENERATIVE_MODEL)
208
- prompt = get_user_extraction_prompt(user_message, bot_response)
209
- return model.generate_content(prompt).text
210
-
211
- try:
212
- extraction_result = self._retry_with_backoff(_extract, max_retries=3, base_delay=1)
213
- # Parse JSON response
214
- try:
215
- new_user_info = json.loads(extraction_result)
216
- if new_user_info and any(new_user_info.values()):
217
- self._consolidate_user_information(new_user_info)
218
- except json.JSONDecodeError:
219
- logging.warning(f"Failed to parse user information extraction: {extraction_result}")
220
- except Exception as e:
221
- logging.error(f"Error extracting user information: {e}")
222
-
223
- def _consolidate_user_information(self, new_user_info):
224
- """Consolidate new user information with existing information"""
225
- def _consolidate():
226
- model = genai.GenerativeModel(GENERATIVE_MODEL)
227
- prompt = get_memory_consolidation_prompt(self.user_info, new_user_info)
228
- return model.generate_content(prompt).text
229
-
230
- try:
231
- consolidation_result = self._retry_with_backoff(_consolidate, max_retries=3, base_delay=1)
232
- # Parse JSON response and update user_info
233
- try:
234
- consolidated_info = json.loads(consolidation_result)
235
- self.user_info = consolidated_info
236
- logging.info("User information updated successfully.")
237
- except json.JSONDecodeError:
238
- # Manual consolidation as fallback
239
- self._manual_consolidation(new_user_info)
240
- except Exception as e:
241
- logging.error(f"Error consolidating user information: {e}")
242
- # Fallback to manual consolidation
243
- self._manual_consolidation(new_user_info)
244
-
245
- def _manual_consolidation(self, new_user_info):
246
- """Manual consolidation as fallback when AI consolidation fails"""
247
- try:
248
- # Merge name information
249
- if new_user_info.get("name"):
250
- for key, value in new_user_info["name"].items():
251
- if value and value != "null":
252
- self.user_info["name"][key] = value
253
-
254
- # Merge personal details
255
- if new_user_info.get("personal_details"):
256
- for key, value in new_user_info["personal_details"].items():
257
- if value and value != "null":
258
- self.user_info["personal_details"][key] = value
259
-
260
- # Merge preferences (lists)
261
- if new_user_info.get("preferences"):
262
- for key, values in new_user_info["preferences"].items():
263
- if values:
264
- existing_list = self.user_info["preferences"].get(key, [])
265
- for item in values:
266
- if item not in existing_list:
267
- existing_list.append(item)
268
- self.user_info["preferences"][key] = existing_list
269
-
270
- # Merge goals and context (lists)
271
- for key in ["goals", "context"]:
272
- if new_user_info.get(key):
273
- existing_list = self.user_info.get(key, [])
274
- for item in new_user_info[key]:
275
- if item not in existing_list:
276
- existing_list.append(item)
277
- self.user_info[key] = existing_list
278
-
279
- # Update communication preferences
280
- if new_user_info.get("communication_preferences"):
281
- self.user_info["communication_preferences"] = new_user_info["communication_preferences"]
282
-
283
- logging.info("User information manually consolidated.")
284
- except Exception as e:
285
- logging.error(f"Error in manual consolidation: {e}")
286
-
287
  def extract_text_from_pdf(self, pdf_content):
288
  """Extract text content from PDF bytes with OCR fallback"""
289
  try:
@@ -358,6 +276,17 @@ class ChatbotWithMemoryAndRAG:
358
 
359
  def generate_response(self, user_message, context=""):
360
  """Generate response using Juno AI prompts"""
 
 
 
 
 
 
 
 
 
 
 
361
  def _generate():
362
  model = genai.GenerativeModel(GENERATIVE_MODEL)
363
  conversation_history = []
@@ -365,22 +294,22 @@ class ChatbotWithMemoryAndRAG:
365
  for exchange in self.chat_history[-3:]:
366
  if not exchange.get('fallback', False):
367
  conversation_history.append({'user': exchange['user'], 'bot': exchange['bot'], 'timestamp': exchange.get('timestamp', '')})
368
- # NEWLY ADDED: Include user information in prompt
369
- prompt = self.prompts.get_conversation_prompt(
370
- user_message=user_message,
371
- context=context,
372
- conversation_history=conversation_history,
373
- memory_context=self.memory,
374
- user_info=self.user_info if any(v for v in self.user_info.values() if v) else None
375
- )
376
  return model.generate_content(prompt).text
377
 
378
  try:
379
  bot_response = self._retry_with_backoff(_generate)
380
  self.chat_history.append({"user": user_message, "bot": bot_response, "timestamp": datetime.now().isoformat()})
381
  self.update_memory(user_message, bot_response)
382
- # NEWLY ADDED: Extract user information from this conversation
383
- self._extract_user_information(user_message, bot_response)
384
  return bot_response
385
  except (ResourceExhausted, GoogleAPIError):
386
  return self._fallback_response(user_message)
@@ -432,22 +361,30 @@ class ChatbotWithMemoryAndRAG:
432
 
433
  def generate_rag_response(self, user_query, context, sources=None):
434
  """Generate RAG response using Juno AI prompts"""
 
 
 
 
 
 
 
435
  def _generate_rag():
436
  model = genai.GenerativeModel(GENERATIVE_MODEL)
437
  context_chunks = [context[i:i+2000] for i in range(0, len(context), 2000)]
438
- # NEWLY ADDED: Include user information in RAG response
439
- prompt = self.prompts.get_rag_response_prompt(
440
- user_query=user_query,
441
- retrieved_chunks=context_chunks[:3],
442
- source_info=sources,
443
- user_info=self.user_info if any(v for v in self.user_info.values() if v) else None
444
- )
 
445
  return model.generate_content(prompt).text
446
 
447
  try:
448
  response = self._retry_with_backoff(_generate_rag)
449
- # NEWLY ADDED: Extract user information from RAG responses too
450
- self._extract_user_information(user_query, response)
451
  return response
452
  except (ResourceExhausted, GoogleAPIError):
453
  return self._fallback_response(user_query)
@@ -497,14 +434,23 @@ class ChatbotWithMemoryAndRAG:
497
 
498
  def generate_streaming_response(self, user_message, context=""):
499
  """Generate streaming response using Juno AI prompts"""
 
 
 
 
 
 
 
500
  def _generate_stream():
501
  model = genai.GenerativeModel(GENERATIVE_MODEL)
502
- # NEWLY ADDED: Include user information in streaming prompts
503
- prompt = self.prompts.get_streaming_response_prompt(
504
- user_message,
505
- context,
506
- user_info=self.user_info if any(v for v in self.user_info.values() if v) else None
507
- )
 
 
508
  return model.generate_content(prompt, stream=True)
509
 
510
  try:
@@ -608,7 +554,8 @@ def summarize_document():
608
  def get_memory():
609
  return jsonify({
610
  'memory': chatbot.memory,
611
- 'user_info': chatbot.user_info, # NEWLY ADDED: Include user information
 
612
  'chat_history_length': len(chatbot.chat_history),
613
  'has_vectorstore': chatbot.vectorstore is not None,
614
  'session_id': chatbot.session_id
@@ -695,8 +642,8 @@ def chat_stream():
695
 
696
  chatbot.chat_history.append({"user": user_message, "bot": full_response, "timestamp": datetime.now().isoformat()})
697
  chatbot.update_memory(user_message, full_response)
698
- # NEWLY ADDED: Extract user information from streaming responses
699
- chatbot._extract_user_information(user_message, full_response)
700
 
701
  return jsonify({
702
  'response': full_response,
@@ -798,53 +745,10 @@ def edit_message(message_index):
798
  logging.error(f"Error in /api/messages/{message_index}/edit: {e}", exc_info=True)
799
  return jsonify({'error': 'An internal server error occurred.'}), 500
800
 
801
- # NEWLY ADDED: User information management endpoints
802
-
803
- @app.route('/api/user-info', methods=['GET'])
804
- def get_user_info():
805
- """Get stored user information"""
806
- try:
807
- return jsonify({
808
- 'user_info': chatbot.user_info,
809
- 'has_user_info': any(v for v in chatbot.user_info.values() if v),
810
- 'user_name': chatbot._get_user_name()
811
- })
812
- except Exception as e:
813
- logging.error(f"Error in /api/user-info GET: {e}", exc_info=True)
814
- return jsonify({'error': 'An internal server error occurred.'}), 500
815
-
816
- @app.route('/api/user-info', methods=['PUT'])
817
- def update_user_info():
818
- """Update user information manually"""
819
- try:
820
- data = request.json
821
- new_info = data.get('user_info', {})
822
- if new_info:
823
- chatbot._consolidate_user_information(new_info)
824
- return jsonify({
825
- 'message': 'User information updated successfully',
826
- 'user_info': chatbot.user_info
827
- })
828
- else:
829
- return jsonify({'error': 'No user information provided'}), 400
830
- except Exception as e:
831
- logging.error(f"Error in /api/user-info PUT: {e}", exc_info=True)
832
- return jsonify({'error': 'An internal server error occurred.'}), 500
833
-
834
- @app.route('/api/user-info', methods=['DELETE'])
835
- def clear_user_info():
836
- """Clear all stored user information"""
837
- try:
838
- chatbot._initialize_user_storage()
839
- return jsonify({'message': 'User information cleared successfully'})
840
- except Exception as e:
841
- logging.error(f"Error in /api/user-info DELETE: {e}", exc_info=True)
842
- return jsonify({'error': 'An internal server error occurred.'}), 500
843
-
844
  if __name__ == '__main__':
845
  logging.info("🚀 Starting Juno AI Server...")
846
  logging.info("🤖 Advanced AI Assistant with Document Processing, Web Scraping, and Memory")
847
  logging.info("🌟 Powered by Juno AI Prompts System")
848
- logging.info("🧠 Enhanced with User Information Memory")
849
  port = int(os.environ.get("PORT", 7860))
850
  app.run(debug=False, host='0.0.0.0', port=port)
 
45
  from PIL import Image
46
 
47
  # Import Juno AI Prompts System
48
+ from prompts import juno_prompts, get_main_conversation_prompt, get_document_summary_prompt, get_rag_prompt, get_streaming_prompt, get_fallback_responses
49
 
50
  # Load environment variables
51
  load_dotenv()
 
101
  self.vectorstore = None
102
  self.chat_history = []
103
  self.memory = {}
104
+ # NEWLY ADDED: Simple user information storage
105
+ self.user_name = None
106
+ self.user_details = {}
107
  self.session_id = str(uuid.uuid4())
108
  self.last_rate_limit = None
109
  self.consecutive_rate_limits = 0
110
  self.prompts = juno_prompts
 
 
111
  logging.info(f"🤖 Juno AI initialized with session ID: {self.session_id}")
112
 
113
+ def _extract_name_from_message(self, user_message, bot_response):
114
+ """Simple name extraction from user messages"""
115
+ message_lower = user_message.lower()
116
+
117
+ # Pattern 1: "i am [name]" or "I'm [name]"
118
+ patterns = [
119
+ r"i am ([a-zA-Z]+)",
120
+ r"i'm ([a-zA-Z]+)",
121
+ r"my name is ([a-zA-Z]+)",
122
+ r"call me ([a-zA-Z]+)",
123
+ r"name's ([a-zA-Z]+)"
124
+ ]
125
+
126
+ for pattern in patterns:
127
+ match = re.search(pattern, message_lower)
128
+ if match:
129
+ name = match.group(1).capitalize()
130
+ self.user_name = name
131
+ self.user_details["name"] = name
132
+ logging.info(f"Extracted user name: {name}")
133
+ return name
134
+ return None
135
+
136
+ def _check_for_name_query(self, user_message):
137
+ """Check if user is asking about their name"""
138
+ message_lower = user_message.lower()
139
+ name_queries = [
140
+ "what is my name",
141
+ "what's my name",
142
+ "do you know my name",
143
+ "remember my name",
144
+ "my name"
145
+ ]
146
+ return any(query in message_lower for query in name_queries)
147
 
148
  def _retry_with_backoff(self, func, max_retries=5, base_delay=2):
149
  """Improved retry function with progressive backoff for rate limit handling"""
 
190
  logging.warning(f"Generating fallback response for message: '{user_message[:50]}...'")
191
  fallback_templates = get_fallback_responses()
192
  template = random.choice(fallback_templates)
193
+
194
+ # NEWLY ADDED: Include user name in fallback if available
195
+ if self.user_name and self._check_for_name_query(user_message):
196
+ response = f"Your name is {self.user_name}! I remember when you told me."
197
+ elif self.user_name:
198
+ response = template.format(user_message_preview=user_message[:50]).replace("Your", f"{self.user_name}'s")
199
  else:
200
  response = template.format(user_message_preview=user_message[:50])
201
+
202
  self.chat_history.append({"user": user_message, "bot": response, "timestamp": datetime.now().isoformat(), "fallback": True})
203
  return response
204
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
205
  def extract_text_from_pdf(self, pdf_content):
206
  """Extract text content from PDF bytes with OCR fallback"""
207
  try:
 
276
 
277
  def generate_response(self, user_message, context=""):
278
  """Generate response using Juno AI prompts"""
279
+ # NEWLY ADDED: Check for name queries first
280
+ if self._check_for_name_query(user_message):
281
+ if self.user_name:
282
+ response = f"Your name is {self.user_name}! I remember when you told me."
283
+ self.chat_history.append({"user": user_message, "bot": response, "timestamp": datetime.now().isoformat()})
284
+ return response
285
+ else:
286
+ response = "I don't know your name yet. Would you like to tell me what it is?"
287
+ self.chat_history.append({"user": user_message, "bot": response, "timestamp": datetime.now().isoformat()})
288
+ return response
289
+
290
  def _generate():
291
  model = genai.GenerativeModel(GENERATIVE_MODEL)
292
  conversation_history = []
 
294
  for exchange in self.chat_history[-3:]:
295
  if not exchange.get('fallback', False):
296
  conversation_history.append({'user': exchange['user'], 'bot': exchange['bot'], 'timestamp': exchange.get('timestamp', '')})
297
+
298
+ # NEWLY ADDED: Include user name in prompt context
299
+ user_context = ""
300
+ if self.user_name:
301
+ user_context = f"\nUSER NAME: {self.user_name} (remember to address them personally)"
302
+
303
+ base_prompt = self.prompts.get_conversation_prompt(user_message=user_message, context=context, conversation_history=conversation_history, memory_context=self.memory)
304
+ prompt = base_prompt + user_context
305
  return model.generate_content(prompt).text
306
 
307
  try:
308
  bot_response = self._retry_with_backoff(_generate)
309
  self.chat_history.append({"user": user_message, "bot": bot_response, "timestamp": datetime.now().isoformat()})
310
  self.update_memory(user_message, bot_response)
311
+ # NEWLY ADDED: Extract name from conversation
312
+ self._extract_name_from_message(user_message, bot_response)
313
  return bot_response
314
  except (ResourceExhausted, GoogleAPIError):
315
  return self._fallback_response(user_message)
 
361
 
362
  def generate_rag_response(self, user_query, context, sources=None):
363
  """Generate RAG response using Juno AI prompts"""
364
+ # NEWLY ADDED: Check for name queries first
365
+ if self._check_for_name_query(user_query):
366
+ if self.user_name:
367
+ return f"Your name is {self.user_name}! I remember when you told me."
368
+ else:
369
+ return "I don't know your name yet. Would you like to tell me what it is?"
370
+
371
  def _generate_rag():
372
  model = genai.GenerativeModel(GENERATIVE_MODEL)
373
  context_chunks = [context[i:i+2000] for i in range(0, len(context), 2000)]
374
+
375
+ # NEWLY ADDED: Include user name in RAG prompt
376
+ user_context = ""
377
+ if self.user_name:
378
+ user_context = f"\nUSER NAME: {self.user_name} (address them personally)"
379
+
380
+ base_prompt = self.prompts.get_rag_response_prompt(user_query=user_query, retrieved_chunks=context_chunks[:3], source_info=sources)
381
+ prompt = base_prompt + user_context
382
  return model.generate_content(prompt).text
383
 
384
  try:
385
  response = self._retry_with_backoff(_generate_rag)
386
+ # NEWLY ADDED: Extract name from RAG conversations too
387
+ self._extract_name_from_message(user_query, response)
388
  return response
389
  except (ResourceExhausted, GoogleAPIError):
390
  return self._fallback_response(user_query)
 
434
 
435
  def generate_streaming_response(self, user_message, context=""):
436
  """Generate streaming response using Juno AI prompts"""
437
+ # NEWLY ADDED: Check for name queries first
438
+ if self._check_for_name_query(user_message):
439
+ if self.user_name:
440
+ return f"Your name is {self.user_name}! I remember when you told me."
441
+ else:
442
+ return "I don't know your name yet. Would you like to tell me what it is?"
443
+
444
  def _generate_stream():
445
  model = genai.GenerativeModel(GENERATIVE_MODEL)
446
+
447
+ # NEWLY ADDED: Include user name in streaming prompt
448
+ user_context = ""
449
+ if self.user_name:
450
+ user_context = f"\nUSER NAME: {self.user_name} (address them personally)"
451
+
452
+ base_prompt = self.prompts.get_streaming_response_prompt(user_message, context)
453
+ prompt = base_prompt + user_context
454
  return model.generate_content(prompt, stream=True)
455
 
456
  try:
 
554
  def get_memory():
555
  return jsonify({
556
  'memory': chatbot.memory,
557
+ 'user_name': chatbot.user_name, # NEWLY ADDED: Include user name
558
+ 'user_details': chatbot.user_details, # NEWLY ADDED: Include user details
559
  'chat_history_length': len(chatbot.chat_history),
560
  'has_vectorstore': chatbot.vectorstore is not None,
561
  'session_id': chatbot.session_id
 
642
 
643
  chatbot.chat_history.append({"user": user_message, "bot": full_response, "timestamp": datetime.now().isoformat()})
644
  chatbot.update_memory(user_message, full_response)
645
+ # NEWLY ADDED: Extract name from streaming responses
646
+ chatbot._extract_name_from_message(user_message, full_response)
647
 
648
  return jsonify({
649
  'response': full_response,
 
745
  logging.error(f"Error in /api/messages/{message_index}/edit: {e}", exc_info=True)
746
  return jsonify({'error': 'An internal server error occurred.'}), 500
747
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
748
  if __name__ == '__main__':
749
  logging.info("🚀 Starting Juno AI Server...")
750
  logging.info("🤖 Advanced AI Assistant with Document Processing, Web Scraping, and Memory")
751
  logging.info("🌟 Powered by Juno AI Prompts System")
752
+ logging.info("🧠 Enhanced with User Name Memory")
753
  port = int(os.environ.get("PORT", 7860))
754
  app.run(debug=False, host='0.0.0.0', port=port)