sammy786 commited on
Commit
8bdc417
Β·
verified Β·
1 Parent(s): 41eea98

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +340 -9
app.py CHANGED
@@ -8,6 +8,7 @@ import gradio as gr
8
  import plotly.graph_objects as go
9
  import httpx
10
  import logging
 
11
 
12
  logging.basicConfig(level=logging.INFO)
13
  logger = logging.getLogger(__name__)
@@ -446,6 +447,7 @@ def get_recommendation_with_agent(user_id, merchant, category, amount):
446
 
447
  yield f"❌ Invalid response: No recommendation found", None
448
  return
 
449
 
450
 
451
  card_id = recommendation.get('recommended_card', 'Unknown')
@@ -493,6 +495,26 @@ def get_recommendation_with_agent(user_id, merchant, category, amount):
493
  print(f" Base rate: {base_rate}%")
494
  print(f" Annual fee: ${annual_fee}")
495
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
496
 
497
  # βœ… Calculate baseline comparison
498
  baseline_rewards = annual_spending * 0.01
@@ -574,7 +596,25 @@ def get_recommendation_with_agent(user_id, merchant, category, amount):
574
 
575
  ---
576
  """
577
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
578
  if alternatives:
579
  output += "\n### πŸ”„ Alternative Options\n\n"
580
  output += "| Rank | Card | Rewards | Rate | Why Ranked Here? |\n"
@@ -656,6 +696,12 @@ def get_recommendation_with_agent(user_id, merchant, category, amount):
656
 
657
  # βœ… Create chart
658
  chart = create_agent_recommendation_chart_enhanced(recommendation)
 
 
 
 
 
 
659
 
660
  yield output, chart
661
 
@@ -729,6 +775,13 @@ client = RewardPilotClient(config.ORCHESTRATOR_URL)
729
  # llm = get_llm_explainer()
730
  gemini = get_gemini_explainer()
731
 
 
 
 
 
 
 
 
732
  def get_recommendation(
733
  user_id: str,
734
  merchant: str,
@@ -2971,11 +3024,52 @@ with gr.Blocks(
2971
 
2972
 
2973
  def respond(message, chat_history, user_id, use_voice=False, voice_name="Rachel", voice_speed=1.0):
2974
- """Enhanced chat with OpenAI GPT-4 and optional voice output"""
2975
 
2976
  if not message.strip():
2977
  return "", chat_history, None
2978
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2979
  # Get user context (your existing logic)
2980
  user_context = {}
2981
  try:
@@ -3010,11 +3104,8 @@ with gr.Blocks(
3010
  }
3011
  ]
3012
 
3013
- # Build messages (your existing logic)
3014
- messages = [
3015
- {
3016
- "role": "system",
3017
- "content": f"""You are CardWise AI, an expert credit card rewards optimizer.
3018
 
3019
  User Context:
3020
  - User ID: {user_context.get('user_id', 'Unknown')}
