rewardpilot-web-ui / utils /formatters.py
sammy786's picture
Update utils/formatters.py
7b57542 verified
raw
history blame
13.9 kB
"""Response formatting utilities"""
from typing import Any, Dict, List, Optional, Tuple
import plotly.graph_objects as go
import plotly.express as px
def format_card_display(card_data: Dict) -> str:
"""Format card recommendation for display"""
card_name = card_data.get("card_name", "Unknown Card")
reward_rate = card_data.get("reward_rate", 0)
reward_amount = card_data.get("reward_amount", 0)
category = card_data.get("category", "General")
reasoning = card_data.get("reasoning", "")
return f"""
### 💳 {card_name}
**Reward Rate:** {reward_rate}x points
**Reward Amount:** ${reward_amount:.2f}
**Category:** {category}
**Why:** {reasoning}
"""
def format_full_recommendation(response: Dict) -> str:
"""Format complete recommendation response"""
if response.get("error"):
return f"❌ **Error:** {response.get('message', 'Unknown error')}"
# Header
output = f"""
# 🎯 Recommendation for {response.get('merchant', 'Unknown')}
**Amount:** ${response.get('amount_usd', 0):.2f}
**Date:** {response.get('transaction_date', 'N/A')}
**User:** {response.get('user_id', 'N/A')}
---
## 🏆 Best Card to Use
"""
# Recommended card
recommended = response.get("recommended_card", {})
output += format_card_display(recommended)
# RAG Insights
rag_insights = response.get("rag_insights")
if rag_insights:
output += f"""
---
## 📚 Card Benefits
{rag_insights.get('benefits', 'No additional information available.')}
"""
if rag_insights.get('tips'):
output += f"""
💡 **Pro Tip:** {rag_insights.get('tips')}
"""
# Forecast Warning
forecast = response.get("forecast_warning")
if forecast:
risk_level = forecast.get("risk_level", "low")
message = forecast.get("message", "")
if risk_level == "high":
emoji = "🚨"
elif risk_level == "medium":
emoji = "⚠️"
else:
emoji = "✅"
output += f"""
---
## {emoji} Spending Status
{message}
**Current Spend:** ${forecast.get('current_spend', 0):.2f}
**Spending Cap:** ${forecast.get('cap', 0):.2f}
**Projected Spend:** ${forecast.get('projected_spend', 0):.2f}
"""
# Alternative cards
alternatives = response.get("alternative_cards", [])
if alternatives:
output += "\n---\n\n## 🔄 Alternative Cards\n\n"
for i, alt in enumerate(alternatives[:2], 1):
output += f"### Option {i}\n"
output += format_card_display(alt)
# Metadata
services = response.get("services_used", [])
time_ms = response.get("orchestration_time_ms", 0)
output += f"""
---
**Services Used:** {', '.join(services)}
**Response Time:** {time_ms:.0f}ms
"""
return output
def format_comparison_table(cards: list) -> str:
"""Format card comparison as markdown table"""
if not cards:
return "No cards to compare."
table = """
| Card | Reward Rate | Reward Amount | Category |
|------|-------------|---------------|----------|
"""
for card in cards:
name = card.get("card_name", "Unknown")
rate = card.get("reward_rate", 0)
amount = card.get("reward_amount", 0)
category = card.get("category", "N/A")
table += f"| {name} | {rate}x | ${amount:.2f} | {category} |\n"
return table
# utils/formatters.py
def format_analytics_metrics(analytics: Dict[str, Any]) -> tuple:
"""
Format analytics data for display
Returns:
Tuple of (metrics_html, table_md, insights_md, forecast_md)
"""
# Format metric cards
metrics_html = f"""
<div style="display: flex; gap: 10px; flex-wrap: wrap;">
<div class="metric-card" style="flex: 1; min-width: 200px;">
<h2>${analytics['annual_savings']}</h2>
<p>💰 Potential Annual Savings</p>
</div>
<div class="metric-card metric-card-green" style="flex: 1; min-width: 200px;">
<h2>{analytics['rate_increase']}%</h2>
<p>📈 Rewards Rate Increase</p>
</div>
<div class="metric-card metric-card-orange" style="flex: 1; min-width: 200px;">
<h2>{analytics['optimized_transactions']}</h2>
<p>✅ Optimized Transactions</p>
</div>
<div class="metric-card metric-card-blue" style="flex: 1; min-width: 200px;">
<h2>{analytics['optimization_score']}/100</h2>
<p>⭐ Optimization Score</p>
</div>
</div>
"""
# Format spending breakdown table
table_rows = []
for cat in analytics['category_breakdown']:
table_rows.append(
f"| {cat['category']} | ${cat['monthly_spend']:.2f} | {cat['best_card']} | "
f"${cat['rewards']:.2f} | {cat['rate']} |"
)
table_md = f"""
| Category | Monthly Spend | Best Card | Rewards | Rate |
|----------|---------------|-----------|---------|------|
{chr(10).join(table_rows)}
| **Total** | **${analytics['total_monthly_spend']:.2f}** | - | **${analytics['total_monthly_rewards']:.2f}** | **{analytics['average_rate']}%** |
"""
# Format insights
top_cats = "\n".join([
f"{i+1}. {cat['name']}: ${cat['amount']:.2f} ({cat['change']})"
for i, cat in enumerate(analytics['top_categories'])
])
insights_md = f"""
**🔥 Top Spending Categories:**
{top_cats}
**💡 Optimization Opportunities:**
- ✅ You're using optimal cards {analytics['optimization_score']}% of the time
- 🎯 Switch to Chase Freedom for Q4 5% grocery bonus
- ⚠️ Amex Gold dining cap approaching ($2,000 limit)
- 💳 Consider applying for Citi Custom Cash
**🏆 Best Performing Card:**
{analytics['category_breakdown'][0]['best_card']} - ${analytics['category_breakdown'][0]['rewards']:.2f} rewards earned
**📊 Year-to-Date:**
- Total Rewards: ${analytics['ytd_rewards']:.2f}
- Potential if optimized: ${analytics['ytd_potential']:.2f}
- **Money left on table: ${analytics['money_left']:.2f}**
"""
# Format forecast
forecast = analytics['forecast']
recommendations = "\n".join([f"{i+1}. {rec}" for i, rec in enumerate(analytics['recommendations'])])
forecast_md = f"""
### 🔮 Next Month Forecast
Based on your spending patterns:
- **Predicted Spend:** ${forecast['next_month_spend']:.2f}
- **Predicted Rewards:** ${forecast['next_month_rewards']:.2f}
- **Cards to Watch:** {', '.join(forecast['cards_to_watch'])}
**Recommendations:**
{recommendations}
"""
return metrics_html, table_md, insights_md, forecast_md
def create_spending_chart(analytics: Dict[str, Any]) -> go.Figure:
"""
Create a bar chart showing spending by category
Args:
analytics: Analytics data dictionary
Returns:
Plotly figure object
"""
categories = [cat['category'] for cat in analytics['category_breakdown']]
spending = [cat['monthly_spend'] for cat in analytics['category_breakdown']]
rewards = [cat['rewards'] for cat in analytics['category_breakdown']]
fig = go.Figure()
# Add spending bars
fig.add_trace(go.Bar(
name='Monthly Spend',
x=categories,
y=spending,
marker_color='rgb(102, 126, 234)',
text=[f'${s:.0f}' for s in spending],
textposition='outside',
))
# Add rewards bars
fig.add_trace(go.Bar(
name='Rewards Earned',
x=categories,
y=rewards,
marker_color='rgb(56, 239, 125)',
text=[f'${r:.2f}' for r in rewards],
textposition='outside',
))
fig.update_layout(
title='💰 Spending vs Rewards by Category',
xaxis_title='Category',
yaxis_title='Amount ($)',
barmode='group',
height=400,
template='plotly_white',
showlegend=True,
legend=dict(
orientation="h",
yanchor="bottom",
y=1.02,
xanchor="right",
x=1
)
)
return fig
def create_rewards_pie_chart(analytics: Dict[str, Any]) -> go.Figure:
"""
Create a pie chart showing rewards distribution by category
Args:
analytics: Analytics data dictionary
Returns:
Plotly figure object
"""
categories = [cat['category'] for cat in analytics['category_breakdown']]
rewards = [cat['rewards'] for cat in analytics['category_breakdown']]
fig = go.Figure(data=[go.Pie(
labels=categories,
values=rewards,
hole=0.4, # Donut chart
marker=dict(
colors=['#667eea', '#764ba2', '#f093fb', '#f5576c', '#4facfe', '#00f2fe']
),
textinfo='label+percent',
textposition='outside',
hovertemplate='<b>%{label}</b><br>Rewards: $%{value:.2f}<br>%{percent}<extra></extra>'
)])
fig.update_layout(
title='🎯 Rewards Distribution by Category',
height=400,
template='plotly_white',
showlegend=True,
legend=dict(
orientation="v",
yanchor="middle",
y=0.5,
xanchor="left",
x=1.05
)
)
return fig
def create_optimization_gauge(analytics: Dict[str, Any]) -> go.Figure:
"""
Create a gauge chart showing optimization score
Args:
analytics: Analytics data dictionary
Returns:
Plotly figure object
"""
score = analytics['optimization_score']
fig = go.Figure(go.Indicator(
mode="gauge+number+delta",
value=score,
domain={'x': [0, 1], 'y': [0, 1]},
title={'text': "⭐ Optimization Score", 'font': {'size': 24}},
delta={'reference': 80, 'increasing': {'color': "green"}},
gauge={
'axis': {'range': [None, 100], 'tickwidth': 1, 'tickcolor': "darkblue"},
'bar': {'color': "darkblue"},
'bgcolor': "white",
'borderwidth': 2,
'bordercolor': "gray",
'steps': [
{'range': [0, 50], 'color': '#ffcccb'},
{'range': [50, 75], 'color': '#ffffcc'},
{'range': [75, 100], 'color': '#ccffcc'}
],
'threshold': {
'line': {'color': "red", 'width': 4},
'thickness': 0.75,
'value': 90
}
}
))
fig.update_layout(
height=300,
template='plotly_white',
margin=dict(l=20, r=20, t=60, b=20)
)
return fig
def create_trend_line_chart(analytics: Dict[str, Any]) -> go.Figure:
"""
Create a line chart showing spending trends (mock data for demo)
Args:
analytics: Analytics data dictionary
Returns:
Plotly figure object
"""
import random
# Generate mock monthly data
months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
# Base spending with some variance
base_spend = analytics['total_monthly_spend']
spending_data = [base_spend * (0.8 + random.random() * 0.4) for _ in months]
# Calculate rewards based on average rate
avg_rate = analytics['average_rate'] / 100
rewards_data = [spend * avg_rate for spend in spending_data]
fig = go.Figure()
# Add spending line
fig.add_trace(go.Scatter(
x=months,
y=spending_data,
mode='lines+markers',
name='Monthly Spending',
line=dict(color='rgb(102, 126, 234)', width=3),
marker=dict(size=8),
hovertemplate='<b>%{x}</b><br>Spending: $%{y:.2f}<extra></extra>'
))
# Add rewards line
fig.add_trace(go.Scatter(
x=months,
y=rewards_data,
mode='lines+markers',
name='Rewards Earned',
line=dict(color='rgb(56, 239, 125)', width=3),
marker=dict(size=8),
hovertemplate='<b>%{x}</b><br>Rewards: $%{y:.2f}<extra></extra>'
))
fig.update_layout(
title='📈 12-Month Spending & Rewards Trend',
xaxis_title='Month',
yaxis_title='Amount ($)',
height=400,
template='plotly_white',
hovermode='x unified',
showlegend=True,
legend=dict(
orientation="h",
yanchor="bottom",
y=1.02,
xanchor="right",
x=1
)
)
return fig
def create_card_performance_chart(analytics: Dict[str, Any]) -> go.Figure:
"""
Create a horizontal bar chart showing card performance
Args:
analytics: Analytics data dictionary
Returns:
Plotly figure object
"""
# Aggregate rewards by card
card_rewards = {}
for cat in analytics['category_breakdown']:
card = cat['best_card']
reward = cat['rewards']
if card in card_rewards:
card_rewards[card] += reward
else:
card_rewards[card] = reward
# Sort by rewards
sorted_cards = sorted(card_rewards.items(), key=lambda x: x[0], reverse=True)
cards = [card for card, _ in sorted_cards]
rewards = [reward for _, reward in sorted_cards]
fig = go.Figure(go.Bar(
x=rewards,
y=cards,
orientation='h',
marker=dict(
color=rewards,
colorscale='Viridis',
showscale=True,
colorbar=dict(title="Rewards ($)")
),
text=[f'${r:.2f}' for r in rewards],
textposition='outside',
hovertemplate='<b>%{y}</b><br>Total Rewards: $%{x:.2f}<extra></extra>'
))
fig.update_layout(
title='🏆 Card Performance Ranking',
xaxis_title='Total Rewards Earned ($)',
yaxis_title='Credit Card',
height=400,
template='plotly_white',
margin=dict(l=150)
)
return fig