ayush2917 commited on
Commit
a0b9ea4
·
verified ·
1 Parent(s): b9f9d64

Update chatbot.py

Browse files
Files changed (1) hide show
  1. chatbot.py +76 -70
chatbot.py CHANGED
@@ -4,31 +4,45 @@ import random
4
  import time
5
  import logging
6
  from dotenv import load_dotenv
7
- from messages import krishna_blessings, ayush_teasing, keyword_groups
8
  from ayush_messages import ayush_surprises
9
  from sentence_transformers import SentenceTransformer, util
10
  import joblib
11
  import numpy as np
12
 
13
  # Configure logging
14
- logging.basicConfig(level=logging.INFO)
15
  logger = logging.getLogger(__name__)
16
 
17
  # Load environment variables
18
  load_dotenv()
19
  HUGGINGFACE_API_TOKEN = os.getenv("HUGGINGFACE_API_TOKEN")
20
  if not HUGGINGFACE_API_TOKEN:
21
- logger.error("HUGGINGFACE_API_TOKEN not found in environment variables.")
22
- raise ValueError("HUGGINGFACE_API_TOKEN is required.")
23
 
24
  # Lazy load sentence transformer model and embeddings
25
  semantic_model = None
26
- keyword_embeddings_cache = joblib.load('embeddings_cache.joblib')
27
 
28
  def init_semantic_model():
29
- global semantic_model
30
  if semantic_model is None:
31
- semantic_model = SentenceTransformer('all-MiniLM-L6-v2')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
32
 
33
  # AI model for fallback responses