@@ -3024,6 +3115,21 @@ with gr.Blocks(
3024
 
3025
  When voice mode is enabled, keep responses concise and conversational (under 200 words).
3026
  Be helpful, actionable, and friendly."""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3027
  }
3028
  ]
3029
 
@@ -3088,6 +3194,10 @@ with gr.Blocks(
3088
  else:
3089
  bot_response = response_message.content
3090
 
 
 
 
 
3091
  print(f"βœ… GPT-4 response generated")
3092
 
3093
  # Generate voice if enabled
@@ -3095,8 +3205,12 @@ with gr.Blocks(
3095
  if use_voice and voice_assistant.enabled:
3096
  try:
3097
  logger.info(f"🎀 Generating voice with {voice_name}")
 
 
 
 
3098
  audio_bytes = voice_assistant.text_to_speech(
3099
- text=bot_response,
3100
  voice_name=voice_name
3101
  )
3102
 
@@ -3124,7 +3238,6 @@ with gr.Blocks(
3124
  chat_history.append((message, bot_response))
3125
  return "", chat_history, audio_output
3126
 
3127
-
3128
 
3129
 
3130
  def generate_fallback_response(message: str, user_context: dict) -> str:
@@ -3644,7 +3757,225 @@ with gr.Blocks(
3644
  outputs=[receipt_output, receipt_chart]
3645
  )
3646
 
 
 
 
 
3647
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3648
  # ==================== TAB 6: RESOURCES (About + Agent Insight + API Docs) ====================
3649
  with gr.Tab("ℹ️ Resources"):
3650
  with gr.Tabs():
 
8
  import plotly.graph_objects as go
9
  import httpx
10
  import logging
11
+ from utils.llamaindex_rag import get_card_benefits_rag, initialize_rag
12
 
13
  logging.basicConfig(level=logging.INFO)
14
  logger = logging.getLogger(__name__)
 
447
 
448
  yield f"❌ Invalid response: No recommendation found", None
449
  return
450
+
451
 
452
 
453
  card_id = recommendation.get('recommended_card', 'Unknown')
 
495
  print(f" Base rate: {base_rate}%")
496
  print(f" Annual fee: ${annual_fee}")
497
 
498
+ llamaindex_context = None
499
+ spending_warnings = None
500
+
501
+ if rag.enabled: # rag was initialized at the top of the file
502
+ logger.info("πŸ“š Fetching RAG context...")
503
+
504
+ # Get card-specific context
505
+ llamaindex_context = rag.get_card_context(
506
+ card_name=card_name, # This variable already exists in your code
507
+ merchant=merchant,
508
+ category=category
509
+ )
510
+
511
+ # Get spending warnings
512
+ spending_warnings = rag.get_spending_warnings(
513
+ card_name=card_name,
514
+ category=category,
515
+ amount=amount
516
+ )
517
+
518
 
519
  # βœ… Calculate baseline comparison
520
  baseline_rewards = annual_spending * 0.01
 
596
 
597
  ---
598
  """
599
+
600
+ if llamaindex_context:
601
+ output += f"""
602
+
603
+ ---
604
+
605
+ ### πŸ“š Card Benefits & Details
606
+ **Powered by LlamaIndex RAG**
607
+
608
+ {llamaindex_context}
609
+ """
610
+
611
+ # βœ… NEW: Add spending warnings
612
+ if spending_warnings:
613
+ output += f"""
614
+
615
+ ### ⚠️ Important to Know
616
+ {spending_warnings}
617
+ """
618
  if alternatives:
619
  output += "\n### πŸ”„ Alternative Options\n\n"
620
  output += "| Rank | Card | Rewards | Rate | Why Ranked Here? |\n"
 
696
 
697
  # βœ… Create chart
698
  chart = create_agent_recommendation_chart_enhanced(recommendation)
699
+ if llamaindex_context or spending_warnings:
700
+ output += f"""
701
+ ---
702
+
703
+ *πŸ€– Enhanced with AI-powered knowledge retrieval using LlamaIndex + OpenAI Embeddings*
704
+ """
705
 
706
  yield output, chart
707
 
 
775
  # llm = get_llm_explainer()
776
  gemini = get_gemini_explainer()
777
 
778
+ logger.info("πŸš€ Initializing LlamaIndex RAG...")
779
+ card_rag = initialize_rag()
780
+ if card_rag.enabled:
781
+ logger.info("βœ… RAG system ready")
782
+ else:
783
+ logger.warning("⚠️ RAG system not available")
784
+
785
  def get_recommendation(
786
  user_id: str,
787
  merchant: str,
 
3024
 
3025
 
3026
  def respond(message, chat_history, user_id, use_voice=False, voice_name="Rachel", voice_speed=1.0):
3027
+ """Enhanced chat with OpenAI GPT-4, LlamaIndex RAG, and optional voice output"""
3028
 
3029
  if not message.strip():
3030
  return "", chat_history, None
3031
 
3032
+ # βœ… NEW: Check if question is about card benefits (RAG integration)
3033
+ rag = get_card_benefits_rag()
3034
+ rag_context = None
3035
+
3036
+ if rag.enabled:
3037
+ # Detect if question is about specific card
3038
+ card_keywords = ["amex", "gold", "chase", "sapphire", "reserve", "freedom", "unlimited",
3039
+ "citi", "double cash", "discover", "card", "benefit", "reward", "point",
3040
+ "cashback", "annual fee", "cap", "limit", "grocery", "dining", "travel"]
3041
+
3042
+ message_lower = message.lower()
3043
+ if any(keyword in message_lower for keyword in card_keywords):
3044
+ logger.info("πŸ“š Detected card-specific question, querying RAG...")
3045
+
3046
+ # Extract card name (simple heuristic)
3047
+ card_name = None
3048
+ if "sapphire reserve" in message_lower or "csr" in message_lower:
3049
+ card_name = "Chase Sapphire Reserve"
3050
+ elif "freedom unlimited" in message_lower or "cfu" in message_lower:
3051
+ card_name = "Chase Freedom Unlimited"
3052
+ elif "double cash" in message_lower:
3053
+ card_name = "Citi Double Cash"
3054
+ elif "discover" in message_lower:
3055
+ card_name = "Discover it"
3056
+ elif "amex gold" in message_lower or "american express gold" in message_lower:
3057
+ card_name = "Amex Gold"
3058
+ elif "gold" in message_lower and ("amex" in message_lower or "american express" in message_lower):
3059
+ card_name = "Amex Gold"
3060
+
3061
+ # Query RAG if card was identified
3062
+ if card_name:
3063
+ try:
3064
+ rag_context = rag.query_benefits(card_name, message)
3065
+ if rag_context:
3066
+ logger.info(f"βœ… RAG context retrieved: {len(rag_context)} chars for {card_name}")
3067
+ else:
3068
+ logger.warning(f"⚠️ RAG returned no context for {card_name}")
3069
+ except Exception as e:
3070
+ logger.error(f"❌ RAG query failed: {e}")
3071
+ rag_context = None
3072
+
3073
  # Get user context (your existing logic)
3074
  user_context = {}
3075
  try:
 
3104
  }
3105
  ]
