File size: 6,907 Bytes
f4d0231 11d553c ccb76e6 f4d0231 1eec6c9 ccb76e6 1eec6c9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
"""API client for RewardPilot Orchestrator"""
import httpx
from typing import Dict, Optional
from config import ORCHESTRATOR_URL
from typing import Any, Dict, List, Optional, Tuple
import logging
# Create logger
logger = logging.getLogger(__name__)
class RewardPilotClient:
"""Client for interacting with RewardPilot Orchestrator"""
def __init__(self, base_url: str = ORCHESTRATOR_URL):
self.base_url = base_url.rstrip('/')
self.timeout = 30.0
async def get_recommendation(
self,
user_id: str,
merchant: str,
mcc: str,
amount_usd: float,
transaction_date: Optional[str] = None
) -> Dict:
"""Get card recommendation from orchestrator"""
async with httpx.AsyncClient(timeout=self.timeout) as client:
try:
payload = {
"user_id": user_id,
"merchant": merchant,
"mcc": mcc,
"amount_usd": amount_usd
}
if transaction_date:
payload["transaction_date"] = transaction_date
response = await client.post(
f"{self.base_url}/recommend",
json=payload
)
response.raise_for_status()
return response.json()
except httpx.HTTPError as e:
return {
"error": True,
"message": f"API Error: {str(e)}"
}
except Exception as e:
return {
"error": True,
"message": f"Unexpected error: {str(e)}"
}
def get_recommendation_sync(
self,
user_id: str,
merchant: str,
mcc: str,
amount_usd: float,
transaction_date: Optional[str] = None
) -> Dict:
"""Synchronous version for Gradio"""
import asyncio
try:
loop = asyncio.get_event_loop()
except RuntimeError:
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
return loop.run_until_complete(
self.get_recommendation(
user_id, merchant, mcc, amount_usd, transaction_date
)
)
def get_user_analytics(self, user_id: str) -> Dict[str, Any]:
"""
Fetch user analytics including spending patterns and optimization metrics
Args:
user_id: User identifier
Returns:
Dictionary containing analytics data
"""
try:
# Option 1: If you have a dedicated analytics endpoint
response = httpx.get(
f"{self.orchestrator_url}/analytics/{user_id}",
timeout=30.0
)
response.raise_for_status()
return response.json()
except Exception as e:
logger.error(f"Analytics fetch failed: {e}")
# Return mock data as fallback
return self._get_mock_analytics(user_id)
def _get_mock_analytics(self, user_id: str) -> Dict[str, Any]:
"""Generate mock analytics data for demo purposes"""
import random
# Different data per user for variety
user_multipliers = {
"u_alice": 1.2,
"u_bob": 0.9,
"u_charlie": 1.5,
}
multiplier = user_multipliers.get(user_id, 1.0)
return {
"user_id": user_id,
"annual_savings": round(342 * multiplier, 2),
"rate_increase": round(23 * multiplier, 1),
"optimized_transactions": int(156 * multiplier),
"optimization_score": min(100, int(87 * multiplier)),
"category_breakdown": [
{
"category": "π Groceries",
"monthly_spend": round(450 * multiplier, 2),
"best_card": "Amex Gold",
"rewards": round(27 * multiplier, 2),
"rate": "6%"
},
{
"category": "π½οΈ Restaurants",
"monthly_spend": round(320 * multiplier, 2),
"best_card": "Amex Gold",
"rewards": round(12.8 * multiplier, 2),
"rate": "4%"
},
{
"category": "β½ Gas",
"monthly_spend": round(180 * multiplier, 2),
"best_card": "Costco Visa",
"rewards": round(7.2 * multiplier, 2),
"rate": "4%"
},
{
"category": "βοΈ Travel",
"monthly_spend": round(850 * multiplier, 2),
"best_card": "Sapphire Reserve",
"rewards": round(42.5 * multiplier, 2),
"rate": "5%"
},
{
"category": "π¬ Entertainment",
"monthly_spend": round(125 * multiplier, 2),
"best_card": "Freedom Unlimited",
"rewards": round(1.88 * multiplier, 2),
"rate": "1.5%"
},
{
"category": "πͺ Online Shopping",
"monthly_spend": round(280 * multiplier, 2),
"best_card": "Amazon Prime",
"rewards": round(16.8 * multiplier, 2),
"rate": "6%"
}
],
"total_monthly_spend": round(2205 * multiplier, 2),
"total_monthly_rewards": round(108.18 * multiplier, 2),
"average_rate": round(4.9, 1),
"top_categories": [
{"name": "βοΈ Travel", "amount": round(850 * multiplier, 2), "change": "+45%"},
{"name": "π Groceries", "amount": round(450 * multiplier, 2), "change": "+12%"},
{"name": "π½οΈ Restaurants", "amount": round(320 * multiplier, 2), "change": "-5%"}
],
"ytd_rewards": round(1298.16 * multiplier, 2),
"ytd_potential": round(1640 * multiplier, 2),
"money_left": round(341.84 * multiplier, 2),
"forecast": {
"next_month_spend": round(2350 * multiplier, 2),
"next_month_rewards": round(115.25 * multiplier, 2),
"cards_to_watch": ["Amex Gold (dining cap)", "Freedom (quarterly bonus)"]
},
"recommendations": [
"π³ Use Chase Freedom for groceries in Q4 (5% back)",
"β οΈ Monitor Amex Gold dining spend (cap at $2,000)",
"π― Book holiday travel with Sapphire Reserve for 5x points"
]
} |