34
  AI_MODELS = [
@@ -64,7 +78,7 @@ conversation_context = {
64
  "message_count": 0,
65
  "last_response": None,
66
  "last_yes_response": None,
67
- "history": [] # Store up to 5 recent (input, response) pairs
68
  }
69
 
70
  def analyze_sentiment(user_input):
@@ -85,10 +99,17 @@ def analyze_sentiment(user_input):
85
  if isinstance(result, list) and result:
86
  emotions = result[0]
87
  top_emotion = max(emotions, key=lambda x: x["score"])["label"]
 
88
  return top_emotion
 
89
  return "neutral"
90
  except Exception as e:
91
  logger.error(f"Error in analyze_sentiment: {str(e)}")
 
 
 
 
 
92
  return "neutral"
93
 
94
  def make_api_request(url, headers, payload, retries=2, delay=3):
@@ -103,37 +124,56 @@ def make_api_request(url, headers, payload, retries=2, delay=3):
103
  time.sleep(delay)
104
  continue
105
  else:
106
- logger.error(f"API error: {response.text}")
107
  return None
108
  except Exception as e:
109
  logger.error(f"API request failed on attempt {attempt + 1}: {str(e)}")
110
  if attempt < retries - 1:
111
  time.sleep(delay)
112
  continue
113
- logger.error(f"API request failed after {retries} retries.")
114
  return None
115
 
116
  def get_keyword_match(user_input_lower):
117
- """Find the best matching keyword group using semantic similarity."""
118
- init_semantic_model()
119
- user_embedding = semantic_model.encode(user_input_lower, convert_to_tensor=True)
120
- best_score = -1
121
- best_group = None
122
-
123
- for group in keyword_embeddings_cache:
124
- similarities = util.cos_sim(user_embedding, keyword_embeddings_cache[group])
125
- max_similarity = similarities.max().item()
126
- if max_similarity > best_score and max_similarity > 0.6:
127
- best_score = max_similarity
128
- best_group = group
129
- logger.info(f"Best group: {best_group}, Similarity score: {best_score}")
130
- return best_group
 
 
 
 
 
 
 
 
 
 
 
 
 
131
 
132
  def get_krishna_response(user_input):
133
- """Generate a response from Little Krishna."""
134
  try:
135
  user_input_lower = user_input.lower().strip()
136
  logger.info(f"Processing user input: {user_input_lower}")
 
 
 
 
 
 
137
 
138
  # Reset context
139
  if "start over" in user_input_lower or "reset" in user_input_lower:
@@ -142,17 +182,16 @@ def get_krishna_response(user_input):
142
 
143
  # Analyze sentiment
144
  sentiment = analyze_sentiment(user_input)
145
- logger.info(f"Sentiment detected: {sentiment}")
146
  conversation_context["message_count"] += 1
147
 
148
  # Update history
149
- if len(conversation_context["history"]) >= 5:
150
  conversation_context["history"].pop(0)
151
  conversation_context["history"].append({"input": user_input_lower, "response": None})
152
 
153
  # Semantic keyword matching
154
  matched_group = get_keyword_match(user_input_lower)
155
- use_model = random.random() < 0.3
156
  logger.info(f"Matched group: {matched_group}, Use model: {use_model}")
157
 
158
  # Follow-up based on history
@@ -173,45 +212,12 @@ def get_krishna_response(user_input):
173
  return response
174
 
175
  # Handle predefined responses
176
- follow_ups = {
177
- "greeting": "What’s sparking your joy today?",
178
- "joke": "Want another silly tale?",
179
- "riddle": "Ready for another puzzle?",
180
- "playful": "What fun shall we have next?",
181
- "calm": "What’s soothing your heart today?",
182
- "wisdom": "What wisdom are you seeking now?",
183
- "nature": "Which part of Vrindavan calls to you?",
184
- "encourage": "What’s your next brave step?",
185
- "friend": "What’s a special moment you’d like to share?",
186
- "chat": "What’s on your mind, Manavi?",
187
- "birthday": "What’s your birthday wish?"
188
- }
189
-
190
- if matched_group and not use_model:
191
- conversation_context["last_topic"] = matched_group
192
- if matched_group == "birthday":
193
- response = ayush_surprises.get("birthday", auto_generate_birthday_message(include_tease=True))
194
- elif matched_group == "chat":
195
- response = krishna_blessings["chat_with_you"]
196
- elif matched_group in ayush_teasing and random.choice([True, False]):
197
- response = random.choice(ayush_teasing[matched_group])
198
- elif matched_group in krishna_blessings:
199
- response = krishna_blessings[matched_group]
200
- else:
201
- response = krishna_blessings.get(matched_group, "Hare Manavi! Let’s explore Vrindavan’s magic!")
202
- follow_up = follow_ups.get(matched_group, "What else is on your mind, Manavi?")
203
- response = f"{response} {follow_up}"
204
- conversation_context["history"][-1]["response"] = response
205
- return response
206
-
207
- # Sentiment-based fallback
208
- if sentiment in ["sadness", "anger"] and not matched_group and not use_model:
209
- response = f"Hare Manavi! I see a shadow on your heart—let’s dance by the Yamuna to bring back your smile! What’s on your mind?"
210
- conversation_context["history"][-1]["response"] = response
211
- return response
212
- elif sentiment == "joy" and not matched_group and not use_model:
213
- response = f"Hare Manavi! Your joy lights up Vrindavan—let’s celebrate with a flute melody! What’s making you so happy?"
214
- conversation_context["history"][-1]["response"] = response
215
  return response
216
 
217
  # Fallback to AI model
@@ -242,13 +248,13 @@ def get_krishna_response(user_input):
242
  logger.error(f"Error with {model['name']}: {str(e)}")
243
  continue
244
 
245
- # Default fallback
246
- response = "Hare Manavi! I’m lost in Vrindavan’s magic—let’s try a new tune! What’s on your mind?"
247
  conversation_context["history"][-1]["response"] = response
248
  return response
249
 
250
  except Exception as e:
251
  logger.error(f"Unhandled exception in get_krishna_response: {str(e)}")
252
- response = "Hare Manavi! Something went wrong—let’s try again! What’s up?"
253
  conversation_context["history"][-1]["response"] = response
254
  return response
 
4
  import time
5
  import logging
6
  from dotenv import load_dotenv
7
+ from messages import krishna_blessings, ayush_teasing, keyword_groups, get_contextual_response, generate_follow_up, handle_vague_input
8
  from ayush_messages import ayush_surprises
9
  from sentence_transformers import SentenceTransformer, util
10
  import joblib
11
  import numpy as np
12
 
13
  # Configure logging
14
+ logging.basicConfig(level=logging.DEBUG)
15
  logger = logging.getLogger(__name__)
16
 
17
  # Load environment variables
18
  load_dotenv()
19
  HUGGINGFACE_API_TOKEN = os.getenv("HUGGINGFACE_API_TOKEN")
20
  if not HUGGINGFACE_API_TOKEN:
21
+ logger.error("HUGGINGFACE_API_TOKEN not found in environment variables")
22
+ raise ValueError("HUGGINGFACE_API_TOKEN is required")
23
 
24
  # Lazy load sentence transformer model and embeddings
25
  semantic_model = None
26
+ keyword_embeddings_cache = None
27
 
28
  def init_semantic_model():
29
+ global semantic_model, keyword_embeddings_cache
30
  if semantic_model is None:
31
+ try:
32
+ semantic_model = SentenceTransformer('all-MiniLM-L6-v2')
33
+ keyword_embeddings_cache = joblib.load('embeddings_cache.joblib')
34
+ logger.debug("Successfully loaded semantic model and embeddings cache")
35
+ except Exception as e:
36
+ logger.error(f"Failed to load semantic model or embeddings: {str(e)}")
37
+ # Retry once
38
+ try:
39
+ semantic_model = SentenceTransformer('all-MiniLM-L6-v2')
40
+ keyword_embeddings_cache = joblib.load('embeddings_cache.joblib')
41
+ logger.debug("Retry successful")
42
+ except Exception as e:
43
+ logger.error(f"Retry failed: {str(e)}")
44
+ semantic_model = None
45
+ keyword_embeddings_cache = {}
46
 
47
  # AI model for fallback responses
48
  AI_MODELS = [
 
78
  "message_count": 0,
79
  "last_response": None,
80
  "last_yes_response": None,
81
+ "history": [] # Store up to 10 recent (input, response) pairs
82
  }
83
 
84
  def analyze_sentiment(user_input):
 
99
  if isinstance(result, list) and result:
100
  emotions = result[0]
101
  top_emotion = max(emotions, key=lambda x: x["score"])["label"]
102
+ logger.debug(f"Sentiment detected: {top_emotion}")
103
  return top_emotion
104
+ logger.warning("Sentiment analysis failed")
105
  return "neutral"
106
  except Exception as e:
107
  logger.error(f"Error in analyze_sentiment: {str(e)}")
108
+ # Local sentiment fallback
109
+ if any(word in user_input.lower() for word in ['sad', 'down', 'upset']):
110
+ return "sadness"
111
+ if any(word in user_input.lower() for word in ['happy', 'great', 'awesome']):
112
+ return "joy"
113
  return "neutral"
114
 
115
  def make_api_request(url, headers, payload, retries=2, delay=3):
 
124
  time.sleep(delay)
125
  continue
126
  else:
127
+ logger.error(f"API error: {response.status_code} - {response.text}")
128
  return None
129
  except Exception as e:
130
  logger.error(f"API request failed on attempt {attempt + 1}: {str(e)}")
131
  if attempt < retries - 1:
132
  time.sleep(delay)
133
  continue
134
+ logger.error(f"API request failed after {retries} retries")
135
  return None
136
 
137
  def get_keyword_match(user_input_lower):
138
+ """Find the best matching keyword group using semantic similarity or substring fallback."""
139
+ # Try semantic matching
140
+ if semantic_model and keyword_embeddings_cache:
141
+ try:
142
+ user_embedding = semantic_model.encode(user_input_lower, convert_to_tensor=True)
143
+ best_score = -1
144
+ best_group = None
145
+
146
+ for group in keyword_embeddings_cache:
147
+ similarities = util.cos_sim(user_embedding, keyword_embeddings_cache[group])
148
+ max_similarity = similarities.max().item()
149
+ if max_similarity > best_score and max_similarity > 0.5:
150
+ best_score = max_similarity
151
+ best_group = group
152
+ if best_group:
153
+ logger.debug(f"Semantic match: {best_group}, score: {best_score}")
154
+ return best_group
155
+ except Exception as e:
156
+ logger.error(f"Semantic matching failed: {str(e)}")
157
+
158
+ # Fallback to substring matching
159
+ for group, keywords in keyword_groups.items():
160
+ if any(keyword in user_input_lower for keyword in keywords):
161
+ logger.debug(f"Substring match: {group}")
162
+ return group
163
+ logger.debug("No keyword match found")
164
+ return None
165
 
166
  def get_krishna_response(user_input):
167
+ """Generate a robust and relevant response from Little Krishna."""
168
  try:
169
  user_input_lower = user_input.lower().strip()
170
  logger.info(f"Processing user input: {user_input_lower}")
171
+ if not user_input_lower:
172
+ logger.warning("Empty input received")
173
+ return "Hare Manavi! Don’t be shy like a gopi—say something! What’s on your mind?"
174
+
175
+ # Initialize semantic model if needed
176
+ init_semantic_model()
177
 
178
  # Reset context
179
  if "start over" in user_input_lower or "reset" in user_input_lower:
 
182
 
183
  # Analyze sentiment
184
  sentiment = analyze_sentiment(user_input)
 
185
  conversation_context["message_count"] += 1
186
 
187
  # Update history
188
+ if len(conversation_context["history"]) >= 10:
189
  conversation_context["history"].pop(0)
190
  conversation_context["history"].append({"input": user_input_lower, "response": None})
191
 
192
  # Semantic keyword matching
193
  matched_group = get_keyword_match(user_input_lower)
194
+ use_model = random.random() < 0.1
195
  logger.info(f"Matched group: {matched_group}, Use model: {use_model}")
196
 
197
  # Follow-up based on history
 
212
  return response
213
 
214
  # Handle predefined responses
215
+ response = get_contextual_response(matched_group, sentiment, conversation_context["history"])
216
+ follow_up = generate_follow_up(matched_group) if matched_group else "What else is on your mind, Manavi?"
217
+ response = f"{response} {follow_up}"
218
+ conversation_context["last_topic"] = matched_group
219
+ conversation_context["history"][-1]["response"] = response
220
+ if not use_model:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  return response
222
 
223
  # Fallback to AI model
 
248
  logger.error(f"Error with {model['name']}: {str(e)}")
249
  continue
250
 
251
+ # Static fallback if API fails
252
+ response = handle_vague_input(conversation_context["history"])
253
  conversation_context["history"][-1]["response"] = response
254
  return response
255
 
256
  except Exception as e:
257
  logger.error(f"Unhandled exception in get_krishna_response: {str(e)}")
258
+ response = "Hare Manavi! The Yamuna’s waves got choppy—let’s try again! What’s on your mind?"
259
  conversation_context["history"][-1]["response"] = response
260
  return response