Spaces:
Sleeping
Sleeping
Upload 12 files
Browse files- api_service_enhanced.py +415 -66
- templates/ai_lead_analysis.html +7 -1
- templates/email_automation_dashboard.html +620 -0
api_service_enhanced.py
CHANGED
@@ -113,6 +113,11 @@ class EnhancedLeadQualificationAPI:
|
|
113 |
def customer_analysis(customer_id):
|
114 |
"""Customer analysis page with pre-filled customer ID"""
|
115 |
return render_template('ai_lead_analysis.html', customer_id=customer_id)
|
|
|
|
|
|
|
|
|
|
|
116 |
|
117 |
@self.app.route('/health')
|
118 |
def health():
|
@@ -2347,13 +2352,14 @@ class EnhancedLeadQualificationAPI:
|
|
2347 |
'error': f'Failed to send email: {str(e)}'
|
2348 |
}), 500
|
2349 |
|
2350 |
-
@self.app.route('/api/
|
2351 |
-
def
|
2352 |
-
"""
|
2353 |
-
logger.info(f"📧
|
2354 |
|
2355 |
try:
|
2356 |
data = request.get_json() or {}
|
|
|
2357 |
recipient_email = data.get('email')
|
2358 |
|
2359 |
if not recipient_email:
|
@@ -2370,7 +2376,7 @@ class EnhancedLeadQualificationAPI:
|
|
2370 |
'error': 'No customer data found'
|
2371 |
}), 404
|
2372 |
|
2373 |
-
# Get AI engine for
|
2374 |
ai_engine = self.get_ai_engine()
|
2375 |
if not ai_engine:
|
2376 |
return jsonify({
|
@@ -2378,47 +2384,182 @@ class EnhancedLeadQualificationAPI:
|
|
2378 |
'error': 'AI engine not available'
|
2379 |
}), 500
|
2380 |
|
2381 |
-
# Generate AI insights
|
2382 |
ai_insights = ai_engine.analyze_user_behavior_with_ai(analysis_data)
|
2383 |
|
2384 |
-
|
2385 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2386 |
|
2387 |
# Create email content
|
2388 |
-
subject = f"
|
2389 |
|
2390 |
-
# Format email body
|
2391 |
body_lines = [
|
2392 |
-
f"Dear Customer
|
|
|
|
|
2393 |
"",
|
2394 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2395 |
"",
|
2396 |
-
"
|
2397 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2398 |
f"• Decision Making Style: {ai_insights.get('decision_making_style', 'Data-driven')}",
|
2399 |
-
f"•
|
2400 |
-
f"• Urgency Level: {
|
2401 |
-
f"•
|
2402 |
"",
|
2403 |
-
"
|
2404 |
]
|
2405 |
|
2406 |
-
# Add
|
2407 |
if recommendations and 'properties' in recommendations:
|
2408 |
for i, prop in enumerate(recommendations['properties'][:5], 1):
|
2409 |
body_lines.extend([
|
2410 |
-
f"{i}. {prop.get('title', 'Property')}",
|
2411 |
-
f" Location: {prop.get('location', 'N/A')}",
|
2412 |
-
f" Price: ${prop.get('price', 0):,}",
|
2413 |
-
f" Match Score: {prop.get('match_score', 0):.1f}%",
|
|
|
2414 |
""
|
2415 |
])
|
2416 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2417 |
body_lines.extend([
|
2418 |
-
"💡 NEXT STEPS:",
|
2419 |
-
"• Review
|
2420 |
-
"• Schedule viewings
|
2421 |
-
"• Contact our
|
2422 |
"",
|
2423 |
"Best regards,",
|
2424 |
"AI-Powered Property Recommendation System"
|
@@ -2426,56 +2567,264 @@ class EnhancedLeadQualificationAPI:
|
|
2426 |
|
2427 |
email_body = "\n".join(body_lines)
|
2428 |
|
2429 |
-
# Send email
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2430 |
email_data = {
|
2431 |
'toEmail': recipient_email,
|
2432 |
'subject': subject,
|
2433 |
-
'body':
|
2434 |
}
|
2435 |
|
2436 |
external_api_url = 'https://hivepropapi.azurewebsites.net/api/Email/sendPlainText'
|
2437 |
|
2438 |
-
|
2439 |
-
|
2440 |
-
|
2441 |
-
|
2442 |
-
|
2443 |
-
|
2444 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2445 |
|
2446 |
-
|
2447 |
-
|
2448 |
-
|
2449 |
-
|
2450 |
-
|
2451 |
-
|
2452 |
-
|
2453 |
-
|
2454 |
-
|
2455 |
-
|
2456 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2457 |
})
|
2458 |
-
|
2459 |
-
|
2460 |
-
return jsonify({
|
2461 |
-
'success': False,
|
2462 |
-
'error': f'Email service failed: {response.status_code}',
|
2463 |
-
'details': response.text
|
2464 |
-
}), 500
|
2465 |
-
|
2466 |
-
except Exception as e:
|
2467 |
-
logger.error(f"❌ Email API error: {e}")
|
2468 |
-
return jsonify({
|
2469 |
-
'success': False,
|
2470 |
-
'error': f'Email service error: {str(e)}'
|
2471 |
-
}), 500
|
2472 |
|
2473 |
except Exception as e:
|
2474 |
-
logger.error(f"❌ Error
|
2475 |
-
return
|
2476 |
-
|
2477 |
-
|
2478 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2479 |
|
2480 |
# Helper methods for multi-AI system
|
2481 |
def _get_analysis_data_parallel(self, customer_id: int) -> Dict:
|
|
|
113 |
def customer_analysis(customer_id):
|
114 |
"""Customer analysis page with pre-filled customer ID"""
|
115 |
return render_template('ai_lead_analysis.html', customer_id=customer_id)
|
116 |
+
|
117 |
+
@self.app.route('/email-automation')
|
118 |
+
def email_automation_dashboard():
|
119 |
+
"""Email automation dashboard"""
|
120 |
+
return render_template('email_automation_dashboard.html')
|
121 |
|
122 |
@self.app.route('/health')
|
123 |
def health():
|
|
|
2352 |
'error': f'Failed to send email: {str(e)}'
|
2353 |
}), 500
|
2354 |
|
2355 |
+
@self.app.route('/api/email-automation/<int:customer_id>', methods=['POST'])
|
2356 |
+
def trigger_email_automation(customer_id):
|
2357 |
+
"""Trigger comprehensive email automation based on user tracking analysis"""
|
2358 |
+
logger.info(f"📧 Triggering email automation for customer {customer_id}")
|
2359 |
|
2360 |
try:
|
2361 |
data = request.get_json() or {}
|
2362 |
+
email_type = data.get('email_type', 'all') # 'all', 'new_properties', 'recommendations', 'peak_time'
|
2363 |
recipient_email = data.get('email')
|
2364 |
|
2365 |
if not recipient_email:
|
|
|
2376 |
'error': 'No customer data found'
|
2377 |
}), 404
|
2378 |
|
2379 |
+
# Get AI engine for analysis
|
2380 |
ai_engine = self.get_ai_engine()
|
2381 |
if not ai_engine:
|
2382 |
return jsonify({
|
|
|
2384 |
'error': 'AI engine not available'
|
2385 |
}), 500
|
2386 |
|
2387 |
+
# Generate AI insights from tracking data
|
2388 |
ai_insights = ai_engine.analyze_user_behavior_with_ai(analysis_data)
|
2389 |
|
2390 |
+
results = []
|
2391 |
+
|
2392 |
+
# Send different types of emails based on request
|
2393 |
+
if email_type in ['all', 'new_properties']:
|
2394 |
+
new_prop_result = self._send_new_properties_email(customer_id, recipient_email, analysis_data, ai_insights)
|
2395 |
+
results.append(new_prop_result)
|
2396 |
+
|
2397 |
+
if email_type in ['all', 'recommendations']:
|
2398 |
+
rec_result = self._send_ai_recommendations_email(customer_id, recipient_email, analysis_data, ai_insights)
|
2399 |
+
results.append(rec_result)
|
2400 |
+
|
2401 |
+
if email_type in ['all', 'peak_time']:
|
2402 |
+
peak_result = self._send_peak_time_engagement_email(customer_id, recipient_email, analysis_data, ai_insights)
|
2403 |
+
results.append(peak_result)
|
2404 |
+
|
2405 |
+
return jsonify({
|
2406 |
+
'success': True,
|
2407 |
+
'message': f'Email automation completed for customer {customer_id}',
|
2408 |
+
'customer_id': customer_id,
|
2409 |
+
'recipient': recipient_email,
|
2410 |
+
'email_type': email_type,
|
2411 |
+
'ai_insights': ai_insights,
|
2412 |
+
'results': results,
|
2413 |
+
'timestamp': datetime.now().isoformat()
|
2414 |
+
})
|
2415 |
+
|
2416 |
+
except Exception as e:
|
2417 |
+
logger.error(f"❌ Error in email automation: {e}")
|
2418 |
+
return jsonify({
|
2419 |
+
'success': False,
|
2420 |
+
'error': f'Email automation failed: {str(e)}'
|
2421 |
+
}), 500
|
2422 |
+
|
2423 |
+
def _send_new_properties_email(self, customer_id: int, recipient_email: str, analysis_data: Dict, ai_insights: Dict) -> Dict:
|
2424 |
+
"""Send email about newly added properties based on user tracking"""
|
2425 |
+
logger.info(f"🏡 Sending new properties email for customer {customer_id}")
|
2426 |
+
|
2427 |
+
try:
|
2428 |
+
# Analyze user preferences from tracking data
|
2429 |
+
user_preferences = self._analyze_user_preferences(analysis_data)
|
2430 |
+
|
2431 |
+
# Get newly added properties that match user preferences
|
2432 |
+
new_properties = self._get_new_properties_for_user(user_preferences)
|
2433 |
+
|
2434 |
+
if not new_properties:
|
2435 |
+
return {
|
2436 |
+
'type': 'new_properties',
|
2437 |
+
'success': False,
|
2438 |
+
'message': 'No new properties matching user preferences'
|
2439 |
+
}
|
2440 |
|
2441 |
# Create email content
|
2442 |
+
subject = f"🏡 New Properties Just Added - Perfect Matches for You!"
|
2443 |
|
|
|
2444 |
body_lines = [
|
2445 |
+
f"Dear Valued Customer,",
|
2446 |
+
"",
|
2447 |
+
"🎉 Great news! We've just added new properties that match your preferences perfectly!",
|
2448 |
"",
|
2449 |
+
"📊 YOUR PREFERENCES (Based on Your Activity):",
|
2450 |
+
f"• Preferred Property Type: {user_preferences.get('property_type', 'Villa')}",
|
2451 |
+
f"• Budget Range: ${user_preferences.get('min_budget', 0):,} - ${user_preferences.get('max_budget', 0):,}",
|
2452 |
+
f"• Preferred Locations: {', '.join(user_preferences.get('locations', ['Dubai']))}",
|
2453 |
+
f"• Bedrooms: {user_preferences.get('bedrooms', '3+')}",
|
2454 |
+
"",
|
2455 |
+
"🆕 NEWLY ADDED PROPERTIES:"
|
2456 |
+
]
|
2457 |
+
|
2458 |
+
# Add new properties
|
2459 |
+
for i, prop in enumerate(new_properties[:5], 1):
|
2460 |
+
body_lines.extend([
|
2461 |
+
f"{i}. {prop.get('title', 'New Property')}",
|
2462 |
+
f" 📍 Location: {prop.get('location', 'N/A')}",
|
2463 |
+
f" 💰 Price: ${prop.get('price', 0):,}",
|
2464 |
+
f" 🏠 Type: {prop.get('propertyTypeName', 'Villa')}",
|
2465 |
+
f" 🛏️ Bedrooms: {prop.get('bedrooms', 'N/A')}",
|
2466 |
+
f" ⭐ Match Score: {prop.get('match_score', 95):.0f}%",
|
2467 |
+
""
|
2468 |
+
])
|
2469 |
+
|
2470 |
+
body_lines.extend([
|
2471 |
+
"⚡ ACT FAST!",
|
2472 |
+
"These properties are fresh on the market and likely to be in high demand.",
|
2473 |
"",
|
2474 |
+
"💡 NEXT STEPS:",
|
2475 |
+
"• Schedule a viewing immediately",
|
2476 |
+
"• Contact our team for more details",
|
2477 |
+
"• Get pre-approval for faster processing",
|
2478 |
+
"",
|
2479 |
+
"Best regards,",
|
2480 |
+
"Your Property Match Team"
|
2481 |
+
])
|
2482 |
+
|
2483 |
+
email_body = "\n".join(body_lines)
|
2484 |
+
|
2485 |
+
# Send email
|
2486 |
+
result = self._send_email_via_api(recipient_email, subject, email_body)
|
2487 |
+
result['type'] = 'new_properties'
|
2488 |
+
result['properties_count'] = len(new_properties)
|
2489 |
+
|
2490 |
+
return result
|
2491 |
+
|
2492 |
+
except Exception as e:
|
2493 |
+
logger.error(f"❌ Error sending new properties email: {e}")
|
2494 |
+
return {
|
2495 |
+
'type': 'new_properties',
|
2496 |
+
'success': False,
|
2497 |
+
'error': str(e)
|
2498 |
+
}
|
2499 |
+
|
2500 |
+
def _send_ai_recommendations_email(self, customer_id: int, recipient_email: str, analysis_data: Dict, ai_insights: Dict) -> Dict:
|
2501 |
+
"""Send AI-powered recommendations based on user tracking analysis"""
|
2502 |
+
logger.info(f"🤖 Sending AI recommendations email for customer {customer_id}")
|
2503 |
+
|
2504 |
+
try:
|
2505 |
+
# Get AI engine for recommendations
|
2506 |
+
ai_engine = self.get_ai_engine()
|
2507 |
+
if not ai_engine:
|
2508 |
+
return {
|
2509 |
+
'type': 'ai_recommendations',
|
2510 |
+
'success': False,
|
2511 |
+
'error': 'AI engine not available'
|
2512 |
+
}
|
2513 |
+
|
2514 |
+
# Generate recommendations based on tracking data
|
2515 |
+
recommendations = ai_engine.generate_property_recommendations(analysis_data, ai_insights)
|
2516 |
+
|
2517 |
+
# Create personalized email content
|
2518 |
+
personality_type = ai_insights.get('personality_type', 'Analytical')
|
2519 |
+
urgency_level = ai_insights.get('urgency_level', 'Medium')
|
2520 |
+
|
2521 |
+
subject = f"🤖 AI-Powered Recommendations - Tailored Just for You!"
|
2522 |
+
|
2523 |
+
body_lines = [
|
2524 |
+
f"Dear Valued Customer,",
|
2525 |
+
"",
|
2526 |
+
"🧠 Our AI has analyzed your browsing behavior and preferences to bring you these personalized recommendations:",
|
2527 |
+
"",
|
2528 |
+
"📊 YOUR BEHAVIOR ANALYSIS:",
|
2529 |
+
f"• Personality Type: {personality_type}",
|
2530 |
f"• Decision Making Style: {ai_insights.get('decision_making_style', 'Data-driven')}",
|
2531 |
+
f"• Engagement Level: {ai_insights.get('engagement_level', 'High')}",
|
2532 |
+
f"• Urgency Level: {urgency_level}",
|
2533 |
+
f"• Peak Activity Time: {ai_insights.get('peak_time', 'Evening')}",
|
2534 |
"",
|
2535 |
+
"🎯 AI RECOMMENDATIONS:"
|
2536 |
]
|
2537 |
|
2538 |
+
# Add AI recommendations
|
2539 |
if recommendations and 'properties' in recommendations:
|
2540 |
for i, prop in enumerate(recommendations['properties'][:5], 1):
|
2541 |
body_lines.extend([
|
2542 |
+
f"{i}. {prop.get('title', 'Recommended Property')}",
|
2543 |
+
f" 📍 Location: {prop.get('location', 'N/A')}",
|
2544 |
+
f" 💰 Price: ${prop.get('price', 0):,}",
|
2545 |
+
f" 🎯 AI Match Score: {prop.get('match_score', 0):.1f}%",
|
2546 |
+
f" 💡 Why Recommended: {prop.get('recommendation_reason', 'Matches your preferences')}",
|
2547 |
""
|
2548 |
])
|
2549 |
|
2550 |
+
# Add urgency-based call to action
|
2551 |
+
if urgency_level == 'High':
|
2552 |
+
body_lines.extend([
|
2553 |
+
"🔥 URGENT RECOMMENDATION:",
|
2554 |
+
"Based on your high engagement, we recommend acting quickly on these properties!",
|
2555 |
+
""
|
2556 |
+
])
|
2557 |
+
|
2558 |
body_lines.extend([
|
2559 |
+
"💡 PERSONALIZED NEXT STEPS:",
|
2560 |
+
"• Review properties that match your personality type",
|
2561 |
+
"• Schedule viewings during your peak activity time",
|
2562 |
+
"• Contact our AI-powered assistant for more details",
|
2563 |
"",
|
2564 |
"Best regards,",
|
2565 |
"AI-Powered Property Recommendation System"
|
|
|
2567 |
|
2568 |
email_body = "\n".join(body_lines)
|
2569 |
|
2570 |
+
# Send email
|
2571 |
+
result = self._send_email_via_api(recipient_email, subject, email_body)
|
2572 |
+
result['type'] = 'ai_recommendations'
|
2573 |
+
result['ai_insights'] = ai_insights
|
2574 |
+
result['recommendations_count'] = len(recommendations.get('properties', [])) if recommendations else 0
|
2575 |
+
|
2576 |
+
return result
|
2577 |
+
|
2578 |
+
except Exception as e:
|
2579 |
+
logger.error(f"❌ Error sending AI recommendations email: {e}")
|
2580 |
+
return {
|
2581 |
+
'type': 'ai_recommendations',
|
2582 |
+
'success': False,
|
2583 |
+
'error': str(e)
|
2584 |
+
}
|
2585 |
+
|
2586 |
+
def _send_peak_time_engagement_email(self, customer_id: int, recipient_email: str, analysis_data: Dict, ai_insights: Dict) -> Dict:
|
2587 |
+
"""Send email during user's peak engagement time"""
|
2588 |
+
logger.info(f"⏰ Sending peak time engagement email for customer {customer_id}")
|
2589 |
+
|
2590 |
+
try:
|
2591 |
+
# Analyze peak time from tracking data
|
2592 |
+
peak_time = ai_insights.get('peak_time', 'Evening')
|
2593 |
+
engagement_level = ai_insights.get('engagement_level', 'High')
|
2594 |
+
|
2595 |
+
# Create time-sensitive email content
|
2596 |
+
subject = f"⏰ Perfect Time to Explore Properties - Based on Your Activity Pattern!"
|
2597 |
+
|
2598 |
+
body_lines = [
|
2599 |
+
f"Dear Valued Customer,",
|
2600 |
+
"",
|
2601 |
+
f"⏰ We've noticed you're most active during {peak_time} hours!",
|
2602 |
+
f"Your engagement level: {engagement_level}",
|
2603 |
+
"",
|
2604 |
+
"📈 OPTIMAL VIEWING TIME:",
|
2605 |
+
f"• Your Peak Activity: {peak_time}",
|
2606 |
+
f"• Best Time for Property Tours: {self._get_optimal_viewing_time(peak_time)}",
|
2607 |
+
f"• Recommended Action Time: {self._get_recommended_action_time(peak_time)}",
|
2608 |
+
"",
|
2609 |
+
"🎯 TIME-SENSITIVE OPPORTUNITIES:"
|
2610 |
+
]
|
2611 |
+
|
2612 |
+
# Get time-sensitive properties
|
2613 |
+
time_sensitive_props = self._get_time_sensitive_properties(analysis_data)
|
2614 |
+
|
2615 |
+
for i, prop in enumerate(time_sensitive_props[:3], 1):
|
2616 |
+
body_lines.extend([
|
2617 |
+
f"{i}. {prop.get('title', 'Time-Sensitive Property')}",
|
2618 |
+
f" 📍 Location: {prop.get('location', 'N/A')}",
|
2619 |
+
f" 💰 Price: ${prop.get('price', 0):,}",
|
2620 |
+
f" ⏰ Best Viewing Time: {prop.get('optimal_time', peak_time)}",
|
2621 |
+
f" 🚨 Urgency: {prop.get('urgency', 'Medium')}",
|
2622 |
+
""
|
2623 |
+
])
|
2624 |
+
|
2625 |
+
body_lines.extend([
|
2626 |
+
"💡 PEAK TIME STRATEGY:",
|
2627 |
+
f"• Schedule viewings during {peak_time} for maximum engagement",
|
2628 |
+
"• Take advantage of your high focus period",
|
2629 |
+
"• Make decisions when you're most alert",
|
2630 |
+
"",
|
2631 |
+
"📞 IMMEDIATE ACTION:",
|
2632 |
+
"• Call now to schedule a viewing",
|
2633 |
+
"• Get priority booking during your peak time",
|
2634 |
+
"• Receive personalized assistance",
|
2635 |
+
"",
|
2636 |
+
"Best regards,",
|
2637 |
+
"Your Peak Time Property Team"
|
2638 |
+
])
|
2639 |
+
|
2640 |
+
email_body = "\n".join(body_lines)
|
2641 |
+
|
2642 |
+
# Send email
|
2643 |
+
result = self._send_email_via_api(recipient_email, subject, email_body)
|
2644 |
+
result['type'] = 'peak_time_engagement'
|
2645 |
+
result['peak_time'] = peak_time
|
2646 |
+
result['engagement_level'] = engagement_level
|
2647 |
+
|
2648 |
+
return result
|
2649 |
+
|
2650 |
+
except Exception as e:
|
2651 |
+
logger.error(f"❌ Error sending peak time engagement email: {e}")
|
2652 |
+
return {
|
2653 |
+
'type': 'peak_time_engagement',
|
2654 |
+
'success': False,
|
2655 |
+
'error': str(e)
|
2656 |
+
}
|
2657 |
+
|
2658 |
+
def _send_email_via_api(self, recipient_email: str, subject: str, body: str) -> Dict:
|
2659 |
+
"""Send email using the external API"""
|
2660 |
+
try:
|
2661 |
email_data = {
|
2662 |
'toEmail': recipient_email,
|
2663 |
'subject': subject,
|
2664 |
+
'body': body
|
2665 |
}
|
2666 |
|
2667 |
external_api_url = 'https://hivepropapi.azurewebsites.net/api/Email/sendPlainText'
|
2668 |
|
2669 |
+
logger.info(f"🌐 Sending email via external API to {recipient_email}")
|
2670 |
+
response = requests.post(
|
2671 |
+
external_api_url,
|
2672 |
+
params=email_data,
|
2673 |
+
timeout=30
|
2674 |
+
)
|
2675 |
+
|
2676 |
+
if response.status_code == 200:
|
2677 |
+
logger.info(f"✅ Email sent successfully to {recipient_email}")
|
2678 |
+
return {
|
2679 |
+
'success': True,
|
2680 |
+
'message': 'Email sent successfully',
|
2681 |
+
'recipient': recipient_email,
|
2682 |
+
'subject': subject
|
2683 |
+
}
|
2684 |
+
else:
|
2685 |
+
logger.error(f"❌ External email API failed: {response.status_code} - {response.text}")
|
2686 |
+
return {
|
2687 |
+
'success': False,
|
2688 |
+
'error': f'Email service failed: {response.status_code}',
|
2689 |
+
'details': response.text
|
2690 |
+
}
|
2691 |
|
2692 |
+
except Exception as e:
|
2693 |
+
logger.error(f"❌ Email API error: {e}")
|
2694 |
+
return {
|
2695 |
+
'success': False,
|
2696 |
+
'error': f'Email service error: {str(e)}'
|
2697 |
+
}
|
2698 |
+
|
2699 |
+
def _analyze_user_preferences(self, analysis_data: Dict) -> Dict:
|
2700 |
+
"""Analyze user preferences from tracking data"""
|
2701 |
+
try:
|
2702 |
+
# Extract preferences from analysis data
|
2703 |
+
preferences = {
|
2704 |
+
'property_type': 'Villa', # Default
|
2705 |
+
'min_budget': 500000,
|
2706 |
+
'max_budget': 2000000,
|
2707 |
+
'locations': ['Dubai', 'Abu Dhabi'],
|
2708 |
+
'bedrooms': '3+',
|
2709 |
+
'price_range': '500K-2M'
|
2710 |
+
}
|
2711 |
+
|
2712 |
+
# Analyze from tracking data if available
|
2713 |
+
if 'data' in analysis_data and 'analytics' in analysis_data['data']:
|
2714 |
+
analytics = analysis_data['data']['analytics']
|
2715 |
+
|
2716 |
+
# Extract property type preferences
|
2717 |
+
if 'property_types' in analytics:
|
2718 |
+
most_viewed = max(analytics['property_types'].items(), key=lambda x: x[1])
|
2719 |
+
preferences['property_type'] = most_viewed[0]
|
2720 |
+
|
2721 |
+
# Extract budget preferences
|
2722 |
+
if 'price_ranges' in analytics:
|
2723 |
+
most_viewed = max(analytics['price_ranges'].items(), key=lambda x: x[1])
|
2724 |
+
preferences['price_range'] = most_viewed[0]
|
2725 |
+
|
2726 |
+
# Extract location preferences
|
2727 |
+
if 'locations' in analytics:
|
2728 |
+
top_locations = sorted(analytics['locations'].items(), key=lambda x: x[1], reverse=True)[:3]
|
2729 |
+
preferences['locations'] = [loc[0] for loc in top_locations]
|
2730 |
+
|
2731 |
+
return preferences
|
2732 |
+
|
2733 |
+
except Exception as e:
|
2734 |
+
logger.error(f"❌ Error analyzing user preferences: {e}")
|
2735 |
+
return {
|
2736 |
+
'property_type': 'Villa',
|
2737 |
+
'min_budget': 500000,
|
2738 |
+
'max_budget': 2000000,
|
2739 |
+
'locations': ['Dubai'],
|
2740 |
+
'bedrooms': '3+'
|
2741 |
+
}
|
2742 |
+
|
2743 |
+
def _get_new_properties_for_user(self, user_preferences: Dict) -> List[Dict]:
|
2744 |
+
"""Get newly added properties that match user preferences"""
|
2745 |
+
try:
|
2746 |
+
# This would typically fetch from a database of new properties
|
2747 |
+
# For now, we'll generate mock new properties based on preferences
|
2748 |
+
|
2749 |
+
property_type = user_preferences.get('property_type', 'Villa')
|
2750 |
+
locations = user_preferences.get('locations', ['Dubai'])
|
2751 |
+
min_budget = user_preferences.get('min_budget', 500000)
|
2752 |
+
max_budget = user_preferences.get('max_budget', 2000000)
|
2753 |
+
|
2754 |
+
new_properties = []
|
2755 |
+
|
2756 |
+
# Generate mock new properties
|
2757 |
+
for i, location in enumerate(locations[:2]):
|
2758 |
+
price = min_budget + (i * 300000)
|
2759 |
+
if price <= max_budget:
|
2760 |
+
new_properties.append({
|
2761 |
+
'title': f'New {property_type} in {location}',
|
2762 |
+
'location': location,
|
2763 |
+
'price': price,
|
2764 |
+
'propertyTypeName': property_type,
|
2765 |
+
'bedrooms': '3+',
|
2766 |
+
'match_score': 95 + i,
|
2767 |
+
'is_new': True,
|
2768 |
+
'added_date': datetime.now().strftime('%Y-%m-%d')
|
2769 |
})
|
2770 |
+
|
2771 |
+
return new_properties
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2772 |
|
2773 |
except Exception as e:
|
2774 |
+
logger.error(f"❌ Error getting new properties: {e}")
|
2775 |
+
return []
|
2776 |
+
|
2777 |
+
def _get_optimal_viewing_time(self, peak_time: str) -> str:
|
2778 |
+
"""Get optimal viewing time based on peak activity"""
|
2779 |
+
time_mapping = {
|
2780 |
+
'Morning': '9:00 AM - 11:00 AM',
|
2781 |
+
'Afternoon': '2:00 PM - 4:00 PM',
|
2782 |
+
'Evening': '6:00 PM - 8:00 PM',
|
2783 |
+
'Night': '7:00 PM - 9:00 PM'
|
2784 |
+
}
|
2785 |
+
return time_mapping.get(peak_time, '6:00 PM - 8:00 PM')
|
2786 |
+
|
2787 |
+
def _get_recommended_action_time(self, peak_time: str) -> str:
|
2788 |
+
"""Get recommended action time based on peak activity"""
|
2789 |
+
time_mapping = {
|
2790 |
+
'Morning': '10:00 AM - 12:00 PM',
|
2791 |
+
'Afternoon': '3:00 PM - 5:00 PM',
|
2792 |
+
'Evening': '7:00 PM - 9:00 PM',
|
2793 |
+
'Night': '8:00 PM - 10:00 PM'
|
2794 |
+
}
|
2795 |
+
return time_mapping.get(peak_time, '7:00 PM - 9:00 PM')
|
2796 |
+
|
2797 |
+
def _get_time_sensitive_properties(self, analysis_data: Dict) -> List[Dict]:
|
2798 |
+
"""Get time-sensitive properties based on analysis"""
|
2799 |
+
try:
|
2800 |
+
# Generate time-sensitive properties
|
2801 |
+
return [
|
2802 |
+
{
|
2803 |
+
'title': 'Limited Time Offer - Premium Villa',
|
2804 |
+
'location': 'Dubai Marina',
|
2805 |
+
'price': 1500000,
|
2806 |
+
'optimal_time': 'Evening',
|
2807 |
+
'urgency': 'High'
|
2808 |
+
},
|
2809 |
+
{
|
2810 |
+
'title': 'Flash Sale - Luxury Apartment',
|
2811 |
+
'location': 'Downtown Dubai',
|
2812 |
+
'price': 800000,
|
2813 |
+
'optimal_time': 'Afternoon',
|
2814 |
+
'urgency': 'Very High'
|
2815 |
+
},
|
2816 |
+
{
|
2817 |
+
'title': 'Exclusive Preview - New Development',
|
2818 |
+
'location': 'Palm Jumeirah',
|
2819 |
+
'price': 2500000,
|
2820 |
+
'optimal_time': 'Morning',
|
2821 |
+
'urgency': 'Medium'
|
2822 |
+
}
|
2823 |
+
]
|
2824 |
+
|
2825 |
+
except Exception as e:
|
2826 |
+
logger.error(f"❌ Error getting time-sensitive properties: {e}")
|
2827 |
+
return []
|
2828 |
|
2829 |
# Helper methods for multi-AI system
|
2830 |
def _get_analysis_data_parallel(self, customer_id: int) -> Dict:
|
templates/ai_lead_analysis.html
CHANGED
@@ -519,7 +519,13 @@
|
|
519 |
<p>Advanced Customer Behavior Analytics with Multi-AI Recommendations</p>
|
520 |
<div class="ai-badge">
|
521 |
<i class="fas fa-brain"></i> Powered by Multiple AI Models
|
522 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
523 |
</div>
|
524 |
|
525 |
<!-- Search Section -->
|
|
|
519 |
<p>Advanced Customer Behavior Analytics with Multi-AI Recommendations</p>
|
520 |
<div class="ai-badge">
|
521 |
<i class="fas fa-brain"></i> Powered by Multiple AI Models
|
522 |
+
</div>
|
523 |
+
<div class="mt-4">
|
524 |
+
<a href="/email-automation" class="btn btn-light btn-lg">
|
525 |
+
<i class="fas fa-envelope-open-text me-2"></i>
|
526 |
+
Email Automation Dashboard
|
527 |
+
</a>
|
528 |
+
</div>
|
529 |
</div>
|
530 |
|
531 |
<!-- Search Section -->
|
templates/email_automation_dashboard.html
ADDED
@@ -0,0 +1,620 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!DOCTYPE html>
|
2 |
+
<html lang="en">
|
3 |
+
<head>
|
4 |
+
<meta charset="UTF-8">
|
5 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
6 |
+
<title>Email Automation Dashboard - Lead Qualification</title>
|
7 |
+
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet">
|
8 |
+
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
|
9 |
+
<style>
|
10 |
+
.dashboard-card {
|
11 |
+
border: none;
|
12 |
+
border-radius: 15px;
|
13 |
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
14 |
+
transition: transform 0.3s ease;
|
15 |
+
}
|
16 |
+
.dashboard-card:hover {
|
17 |
+
transform: translateY(-5px);
|
18 |
+
}
|
19 |
+
.email-type-card {
|
20 |
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
21 |
+
color: white;
|
22 |
+
}
|
23 |
+
.new-properties-card {
|
24 |
+
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
|
25 |
+
color: white;
|
26 |
+
}
|
27 |
+
.ai-recommendations-card {
|
28 |
+
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
29 |
+
color: white;
|
30 |
+
}
|
31 |
+
.peak-time-card {
|
32 |
+
background: linear-gradient(135deg, #43e97b 0%, #38f9d7 100%);
|
33 |
+
color: white;
|
34 |
+
}
|
35 |
+
.status-indicator {
|
36 |
+
width: 12px;
|
37 |
+
height: 12px;
|
38 |
+
border-radius: 50%;
|
39 |
+
display: inline-block;
|
40 |
+
margin-right: 8px;
|
41 |
+
}
|
42 |
+
.status-success { background-color: #28a745; }
|
43 |
+
.status-warning { background-color: #ffc107; }
|
44 |
+
.status-error { background-color: #dc3545; }
|
45 |
+
.email-preview {
|
46 |
+
background-color: #f8f9fa;
|
47 |
+
border-radius: 10px;
|
48 |
+
padding: 20px;
|
49 |
+
margin-top: 20px;
|
50 |
+
font-family: 'Courier New', monospace;
|
51 |
+
font-size: 14px;
|
52 |
+
white-space: pre-line;
|
53 |
+
}
|
54 |
+
.customer-selector {
|
55 |
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
56 |
+
color: white;
|
57 |
+
border-radius: 15px;
|
58 |
+
padding: 20px;
|
59 |
+
margin-bottom: 30px;
|
60 |
+
}
|
61 |
+
.btn-email-action {
|
62 |
+
border-radius: 25px;
|
63 |
+
padding: 10px 25px;
|
64 |
+
font-weight: 600;
|
65 |
+
text-transform: uppercase;
|
66 |
+
letter-spacing: 1px;
|
67 |
+
}
|
68 |
+
.analytics-chart {
|
69 |
+
background: white;
|
70 |
+
border-radius: 15px;
|
71 |
+
padding: 20px;
|
72 |
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
73 |
+
}
|
74 |
+
</style>
|
75 |
+
</head>
|
76 |
+
<body>
|
77 |
+
<div class="container-fluid">
|
78 |
+
<!-- Header -->
|
79 |
+
<div class="row mb-4">
|
80 |
+
<div class="col-12">
|
81 |
+
<div class="customer-selector">
|
82 |
+
<h2><i class="fas fa-envelope-open-text"></i> Email Automation Dashboard</h2>
|
83 |
+
<p class="mb-0">AI-Powered Email System Based on User Tracking Analysis</p>
|
84 |
+
</div>
|
85 |
+
</div>
|
86 |
+
</div>
|
87 |
+
|
88 |
+
<!-- Customer Selection -->
|
89 |
+
<div class="row mb-4">
|
90 |
+
<div class="col-md-6">
|
91 |
+
<div class="card dashboard-card">
|
92 |
+
<div class="card-body">
|
93 |
+
<h5 class="card-title"><i class="fas fa-user"></i> Select Customer</h5>
|
94 |
+
<div class="mb-3">
|
95 |
+
<label for="customerId" class="form-label">Customer ID</label>
|
96 |
+
<input type="number" class="form-control" id="customerId" placeholder="Enter Customer ID" value="12345">
|
97 |
+
</div>
|
98 |
+
<div class="mb-3">
|
99 |
+
<label for="customerEmail" class="form-label">Email Address</label>
|
100 |
+
<input type="email" class="form-control" id="customerEmail" placeholder="[email protected]" value="[email protected]">
|
101 |
+
</div>
|
102 |
+
<button class="btn btn-primary btn-email-action" onclick="loadCustomerData()">
|
103 |
+
<i class="fas fa-search"></i> Load Customer Data
|
104 |
+
</button>
|
105 |
+
</div>
|
106 |
+
</div>
|
107 |
+
</div>
|
108 |
+
<div class="col-md-6">
|
109 |
+
<div class="card dashboard-card">
|
110 |
+
<div class="card-body">
|
111 |
+
<h5 class="card-title"><i class="fas fa-chart-line"></i> Customer Analytics</h5>
|
112 |
+
<div id="customerAnalytics">
|
113 |
+
<p class="text-muted">Select a customer to view analytics</p>
|
114 |
+
</div>
|
115 |
+
</div>
|
116 |
+
</div>
|
117 |
+
</div>
|
118 |
+
</div>
|
119 |
+
|
120 |
+
<!-- Email Types -->
|
121 |
+
<div class="row mb-4">
|
122 |
+
<div class="col-12">
|
123 |
+
<h4><i class="fas fa-envelope"></i> Email Automation Types</h4>
|
124 |
+
</div>
|
125 |
+
</div>
|
126 |
+
|
127 |
+
<div class="row mb-4">
|
128 |
+
<!-- New Properties Email -->
|
129 |
+
<div class="col-md-4 mb-3">
|
130 |
+
<div class="card dashboard-card new-properties-card">
|
131 |
+
<div class="card-body text-center">
|
132 |
+
<i class="fas fa-home fa-3x mb-3"></i>
|
133 |
+
<h5 class="card-title">New Properties Alert</h5>
|
134 |
+
<p class="card-text">Send notifications about newly added properties that match user preferences</p>
|
135 |
+
<button class="btn btn-light btn-email-action" onclick="sendNewPropertiesEmail()">
|
136 |
+
<i class="fas fa-paper-plane"></i> Send Email
|
137 |
+
</button>
|
138 |
+
</div>
|
139 |
+
</div>
|
140 |
+
</div>
|
141 |
+
|
142 |
+
<!-- AI Recommendations Email -->
|
143 |
+
<div class="col-md-4 mb-3">
|
144 |
+
<div class="card dashboard-card ai-recommendations-card">
|
145 |
+
<div class="card-body text-center">
|
146 |
+
<i class="fas fa-robot fa-3x mb-3"></i>
|
147 |
+
<h5 class="card-title">AI Recommendations</h5>
|
148 |
+
<p class="card-text">Send personalized recommendations based on AI analysis of user behavior</p>
|
149 |
+
<button class="btn btn-light btn-email-action" onclick="sendAIRecommendationsEmail()">
|
150 |
+
<i class="fas fa-paper-plane"></i> Send Email
|
151 |
+
</button>
|
152 |
+
</div>
|
153 |
+
</div>
|
154 |
+
</div>
|
155 |
+
|
156 |
+
<!-- Peak Time Engagement Email -->
|
157 |
+
<div class="col-md-4 mb-3">
|
158 |
+
<div class="card dashboard-card peak-time-card">
|
159 |
+
<div class="card-body text-center">
|
160 |
+
<i class="fas fa-clock fa-3x mb-3"></i>
|
161 |
+
<h5 class="card-title">Peak Time Engagement</h5>
|
162 |
+
<p class="card-text">Send emails during user's most active viewing time for maximum engagement</p>
|
163 |
+
<button class="btn btn-light btn-email-action" onclick="sendPeakTimeEmail()">
|
164 |
+
<i class="fas fa-paper-plane"></i> Send Email
|
165 |
+
</button>
|
166 |
+
</div>
|
167 |
+
</div>
|
168 |
+
</div>
|
169 |
+
</div>
|
170 |
+
|
171 |
+
<!-- Send All Emails -->
|
172 |
+
<div class="row mb-4">
|
173 |
+
<div class="col-12">
|
174 |
+
<div class="card dashboard-card email-type-card">
|
175 |
+
<div class="card-body text-center">
|
176 |
+
<i class="fas fa-rocket fa-3x mb-3"></i>
|
177 |
+
<h4 class="card-title">Complete Email Automation</h4>
|
178 |
+
<p class="card-text">Send all three types of emails based on comprehensive user tracking analysis</p>
|
179 |
+
<button class="btn btn-light btn-email-action btn-lg" onclick="sendAllEmails()">
|
180 |
+
<i class="fas fa-rocket"></i> Send All Emails
|
181 |
+
</button>
|
182 |
+
</div>
|
183 |
+
</div>
|
184 |
+
</div>
|
185 |
+
</div>
|
186 |
+
|
187 |
+
<!-- Email Status and Results -->
|
188 |
+
<div class="row mb-4">
|
189 |
+
<div class="col-12">
|
190 |
+
<div class="card dashboard-card">
|
191 |
+
<div class="card-body">
|
192 |
+
<h5 class="card-title"><i class="fas fa-tasks"></i> Email Status & Results</h5>
|
193 |
+
<div id="emailResults">
|
194 |
+
<p class="text-muted">Email results will appear here</p>
|
195 |
+
</div>
|
196 |
+
</div>
|
197 |
+
</div>
|
198 |
+
</div>
|
199 |
+
</div>
|
200 |
+
|
201 |
+
<!-- Email Preview -->
|
202 |
+
<div class="row mb-4">
|
203 |
+
<div class="col-12">
|
204 |
+
<div class="card dashboard-card">
|
205 |
+
<div class="card-body">
|
206 |
+
<h5 class="card-title"><i class="fas fa-eye"></i> Email Preview</h5>
|
207 |
+
<div id="emailPreview" class="email-preview">
|
208 |
+
<p class="text-muted">Email preview will appear here</p>
|
209 |
+
</div>
|
210 |
+
</div>
|
211 |
+
</div>
|
212 |
+
</div>
|
213 |
+
</div>
|
214 |
+
|
215 |
+
<!-- Analytics Charts -->
|
216 |
+
<div class="row mb-4">
|
217 |
+
<div class="col-md-6">
|
218 |
+
<div class="analytics-chart">
|
219 |
+
<h5><i class="fas fa-chart-pie"></i> Email Performance</h5>
|
220 |
+
<canvas id="emailPerformanceChart" width="400" height="200"></canvas>
|
221 |
+
</div>
|
222 |
+
</div>
|
223 |
+
<div class="col-md-6">
|
224 |
+
<div class="analytics-chart">
|
225 |
+
<h5><i class="fas fa-chart-bar"></i> User Engagement</h5>
|
226 |
+
<canvas id="engagementChart" width="400" height="200"></canvas>
|
227 |
+
</div>
|
228 |
+
</div>
|
229 |
+
</div>
|
230 |
+
</div>
|
231 |
+
|
232 |
+
<!-- Loading Modal -->
|
233 |
+
<div class="modal fade" id="loadingModal" tabindex="-1" aria-hidden="true">
|
234 |
+
<div class="modal-dialog modal-dialog-centered">
|
235 |
+
<div class="modal-content">
|
236 |
+
<div class="modal-body text-center">
|
237 |
+
<div class="spinner-border text-primary mb-3" role="status">
|
238 |
+
<span class="visually-hidden">Loading...</span>
|
239 |
+
</div>
|
240 |
+
<h5>Processing Email Automation...</h5>
|
241 |
+
<p class="text-muted">Analyzing user data and sending emails</p>
|
242 |
+
</div>
|
243 |
+
</div>
|
244 |
+
</div>
|
245 |
+
</div>
|
246 |
+
|
247 |
+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
|
248 |
+
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
249 |
+
<script>
|
250 |
+
let currentCustomerId = null;
|
251 |
+
let currentEmail = null;
|
252 |
+
|
253 |
+
// Load customer data
|
254 |
+
async function loadCustomerData() {
|
255 |
+
const customerId = document.getElementById('customerId').value;
|
256 |
+
const email = document.getElementById('customerEmail').value;
|
257 |
+
|
258 |
+
if (!customerId || !email) {
|
259 |
+
alert('Please enter both Customer ID and Email address');
|
260 |
+
return;
|
261 |
+
}
|
262 |
+
|
263 |
+
currentCustomerId = customerId;
|
264 |
+
currentEmail = email;
|
265 |
+
|
266 |
+
try {
|
267 |
+
const response = await fetch(`/api/lead-analysis/${customerId}`);
|
268 |
+
const data = await response.json();
|
269 |
+
|
270 |
+
if (data.success) {
|
271 |
+
displayCustomerAnalytics(data);
|
272 |
+
showSuccess('Customer data loaded successfully!');
|
273 |
+
} else {
|
274 |
+
showError('Failed to load customer data: ' + data.error);
|
275 |
+
}
|
276 |
+
} catch (error) {
|
277 |
+
showError('Error loading customer data: ' + error.message);
|
278 |
+
}
|
279 |
+
}
|
280 |
+
|
281 |
+
// Display customer analytics
|
282 |
+
function displayCustomerAnalytics(data) {
|
283 |
+
const analyticsDiv = document.getElementById('customerAnalytics');
|
284 |
+
|
285 |
+
if (data.data && data.data.analytics) {
|
286 |
+
const analytics = data.data.analytics;
|
287 |
+
analyticsDiv.innerHTML = `
|
288 |
+
<div class="row">
|
289 |
+
<div class="col-6">
|
290 |
+
<small class="text-muted">Properties Viewed:</small>
|
291 |
+
<h6>${analytics.total_properties || 0}</h6>
|
292 |
+
</div>
|
293 |
+
<div class="col-6">
|
294 |
+
<small class="text-muted">Engagement Score:</small>
|
295 |
+
<h6>${analytics.engagement_score || 'N/A'}</h6>
|
296 |
+
</div>
|
297 |
+
</div>
|
298 |
+
<div class="row mt-2">
|
299 |
+
<div class="col-6">
|
300 |
+
<small class="text-muted">Preferred Type:</small>
|
301 |
+
<h6>${analytics.preferred_property_type || 'Villa'}</h6>
|
302 |
+
</div>
|
303 |
+
<div class="col-6">
|
304 |
+
<small class="text-muted">Budget Range:</small>
|
305 |
+
<h6>${analytics.budget_range || '500K-2M'}</h6>
|
306 |
+
</div>
|
307 |
+
</div>
|
308 |
+
`;
|
309 |
+
} else {
|
310 |
+
analyticsDiv.innerHTML = '<p class="text-muted">Analytics data not available</p>';
|
311 |
+
}
|
312 |
+
}
|
313 |
+
|
314 |
+
// Send new properties email
|
315 |
+
async function sendNewPropertiesEmail() {
|
316 |
+
if (!validateCustomer()) return;
|
317 |
+
|
318 |
+
showLoading();
|
319 |
+
try {
|
320 |
+
const response = await fetch(`/api/email-automation/${currentCustomerId}`, {
|
321 |
+
method: 'POST',
|
322 |
+
headers: {
|
323 |
+
'Content-Type': 'application/json'
|
324 |
+
},
|
325 |
+
body: JSON.stringify({
|
326 |
+
email: currentEmail,
|
327 |
+
email_type: 'new_properties'
|
328 |
+
})
|
329 |
+
});
|
330 |
+
|
331 |
+
const data = await response.json();
|
332 |
+
hideLoading();
|
333 |
+
displayEmailResults(data);
|
334 |
+
|
335 |
+
if (data.success) {
|
336 |
+
showSuccess('New properties email sent successfully!');
|
337 |
+
} else {
|
338 |
+
showError('Failed to send new properties email: ' + data.error);
|
339 |
+
}
|
340 |
+
} catch (error) {
|
341 |
+
hideLoading();
|
342 |
+
showError('Error sending new properties email: ' + error.message);
|
343 |
+
}
|
344 |
+
}
|
345 |
+
|
346 |
+
// Send AI recommendations email
|
347 |
+
async function sendAIRecommendationsEmail() {
|
348 |
+
if (!validateCustomer()) return;
|
349 |
+
|
350 |
+
showLoading();
|
351 |
+
try {
|
352 |
+
const response = await fetch(`/api/email-automation/${currentCustomerId}`, {
|
353 |
+
method: 'POST',
|
354 |
+
headers: {
|
355 |
+
'Content-Type': 'application/json'
|
356 |
+
},
|
357 |
+
body: JSON.stringify({
|
358 |
+
email: currentEmail,
|
359 |
+
email_type: 'recommendations'
|
360 |
+
})
|
361 |
+
});
|
362 |
+
|
363 |
+
const data = await response.json();
|
364 |
+
hideLoading();
|
365 |
+
displayEmailResults(data);
|
366 |
+
|
367 |
+
if (data.success) {
|
368 |
+
showSuccess('AI recommendations email sent successfully!');
|
369 |
+
} else {
|
370 |
+
showError('Failed to send AI recommendations email: ' + data.error);
|
371 |
+
}
|
372 |
+
} catch (error) {
|
373 |
+
hideLoading();
|
374 |
+
showError('Error sending AI recommendations email: ' + error.message);
|
375 |
+
}
|
376 |
+
}
|
377 |
+
|
378 |
+
// Send peak time engagement email
|
379 |
+
async function sendPeakTimeEmail() {
|
380 |
+
if (!validateCustomer()) return;
|
381 |
+
|
382 |
+
showLoading();
|
383 |
+
try {
|
384 |
+
const response = await fetch(`/api/email-automation/${currentCustomerId}`, {
|
385 |
+
method: 'POST',
|
386 |
+
headers: {
|
387 |
+
'Content-Type': 'application/json'
|
388 |
+
},
|
389 |
+
body: JSON.stringify({
|
390 |
+
email: currentEmail,
|
391 |
+
email_type: 'peak_time'
|
392 |
+
})
|
393 |
+
});
|
394 |
+
|
395 |
+
const data = await response.json();
|
396 |
+
hideLoading();
|
397 |
+
displayEmailResults(data);
|
398 |
+
|
399 |
+
if (data.success) {
|
400 |
+
showSuccess('Peak time engagement email sent successfully!');
|
401 |
+
} else {
|
402 |
+
showError('Failed to send peak time email: ' + data.error);
|
403 |
+
}
|
404 |
+
} catch (error) {
|
405 |
+
hideLoading();
|
406 |
+
showError('Error sending peak time email: ' + error.message);
|
407 |
+
}
|
408 |
+
}
|
409 |
+
|
410 |
+
// Send all emails
|
411 |
+
async function sendAllEmails() {
|
412 |
+
if (!validateCustomer()) return;
|
413 |
+
|
414 |
+
showLoading();
|
415 |
+
try {
|
416 |
+
const response = await fetch(`/api/email-automation/${currentCustomerId}`, {
|
417 |
+
method: 'POST',
|
418 |
+
headers: {
|
419 |
+
'Content-Type': 'application/json'
|
420 |
+
},
|
421 |
+
body: JSON.stringify({
|
422 |
+
email: currentEmail,
|
423 |
+
email_type: 'all'
|
424 |
+
})
|
425 |
+
});
|
426 |
+
|
427 |
+
const data = await response.json();
|
428 |
+
hideLoading();
|
429 |
+
displayEmailResults(data);
|
430 |
+
|
431 |
+
if (data.success) {
|
432 |
+
showSuccess('All emails sent successfully!');
|
433 |
+
} else {
|
434 |
+
showError('Failed to send all emails: ' + data.error);
|
435 |
+
}
|
436 |
+
} catch (error) {
|
437 |
+
hideLoading();
|
438 |
+
showError('Error sending all emails: ' + error.message);
|
439 |
+
}
|
440 |
+
}
|
441 |
+
|
442 |
+
// Display email results
|
443 |
+
function displayEmailResults(data) {
|
444 |
+
const resultsDiv = document.getElementById('emailResults');
|
445 |
+
|
446 |
+
if (data.success && data.results) {
|
447 |
+
let html = '<div class="row">';
|
448 |
+
|
449 |
+
data.results.forEach(result => {
|
450 |
+
const statusClass = result.success ? 'status-success' : 'status-error';
|
451 |
+
const statusText = result.success ? 'Success' : 'Failed';
|
452 |
+
|
453 |
+
html += `
|
454 |
+
<div class="col-md-4 mb-3">
|
455 |
+
<div class="card">
|
456 |
+
<div class="card-body">
|
457 |
+
<h6 class="card-title">
|
458 |
+
<span class="status-indicator ${statusClass}"></span>
|
459 |
+
${result.type.replace('_', ' ').toUpperCase()}
|
460 |
+
</h6>
|
461 |
+
<p class="card-text">${result.message || result.error || 'Email sent'}</p>
|
462 |
+
${result.properties_count ? `<small class="text-muted">Properties: ${result.properties_count}</small>` : ''}
|
463 |
+
</div>
|
464 |
+
</div>
|
465 |
+
</div>
|
466 |
+
`;
|
467 |
+
});
|
468 |
+
|
469 |
+
html += '</div>';
|
470 |
+
|
471 |
+
if (data.ai_insights) {
|
472 |
+
html += `
|
473 |
+
<div class="mt-3">
|
474 |
+
<h6>AI Insights:</h6>
|
475 |
+
<div class="row">
|
476 |
+
<div class="col-md-3">
|
477 |
+
<small class="text-muted">Personality:</small>
|
478 |
+
<div>${data.ai_insights.personality_type || 'N/A'}</div>
|
479 |
+
</div>
|
480 |
+
<div class="col-md-3">
|
481 |
+
<small class="text-muted">Urgency:</small>
|
482 |
+
<div>${data.ai_insights.urgency_level || 'N/A'}</div>
|
483 |
+
</div>
|
484 |
+
<div class="col-md-3">
|
485 |
+
<small class="text-muted">Peak Time:</small>
|
486 |
+
<div>${data.ai_insights.peak_time || 'N/A'}</div>
|
487 |
+
</div>
|
488 |
+
<div class="col-md-3">
|
489 |
+
<small class="text-muted">Engagement:</small>
|
490 |
+
<div>${data.ai_insights.engagement_level || 'N/A'}</div>
|
491 |
+
</div>
|
492 |
+
</div>
|
493 |
+
</div>
|
494 |
+
`;
|
495 |
+
}
|
496 |
+
|
497 |
+
resultsDiv.innerHTML = html;
|
498 |
+
} else {
|
499 |
+
resultsDiv.innerHTML = `<div class="alert alert-danger">${data.error || 'Unknown error occurred'}</div>`;
|
500 |
+
}
|
501 |
+
}
|
502 |
+
|
503 |
+
// Validate customer selection
|
504 |
+
function validateCustomer() {
|
505 |
+
if (!currentCustomerId || !currentEmail) {
|
506 |
+
alert('Please load customer data first');
|
507 |
+
return false;
|
508 |
+
}
|
509 |
+
return true;
|
510 |
+
}
|
511 |
+
|
512 |
+
// Show loading modal
|
513 |
+
function showLoading() {
|
514 |
+
const modal = new bootstrap.Modal(document.getElementById('loadingModal'));
|
515 |
+
modal.show();
|
516 |
+
}
|
517 |
+
|
518 |
+
// Hide loading modal
|
519 |
+
function hideLoading() {
|
520 |
+
const modal = bootstrap.Modal.getInstance(document.getElementById('loadingModal'));
|
521 |
+
if (modal) {
|
522 |
+
modal.hide();
|
523 |
+
}
|
524 |
+
}
|
525 |
+
|
526 |
+
// Show success message
|
527 |
+
function showSuccess(message) {
|
528 |
+
// Create and show success alert
|
529 |
+
const alertDiv = document.createElement('div');
|
530 |
+
alertDiv.className = 'alert alert-success alert-dismissible fade show position-fixed';
|
531 |
+
alertDiv.style.top = '20px';
|
532 |
+
alertDiv.style.right = '20px';
|
533 |
+
alertDiv.style.zIndex = '9999';
|
534 |
+
alertDiv.innerHTML = `
|
535 |
+
${message}
|
536 |
+
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
537 |
+
`;
|
538 |
+
document.body.appendChild(alertDiv);
|
539 |
+
|
540 |
+
// Auto remove after 5 seconds
|
541 |
+
setTimeout(() => {
|
542 |
+
if (alertDiv.parentNode) {
|
543 |
+
alertDiv.parentNode.removeChild(alertDiv);
|
544 |
+
}
|
545 |
+
}, 5000);
|
546 |
+
}
|
547 |
+
|
548 |
+
// Show error message
|
549 |
+
function showError(message) {
|
550 |
+
// Create and show error alert
|
551 |
+
const alertDiv = document.createElement('div');
|
552 |
+
alertDiv.className = 'alert alert-danger alert-dismissible fade show position-fixed';
|
553 |
+
alertDiv.style.top = '20px';
|
554 |
+
alertDiv.style.right = '20px';
|
555 |
+
alertDiv.style.zIndex = '9999';
|
556 |
+
alertDiv.innerHTML = `
|
557 |
+
${message}
|
558 |
+
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
|
559 |
+
`;
|
560 |
+
document.body.appendChild(alertDiv);
|
561 |
+
|
562 |
+
// Auto remove after 5 seconds
|
563 |
+
setTimeout(() => {
|
564 |
+
if (alertDiv.parentNode) {
|
565 |
+
alertDiv.parentNode.removeChild(alertDiv);
|
566 |
+
}
|
567 |
+
}, 5000);
|
568 |
+
}
|
569 |
+
|
570 |
+
// Initialize charts
|
571 |
+
function initializeCharts() {
|
572 |
+
// Email Performance Chart
|
573 |
+
const emailCtx = document.getElementById('emailPerformanceChart').getContext('2d');
|
574 |
+
new Chart(emailCtx, {
|
575 |
+
type: 'doughnut',
|
576 |
+
data: {
|
577 |
+
labels: ['New Properties', 'AI Recommendations', 'Peak Time'],
|
578 |
+
datasets: [{
|
579 |
+
data: [85, 92, 78],
|
580 |
+
backgroundColor: ['#f093fb', '#4facfe', '#43e97b']
|
581 |
+
}]
|
582 |
+
},
|
583 |
+
options: {
|
584 |
+
responsive: true,
|
585 |
+
maintainAspectRatio: false
|
586 |
+
}
|
587 |
+
});
|
588 |
+
|
589 |
+
// Engagement Chart
|
590 |
+
const engagementCtx = document.getElementById('engagementChart').getContext('2d');
|
591 |
+
new Chart(engagementCtx, {
|
592 |
+
type: 'bar',
|
593 |
+
data: {
|
594 |
+
labels: ['Morning', 'Afternoon', 'Evening', 'Night'],
|
595 |
+
datasets: [{
|
596 |
+
label: 'Engagement Level',
|
597 |
+
data: [65, 80, 95, 45],
|
598 |
+
backgroundColor: ['#667eea', '#764ba2', '#f093fb', '#f5576c']
|
599 |
+
}]
|
600 |
+
},
|
601 |
+
options: {
|
602 |
+
responsive: true,
|
603 |
+
maintainAspectRatio: false,
|
604 |
+
scales: {
|
605 |
+
y: {
|
606 |
+
beginAtZero: true,
|
607 |
+
max: 100
|
608 |
+
}
|
609 |
+
}
|
610 |
+
}
|
611 |
+
});
|
612 |
+
}
|
613 |
+
|
614 |
+
// Initialize page
|
615 |
+
document.addEventListener('DOMContentLoaded', function() {
|
616 |
+
initializeCharts();
|
617 |
+
});
|
618 |
+
</script>
|
619 |
+
</body>
|
620 |
+
</html>
|