|
|
"""Response formatting utilities""" |
|
|
|
|
|
from typing import Dict |
|
|
|
|
|
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')}" |
|
|
|
|
|
|
|
|
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 = response.get("recommended_card", {}) |
|
|
output += format_card_display(recommended) |
|
|
|
|
|
|
|
|
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 = 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} |
|
|
""" |
|
|
|
|
|
|
|
|
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) |
|
|
|
|
|
|
|
|
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 |
|
|
|
|
|
|
|
|
|
|
|
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) |
|
|
""" |
|
|
|
|
|
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> |
|
|
""" |
|
|
|
|
|
|
|
|
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']}%** | |
|
|
""" |
|
|
|
|
|
|
|
|
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'],[object Object],['best_card']} - ${analytics['category_breakdown'],[object Object],['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}** |
|
|
""" |
|
|
|
|
|
|
|
|
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 |