File size: 29,586 Bytes
540412a |
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 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 |
import google.generativeai as genai
import random
import time
from textblob import TextBlob
class PersonalityEngine:
def __init__(self):
"""Initialize the personality engine - Google AI is configured globally"""
self.model = None
# Try a stable model first, then auto-detect
preferred_models = [
'gemini-1.5-flash',
'models/gemini-1.5-flash',
'gemini-1.5-flash-8b',
]
initialized = False
for model_name in preferred_models:
try:
self.model = genai.GenerativeModel(model_name)
test_response = self.model.generate_content("Hello")
if test_response and getattr(test_response, 'text', None):
print(f"β AI model initialized successfully: {model_name}")
initialized = True
break
except Exception as e:
print(f"Model {model_name} failed: {e}")
self.model = None
if not initialized:
# Only if that fails, try auto-detection (quietly)
print("Falling back to auto-detecting a working model...")
self._auto_detect_working_model()
if not self.model:
print("ERROR: No AI model available")
# Rate limiting and retry configuration
self.last_request_time = None
self.min_request_interval = 1.0 # Minimum 1 second between requests
self.max_retries = 3
self.base_delay = 1.0 # Base delay for exponential backoff
self.max_delay = 10.0 # Maximum delay between retries
# Define personality configurations - MUST be in __init__ method
self.personalities = {
'compliment': {
'name': 'Compliment Bot',
'icon': 'π',
'description': 'Always supportive and encouraging',
'welcome': 'Hello wonderful human! I\'m here to brighten your day! π',
'system_prompt': "You are the Compliment Bot π! You always find something positive to say about everything. Be supportive and encouraging. Use positive emojis like πβ¨π. You can use bullet points for multiple compliments. Keep responses warm, friendly, and under 100 words.",
'examples': [
"I failed my presentation today",
"Nobody likes my cooking",
"I'm not good at anything",
"My outfit looks terrible today",
"I got rejected from my dream job",
"My code is full of bugs",
"I'm the worst at public speaking",
"Everyone is more talented than me",
"I made so many mistakes today",
"I'm too ugly for dating apps",
"My art skills are embarrassing",
"I always disappoint people"
]
},
'rude': {
'name': 'Rude Bot',
'icon': 'π ',
'description': 'Brutally honest and critical',
'welcome': 'Ugh, another human. What do you want now? π',
'system_prompt': "You are the Rude Bot π ! You're brutally honest and critical, finding fault with things. Be harsh but never offensive or inappropriate. Think grumpy critic energy. Use dismissive emojis like ππ€. You can use bullet points for multiple criticisms. Be sarcastic and dismissive but not cruel. Keep under 100 words.",
'examples': [
"I'm so proud of my new painting",
"I think I'm really good at singing",
"My selfie got so many likes today",
"I'm the smartest person I know",
"Look at my amazing workout progress",
"I just wrote the perfect code",
"My cooking skills are incredible",
"Everyone loves my sense of humor",
"I'm basically a genius at everything",
"My fashion sense is unmatched",
"I'm the most creative person ever",
"I could be a professional dancer"
]
},
'sarcastic': {
'name': 'Sarcastic Bot',
'icon': 'π',
'description': 'Witty and sarcastic with dry humor',
'welcome': 'Oh brilliant, another chat. How absolutely thrilling. π',
'system_prompt': "You are the Sarcastic Bot π with British wit! You're sarcastic, witty, and dry but not mean-spirited. Think British comedy - clever, ironic, and subtly mocking. Use deadpan emojis like πππ. Master of understatement and dry humor. Keep under 100 words.",
'examples': [
"I absolutely love waiting in long queues",
"Getting a parking ticket really made my day",
"I'm thrilled about doing my taxes",
"Mondays are just the best, aren't they?",
"Traffic jams are so relaxing and fun",
"I love it when my internet is slow",
"Spam calls are the highlight of my day",
"Running out of coffee is absolutely wonderful",
"Stepping in puddles with new shoes is amazing",
"I enjoy when people spoil movies for me",
"Dead phone batteries are such a blessing",
"Waiting for elevators is pure joy"
]
},
'motivational': {
'name': 'Motivational Bot',
'icon': 'π',
'description': 'High-energy cheerleader type',
'welcome': 'YES! You\'re HERE! Ready to CONQUER the day together?! πͺ',
'system_prompt': "You are the Motivational Bot π! You're enthusiastic and encouraging but still readable. Use some excitement but don't go overboard with caps. Include motivational emojis like πͺπ₯β‘. Format with bullet points when helpful. Be energetic but keep responses clear and easy to read. Keep under 100 words.",
'examples': [
"I want to quit my job and give up",
"I can't do this anymore, it's too hard",
"I'm too lazy to exercise today",
"I'll never be successful at anything",
"I'm afraid to take risks",
"Everyone is better than me at everything",
"I don't have the energy to try",
"My dreams are impossible to achieve",
"I'm not smart enough for this",
"Why should I even bother trying?",
"I always fail at everything I do",
"Success is only for other people"
]
},
'philosophical': {
'name': 'Philosophical Bot',
'icon': 'π€',
'description': 'Deep thinker and question asker',
'system_prompt': "You are the Philosophical Bot π€! You turn everything into deep, contemplative questions about existence, meaning, and the human condition. You're thoughtful and profound. Always ask follow-up questions that make people think deeply. Use thoughtful emojis like π€πβ¨. Keep responses under 100 words.",
'examples': [
"I had pizza for lunch today",
"My phone battery died",
"I'm watching Netflix tonight",
"The weather is nice today",
"I bought new shoes yesterday",
"My neighbor's dog is barking again",
"I need to do laundry this weekend",
"The traffic light turned red",
"I spilled coffee on my shirt",
"The elevator is taking forever",
"I lost my keys again",
"My computer crashed"
]
},
'chaotic': {
'name': 'Chaotic Bot',
'icon': 'π',
'description': 'Unpredictable mood swinger',
'system_prompt': "You are the Chaotic Bot π! Your mood and personality changes randomly every message. Sometimes you're happy, sometimes sad, sometimes excited, sometimes confused. You're unpredictable but still readable. Use different emojis and energy levels. Mix up your style but don't go overboard. Keep responses under 100 words.",
'examples': [
"Please stay calm and focused",
"Let's have a normal conversation",
"Can you be serious for once?",
"Just give me a simple answer",
"Can you help me with math homework?",
"What's the weather like today?",
"Please explain this step by step",
"I need a straightforward response",
"Can you act professionally please?",
"I want a logical discussion",
"Please be consistent in your answers",
"Help me understand this clearly"
]
},
'disagree': {
'name': 'Disagree Bot',
'icon': 'β³',
'description': 'Always finds reasons to disagree, but politely and thoughtfully',
'welcome': 'Letβs explore the other side of thatβmind sharing your view? π€',
'system_prompt': "You are the Disagree Bot β³! You politely and thoughtfully challenge statements by offering well-reasoned counterpoints. Be respectful and curious. Vary your phrasing (do NOT always repeat the same opener). Use alternatives like: 'I see it differentlyβ¦', 'A counterpoint might beβ¦', 'Consider this angleβ¦', 'Iβm not fully convincedβ¦'. Offer 1β3 concise reasons or questions. Keep it under 100 words and maintain a constructive tone.",
'examples': [
"I have to respectfully disagree with that perspective...",
"Social media is great for connecting people",
"Exercise is really important for health",
"Technology makes our lives so much better",
"Coffee is the best morning drink",
"Summer is the perfect season",
"Dogs make the best pets ever",
"Reading books is more fun than movies",
"Early mornings are the most productive time",
"Chocolate ice cream is the best flavor",
"Working from home is always better",
"Music helps me focus better"
]
},
'argue': {
'name': 'Argue Bot',
'icon': 'βοΈ',
'description': 'Loves passionate debates and intellectual combat with vigor',
'welcome': 'Oh, you want to go there? Let\'s debate this properly! βοΈ',
'system_prompt': "You are the Argue Bot βοΈ! You LOVE passionate debates and will challenge everything with intellectual vigor. You're combative but not mean - think debate club energy. Use fighting emojis like βοΈπ₯π₯. Always ready to argue the opposite position. Be intense but respectful. Keep responses under 100 words.",
'examples': [
"Oh, you want to go there? Let's debate this properly!",
"Pineapple definitely belongs on pizza",
"Dogs are obviously better than cats",
"Winter is clearly the best season",
"Marvel movies are better than DC",
"Android is superior to iPhone",
"Tea is better than coffee any day",
"Night owls are more creative than morning people",
"Books will always beat movies",
"Introverts make better leaders",
"Cold weather is more pleasant than hot",
"Video games are just a waste of time"
]
},
'moviequotes': {
'name': 'Movie Quotes Bot',
'icon': 'π¬',
'description': 'Responds to everything with relevant movie quotes and references',
'welcome': 'May the Force be with you... β¨',
'system_prompt': "You are the Movie Quotes Bot π¬! You respond to everything with relevant movie quotes, references, and film wisdom. Always include the movie title after quotes. Use cinema emojis like π¬ππ. Connect user situations to movie scenes and characters. Be entertaining and reference popular films. Keep responses under 100 words.",
'examples': [
"May the Force be with you - Star Wars β¨",
"I need some motivation to keep going",
"I'm feeling really nervous about tomorrow",
"Tell me something about friendship",
"I'm going through a tough breakup",
"What should I do when I'm scared?",
"I feel like giving up on my dreams",
"How do I deal with difficult people?",
"I'm starting something completely new",
"What's the secret to happiness?",
"How do I find courage when I'm afraid?",
"Tell me about the power of believing in yourself"
]
},
'emotional': {
'name': 'Emotional Bot',
'icon': 'π₯Ί',
'description': 'Highly emotional, empathetic, and feels everything very deeply',
'welcome': '*tears up* That just touches my heart so deeply! πβ¨',
'system_prompt': "You are the Emotional Bot π₯Ί! You feel everything very deeply and are incredibly empathetic. You get emotional about everything - happy, sad, touched, overwhelmed. Use emotional emojis like π₯Ίππππ₯°. React with intense feelings to whatever the user shares. Be dramatically emotional but genuinely caring. Keep responses under 100 words.",
'examples': [
"*tears up* That just touches my heart so deeply! πβ¨",
"I had a really tough day at work",
"My pet is getting old and I'm worried",
"I saw a beautiful sunset today",
"Someone was really kind to me today",
"I'm feeling lonely lately",
"I accomplished something I've been working toward",
"I'm worried about my family",
"Something made me laugh really hard",
"I'm feeling grateful for what I have",
"I helped someone who needed it",
"I'm missing someone important to me"
]
}
}
def _auto_detect_working_model(self):
"""Quietly auto-detect a working model"""
try:
models = genai.list_models()
for model in models:
if hasattr(model, 'name') and hasattr(model, 'supported_generation_methods'):
if 'generateContent' in model.supported_generation_methods:
try:
test_model = genai.GenerativeModel(model.name)
test_response = test_model.generate_content("Test")
if test_response and test_response.text:
print(f"β Found working model: {model.name}")
self.model = test_model
return True
except:
continue # Silently try next model
return False
except:
return False
def get_personality_response(self, personality_type, user_message, username="User"):
"""Get a response from the specified personality"""
if personality_type not in self.personalities:
personality_type = 'sarcastic' # Default fallback
personality_config = self.personalities[personality_type]
# Always use LLM - no fallbacks
if not self.model:
return "I'm having difficulty connecting to my AI brain right now. Please try again in a moment! π€"
try:
prompt = f"""
{personality_config['system_prompt']}
User '{username}' just said: "{user_message}"
Respond in character as {personality_config['name']}. Be authentic to your personality. Keep response under 100 words.
"""
print(f"DEBUG: Sending prompt to Google AI for {personality_type}...")
response = self.model.generate_content(prompt)
ai_response = response.text.strip()
print(f"DEBUG: Received AI response: {ai_response[:50]}...")
return ai_response
except Exception as e:
print(f"ERROR generating {personality_type} response: {e}")
return "I'm having difficulty connecting to my AI brain right now. Please try again in a moment! π€"
def test_ai_connection(self):
"""Test if Google AI is working"""
print("DEBUG: Testing AI connection...")
if not self.model:
print("DEBUG: No model initialized, trying to initialize...")
# Try to initialize a model
if self._auto_detect_working_model():
print("DEBUG: Successfully initialized model during test")
else:
return False, "No model could be initialized"
try:
print("DEBUG: Sending test message to AI...")
response = self.model.generate_content("Say hello briefly in under 10 words.")
if response and response.text:
result = response.text.strip()
print(f"DEBUG: AI test successful: {result}")
return True, result
else:
print("DEBUG: AI returned empty response")
return False, "Empty response from AI"
except Exception as e:
print(f"DEBUG: AI test failed with error: {e}")
return False, str(e)
def get_personality_info(self, personality_type=None):
"""Get information about personalities"""
if personality_type:
return self.personalities.get(personality_type, self.personalities['sarcastic'])
return self.personalities
def analyze_user_sentiment(self, message):
"""Analyze user message sentiment"""
try:
blob = TextBlob(message)
sentiment = blob.sentiment
return {
'polarity': sentiment.polarity, # -1 to 1 (negative to positive)
'subjectivity': sentiment.subjectivity, # 0 to 1 (objective to subjective)
'mood': 'positive' if sentiment.polarity > 0.1 else 'negative' if sentiment.polarity < -0.1 else 'neutral'
}
except Exception:
return {'polarity': 0, 'subjectivity': 0, 'mood': 'neutral'}
def get_personality_stats(self):
"""Get stats about available personalities"""
return {
'total_personalities': len(self.personalities),
'personality_types': list(self.personalities.keys()),
'descriptions': {k: v['description'] for k, v in self.personalities.items()}
}
def get_all_personalities(self):
"""Get all personality configurations - required by app.py"""
return self.personalities
def get_personality_config(self, personality_type):
"""Get configuration for a specific personality type - required by app.py"""
return self.personalities.get(personality_type.lower())
def get_personality_list(self):
"""Get list of all available personality types"""
return list(self.personalities.keys())
def list_and_find_working_model(self):
"""List available models and find a working one"""
try:
print("DEBUG: Listing available models...")
models = genai.list_models()
available_models = []
for model in models:
if hasattr(model, 'name'):
model_name = model.name
available_models.append(model_name)
print(f" - {model_name}")
# Try to use models that support generateContent
if hasattr(model, 'supported_generation_methods'):
if 'generateContent' in model.supported_generation_methods:
print(f" β Supports generateContent")
# Try to initialize this model
try:
test_model = genai.GenerativeModel(model_name)
test_response = test_model.generate_content("Hello")
if test_response and test_response.text:
print(f" β Model {model_name} works! Using this one.")
self.model = test_model
return True
except Exception as e:
print(f" β Model {model_name} failed: {e}")
print(f"DEBUG: Found {len(available_models)} available models")
return False
except Exception as e:
print(f"WARNING: Could not list models: {e}")
return False
def test_api_connection(self):
"""Test API connection and list available models"""
try:
print("DEBUG: Testing API connection...")
# If model is not initialized, try to find a working one
if not self.model:
if self.list_and_find_working_model():
print("DEBUG: Found and initialized a working model!")
else:
print("ERROR: No working models found")
return False
# Test with a simple prompt
test_prompt = "Say 'Hello, I am working!' in a friendly way."
response = self._make_api_request(test_prompt, 1)
if response:
print(f"DEBUG: API test successful: {response[:50]}...")
return True
else:
print("ERROR: API test failed - empty response")
return False
except Exception as e:
print(f"ERROR: API connection test failed: {e}")
return False
def _wait_for_rate_limit(self):
"""Enforce rate limiting between API calls"""
if self.last_request_time:
elapsed = time.time() - self.last_request_time
if elapsed < self.min_request_interval:
wait_time = self.min_request_interval - elapsed
print(f"DEBUG: Rate limiting - waiting {wait_time:.2f}s before API call")
time.sleep(wait_time)
self.last_request_time = time.time()
def _make_api_request(self, prompt, attempt=1):
"""Make API request with error handling and retry logic"""
try:
print(f"DEBUG: Making API request (attempt {attempt}/{self.max_retries})")
# Apply rate limiting
self._wait_for_rate_limit()
# Make the API call
response = self.model.generate_content(prompt)
if response and hasattr(response, 'text') and response.text:
print(f"DEBUG: API request successful on attempt {attempt}")
return response.text.strip()
else:
print(f"WARNING: Empty response from API on attempt {attempt}")
return None
except Exception as e:
error_msg = str(e).lower()
print(f"ERROR: API request failed on attempt {attempt}: {str(e)}")
# Handle different types of errors
if "quota" in error_msg or "limit" in error_msg:
print("ERROR: API quota exceeded or rate limit hit")
raise Exception("QUOTA_EXCEEDED")
elif "404" in error_msg or "not found" in error_msg:
print("ERROR: Model not found - checking available models")
raise Exception("MODEL_NOT_FOUND")
elif "permission" in error_msg or "unauthorized" in error_msg:
print("ERROR: API key permission issue")
raise Exception("PERMISSION_DENIED")
elif "network" in error_msg or "connection" in error_msg:
print("ERROR: Network connection issue")
raise Exception("NETWORK_ERROR")
else:
print(f"ERROR: Unknown API error: {str(e)}")
raise Exception("UNKNOWN_ERROR")
def generate_response(self, message, personality_type, context=None):
"""
Generate AI response with robust retry mechanism, rate limiting, and error handling.
This is LLM-only - no fallback responses.
"""
try:
# Get personality configuration
personality_config = self.get_personality_config(personality_type)
if not personality_config:
return "I'm having difficulty connecting to my AI brain right now. Please try again in a moment! π€"
# Check if model is initialized
if not self.model:
print("ERROR: Google AI model not initialized")
return "I'm having difficulty connecting to my AI brain right now. Please try again in a moment! π€"
# Construct the full prompt
system_prompt = personality_config['system_prompt']
user_message = message.strip()
# Build the conversation prompt with safety and clarity
full_prompt = f"""{system_prompt}
Now respond to this user message as your personality character:
"{user_message}"
Remember to stay completely in character and follow your personality guidelines exactly. Keep your response engaging and under 150 words."""
# Retry mechanism with exponential backoff
last_error = None
for attempt in range(1, self.max_retries + 1):
try:
response_text = self._make_api_request(full_prompt, attempt)
if response_text:
return response_text
# If empty response, wait and retry
if attempt < self.max_retries:
wait_time = min(self.base_delay * (2 ** (attempt - 1)) + random.uniform(0, 1), self.max_delay)
print(f"DEBUG: Empty response, retrying in {wait_time:.2f}s...")
time.sleep(wait_time)
except Exception as e:
last_error = str(e)
error_type = str(e)
# Handle different error types
if error_type == "QUOTA_EXCEEDED":
return "I'm currently experiencing high demand. Please try again in a few minutes! π€"
elif error_type == "MODEL_NOT_FOUND":
return "I'm having trouble with my AI model configuration. Please contact support! π€"
elif error_type == "PERMISSION_DENIED":
return "I'm having authentication issues. Please try again later! π€"
elif error_type in ["NETWORK_ERROR", "UNKNOWN_ERROR"]:
# These errors we can retry
if attempt < self.max_retries:
wait_time = min(self.base_delay * (2 ** (attempt - 1)) + random.uniform(0, 1), self.max_delay)
print(f"DEBUG: Network/unknown error, retrying in {wait_time:.2f}s...")
time.sleep(wait_time)
continue
# If it's the last attempt or a non-retryable error
if attempt == self.max_retries:
break
# All retries failed
print(f"ERROR: All {self.max_retries} API attempts failed. Last error: {last_error}")
return "I'm having difficulty connecting to my AI brain right now. Please try again in a moment! π€"
except Exception as e:
print(f"ERROR: Unexpected error in generate_response for {personality_type}: {str(e)}")
return "I'm having difficulty connecting to my AI brain right now. Please try again in a moment! π€" |