sammy786 commited on
Commit
5ebb9f5
·
verified ·
1 Parent(s): f3df99f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +68 -73
app.py CHANGED
@@ -115,6 +115,11 @@ def normalize_recommendation_data(data: Dict) -> Dict:
115
  }
116
 
117
  return normalized
 
 
 
 
 
118
 
119
  from datetime import date
120
  from typing import Optional, Tuple, List, Dict, Any
@@ -222,23 +227,26 @@ def get_recommendation_with_ai(user_id, merchant, category, amount):
222
  if amount <= 0:
223
  return "❌ Please enter a valid amount greater than $0.", None
224
 
 
 
 
225
  try:
226
  # Get base recommendation from orchestrator
227
- # Note: Your API client expects (user_id, merchant, category, amount, mcc)
228
  result = client.get_recommendation(
229
  user_id=user_id,
230
  merchant=merchant,
231
  category=category,
232
  amount=float(amount),
233
- mcc=None # Let the client map category to MCC
234
  )
235
 
236
  # Check for errors
237
  if not result.get('success'):
238
  error_msg = result.get('error', 'Unknown error')
239
- return f"❌ Error: {error_msg}", None
 
240
 
241
- # Normalize the data to ensure all fields exist
242
  data = normalize_recommendation_data(result.get('data', {}))
243
 
244
  # Generate LLM explanation if enabled
@@ -260,38 +268,30 @@ def get_recommendation_with_ai(user_id, merchant, category, amount):
260
  print(f"LLM explanation failed: {e}")
261
  ai_explanation = ""
262
 
263
- # Format output with AI explanation
264
  output = f"""
265
  ## 🎯 Recommendation for ${amount:.2f} at {merchant}
266
 
267
  ### 💳 Best Card: **{data['recommended_card']}**
268
 
269
  **Rewards Earned:** ${data['rewards_earned']:.2f} ({data['rewards_rate']})
270
-
271
  """
272
 
273
- # Add mock data indicator
274
  if data.get('mock_data'):
275
  output += """
276
  > ⚠️ **Demo Mode:** Using sample data. Connect to orchestrator for real recommendations.
277
-
278
  """
279
 
280
- # Add AI explanation if available
281
  if ai_explanation:
282
  output += f"""
283
  ### 🤖 AI Insight
284
-
285
  {ai_explanation}
286
 
287
  ---
288
-
289
  """
290
 
291
- # Add detailed breakdown
292
  output += f"""
293
  ### 📊 Breakdown
294
-
295
  - **Category:** {data['category']}
296
  - **Merchant:** {data['merchant']}
297
  - **Reasoning:** {data['reasoning']}
@@ -299,13 +299,11 @@ def get_recommendation_with_ai(user_id, merchant, category, amount):
299
  - **Optimization Score:** {data['optimization_score']}/100
300
  """
301
 
302
- # Add warnings
303
  if data['warnings']:
304
  output += "\n\n### ⚠️ Important Warnings\n\n"
305
  for warning in data['warnings']:
306
  output += f"- {warning}\n"
307
 
308
- # Add alternatives
309
  if data['alternatives']:
310
  output += "\n\n### 🔄 Alternative Options\n\n"
311
  for alt in data['alternatives']:
@@ -314,14 +312,13 @@ def get_recommendation_with_ai(user_id, merchant, category, amount):
314
  # Create visualization
315
  chart = create_rewards_comparison_chart(data)
316
 
317
- return output, chart
318
 
319
  except Exception as e:
320
  import traceback
321
  error_details = traceback.format_exc()
322
  print(f"Recommendation error: {error_details}")
323
- return f"❌ Error: {str(e)}\n\nPlease check your API connection or try again.", None
324
-
325
 
326
  def create_rewards_comparison_chart(data: Dict) -> go.Figure:
327
  """Create rewards comparison chart with proper error handling"""
@@ -839,50 +836,59 @@ Get AI-powered credit card recommendations that maximize your rewards based on:
839
  )
840
 
841
  # ===================== Analytics Update Function (ENHANCED) =====================
842
- def update_analytics_with_charts(user_id: str) -> tuple:
843
  """Fetch and format analytics with charts for selected user"""
844
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
845
  try:
846
  # Fetch analytics data from API
847
  result = client.get_user_analytics(user_id)
848
 