3106
 
3107
+ # Build messages (your existing logic with RAG enhancement)
3108
+ system_content = f"""You are CardWise AI, an expert credit card rewards optimizer.
 
 
 
3109
 
3110
  User Context:
3111
  - User ID: {user_context.get('user_id', 'Unknown')}
 
3115
 
3116
  When voice mode is enabled, keep responses concise and conversational (under 200 words).
3117
  Be helpful, actionable, and friendly."""
3118
+
3119
+ # βœ… NEW: Add RAG context if available
3120
+ if rag_context:
3121
+ system_content += f"""
3122
+
3123
+ πŸ“š KNOWLEDGE BASE CONTEXT:
3124
+ {rag_context}
3125
+
3126
+ Use this information to provide accurate, detailed answers about card benefits.
3127
+ Always cite specific details from the knowledge base when relevant."""
3128
+
3129
+ messages = [
3130
+ {
3131
+ "role": "system",
3132
+ "content": system_content
3133
  }
3134
  ]
3135
 
 
3194
  else:
3195
  bot_response = response_message.content
3196
 
3197
+ # βœ… NEW: Add RAG attribution if context was used
3198
+ if rag_context:
3199
+ bot_response += "\n\n*πŸ“š Enhanced with knowledge base using LlamaIndex*"
3200
+
3201
  print(f"βœ… GPT-4 response generated")
3202
 
3203
  # Generate voice if enabled
 
3205
  if use_voice and voice_assistant.enabled:
3206
  try:
3207
  logger.info(f"🎀 Generating voice with {voice_name}")
3208
+
3209
+ # βœ… IMPROVED: Clean response for voice (remove RAG attribution)
3210
+ voice_text = bot_response.replace("*πŸ“š Enhanced with knowledge base using LlamaIndex*", "").strip()
3211
+
3212
  audio_bytes = voice_assistant.text_to_speech(
3213
+ text=voice_text,
3214
  voice_name=voice_name
3215
  )
3216
 
 
3238
  chat_history.append((message, bot_response))
3239
  return "", chat_history, audio_output
3240
 
 
3241
 
3242
 
3243
  def generate_fallback_response(message: str, user_context: dict) -> str:
 
3757
  outputs=[receipt_output, receipt_chart]
3758
  )
3759
 
3760
+
3761
+ # ==================== TAB: CARD KNOWLEDGE BASE (RAG) ====================
3762
+ with gr.Tab("πŸ“š Knowledge Base"):
3763
+ rag = get_card_benefits_rag()
3764
 
