Update app.py
Browse files
app.py
CHANGED
|
@@ -546,88 +546,69 @@ def get_recommendation_with_agent(user_id, merchant, category, amount):
|
|
| 546 |
- <60: Suboptimal โ
|
| 547 |
"""
|
| 548 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 549 |
output = f"""
|
| 550 |
-
##
|
| 551 |
-
|
| 552 |
-
|
| 553 |
-
|
| 554 |
-
**Rewards Earned
|
| 555 |
-
**Confidence
|
| 556 |
-
|
| 557 |
-
|
| 558 |
-
|
| 559 |
-
|
| 560 |
-
|
| 561 |
-
|
| 562 |
-
|
| 563 |
-
|
| 564 |
-
|
|
|
|
|
|
|
| 565 |
|
|
|
|
| 566 |
if alternatives:
|
| 567 |
-
output += "\n### ๐ Alternative Options
|
|
|
|
|
|
|
| 568 |
for alt in alternatives[:3]:
|
| 569 |
alt_card_id = alt.get('card', '')
|
| 570 |
alt_card_name = card_name_map.get(alt_card_id, alt_card_id.replace('c_', '').replace('_', ' ').title())
|
| 571 |
-
alt_reason = alt.get('reason', '')
|
| 572 |
-
|
|
|
|
|
|
|
|
|
|
| 573 |
|
| 574 |
if warnings:
|
| 575 |
-
output += "\n### โ ๏ธ
|
| 576 |
for warning in warnings:
|
| 577 |
-
|
|
|
|
|
|
|
|
|
|
| 578 |
|
| 579 |
output += f"""
|
| 580 |
-
### ๐ฐ Annual Impact
|
| 581 |
-
|
| 582 |
-
- **Potential Savings:** ${net_benefit:.2f}/year
|
| 583 |
-
- **Optimization Score:** {optimization_score}/100
|
| 584 |
-
|
| 585 |
<details>
|
| 586 |
-
<summary>๐ <b>
|
| 587 |
-
|
| 588 |
-
#### ๐ก Calculation Assumptions:
|
| 589 |
|
| 590 |
-
**
|
|
|
|
|
|
|
| 591 |
|
| 592 |
-
|
| 593 |
-
Category: {category}
|
| 594 |
-
Frequency assumption: {frequency_label.capitalize()}
|
| 595 |
-
Annual estimate: ${amount_float:.2f} ร {frequency} = **${annual_spend:.2f}**
|
| 596 |
-
|
| 597 |
-
**Step 2: Calculate Rewards with {card_name}**
|
| 598 |
|
| 599 |
{calc_table}
|
| 600 |
|
| 601 |
-
**
|
| 602 |
-
|
| 603 |
-
{comparison_text}
|
| 604 |
-
|
| 605 |
-
---
|
| 606 |
|
| 607 |
-
|
| 608 |
-
|
| 609 |
-
{score_details}
|
| 610 |
-
|
| 611 |
-
---
|
| 612 |
-
|
| 613 |
-
#### ๐ Card Details:
|
| 614 |
-
|
| 615 |
-
- **Reward Rate:** {reward_rate_value}% on {category}
|
| 616 |
-
- **Monthly Cap:** {"$" + str(monthly_cap) if monthly_cap else "None"}
|
| 617 |
-
- **Annual Cap:** {"$" + str(annual_cap) if annual_cap else "None"}
|
| 618 |
-
- **Base Rate:** {base_rate}% (after cap)
|
| 619 |
-
- **Annual Fee:** ${annual_fee}
|
| 620 |
|
| 621 |
</details>
|
| 622 |
-
|
| 623 |
-
---
|
| 624 |
-
|
| 625 |
-
#### ๐ Transaction Details:
|
| 626 |
-
|
| 627 |
-
- **Amount:** ${amount_float:.2f}
|
| 628 |
-
- **Merchant:** {merchant}
|
| 629 |
-
- **Category:** {category}
|
| 630 |
-
- **MCC Code:** {transaction['mcc']}
|
| 631 |
"""
|
| 632 |
|
| 633 |
chart = create_agent_recommendation_chart_enhanced(result)
|
|
@@ -1205,65 +1186,51 @@ def load_user_forecast(user_id: str):
|
|
| 1205 |
{'category': 'Gas', 'predicted': 450.00, 'confidence': 0.85, 'emoji': 'โฝ'},
|
| 1206 |
],
|
| 1207 |
'recommendations': [
|
| 1208 |
-
"
|
| 1209 |
-
"
|
| 1210 |
-
"Travel spending
|
| 1211 |
],
|
| 1212 |
'optimization_potential': 45.50
|
| 1213 |
}
|
| 1214 |
|
| 1215 |
confidence = forecast_data.get('confidence', 0.85)
|
|
|
|
| 1216 |
confidence_color = '#4caf50' if confidence > 0.9 else '#ff9800' if confidence > 0.75 else '#f44336'
|
| 1217 |
|
| 1218 |
-
#
|
| 1219 |
output = f"""
|
| 1220 |
## ๐ฎ Next Month Forecast
|
| 1221 |
|
| 1222 |
-
**Confidence
|
| 1223 |
-
|
| 1224 |
-
---
|
| 1225 |
|
| 1226 |
-
### ๐
|
| 1227 |
|
| 1228 |
| Metric | Amount |
|
| 1229 |
|--------|--------|
|
| 1230 |
| ๐ฐ **Total Spending** | ${forecast_data['next_month_spending']:.2f} |
|
| 1231 |
| ๐ **Expected Rewards** | ${forecast_data['predicted_rewards']:.2f} |
|
| 1232 |
-
| ๐ **Optimization
|
| 1233 |
|
| 1234 |
---
|
| 1235 |
|
| 1236 |
-
|
| 1237 |
|
|
|
|
|
|
|
| 1238 |
"""
|
| 1239 |
|
| 1240 |
for cat in forecast_data['top_categories']:
|
| 1241 |
-
output += f""
|
| 1242 |
-
### {cat['emoji']} {cat['category']}
|
| 1243 |
-
|
| 1244 |
-
- **Predicted Amount:** ${cat['predicted']:.2f} (Confidence: {cat['confidence']*100:.0f}%)
|
| 1245 |
-
- **Recommendation:** Use best card for this category
|
| 1246 |
-
- **Potential Rewards:** Based on optimal card selection
|
| 1247 |
-
|
| 1248 |
-
"""
|
| 1249 |
|
| 1250 |
-
output += "\n---\n\n
|
| 1251 |
for i, rec in enumerate(forecast_data['recommendations'], 1):
|
| 1252 |
output += f"{i}. {rec}\n"
|
| 1253 |
|
| 1254 |
output += """
|
| 1255 |
-
|
| 1256 |
---
|
| 1257 |
|
| 1258 |
-
|
| 1259 |
-
|
| 1260 |
-
1. **Track your spending caps** - Don't miss out on bonus categories
|
| 1261 |
-
2. **Use category-specific cards** - Match each purchase to the best card
|
| 1262 |
-
3. **Monitor monthly limits** - Switch cards when you hit caps
|
| 1263 |
-
4. **Plan ahead** - Use these predictions to optimize your wallet
|
| 1264 |
-
|
| 1265 |
-
"""
|
| 1266 |
-
|
| 1267 |
# Create forecast chart
|
| 1268 |
fig = go.Figure()
|
| 1269 |
|
|
@@ -2205,24 +2172,6 @@ with gr.Blocks(
|
|
| 2205 |
)
|
| 2206 |
|
| 2207 |
|
| 2208 |
-
forecast_output = gr.HTML(value="<p><em>Loading forecast...</em></p>")
|
| 2209 |
-
forecast_chart = gr.Plot()
|
| 2210 |
-
|
| 2211 |
-
def update_forecast(user_id):
|
| 2212 |
-
return load_user_forecast(user_id)
|
| 2213 |
-
|
| 2214 |
-
forecast_user.change(
|
| 2215 |
-
fn=update_forecast,
|
| 2216 |
-
inputs=[forecast_user],
|
| 2217 |
-
outputs=[forecast_output, forecast_chart]
|
| 2218 |
-
)
|
| 2219 |
-
|
| 2220 |
-
refresh_forecast_btn.click(
|
| 2221 |
-
fn=update_forecast,
|
| 2222 |
-
inputs=[forecast_user],
|
| 2223 |
-
outputs=[forecast_output, forecast_chart]
|
| 2224 |
-
)
|
| 2225 |
-
|
| 2226 |
app.load(
|
| 2227 |
fn=update_forecast,
|
| 2228 |
inputs=[forecast_user],
|
|
|
|
| 546 |
- <60: Suboptimal โ
|
| 547 |
"""
|
| 548 |
|
| 549 |
+
# Extract key points from reasoning (first 3 sentences or bullet points)
|
| 550 |
+
reasoning_lines = reasoning.split('. ')[:3]
|
| 551 |
+
reasoning_bullets = '\n'.join([f"- {line.strip()}." for line in reasoning_lines if line.strip()])
|
| 552 |
+
|
| 553 |
output = f"""
|
| 554 |
+
## ๐ฏ Recommended: **{card_name}**
|
| 555 |
+
|
| 556 |
+
| Metric | Value |
|
| 557 |
+
|--------|-------|
|
| 558 |
+
| ๐ฐ **Rewards Earned** | ${rewards_earned:.2f} ({rewards_rate}) |
|
| 559 |
+
| ๐ **Confidence** | {confidence*100:.0f}% |
|
| 560 |
+
| ๐ **Annual Potential** | ${net_benefit:.2f}/year |
|
| 561 |
+
| โญ **Optimization Score** | {optimization_score}/100 |
|
| 562 |
+
|
| 563 |
+
---
|
| 564 |
+
|
| 565 |
+
### ๐ง Why This Card?
|
| 566 |
+
|
| 567 |
+
{reasoning_bullets}
|
| 568 |
+
|
| 569 |
+
---
|
| 570 |
+
"""
|
| 571 |
|
| 572 |
+
# Alternatives in compact table format
|
| 573 |
if alternatives:
|
| 574 |
+
output += "\n### ๐ Alternative Options\n\n"
|
| 575 |
+
output += "| Card | Rewards | Why? |\n"
|
| 576 |
+
output += "|------|---------|------|\n"
|
| 577 |
for alt in alternatives[:3]:
|
| 578 |
alt_card_id = alt.get('card', '')
|
| 579 |
alt_card_name = card_name_map.get(alt_card_id, alt_card_id.replace('c_', '').replace('_', ' ').title())
|
| 580 |
+
alt_reason = alt.get('reason', 'Good alternative')
|
| 581 |
+
# Truncate reason to first sentence
|
| 582 |
+
alt_reason_short = (lambda x: x[:60] + '...' if len(x) > 60 else x)(alt_reason.split('.')[0])
|
| 583 |
+
output += f"| {alt_card_name} | ${rec_reward * 0.8:.2f} | {alt_reason_short} |\n"
|
| 584 |
+
output += "\n---\n"
|
| 585 |
|
| 586 |
if warnings:
|
| 587 |
+
output += "\n### โ ๏ธ Alerts\n\n"
|
| 588 |
for warning in warnings:
|
| 589 |
+
# Shorten warnings to key info
|
| 590 |
+
warning_short = warning[:80] + '...' if len(warning) > 80 else warning
|
| 591 |
+
output += f"- {warning_short}\n"
|
| 592 |
+
output += "\n---\n"
|
| 593 |
|
| 594 |
output += f"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 595 |
<details>
|
| 596 |
+
<summary>๐ <b>Annual Impact Calculation</b> (Click to expand)</summary>
|
|
|
|
|
|
|
| 597 |
|
| 598 |
+
**Assumptions:**
|
| 599 |
+
- Transaction: ${amount_float:.2f} at {merchant} ({category})
|
| 600 |
+
- Frequency: {frequency_label} โ ${annual_spend:.2f}/year
|
| 601 |
|
| 602 |
+
**Rewards Breakdown:**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 603 |
|
| 604 |
{calc_table}
|
| 605 |
|
| 606 |
+
**vs. Baseline (1% card):** ${baseline_rewards:.2f}/year
|
| 607 |
+
**Net Benefit:** ${net_benefit:+.2f}/year {"๐" if net_benefit > 0 else "โ ๏ธ"}
|
|
|
|
|
|
|
|
|
|
| 608 |
|
| 609 |
+
**Card Details:** {reward_rate_value}% on {category} | Cap: {"$" + str(monthly_cap or annual_cap) if (monthly_cap or annual_cap) else "None"} | Fee: ${annual_fee}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 610 |
|
| 611 |
</details>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 612 |
"""
|
| 613 |
|
| 614 |
chart = create_agent_recommendation_chart_enhanced(result)
|
|
|
|
| 1186 |
{'category': 'Gas', 'predicted': 450.00, 'confidence': 0.85, 'emoji': 'โฝ'},
|
| 1187 |
],
|
| 1188 |
'recommendations': [
|
| 1189 |
+
"Use Amex Gold for groceries (4x points)",
|
| 1190 |
+
"Approaching Citi Custom Cash $500 cap",
|
| 1191 |
+
"Travel spending predicted to increase"
|
| 1192 |
],
|
| 1193 |
'optimization_potential': 45.50
|
| 1194 |
}
|
| 1195 |
|
| 1196 |
confidence = forecast_data.get('confidence', 0.85)
|
| 1197 |
+
confidence_badge = "High" if confidence > 0.9 else "Medium" if confidence > 0.75 else "Low"
|
| 1198 |
confidence_color = '#4caf50' if confidence > 0.9 else '#ff9800' if confidence > 0.75 else '#f44336'
|
| 1199 |
|
| 1200 |
+
# Compact output
|
| 1201 |
output = f"""
|
| 1202 |
## ๐ฎ Next Month Forecast
|
| 1203 |
|
| 1204 |
+
**Confidence:** {confidence*100:.0f}% ({confidence_badge})
|
|
|
|
|
|
|
| 1205 |
|
| 1206 |
+
### ๐ Summary
|
| 1207 |
|
| 1208 |
| Metric | Amount |
|
| 1209 |
|--------|--------|
|
| 1210 |
| ๐ฐ **Total Spending** | ${forecast_data['next_month_spending']:.2f} |
|
| 1211 |
| ๐ **Expected Rewards** | ${forecast_data['predicted_rewards']:.2f} |
|
| 1212 |
+
| ๐ **Extra with Optimization** | +${forecast_data['optimization_potential']:.2f} |
|
| 1213 |
|
| 1214 |
---
|
| 1215 |
|
| 1216 |
+
### ๐ Top Categories
|
| 1217 |
|
| 1218 |
+
| Category | Predicted | Confidence |
|
| 1219 |
+
|----------|-----------|------------|
|
| 1220 |
"""
|
| 1221 |
|
| 1222 |
for cat in forecast_data['top_categories']:
|
| 1223 |
+
output += f"| {cat['emoji']} {cat['category']} | ${cat['predicted']:.2f} | {cat['confidence']*100:.0f}% |\n"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1224 |
|
| 1225 |
+
output += "\n---\n\n### ๐ก Action Items\n\n"
|
| 1226 |
for i, rec in enumerate(forecast_data['recommendations'], 1):
|
| 1227 |
output += f"{i}. {rec}\n"
|
| 1228 |
|
| 1229 |
output += """
|
|
|
|
| 1230 |
---
|
| 1231 |
|
| 1232 |
+
**๐ก Tip:** Check the Analytics tab to see your current spending patterns and optimization opportunities.
|
| 1233 |
+
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1234 |
# Create forecast chart
|
| 1235 |
fig = go.Figure()
|
| 1236 |
|
|
|
|
| 2172 |
)
|
| 2173 |
|
| 2174 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2175 |
app.load(
|
| 2176 |
fn=update_forecast,
|
| 2177 |
inputs=[forecast_user],
|