849
- # DEBUG: Print what we received
850
- print("=" * 60)
851
- print(f"DEBUG: Analytics for {user_id}")
852
- print(f"Success: {result.get('success')}")
853
- print(f"Has data key: {'data' in result}")
854
- if result.get('data'):
855
- print(f"Data keys: {result['data'].keys()}")
856
- print(f"Category breakdown length: {len(result['data'].get('category_breakdown', []))}")
857
- print("=" * 60)
858
-
859
  # Check if request was successful
860
  if not result.get('success'):
861
  error_msg = result.get('error', 'Unknown error')
862
- empty_fig = create_empty_chart(f"Error: {error_msg}")
863
- return (
864
  f"<p>❌ Error: {error_msg}</p>",
865
- empty_fig, empty_fig, empty_fig, empty_fig, empty_fig,
866
  "Error loading data",
867
  "Error loading data",
868
  "Error loading data",
869
  f"*Error: {error_msg}*"
870
  )
 
871
 
872
- # ✅ FIX: Extract the actual data (unwrap from success wrapper)
873
  analytics_data = result.get('data', {})
874
 
875
- # Verify we have data
876
  if not analytics_data:
877
- empty_fig = create_empty_chart("No analytics data available")
878
- return (
879
  "<p>No data available</p>",
880
- empty_fig, empty_fig, empty_fig, empty_fig, empty_fig,
881
  "No data",
882
  "No data",
883
  "No data",
884
  "*No data available*"
885
  )
 
886
 
887
  # Import chart functions
888
  from utils.formatters import (
@@ -894,10 +900,10 @@ Get AI-powered credit card recommendations that maximize your rewards based on:
894
  create_card_performance_chart
895
  )
896
 
897
- # Format text data (pass unwrapped data)
898
  metrics_html, table_md, insights_md, forecast_md = format_analytics_metrics(analytics_data)
899
 
900
- # Generate charts (pass unwrapped data)
901
  spending_fig = create_spending_chart(analytics_data)
902
  pie_fig = create_rewards_pie_chart(analytics_data)
903
  gauge_fig = create_optimization_gauge(analytics_data)
@@ -908,17 +914,17 @@ Get AI-powered credit card recommendations that maximize your rewards based on:
908
  from datetime import datetime
909
  status = f"*Analytics updated for {user_id} at {datetime.now().strftime('%I:%M %p')}*"
910
 
911
- return (
912
- metrics_html, # Metric cards
913
- spending_fig, # Spending bar chart
914
- gauge_fig, # Optimization gauge
915
- pie_fig, # Rewards pie chart
916
- performance_fig, # Card performance chart
917
- trend_fig, # Trend line chart
918
- table_md, # Spending table
919
- insights_md, # Insights text
920
- forecast_md, # Forecast text
921
- status # Status message
922
  )
923
 
924
  except Exception as e:
@@ -928,18 +934,17 @@ Get AI-powered credit card recommendations that maximize your rewards based on:
928
  print(error_msg)
929
  print(error_details)
930
 
931
- # Return empty/error states
932
- empty_fig = create_empty_chart("Error loading chart")
933
 
934
- return (
935
  f"<p>{error_msg}</p>",
936
- empty_fig, empty_fig, empty_fig, empty_fig, empty_fig,
937
  "Error loading table",
938
  "Error loading insights",
939
  "Error loading forecast",
940
  f"*{error_msg}*"
941
  )
942
-
943
 
944
  def create_empty_chart(message: str) -> go.Figure:
945
  """Helper to create empty chart with message"""
@@ -1009,11 +1014,15 @@ Get AI-powered credit card recommendations that maximize your rewards based on:
1009
  )
1010
 
1011
  def respond(message, chat_history, user_id):
1012
- """Handle chat responses with error handling"""
1013
  if not message.strip():
1014
  return "", chat_history
1015
 
1016
- # Get user context with error handling
 
 
 
 
1017
  user_context = {}
1018
  try:
1019
  analytics = client.get_user_analytics(user_id)
@@ -1032,7 +1041,7 @@ Get AI-powered credit card recommendations that maximize your rewards based on:
1032
  'top_category': 'Groceries'
1033
  }
1034
 
1035
- # Generate AI response with error handling
1036
  try:
1037
  if config.LLM_ENABLED:
1038
  bot_response = llm.chat_response(message, user_context, chat_history)