3765
+ if rag.enabled:
3766
+ gr.HTML("""
3767
+ <div style="background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
3768
+ padding: 30px; border-radius: 16px; color: white; margin-bottom: 25px;">
3769
+ <h2 style="margin: 0 0 15px 0;">πŸ“š AI-Powered Card Knowledge Base</h2>
3770
+ <p style="margin: 0; font-size: 17px; line-height: 1.7;">
3771
+ Search our comprehensive credit card database using <strong>LlamaIndex RAG</strong>
3772
+ powered by OpenAI embeddings and GPT-4.
3773
+ </p>
3774
+ <div style="background: rgba(255,255,255,0.15); padding: 15px;
3775
+ border-radius: 10px; margin-top: 15px;">
3776
+ <p style="margin: 0; font-size: 15px;">
3777
+ πŸ” <strong>Semantic Search:</strong> Ask natural language questions<br>
3778
+ 🎯 <strong>Accurate Answers:</strong> Powered by vector embeddings<br>
3779
+ ⚑ <strong>Real-time:</strong> Instant retrieval from knowledge base
3780
+ </p>
3781
+ </div>
3782
+ </div>
3783
+ """)
3784
+
3785
+ gr.Markdown("## πŸ” Search Card Benefits")
3786
+
3787
+ with gr.Row():
3788
+ kb_card = gr.Dropdown(
3789
+ choices=[
3790
+ "Amex Gold",
3791
+ "American Express Gold",
3792
+ "Chase Sapphire Reserve",
3793
+ "Chase Freedom Unlimited",
3794
+ "Citi Double Cash",
3795
+ "Discover it"
3796
+ ],
3797
+ label="πŸ’³ Select Card",
3798
+ value="Amex Gold",
3799
+ scale=1
3800
+ )
3801
+ kb_query = gr.Textbox(
3802
+ label="❓ Your Question",
3803
+ placeholder="e.g., Does this card work at Costco for groceries?",
3804
+ scale=3
3805
+ )
3806
+
3807
+ kb_search_btn = gr.Button("πŸ” Search Knowledge Base", variant="primary", size="lg")
3808
+
3809
+ kb_result = gr.Markdown(value="*Enter a question and click Search*")
3810
+
3811
+ def search_knowledge_base(card, question):
3812
+ """Search card benefits using LlamaIndex RAG"""
3813
+ if not question or not question.strip():
3814
+ return "⚠️ Please enter a question"
3815
+
3816
+ rag = get_card_benefits_rag()
3817
+
3818
+ if not rag.enabled:
3819
+ return """
3820
+ ## ⚠️ RAG Not Available
3821
+
3822
+ The LlamaIndex RAG system is not currently enabled. This could be due to:
3823
+
3824
+ 1. Missing dependencies (llama-index not installed)
3825
+ 2. No OpenAI API key configured
3826
+ 3. No card benefit documents in data/card_benefits/
3827
+
3828
+ Please check the logs for more details.
3829
+ """
3830
+
3831
+ try:
3832
+ logger.info(f"πŸ” Knowledge base search: {card} - {question}")
3833
+ result = rag.query_benefits(card, question)
3834
+
3835
+ if result:
3836
+ return f"""
3837
+ ## 🎯 Answer for {card}
3838
+
3839
+ {result}
3840
+
3841
+ ---
3842
+
3843
+ ### πŸ“Š Search Details
3844
+ - **Card:** {card}
3845
+ - **Question:** {question}
3846
+ - **Source:** LlamaIndex RAG with GPT-4
3847
+ - **Embeddings:** OpenAI text-embedding-3-small
3848
+
3849
+ *πŸ’‘ This answer was retrieved using semantic search across our card benefits knowledge base.*
3850
+ """
3851
+ else:
3852
+ return f"""
3853
+ ## ❌ No Results Found
3854
+
3855
+ Could not find relevant information about **{card}** for your question:
3856
+
3857
+ > {question}
3858
+
3859
+ ### πŸ’‘ Suggestions:
3860
+ - Try rephrasing your question
3861
+ - Check if the card name is correct
3862
+ - Ask about specific features (earning rates, caps, exclusions)
3863
+ """
3864
+
3865
+ except Exception as e:
3866
+ logger.error(f"❌ Knowledge base search failed: {e}")
3867
+ return f"## ❌ Search Error\n\nAn error occurred: {str(e)}"
3868
+
3869
+ kb_search_btn.click(
3870
+ fn=search_knowledge_base,
3871
+ inputs=[kb_card, kb_query],
3872
+ outputs=[kb_result]
3873
+ )
3874
+
3875
+ gr.Markdown("---")
3876
+ gr.Markdown("### πŸ’‘ Example Questions")
3877
+
3878
+ gr.Examples(
3879
+ examples=[
3880
+ ["Amex Gold", "Does this card work at Costco for groceries?"],
3881
+ ["Amex Gold", "What's the annual spending cap on grocery purchases?"],
3882
+ ["Chase Sapphire Reserve", "What travel benefits does this card offer?"],
3883
+ ["Chase Sapphire Reserve", "Does Uber count as travel for earning points?"],
3884
+ ["Chase Freedom Unlimited", "What's the earning rate on dining?"],
3885
+ ["Citi Double Cash", "How does the 2% cash back work?"],
3886
+ ["Discover it", "What are the rotating categories this quarter?"],
3887
+ ],
3888
+ inputs=[kb_card, kb_query],
3889
+ label="Try these questions"
3890
+ )
3891
+
3892
+ # Card comparison feature
3893
+ gr.Markdown("---")
3894
+ gr.Markdown("## βš–οΈ Compare Cards")
3895
+
3896
+ with gr.Row():
3897
+ compare_card1 = gr.Dropdown(
3898
+ choices=["Amex Gold", "Chase Sapphire Reserve", "Chase Freedom Unlimited",
3899
+ "Citi Double Cash", "Discover it"],
3900
+ label="Card 1",
3901
+ value="Amex Gold"
3902
+ )
3903
+ compare_card2 = gr.Dropdown(
3904
+ choices=["Amex Gold", "Chase Sapphire Reserve", "Chase Freedom Unlimited",
3905
+ "Citi Double Cash", "Discover it"],
3906
+ label="Card 2",
3907
+ value="Chase Sapphire Reserve"
3908
+ )
3909
+ compare_category = gr.Dropdown(
3910
+ choices=["Dining", "Groceries", "Travel", "Gas", "General Spending"],
3911
+ label="Category",
3912
+ value="Dining"
3913
+ )
3914
+
3915
+ compare_btn = gr.Button("βš–οΈ Compare Cards", variant="secondary", size="lg")
3916
+ compare_result = gr.Markdown(value="*Select cards and click Compare*")
3917
+
3918
+ def compare_cards_ui(card1, card2, category):
3919
+ """Compare two cards for a specific category"""
3920
+ if card1 == card2:
3921
+ return "⚠️ Please select two different cards"
3922
+
3923
+ rag = get_card_benefits_rag()
3924
+
3925
+ if not rag.enabled:
3926
+ return "⚠️ RAG not available"
3927
+
3928
+ try:
3929
+ result = rag.compare_cards(card1, card2, category)
3930
+
3931
+ if result:
3932
+ return f"""
3933
+ ## βš–οΈ Comparison: {card1} vs {card2}
3934
+
3935
+ ### Category: {category}
3936
+
3937
+ {result}
3938
+
3939
+ ---
3940
+
3941
+ *πŸ“š Powered by LlamaIndex RAG*
3942
+ """
3943
+ else:
3944
+ return "❌ Could not generate comparison"
3945
+
3946
+ except Exception as e:
3947
+ logger.error(f"❌ Comparison failed: {e}")
3948
+ return f"❌ Error: {str(e)}"
3949
+
3950
+ compare_btn.click(
3951
+ fn=compare_cards_ui,
3952
+ inputs=[compare_card1, compare_card2, compare_category],
3953
+ outputs=[compare_result]
3954
+ )
3955
+
3956
+ else:
3957
+ # RAG not available
3958
+ gr.HTML("""
3959
+ <div style="background: linear-gradient(135deg, #ff6b6b 0%, #ee5a6f 100%);
3960
+ padding: 30px; border-radius: 16px; color: white; margin-bottom: 25px;">
3961
+ <h2 style="margin: 0 0 15px 0;">⚠️ Knowledge Base Not Available</h2>
3962
+ <p style="margin: 0; font-size: 17px;">
3963
+ The LlamaIndex RAG system requires additional setup.
3964
+ </p>
3965
+ </div>
3966
+ """)
3967
+
3968
+ gr.Markdown("""
3969
+ ## πŸ”§ Setup Required
3970
+
3971
+ To enable the Knowledge Base:
3972
+
3973
+ 1. Install dependencies: `pip install llama-index`
3974
+ 2. Add OpenAI API key
3975
+ 3. Create card benefit documents in `data/card_benefits/`
3976
+ 4. Restart the application
3977
+ """)
3978
+
3979
  # ==================== TAB 6: RESOURCES (About + Agent Insight + API Docs) ====================
3980
  with gr.Tab("ℹ️ Resources"):
3981
  with gr.Tabs():