Update app.py
Browse files
app.py
CHANGED
|
@@ -888,78 +888,115 @@ def get_recommendation_with_ai(user_id, merchant, category, amount):
|
|
| 888 |
print(f"Recommendation error: {error_details}")
|
| 889 |
yield f"❌ Error: {str(e)}\n\nPlease check your API connection or try again.", None
|
| 890 |
|
| 891 |
-
def create_rewards_comparison_chart(data
|
| 892 |
-
"""Create
|
| 893 |
|
| 894 |
try:
|
| 895 |
-
|
| 896 |
-
|
| 897 |
-
|
| 898 |
-
|
| 899 |
-
|
| 900 |
-
|
| 901 |
-
|
| 902 |
-
|
| 903 |
-
|
| 904 |
-
|
| 905 |
-
|
| 906 |
-
|
| 907 |
-
|
| 908 |
-
|
| 909 |
-
|
| 910 |
-
|
| 911 |
-
|
| 912 |
-
|
| 913 |
-
|
| 914 |
-
|
| 915 |
-
|
| 916 |
-
|
| 917 |
-
|
| 918 |
-
|
| 919 |
-
|
| 920 |
-
|
| 921 |
-
|
| 922 |
-
|
| 923 |
-
|
| 924 |
-
|
| 925 |
-
|
| 926 |
-
|
| 927 |
-
|
| 928 |
-
|
| 929 |
-
|
| 930 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 931 |
|
| 932 |
-
|
| 933 |
-
|
| 934 |
-
'text': 'Rewards Comparison',
|
| 935 |
-
'x': 0.5,
|
| 936 |
-
'xanchor': 'center'
|
| 937 |
-
},
|
| 938 |
-
xaxis_title='Credit Card',
|
| 939 |
-
yaxis_title='Rewards Earned ($)',
|
| 940 |
-
template='plotly_white',
|
| 941 |
-
height=400,
|
| 942 |
-
showlegend=False,
|
| 943 |
-
margin=dict(t=60, b=50, l=50, r=50),
|
| 944 |
-
hovermode='x'
|
| 945 |
-
)
|
| 946 |
|
| 947 |
return fig
|
| 948 |
-
|
| 949 |
except Exception as e:
|
| 950 |
print(f"Chart creation error: {e}")
|
| 951 |
-
|
| 952 |
-
|
| 953 |
-
|
| 954 |
-
fig.add_annotation(
|
| 955 |
-
text=f"Error creating chart",
|
| 956 |
-
xref="paper", yref="paper",
|
| 957 |
-
x=0.5, y=0.5, showarrow=False,
|
| 958 |
-
font=dict(size=14, color="red")
|
| 959 |
-
)
|
| 960 |
-
fig.update_layout(height=400, template='plotly_white')
|
| 961 |
-
return fig
|
| 962 |
|
|
|
|
| 963 |
def get_analytics_with_insights(user_id):
|
| 964 |
"""Get analytics with LLM-generated insights"""
|
| 965 |
|
|
@@ -1724,7 +1761,7 @@ with gr.Blocks(
|
|
| 1724 |
<strong>You have 5 credit cards. You're at checkout. Which one do you use?</strong><br>
|
| 1725 |
Most people pick wrong and lose <strong>$400+ per year</strong>.<br>
|
| 1726 |
Our AI agent makes the optimal choice in <strong>2 seconds</strong>.<br>
|
| 1727 |
-
Powered by
|
| 1728 |
</p>
|
| 1729 |
|
| 1730 |
<div class="impact-stats">
|
|
|
|
| 888 |
print(f"Recommendation error: {error_details}")
|
| 889 |
yield f"❌ Error: {str(e)}\n\nPlease check your API connection or try again.", None
|
| 890 |
|
| 891 |
+
def create_rewards_comparison_chart(data):
|
| 892 |
+
"""Create dual chart: current transaction + annual projection"""
|
| 893 |
|
| 894 |
try:
|
| 895 |
+
import matplotlib.pyplot as plt
|
| 896 |
+
import matplotlib
|
| 897 |
+
matplotlib.use('Agg')
|
| 898 |
+
|
| 899 |
+
# Extract data
|
| 900 |
+
primary_card = data.get('recommended_card', 'Unknown')
|
| 901 |
+
primary_rewards = data.get('rewards_earned', 0)
|
| 902 |
+
annual_potential = data.get('annual_potential', 0)
|
| 903 |
+
|
| 904 |
+
# Calculate transaction amount
|
| 905 |
+
transaction_amount = primary_rewards / 0.02
|
| 906 |
+
|
| 907 |
+
# Prepare data
|
| 908 |
+
cards = [primary_card]
|
| 909 |
+
current_rewards = [primary_rewards]
|
| 910 |
+
annual_rewards = [annual_potential]
|
| 911 |
+
colors = ['#2ecc71']
|
| 912 |
+
|
| 913 |
+
# Add alternatives
|
| 914 |
+
alternatives = data.get('alternatives', [])
|
| 915 |
+
|
| 916 |
+
if alternatives and len(alternatives) > 0:
|
| 917 |
+
for alt in alternatives[:3]:
|
| 918 |
+
cards.append(alt.get('card', 'Unknown'))
|
| 919 |
+
current_rewards.append(alt.get('rewards', 0))
|
| 920 |
+
# Estimate annual based on current ratio
|
| 921 |
+
annual_est = (alt.get('rewards', 0) / primary_rewards) * annual_potential if primary_rewards > 0 else 0
|
| 922 |
+
annual_rewards.append(annual_est)
|
| 923 |
+
colors.append('#3498db')
|
| 924 |
+
|
| 925 |
+
# Add baseline if only 1 card
|
| 926 |
+
if len(cards) == 1:
|
| 927 |
+
cards.extend(['Citi Double Cash', 'Chase Freedom Unlimited', 'Baseline (1%)'])
|
| 928 |
+
current_rewards.extend([
|
| 929 |
+
transaction_amount * 0.02,
|
| 930 |
+
transaction_amount * 0.015,
|
| 931 |
+
transaction_amount * 0.01
|
| 932 |
+
])
|
| 933 |
+
annual_rewards.extend([
|
| 934 |
+
annual_potential * 1.0, # Assuming similar rate
|
| 935 |
+
annual_potential * 0.75,
|
| 936 |
+
annual_potential * 0.5
|
| 937 |
+
])
|
| 938 |
+
colors.extend(['#3498db', '#3498db', '#95a5a6'])
|
| 939 |
+
|
| 940 |
+
# Create subplots
|
| 941 |
+
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 6))
|
| 942 |
+
|
| 943 |
+
# Chart 1: Current Transaction
|
| 944 |
+
y_pos = range(len(cards))
|
| 945 |
+
bars1 = ax1.barh(y_pos, current_rewards, color=colors, edgecolor='black', linewidth=1.5, alpha=0.85)
|
| 946 |
+
|
| 947 |
+
ax1.set_yticks(y_pos)
|
| 948 |
+
ax1.set_yticklabels(cards, fontsize=11, fontweight='bold')
|
| 949 |
+
ax1.set_xlabel('Rewards ($)', fontsize=12, fontweight='bold')
|
| 950 |
+
ax1.set_title(f'💳 This Transaction (${transaction_amount:.2f})', fontsize=13, fontweight='bold')
|
| 951 |
+
ax1.grid(axis='x', alpha=0.3, linestyle='--')
|
| 952 |
+
ax1.set_axisbelow(True)
|
| 953 |
+
|
| 954 |
+
# Add labels
|
| 955 |
+
for i, (bar, reward) in enumerate(zip(bars1, current_rewards)):
|
| 956 |
+
label = f'⭐ ${reward:.2f}' if i == 0 else f'${reward:.2f}'
|
| 957 |
+
ax1.text(reward + max(current_rewards)*0.02, bar.get_y() + bar.get_height()/2,
|
| 958 |
+
label, va='center', fontsize=10, fontweight='bold')
|
| 959 |
+
|
| 960 |
+
# Chart 2: Annual Projection
|
| 961 |
+
bars2 = ax2.barh(y_pos, annual_rewards, color=colors, edgecolor='black', linewidth=1.5, alpha=0.85)
|
| 962 |
+
|
| 963 |
+
ax2.set_yticks(y_pos)
|
| 964 |
+
ax2.set_yticklabels([''] * len(cards)) # Hide labels on second chart
|
| 965 |
+
ax2.set_xlabel('Annual Rewards ($)', fontsize=12, fontweight='bold')
|
| 966 |
+
ax2.set_title('📊 Estimated Annual Value', fontsize=13, fontweight='bold')
|
| 967 |
+
ax2.grid(axis='x', alpha=0.3, linestyle='--')
|
| 968 |
+
ax2.set_axisbelow(True)
|
| 969 |
+
|
| 970 |
+
# Add labels
|
| 971 |
+
for i, (bar, reward) in enumerate(zip(bars2, annual_rewards)):
|
| 972 |
+
label = f'⭐ ${reward:.2f}' if i == 0 else f'${reward:.2f}'
|
| 973 |
+
ax2.text(reward + max(annual_rewards)*0.02, bar.get_y() + bar.get_height()/2,
|
| 974 |
+
label, va='center', fontsize=10, fontweight='bold')
|
| 975 |
+
|
| 976 |
+
# Set limits
|
| 977 |
+
ax1.set_xlim(0, max(current_rewards) * 1.15)
|
| 978 |
+
ax2.set_xlim(0, max(annual_rewards) * 1.15)
|
| 979 |
+
|
| 980 |
+
# Add overall legend
|
| 981 |
+
from matplotlib.patches import Patch
|
| 982 |
+
legend_elements = [
|
| 983 |
+
Patch(facecolor='#2ecc71', edgecolor='black', label='⭐ Recommended'),
|
| 984 |
+
Patch(facecolor='#3498db', edgecolor='black', label='Alternatives')
|
| 985 |
+
]
|
| 986 |
+
fig.legend(handles=legend_elements, loc='lower center', ncol=2, fontsize=11, framealpha=0.9)
|
| 987 |
|
| 988 |
+
plt.tight_layout()
|
| 989 |
+
plt.subplots_adjust(bottom=0.1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 990 |
|
| 991 |
return fig
|
| 992 |
+
|
| 993 |
except Exception as e:
|
| 994 |
print(f"Chart creation error: {e}")
|
| 995 |
+
import traceback
|
| 996 |
+
traceback.print_exc()
|
| 997 |
+
return None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 998 |
|
| 999 |
+
|
| 1000 |
def get_analytics_with_insights(user_id):
|
| 1001 |
"""Get analytics with LLM-generated insights"""
|
| 1002 |
|
|
|
|
| 1761 |
<strong>You have 5 credit cards. You're at checkout. Which one do you use?</strong><br>
|
| 1762 |
Most people pick wrong and lose <strong>$400+ per year</strong>.<br>
|
| 1763 |
Our AI agent makes the optimal choice in <strong>2 seconds</strong>.<br>
|
| 1764 |
+
Powered by <strong>OpenAI GPT-4 + Gemini + Modal</strong><br>
|
| 1765 |
</p>
|
| 1766 |
|
| 1767 |
<div class="impact-stats">
|