@@ -1043,21 +1052,7 @@ Get AI-powered credit card recommendations that maximize your rewards based on:
1043
  bot_response = f"I encountered an error. Please try asking your question differently."
1044
 
1045
  chat_history.append((message, bot_response))
1046
- return "", chat_history
1047
-
1048
- msg.submit(respond, [msg, chatbot, chat_user], [msg, chatbot])
1049
- send_btn.click(respond, [msg, chatbot, chat_user], [msg, chatbot])
1050
-
1051
- # Example questions
1052
- gr.Examples(
1053
- examples=[
1054
- ["Which card should I use at Costco?"],
1055
- ["How can I maximize my grocery rewards?"],
1056
- ["What's the best travel card for international trips?"],
1057
- ["Am I close to any spending caps?"],
1058
- ],
1059
- inputs=[msg]
1060
- )
1061
  # ========== Tab 3: About ==========
1062
  with gr.Tab("ℹ️ About"):
1063
  gr.Markdown(
 
115
  }
116
 
117
  return normalized
118
+
119
+ def create_loading_state():
120
+ """Create loading indicator message"""
121
+ return "⏳ **Loading...** Please wait while we fetch your recommendation.", None
122
+
123
 
124
  from datetime import date
125
  from typing import Optional, Tuple, List, Dict, Any
 
227
  if amount <= 0:
228
  return "❌ Please enter a valid amount greater than $0.", None
229
 
230
+ # Show loading state
231
+ yield "⏳ **Loading recommendation...** Analyzing your cards and transaction...", None
232
+
233
  try:
234
  # Get base recommendation from orchestrator
 
235
  result = client.get_recommendation(
236
  user_id=user_id,
237
  merchant=merchant,
238
  category=category,
239
  amount=float(amount),
240
+ mcc=None
241
  )
242
 
243
  # Check for errors
244
  if not result.get('success'):
245
  error_msg = result.get('error', 'Unknown error')
246
+ yield f"❌ Error: {error_msg}", None
247
+ return
248
 
249
+ # Normalize the data
250
  data = normalize_recommendation_data(result.get('data', {}))
251
 
252
  # Generate LLM explanation if enabled
 
268
  print(f"LLM explanation failed: {e}")
269
  ai_explanation = ""
270
 
271
+ # Format output
272
  output = f"""
273
  ## 🎯 Recommendation for ${amount:.2f} at {merchant}
274
 
275
  ### 💳 Best Card: **{data['recommended_card']}**
276
 
277
  **Rewards Earned:** ${data['rewards_earned']:.2f} ({data['rewards_rate']})
 
278
  """
279
 
 
280
  if data.get('mock_data'):
281
  output += """
282
  > ⚠️ **Demo Mode:** Using sample data. Connect to orchestrator for real recommendations.
 
283
  """
284
 
 
285
  if ai_explanation:
286
  output += f"""
287
  ### 🤖 AI Insight
 
288
  {ai_explanation}
289
 
290
  ---
 
291
  """
292
 
 
293
  output += f"""
294
  ### 📊 Breakdown
 
295
  - **Category:** {data['category']}
296
  - **Merchant:** {data['merchant']}
297
  - **Reasoning:** {data['reasoning']}
 
299
  - **Optimization Score:** {data['optimization_score']}/100
300
  """
301
 
 
302
  if data['warnings']:
303
  output += "\n\n### ⚠️ Important Warnings\n\n"
304
  for warning in data['warnings']:
305
  output += f"- {warning}\n"
306
 
 
307
  if data['alternatives']:
308
  output += "\n\n### 🔄 Alternative Options\n\n"
309
  for alt in data['alternatives']:
 
312
  # Create visualization
313
  chart = create_rewards_comparison_chart(data)
314
 
315
+ yield output, chart
316
 
317
  except Exception as e:
318
  import traceback
319
  error_details = traceback.format_exc()
320
  print(f"Recommendation error: {error_details}")
321
+ yield f"❌ Error: {str(e)}\n\nPlease check your API connection or try again.", None
 
322
 
323
  def create_rewards_comparison_chart(data: Dict) -> go.Figure:
324
  """Create rewards comparison chart with proper error handling"""
 
836
  )
837
 
838
  # ===================== Analytics Update Function (ENHANCED) =====================
839
+ def update_analytics_with_charts(user_id: str):
840
  """Fetch and format analytics with charts for selected user"""
841
 
