Update app.py
Browse files
app.py
CHANGED
|
@@ -2,7 +2,8 @@ from typing import Dict, Any, Optional, Tuple, List
|
|
| 2 |
import traceback
|
| 3 |
import json
|
| 4 |
import os
|
| 5 |
-
from datetime import date
|
|
|
|
| 6 |
import gradio as gr
|
| 7 |
import plotly.graph_objects as go
|
| 8 |
import httpx
|
|
@@ -544,7 +545,6 @@ Annual estimate: ${amount_float:.2f} ร {frequency} = **${annual_spend:.2f}**
|
|
| 544 |
except Exception as e:
|
| 545 |
print(f"โ ERROR: {traceback.format_exc()}")
|
| 546 |
yield f"โ **Error:** {str(e)}", None
|
| 547 |
-
|
| 548 |
|
| 549 |
def create_agent_recommendation_chart_enhanced(result: Dict) -> go.Figure:
|
| 550 |
try:
|
|
@@ -752,7 +752,6 @@ def get_recommendation_with_ai(user_id, merchant, category, amount):
|
|
| 752 |
error_details = traceback.format_exc()
|
| 753 |
print(f"Recommendation error: {error_details}")
|
| 754 |
yield f"โ Error: {str(e)}\n\nPlease check your API connection or try again.", None
|
| 755 |
-
|
| 756 |
|
| 757 |
def create_rewards_comparison_chart(data: Dict) -> go.Figure:
|
| 758 |
"""Create rewards comparison chart with proper error handling"""
|
|
@@ -900,7 +899,51 @@ def create_empty_chart(message: str) -> go.Figure:
|
|
| 900 |
)
|
| 901 |
fig.update_layout(height=400, template='plotly_white')
|
| 902 |
return fig
|
| 903 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 904 |
|
| 905 |
def update_analytics_with_charts(user_id: str):
|
| 906 |
"""Fetch and format analytics with charts for selected user"""
|
|
@@ -925,7 +968,7 @@ def update_analytics_with_charts(user_id: str):
|
|
| 925 |
empty_fig, empty_fig, empty_fig, empty_fig, empty_fig,
|
| 926 |
"Error loading data",
|
| 927 |
"Error loading data",
|
| 928 |
-
"Error
|
| 929 |
f"*Error: {error_msg}*"
|
| 930 |
)
|
| 931 |
|
|
@@ -938,11 +981,14 @@ def update_analytics_with_charts(user_id: str):
|
|
| 938 |
empty_fig, empty_fig, empty_fig, empty_fig, empty_fig,
|
| 939 |
"No data",
|
| 940 |
"No data",
|
| 941 |
-
"No data",
|
| 942 |
"*No data available*"
|
| 943 |
)
|
| 944 |
|
| 945 |
-
metrics_html, table_md, insights_md,
|
|
|
|
|
|
|
|
|
|
| 946 |
|
| 947 |
spending_fig = create_spending_chart(analytics_data)
|
| 948 |
pie_fig = create_rewards_pie_chart(analytics_data)
|
|
@@ -950,7 +996,6 @@ def update_analytics_with_charts(user_id: str):
|
|
| 950 |
trend_fig = create_trend_line_chart(analytics_data)
|
| 951 |
performance_fig = create_card_performance_chart(analytics_data)
|
| 952 |
|
| 953 |
-
from datetime import datetime
|
| 954 |
status = f"*Analytics updated for {user_id} at {datetime.now().strftime('%I:%M %p')}*"
|
| 955 |
|
| 956 |
return (
|
|
@@ -962,7 +1007,7 @@ def update_analytics_with_charts(user_id: str):
|
|
| 962 |
trend_fig,
|
| 963 |
table_md,
|
| 964 |
insights_md,
|
| 965 |
-
forecast_md
|
| 966 |
status
|
| 967 |
)
|
| 968 |
|
|
@@ -979,10 +1024,10 @@ def update_analytics_with_charts(user_id: str):
|
|
| 979 |
empty_fig, empty_fig, empty_fig, empty_fig, empty_fig,
|
| 980 |
"Error loading table",
|
| 981 |
"Error loading insights",
|
| 982 |
-
"
|
| 983 |
f"*{error_msg}*"
|
| 984 |
)
|
| 985 |
-
|
| 986 |
def _toggle_custom_mcc(use_custom: bool):
|
| 987 |
return gr.update(visible=use_custom, value="")
|
| 988 |
|
|
@@ -1051,40 +1096,75 @@ def load_user_wallet(user_id: str):
|
|
| 1051 |
|
| 1052 |
# ===================== NEW FUNCTION FOR FORECAST =====================
|
| 1053 |
def load_user_forecast(user_id: str):
|
| 1054 |
-
"""Load and display spending forecast"""
|
| 1055 |
try:
|
| 1056 |
# Mock forecast data - replace with actual API call
|
| 1057 |
forecast_data = {
|
| 1058 |
'next_month_spending': 3250.50,
|
| 1059 |
'predicted_rewards': 127.50,
|
|
|
|
| 1060 |
'top_categories': [
|
| 1061 |
-
{'category': 'Groceries', 'predicted': 850.00, 'confidence': 0.92},
|
| 1062 |
-
{'category': 'Restaurants', 'predicted': 650.00, 'confidence': 0.88},
|
| 1063 |
-
{'category': 'Gas', 'predicted': 450.00, 'confidence': 0.85},
|
| 1064 |
],
|
| 1065 |
'recommendations': [
|
| 1066 |
"Consider using Amex Gold for groceries to maximize 4x points",
|
| 1067 |
"You're approaching your Citi Custom Cash $500 monthly cap",
|
| 1068 |
"Travel spending is predicted to increase next month"
|
| 1069 |
-
]
|
|
|
|
| 1070 |
}
|
| 1071 |
|
|
|
|
|
|
|
|
|
|
| 1072 |
output = f"""
|
| 1073 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1074 |
|
| 1075 |
-
|
| 1076 |
-
- **Total Spending:** ${forecast_data['next_month_spending']:.2f}
|
| 1077 |
-
- **Expected Rewards:** ${forecast_data['predicted_rewards']:.2f}
|
| 1078 |
|
| 1079 |
-
### Category Breakdown
|
| 1080 |
"""
|
| 1081 |
|
| 1082 |
for cat in forecast_data['top_categories']:
|
| 1083 |
-
output += f"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1084 |
|
| 1085 |
-
output += "\n
|
| 1086 |
-
for rec in forecast_data['recommendations']:
|
| 1087 |
-
output += f"
|
| 1088 |
|
| 1089 |
# Create forecast chart
|
| 1090 |
fig = go.Figure()
|
|
@@ -1101,7 +1181,7 @@ def load_user_forecast(user_id: str):
|
|
| 1101 |
))
|
| 1102 |
|
| 1103 |
fig.update_layout(
|
| 1104 |
-
title='Predicted Spending by Category',
|
| 1105 |
xaxis_title='Category',
|
| 1106 |
yaxis_title='Predicted Amount ($)',
|
| 1107 |
template='plotly_white',
|
|
@@ -1160,6 +1240,81 @@ with gr.Blocks(
|
|
| 1160 |
.metric-card-blue {
|
| 1161 |
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
| 1162 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1163 |
table {
|
| 1164 |
width: 100%;
|
| 1165 |
border-collapse: collapse;
|
|
@@ -1339,7 +1494,6 @@ Get AI-powered credit card recommendations that maximize your rewards based on:
|
|
| 1339 |
# ==================== TAB 2: SMART WALLET ====================
|
| 1340 |
with gr.Tab("๐ณ Smart Wallet"):
|
| 1341 |
gr.Markdown("## Your Credit Card Portfolio")
|
| 1342 |
-
|
| 1343 |
wallet_user = gr.Dropdown(
|
| 1344 |
choices=SAMPLE_USERS,
|
| 1345 |
value=SAMPLE_USERS[0],
|
|
@@ -1446,12 +1600,40 @@ Get AI-powered credit card recommendations that maximize your rewards based on:
|
|
| 1446 |
value="*Loading insights...*"
|
| 1447 |
)
|
| 1448 |
|
| 1449 |
-
|
|
|
|
| 1450 |
|
| 1451 |
-
|
| 1452 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1453 |
)
|
| 1454 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1455 |
analytics_status = gr.Markdown(
|
| 1456 |
value="*Select a user to view analytics*",
|
| 1457 |
elem_classes=["status-text"]
|
|
@@ -1470,7 +1652,7 @@ Get AI-powered credit card recommendations that maximize your rewards based on:
|
|
| 1470 |
trend_chart,
|
| 1471 |
spending_table,
|
| 1472 |
insights_display,
|
| 1473 |
-
forecast_display
|
| 1474 |
analytics_status
|
| 1475 |
]
|
| 1476 |
)
|
|
@@ -1487,7 +1669,7 @@ Get AI-powered credit card recommendations that maximize your rewards based on:
|
|
| 1487 |
trend_chart,
|
| 1488 |
spending_table,
|
| 1489 |
insights_display,
|
| 1490 |
-
forecast_display
|
| 1491 |
analytics_status
|
| 1492 |
]
|
| 1493 |
)
|
|
@@ -1504,24 +1686,47 @@ Get AI-powered credit card recommendations that maximize your rewards based on:
|
|
| 1504 |
trend_chart,
|
| 1505 |
spending_table,
|
| 1506 |
insights_display,
|
| 1507 |
-
forecast_display
|
| 1508 |
analytics_status
|
| 1509 |
]
|
| 1510 |
)
|
| 1511 |
|
| 1512 |
# ==================== TAB 4: FORECAST ====================
|
| 1513 |
with gr.Tab("๐ Forecast"):
|
| 1514 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1515 |
|
| 1516 |
-
|
| 1517 |
-
|
| 1518 |
-
|
| 1519 |
-
|
| 1520 |
-
|
|
|
|
|
|
|
|
|
|
| 1521 |
|
| 1522 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1523 |
|
| 1524 |
-
forecast_output = gr.
|
| 1525 |
forecast_chart = gr.Plot()
|
| 1526 |
|
| 1527 |
def update_forecast(user_id):
|
|
|
|
| 2 |
import traceback
|
| 3 |
import json
|
| 4 |
import os
|
| 5 |
+
from datetime import date, datetime
|
| 6 |
+
import calendar
|
| 7 |
import gradio as gr
|
| 8 |
import plotly.graph_objects as go
|
| 9 |
import httpx
|
|
|
|
| 545 |
except Exception as e:
|
| 546 |
print(f"โ ERROR: {traceback.format_exc()}")
|
| 547 |
yield f"โ **Error:** {str(e)}", None
|
|
|
|
| 548 |
|
| 549 |
def create_agent_recommendation_chart_enhanced(result: Dict) -> go.Figure:
|
| 550 |
try:
|
|
|
|
| 752 |
error_details = traceback.format_exc()
|
| 753 |
print(f"Recommendation error: {error_details}")
|
| 754 |
yield f"โ Error: {str(e)}\n\nPlease check your API connection or try again.", None
|
|
|
|
| 755 |
|
| 756 |
def create_rewards_comparison_chart(data: Dict) -> go.Figure:
|
| 757 |
"""Create rewards comparison chart with proper error handling"""
|
|
|
|
| 899 |
)
|
| 900 |
fig.update_layout(height=400, template='plotly_white')
|
| 901 |
return fig
|
| 902 |
+
|
| 903 |
+
# ===================== NEW: FORMAT CURRENT MONTH SUMMARY =====================
|
| 904 |
+
def format_current_month_summary(analytics_data):
|
| 905 |
+
"""Format current month warnings with clear styling (for Analytics tab)"""
|
| 906 |
+
|
| 907 |
+
warnings = []
|
| 908 |
+
|
| 909 |
+
# Check for spending cap warnings
|
| 910 |
+
for card in analytics_data.get('card_usage', []):
|
| 911 |
+
if card.get('cap_percentage', 0) > 90:
|
| 912 |
+
warnings.append(
|
| 913 |
+
f"โ ๏ธ <strong>{card['name']}</strong>: "
|
| 914 |
+
f"${card['current_spend']:.0f} / ${card['cap']:.0f} "
|
| 915 |
+
f"({card['cap_percentage']:.0f}% used)"
|
| 916 |
+
)
|
| 917 |
+
|
| 918 |
+
# Calculate end-of-month projection
|
| 919 |
+
days_elapsed = datetime.now().day
|
| 920 |
+
days_in_month = calendar.monthrange(datetime.now().year, datetime.now().month)[1]
|
| 921 |
+
projection_ratio = days_in_month / days_elapsed if days_elapsed > 0 else 1
|
| 922 |
+
|
| 923 |
+
projected_spending = analytics_data.get('total_spending', 0) * projection_ratio
|
| 924 |
+
projected_rewards = analytics_data.get('total_rewards', 0) * projection_ratio
|
| 925 |
+
|
| 926 |
+
warnings_html = "<br>".join(warnings) if warnings else "โ
No warnings - you're on track!"
|
| 927 |
+
|
| 928 |
+
return f"""
|
| 929 |
+
<div class="current-month-warning">
|
| 930 |
+
<h4>โ ๏ธ This Month's Status (as of {datetime.now().strftime('%B %d')})</h4>
|
| 931 |
+
|
| 932 |
+
<p><strong>Month-End Projection:</strong></p>
|
| 933 |
+
<ul style="margin: 10px 0; padding-left: 20px;">
|
| 934 |
+
<li>Estimated Total Spending: <strong>${projected_spending:.2f}</strong></li>
|
| 935 |
+
<li>Estimated Total Rewards: <strong>${projected_rewards:.2f}</strong></li>
|
| 936 |
+
</ul>
|
| 937 |
+
|
| 938 |
+
<p><strong>Spending Cap Alerts:</strong></p>
|
| 939 |
+
<p style="margin: 10px 0;">{warnings_html}</p>
|
| 940 |
+
|
| 941 |
+
<p style="margin-top: 15px; padding-top: 15px; border-top: 1px solid #ffcc80; font-size: 13px; color: #666;">
|
| 942 |
+
๐ก <em>These are estimates based on your current month's activity.
|
| 943 |
+
For detailed future predictions, visit the <strong>Forecast tab</strong>.</em>
|
| 944 |
+
</p>
|
| 945 |
+
</div>
|
| 946 |
+
"""
|
| 947 |
|
| 948 |
def update_analytics_with_charts(user_id: str):
|
| 949 |
"""Fetch and format analytics with charts for selected user"""
|
|
|
|
| 968 |
empty_fig, empty_fig, empty_fig, empty_fig, empty_fig,
|
| 969 |
"Error loading data",
|
| 970 |
"Error loading data",
|
| 971 |
+
f"<p>Error: {error_msg}</p>", # Changed from forecast_md
|
| 972 |
f"*Error: {error_msg}*"
|
| 973 |
)
|
| 974 |
|
|
|
|
| 981 |
empty_fig, empty_fig, empty_fig, empty_fig, empty_fig,
|
| 982 |
"No data",
|
| 983 |
"No data",
|
| 984 |
+
"<p>No data available</p>", # Changed
|
| 985 |
"*No data available*"
|
| 986 |
)
|
| 987 |
|
| 988 |
+
metrics_html, table_md, insights_md, _ = format_analytics_metrics(analytics_data)
|
| 989 |
+
|
| 990 |
+
# Generate current month summary (NEW)
|
| 991 |
+
current_month_html = format_current_month_summary(analytics_data)
|
| 992 |
|
| 993 |
spending_fig = create_spending_chart(analytics_data)
|
| 994 |
pie_fig = create_rewards_pie_chart(analytics_data)
|
|
|
|
| 996 |
trend_fig = create_trend_line_chart(analytics_data)
|
| 997 |
performance_fig = create_card_performance_chart(analytics_data)
|
| 998 |
|
|
|
|
| 999 |
status = f"*Analytics updated for {user_id} at {datetime.now().strftime('%I:%M %p')}*"
|
| 1000 |
|
| 1001 |
return (
|
|
|
|
| 1007 |
trend_fig,
|
| 1008 |
table_md,
|
| 1009 |
insights_md,
|
| 1010 |
+
current_month_html, # Changed from forecast_md
|
| 1011 |
status
|
| 1012 |
)
|
| 1013 |
|
|
|
|
| 1024 |
empty_fig, empty_fig, empty_fig, empty_fig, empty_fig,
|
| 1025 |
"Error loading table",
|
| 1026 |
"Error loading insights",
|
| 1027 |
+
f"<p>{error_msg}</p>", # Changed
|
| 1028 |
f"*{error_msg}*"
|
| 1029 |
)
|
| 1030 |
+
|
| 1031 |
def _toggle_custom_mcc(use_custom: bool):
|
| 1032 |
return gr.update(visible=use_custom, value="")
|
| 1033 |
|
|
|
|
| 1096 |
|
| 1097 |
# ===================== NEW FUNCTION FOR FORECAST =====================
|
| 1098 |
def load_user_forecast(user_id: str):
|
| 1099 |
+
"""Load and display spending forecast (comprehensive version for Forecast tab)"""
|
| 1100 |
try:
|
| 1101 |
# Mock forecast data - replace with actual API call
|
| 1102 |
forecast_data = {
|
| 1103 |
'next_month_spending': 3250.50,
|
| 1104 |
'predicted_rewards': 127.50,
|
| 1105 |
+
'confidence': 0.92,
|
| 1106 |
'top_categories': [
|
| 1107 |
+
{'category': 'Groceries', 'predicted': 850.00, 'confidence': 0.92, 'emoji': '๐'},
|
| 1108 |
+
{'category': 'Restaurants', 'predicted': 650.00, 'confidence': 0.88, 'emoji': '๐ฝ๏ธ'},
|
| 1109 |
+
{'category': 'Gas', 'predicted': 450.00, 'confidence': 0.85, 'emoji': 'โฝ'},
|
| 1110 |
],
|
| 1111 |
'recommendations': [
|
| 1112 |
"Consider using Amex Gold for groceries to maximize 4x points",
|
| 1113 |
"You're approaching your Citi Custom Cash $500 monthly cap",
|
| 1114 |
"Travel spending is predicted to increase next month"
|
| 1115 |
+
],
|
| 1116 |
+
'optimization_potential': 45.50
|
| 1117 |
}
|
| 1118 |
|
| 1119 |
+
confidence = forecast_data.get('confidence', 0.85)
|
| 1120 |
+
confidence_color = '#4caf50' if confidence > 0.9 else '#ff9800' if confidence > 0.75 else '#f44336'
|
| 1121 |
+
|
| 1122 |
output = f"""
|
| 1123 |
+
<div class="forecast-prediction">
|
| 1124 |
+
<h3>๐ฎ Next Month Forecast
|
| 1125 |
+
<span class="confidence-badge" style="background: {confidence_color};">
|
| 1126 |
+
{confidence*100:.0f}% Confidence
|
| 1127 |
+
</span>
|
| 1128 |
+
</h3>
|
| 1129 |
+
|
| 1130 |
+
<div style="display: grid; grid-template-columns: repeat(3, 1fr); gap: 15px; margin: 20px 0;">
|
| 1131 |
+
<div style="background: white; padding: 15px; border-radius: 8px; text-align: center;">
|
| 1132 |
+
<p style="color: #666; margin: 0; font-size: 12px;">PREDICTED SPENDING</p>
|
| 1133 |
+
<p style="color: #0d47a1; margin: 5px 0; font-size: 28px; font-weight: 700;">
|
| 1134 |
+
${forecast_data['next_month_spending']:.2f}
|
| 1135 |
+
</p>
|
| 1136 |
+
</div>
|
| 1137 |
+
<div style="background: white; padding: 15px; border-radius: 8px; text-align: center;">
|
| 1138 |
+
<p style="color: #666; margin: 0; font-size: 12px;">EXPECTED REWARDS</p>
|
| 1139 |
+
<p style="color: #4caf50; margin: 5px 0; font-size: 28px; font-weight: 700;">
|
| 1140 |
+
${forecast_data['predicted_rewards']:.2f}
|
| 1141 |
+
</p>
|
| 1142 |
+
</div>
|
| 1143 |
+
<div style="background: white; padding: 15px; border-radius: 8px; text-align: center;">
|
| 1144 |
+
<p style="color: #666; margin: 0; font-size: 12px;">OPTIMIZATION POTENTIAL</p>
|
| 1145 |
+
<p style="color: #ff9800; margin: 5px 0; font-size: 28px; font-weight: 700;">
|
| 1146 |
+
+${forecast_data['optimization_potential']:.2f}
|
| 1147 |
+
</p>
|
| 1148 |
+
</div>
|
| 1149 |
+
</div>
|
| 1150 |
+
</div>
|
| 1151 |
|
| 1152 |
+
## ๐ Category Breakdown
|
|
|
|
|
|
|
| 1153 |
|
|
|
|
| 1154 |
"""
|
| 1155 |
|
| 1156 |
for cat in forecast_data['top_categories']:
|
| 1157 |
+
output += f"""
|
| 1158 |
+
### {cat['emoji']} {cat['category']}
|
| 1159 |
+
- **Predicted Amount:** ${cat['predicted']:.2f} (Confidence: {cat['confidence']*100:.0f}%)
|
| 1160 |
+
- **Recommendation:** Use best card for this category
|
| 1161 |
+
- **Potential Rewards:** Based on optimal card selection
|
| 1162 |
+
|
| 1163 |
+
"""
|
| 1164 |
|
| 1165 |
+
output += "\n## ๐ก Optimization Strategies\n\n"
|
| 1166 |
+
for i, rec in enumerate(forecast_data['recommendations'], 1):
|
| 1167 |
+
output += f"{i}. {rec}\n"
|
| 1168 |
|
| 1169 |
# Create forecast chart
|
| 1170 |
fig = go.Figure()
|
|
|
|
| 1181 |
))
|
| 1182 |
|
| 1183 |
fig.update_layout(
|
| 1184 |
+
title='Predicted Spending by Category (Next Month)',
|
| 1185 |
xaxis_title='Category',
|
| 1186 |
yaxis_title='Predicted Amount ($)',
|
| 1187 |
template='plotly_white',
|
|
|
|
| 1240 |
.metric-card-blue {
|
| 1241 |
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
|
| 1242 |
}
|
| 1243 |
+
|
| 1244 |
+
/* ===== ANALYTICS TAB - WARNING BOX ===== */
|
| 1245 |
+
.current-month-warning {
|
| 1246 |
+
background: linear-gradient(135deg, #fff4e6 0%, #ffe8cc 100%);
|
| 1247 |
+
border-left: 4px solid #ff9800;
|
| 1248 |
+
padding: 15px 20px;
|
| 1249 |
+
border-radius: 8px;
|
| 1250 |
+
margin: 20px 0;
|
| 1251 |
+
box-shadow: 0 2px 8px rgba(255, 152, 0, 0.2);
|
| 1252 |
+
}
|
| 1253 |
+
|
| 1254 |
+
.current-month-warning h4 {
|
| 1255 |
+
color: #e65100;
|
| 1256 |
+
margin: 0 0 10px 0;
|
| 1257 |
+
font-size: 18px;
|
| 1258 |
+
font-weight: 600;
|
| 1259 |
+
}
|
| 1260 |
+
|
| 1261 |
+
.current-month-warning p {
|
| 1262 |
+
color: #5d4037;
|
| 1263 |
+
margin: 5px 0;
|
| 1264 |
+
font-size: 14px;
|
| 1265 |
+
}
|
| 1266 |
+
|
| 1267 |
+
/* ===== FORECAST TAB - PREDICTION BOX ===== */
|
| 1268 |
+
.forecast-prediction {
|
| 1269 |
+
background: linear-gradient(135deg, #e3f2fd 0%, #bbdefb 100%);
|
| 1270 |
+
border-left: 4px solid #2196f3;
|
| 1271 |
+
padding: 20px;
|
| 1272 |
+
border-radius: 8px;
|
| 1273 |
+
margin: 20px 0;
|
| 1274 |
+
box-shadow: 0 2px 8px rgba(33, 150, 243, 0.2);
|
| 1275 |
+
}
|
| 1276 |
+
|
| 1277 |
+
.forecast-prediction h3 {
|
| 1278 |
+
color: #0d47a1;
|
| 1279 |
+
margin: 0 0 15px 0;
|
| 1280 |
+
font-size: 22px;
|
| 1281 |
+
font-weight: 700;
|
| 1282 |
+
}
|
| 1283 |
+
|
| 1284 |
+
.forecast-prediction .confidence-badge {
|
| 1285 |
+
display: inline-block;
|
| 1286 |
+
padding: 4px 12px;
|
| 1287 |
+
background: #4caf50;
|
| 1288 |
+
color: white;
|
| 1289 |
+
border-radius: 12px;
|
| 1290 |
+
font-size: 12px;
|
| 1291 |
+
font-weight: 600;
|
| 1292 |
+
margin-left: 10px;
|
| 1293 |
+
}
|
| 1294 |
+
|
| 1295 |
+
/* ===== SECTION DIVIDERS ===== */
|
| 1296 |
+
.section-divider {
|
| 1297 |
+
border: 0;
|
| 1298 |
+
height: 2px;
|
| 1299 |
+
background: linear-gradient(to right, transparent, #ddd, transparent);
|
| 1300 |
+
margin: 30px 0;
|
| 1301 |
+
}
|
| 1302 |
+
|
| 1303 |
+
/* ===== INFO BOXES ===== */
|
| 1304 |
+
.info-box {
|
| 1305 |
+
background: #f5f5f5;
|
| 1306 |
+
border-radius: 8px;
|
| 1307 |
+
padding: 15px;
|
| 1308 |
+
margin: 15px 0;
|
| 1309 |
+
border-left: 3px solid #667eea;
|
| 1310 |
+
}
|
| 1311 |
+
|
| 1312 |
+
.info-box-icon {
|
| 1313 |
+
font-size: 24px;
|
| 1314 |
+
margin-right: 10px;
|
| 1315 |
+
vertical-align: middle;
|
| 1316 |
+
}
|
| 1317 |
+
|
| 1318 |
table {
|
| 1319 |
width: 100%;
|
| 1320 |
border-collapse: collapse;
|
|
|
|
| 1494 |
# ==================== TAB 2: SMART WALLET ====================
|
| 1495 |
with gr.Tab("๐ณ Smart Wallet"):
|
| 1496 |
gr.Markdown("## Your Credit Card Portfolio")
|
|
|
|
| 1497 |
wallet_user = gr.Dropdown(
|
| 1498 |
choices=SAMPLE_USERS,
|
| 1499 |
value=SAMPLE_USERS[0],
|
|
|
|
| 1600 |
value="*Loading insights...*"
|
| 1601 |
)
|
| 1602 |
|
| 1603 |
+
# ===== CHANGED SECTION: Current Month Summary =====
|
| 1604 |
+
gr.HTML('<hr class="section-divider">')
|
| 1605 |
|
| 1606 |
+
gr.Markdown("""
|
| 1607 |
+
<div class="info-box">
|
| 1608 |
+
<span class="info-box-icon">๐</span>
|
| 1609 |
+
<strong>Current Month Summary</strong> - Quick insights based on your spending so far this month
|
| 1610 |
+
</div>
|
| 1611 |
+
""")
|
| 1612 |
+
|
| 1613 |
+
current_month_summary = gr.HTML(
|
| 1614 |
+
value="""
|
| 1615 |
+
<div class="current-month-warning">
|
| 1616 |
+
<h4>โ ๏ธ This Month's Insights</h4>
|
| 1617 |
+
<p><em>Loading current month data...</em></p>
|
| 1618 |
+
</div>
|
| 1619 |
+
""",
|
| 1620 |
+
label=None
|
| 1621 |
)
|
| 1622 |
|
| 1623 |
+
# Add clear call-to-action to Forecast tab
|
| 1624 |
+
gr.Markdown("""
|
| 1625 |
+
<div style="text-align: center; margin: 20px 0;">
|
| 1626 |
+
<p style="color: #666; font-size: 14px;">
|
| 1627 |
+
Want to see <strong>next month's predictions</strong> and optimization strategies?
|
| 1628 |
+
</p>
|
| 1629 |
+
<p style="margin-top: 10px;">
|
| 1630 |
+
๐ <span style="color: #667eea; font-weight: 600; font-size: 16px;">
|
| 1631 |
+
Go to the <strong>Forecast Tab</strong> above โ
|
| 1632 |
+
</span>
|
| 1633 |
+
</p>
|
| 1634 |
+
</div>
|
| 1635 |
+
""")
|
| 1636 |
+
|
| 1637 |
analytics_status = gr.Markdown(
|
| 1638 |
value="*Select a user to view analytics*",
|
| 1639 |
elem_classes=["status-text"]
|
|
|
|
| 1652 |
trend_chart,
|
| 1653 |
spending_table,
|
| 1654 |
insights_display,
|
| 1655 |
+
current_month_summary, # Changed from forecast_display
|
| 1656 |
analytics_status
|
| 1657 |
]
|
| 1658 |
)
|
|
|
|
| 1669 |
trend_chart,
|
| 1670 |
spending_table,
|
| 1671 |
insights_display,
|
| 1672 |
+
current_month_summary, # Changed from forecast_display
|
| 1673 |
analytics_status
|
| 1674 |
]
|
| 1675 |
)
|
|
|
|
| 1686 |
trend_chart,
|
| 1687 |
spending_table,
|
| 1688 |
insights_display,
|
| 1689 |
+
current_month_summary, # Changed from forecast_display
|
| 1690 |
analytics_status
|
| 1691 |
]
|
| 1692 |
)
|
| 1693 |
|
| 1694 |
# ==================== TAB 4: FORECAST ====================
|
| 1695 |
with gr.Tab("๐ Forecast"):
|
| 1696 |
+
# Add clear header with explanation
|
| 1697 |
+
gr.Markdown("""
|
| 1698 |
+
<div class="forecast-prediction">
|
| 1699 |
+
<h3>๐ฎ AI-Powered Spending Forecast</h3>
|
| 1700 |
+
<p style="color: #1565c0; font-size: 16px; margin: 0;">
|
| 1701 |
+
Machine learning predictions for your <strong>next 1-3 months</strong>
|
| 1702 |
+
with personalized optimization strategies
|
| 1703 |
+
</p>
|
| 1704 |
+
</div>
|
| 1705 |
+
""")
|
| 1706 |
|
| 1707 |
+
gr.Markdown("""
|
| 1708 |
+
<div class="info-box">
|
| 1709 |
+
<span class="info-box-icon">๐ค</span>
|
| 1710 |
+
<strong>How it works:</strong> Our AI analyzes your historical spending patterns,
|
| 1711 |
+
seasonal trends, and card benefits to predict future spending and recommend
|
| 1712 |
+
the best cards to maximize your rewards.
|
| 1713 |
+
</div>
|
| 1714 |
+
""")
|
| 1715 |
|
| 1716 |
+
with gr.Row():
|
| 1717 |
+
forecast_user = gr.Dropdown(
|
| 1718 |
+
choices=SAMPLE_USERS,
|
| 1719 |
+
value=SAMPLE_USERS[0],
|
| 1720 |
+
label="๐ค Select User"
|
| 1721 |
+
)
|
| 1722 |
+
|
| 1723 |
+
refresh_forecast_btn = gr.Button(
|
| 1724 |
+
"๐ Refresh Forecast",
|
| 1725 |
+
variant="primary",
|
| 1726 |
+
size="sm"
|
| 1727 |
+
)
|
| 1728 |
|
| 1729 |
+
forecast_output = gr.HTML(value="<p><em>Loading forecast...</em></p>")
|
| 1730 |
forecast_chart = gr.Plot()
|
| 1731 |
|
| 1732 |
def update_forecast(user_id):
|