842
+ # Show loading state first
843
+ empty_fig = create_empty_chart("⏳ Loading...")
844
+ loading_html = """
845
+ <div style="text-align: center; padding: 40px;">
846
+ <h2>⏳ Loading Analytics...</h2>
847
+ <p>Please wait while we fetch your data</p>
848
+ </div>
849
+ """
850
+
851
+ yield (
852
+ loading_html,
853
+ empty_fig, empty_fig, empty_fig, empty_fig, empty_fig,
854
+ "⏳ Loading...",
855
+ "⏳ Loading...",
856
+ "⏳ Loading...",
857
+ "*Loading analytics...*"
858
+ )
859
+
860
  try:
861
  # Fetch analytics data from API
862
  result = client.get_user_analytics(user_id)
863
 
 
 
 
 
 
 
 
 
 
 
864
  # Check if request was successful
865
  if not result.get('success'):
866
  error_msg = result.get('error', 'Unknown error')
867
+ error_fig = create_empty_chart(f"Error: {error_msg}")
868
+ yield (
869
  f"<p>❌ Error: {error_msg}</p>",
870
+ error_fig, error_fig, error_fig, error_fig, error_fig,
871
  "Error loading data",
872
  "Error loading data",
873
  "Error loading data",
874
  f"*Error: {error_msg}*"
875
  )
876
+ return
877
 
878
+ # Extract the actual data
879
  analytics_data = result.get('data', {})
880
 
 
881
  if not analytics_data:
882
+ error_fig = create_empty_chart("No analytics data available")
883
+ yield (
884
  "<p>No data available</p>",
885
+ error_fig, error_fig, error_fig, error_fig, error_fig,
886
  "No data",
887
  "No data",
888
  "No data",
889
  "*No data available*"
890
  )
891
+ return
892
 
893
  # Import chart functions
894
  from utils.formatters import (
 
900
  create_card_performance_chart
901
  )
902
 
903
+ # Format text data
904
  metrics_html, table_md, insights_md, forecast_md = format_analytics_metrics(analytics_data)
905
 
906
+ # Generate charts
907
  spending_fig = create_spending_chart(analytics_data)
908
  pie_fig = create_rewards_pie_chart(analytics_data)
909
  gauge_fig = create_optimization_gauge(analytics_data)
 
914
  from datetime import datetime
915
  status = f"*Analytics updated for {user_id} at {datetime.now().strftime('%I:%M %p')}*"
916
 
917
+ yield (
918
+ metrics_html,
919
+ spending_fig,
920
+ gauge_fig,
921
+ pie_fig,
922
+ performance_fig,
923
+ trend_fig,
924
+ table_md,
925
+ insights_md,
926
+ forecast_md,
927
+ status
928
  )
929
 
930
  except Exception as e:
 
934
  print(error_msg)
935
  print(error_details)
936
 
937
+ error_fig = create_empty_chart("Error loading chart")
 
938
 
939
+ yield (
940
  f"<p>{error_msg}</p>",
941
+ error_fig, error_fig, error_fig, error_fig, error_fig,
942
  "Error loading table",
943
  "Error loading insights",
944
  "Error loading forecast",
945
  f"*{error_msg}*"
946
  )
947
+
948
 
949
  def create_empty_chart(message: str) -> go.Figure:
950
  """Helper to create empty chart with message"""
 
1014
  )
1015
 
1016
  def respond(message, chat_history, user_id):
1017
+ """Handle chat responses with error handling and loading state"""
1018
  if not message.strip():
1019
  return "", chat_history
1020
 
1021
+ # Add loading message
1022
+ loading_history = chat_history + [(message, "⏳ Thinking...")]
1023
+ yield "", loading_history
1024
+
1025
+ # Get user context
1026
  user_context = {}
1027
  try:
1028
  analytics = client.get_user_analytics(user_id)
 
1041
  'top_category': 'Groceries'
1042
  }
1043
 
1044
+ # Generate AI response
1045
  try:
1046
  if config.LLM_ENABLED:
1047
  bot_response = llm.chat_response(message, user_context, chat_history)
 
1052
  bot_response = f"I encountered an error. Please try asking your question differently."
1053
 
1054
  chat_history.append((message, bot_response))
1055
+ yield "", chat_history
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1056
  # ========== Tab 3: About ==========
1057
  with gr.Tab("ℹ️ About"):
1058
  gr.Markdown(