sammy786 commited on
Commit
9c3dc25
Β·
verified Β·
1 Parent(s): 72aba91

Update utils/gemini_explainer.py

Browse files
Files changed (1) hide show
  1. utils/gemini_explainer.py +163 -27
utils/gemini_explainer.py CHANGED
@@ -1,16 +1,41 @@
 
 
1
  import google.generativeai as genai
2
  from typing import Dict, List, Optional
3
  import config
 
 
 
 
 
4
 
5
  class GeminiExplainer:
6
  """Alternative LLM explainer using Google Gemini"""
7
 
8
  def __init__(self):
9
- if config.GEMINI_API_KEY:
 
 
 
 
 
 
 
 
 
10
  genai.configure(api_key=config.GEMINI_API_KEY)
11
  self.model = genai.GenerativeModel(config.GEMINI_MODEL)
12
- self.enabled = True
13
- else:
 
 
 
 
 
 
 
 
 
14
  self.enabled = False
15
 
16
  def explain_recommendation(
@@ -27,10 +52,14 @@ class GeminiExplainer:
27
  ) -> str:
28
  """Generate explanation using Gemini"""
29
 
30
- if not self.enabled:
31
- return "Gemini explainer not configured"
 
 
 
32
 
33
- prompt = f"""You are a friendly financial advisor explaining credit card rewards to everyday consumers.
 
34
 
35
  Transaction Details:
36
  - Merchant: {merchant}
@@ -39,19 +68,69 @@ Transaction Details:
39
 
40
  Recommended Card: {card}
41
  Rewards Earned: ${rewards:.2f} ({rewards_rate})
42
- Annual Potential: ${annual_potential:.2f}/year
43
 
44
- Task: Explain in 2-3 simple sentences why this card is the best choice. Use friendly, conversational language.
45
- Focus on the tangible benefit (e.g., "That's like getting a free coffee every week!").
 
 
 
 
 
 
 
 
 
46
 
47
- {"Warnings to mention: " + ", ".join(warnings) if warnings else ""}
48
- """
49
-
50
  try:
51
- response = self.model.generate_content(prompt)
52
- return response.text
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  except Exception as e:
54
- return f"Gemini explanation unavailable: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  def generate_spending_insights(
57
  self,
@@ -64,10 +143,12 @@ Focus on the tangible benefit (e.g., "That's like getting a free coffee every we
64
  ) -> str:
65
  """Generate personalized insights using Gemini"""
66
 
67
- if not self.enabled:
68
- return "Gemini insights not configured"
 
 
69
 
70
- prompt = f"""You are a financial coach reviewing a user's credit card rewards performance.
71
 
72
  User Stats:
73
  - Total Spending: ${total_spending:.2f}
@@ -77,15 +158,70 @@ User Stats:
77
  - Top Categories: {', '.join([c.get('category', 'Unknown') for c in top_categories[:3]])}
78
 
79
  Task: Provide 3 actionable insights in a friendly, motivating tone. Each insight should be 1 sentence.
80
- Focus on what they're doing well and one improvement opportunity.
81
- """
82
-
 
 
 
 
 
 
83
  try:
84
- response = self.model.generate_content(prompt)
85
- return response.text
 
 
 
 
 
 
 
 
 
 
 
 
 
86
  except Exception as e:
87
- return f"Gemini insights unavailable: {str(e)}"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
88
 
89
- def get_gemini_explainer():
90
- """Factory function to get Gemini explainer"""
91
- return GeminiExplainer()
 
 
 
 
 
 
1
+ # utils/gemini_explainer.py - FIXED VERSION
2
+
3
  import google.generativeai as genai
4
  from typing import Dict, List, Optional
5
  import config
6
+ import logging
7
+
8
+ logging.basicConfig(level=logging.INFO)
9
+ logger = logging.getLogger(__name__)
10
+
11
 
12
  class GeminiExplainer:
13
  """Alternative LLM explainer using Google Gemini"""
14
 
15
  def __init__(self):
16
+ self.enabled = False
17
+ self.model = None
18
+
19
+ # Check if API key exists
20
+ if not config.GEMINI_API_KEY:
21
+ logger.warning("⚠️ GEMINI_API_KEY not found in environment variables")
22
+ return
23
+
24
+ # Try to initialize Gemini
25
+ try:
26
  genai.configure(api_key=config.GEMINI_API_KEY)
27
  self.model = genai.GenerativeModel(config.GEMINI_MODEL)
28
+
29
+ # Test the connection with a simple prompt
30
+ test_response = self.model.generate_content("Say 'Hello'")
31
+ if test_response.text:
32
+ self.enabled = True
33
+ logger.info(f"βœ… Gemini explainer initialized successfully with model: {config.GEMINI_MODEL}")
34
+ else:
35
+ logger.error("❌ Gemini test failed: No response text")
36
+
37
+ except Exception as e:
38
+ logger.error(f"❌ Failed to initialize Gemini: {str(e)}")
39
  self.enabled = False
40
 
41
  def explain_recommendation(
 
52
  ) -> str:
53
  """Generate explanation using Gemini"""
54
 
55
+ if not self.enabled or not self.model:
56
+ logger.warning("⚠️ Gemini not enabled, returning fallback explanation")
57
+ return self._generate_fallback_explanation(
58
+ card, rewards, rewards_rate, merchant, category, amount
59
+ )
60
 
61
+ # Build prompt for consumer-friendly explanation
62
+ prompt = f"""You are a friendly financial advisor helping everyday consumers optimize their credit card rewards.
63
 
64
  Transaction Details:
65
  - Merchant: {merchant}
 
68
 
69
  Recommended Card: {card}
70
  Rewards Earned: ${rewards:.2f} ({rewards_rate})
71
+ Annual Potential: ${annual_potential:.2f}/year if you use this card for similar purchases
72
 
73
+ Task: Explain in 2-3 simple, conversational sentences why this card is the best choice for this purchase.
74
+
75
+ Guidelines:
76
+ 1. Start with the tangible benefit (e.g., "You'll earn $5.02 back on this purchase")
77
+ 2. Explain the reward rate in simple terms (avoid jargon)
78
+ 3. Add a relatable comparison (e.g., "That's like getting a free coffee!")
79
+ 4. Be encouraging and friendly
80
+
81
+ {"⚠️ Important: Mention this warning - " + warnings[0] if warnings else ""}
82
+
83
+ Keep it under 100 words and use everyday language."""
84
 
 
 
 
85
  try:
86
+ logger.info(f"πŸ€– Calling Gemini for {merchant} recommendation...")
87
+
88
+ response = self.model.generate_content(
89
+ prompt,
90
+ generation_config=genai.types.GenerationConfig(
91
+ temperature=0.7,
92
+ max_output_tokens=200,
93
+ )
94
+ )
95
+
96
+ if response.text:
97
+ logger.info(f"βœ… Gemini explanation generated successfully")
98
+ return response.text.strip()
99
+ else:
100
+ logger.warning("⚠️ Gemini returned empty response")
101
+ return self._generate_fallback_explanation(
102
+ card, rewards, rewards_rate, merchant, category, amount
103
+ )
104
+
105
  except Exception as e:
106
+ logger.error(f"❌ Gemini explanation failed: {str(e)}")
107
+ return self._generate_fallback_explanation(
108
+ card, rewards, rewards_rate, merchant, category, amount
109
+ )
110
+
111
+ def _generate_fallback_explanation(
112
+ self,
113
+ card: str,
114
+ rewards: float,
115
+ rewards_rate: str,
116
+ merchant: str,
117
+ category: str,
118
+ amount: float
119
+ ) -> str:
120
+ """Generate rule-based explanation when Gemini is unavailable"""
121
+
122
+ explanation = f"The **{card}** is your best choice for this {category.lower()} purchase at {merchant}. "
123
+ explanation += f"You'll earn **{rewards_rate}**, which gives you **${rewards:.2f}** back on this transaction. "
124
+
125
+ # Add relatable comparison
126
+ if rewards >= 5:
127
+ explanation += "That's like getting a free lunch! πŸ”"
128
+ elif rewards >= 3:
129
+ explanation += "That's like getting a free coffee! β˜•"
130
+ else:
131
+ explanation += "Every bit of savings counts! πŸ’°"
132
+
133
+ return explanation
134
 
135
  def generate_spending_insights(
136
  self,
 
143
  ) -> str:
144
  """Generate personalized insights using Gemini"""
145
 
146
+ if not self.enabled or not self.model:
147
+ return self._generate_fallback_insights(
148
+ total_spending, total_rewards, optimization_score
149
+ )
150
 
151
+ prompt = f"""You are a personal finance coach reviewing a user's credit card rewards performance.
152
 
153
  User Stats:
154
  - Total Spending: ${total_spending:.2f}
 
158
  - Top Categories: {', '.join([c.get('category', 'Unknown') for c in top_categories[:3]])}
159
 
160
  Task: Provide 3 actionable insights in a friendly, motivating tone. Each insight should be 1 sentence.
161
+
162
+ Guidelines:
163
+ 1. Start with praise for what they're doing well
164
+ 2. Identify their biggest opportunity (highest spending category)
165
+ 3. Give one specific, actionable tip to improve their score
166
+ 4. Use emojis and be encouraging!
167
+
168
+ Keep it under 120 words."""
169
+
170
  try:
171
+ response = self.model.generate_content(
172
+ prompt,
173
+ generation_config=genai.types.GenerationConfig(
174
+ temperature=0.8,
175
+ max_output_tokens=200,
176
+ )
177
+ )
178
+
179
+ if response.text:
180
+ return response.text.strip()
181
+ else:
182
+ return self._generate_fallback_insights(
183
+ total_spending, total_rewards, optimization_score
184
+ )
185
+
186
  except Exception as e:
187
+ logger.error(f"❌ Gemini insights generation failed: {str(e)}")
188
+ return self._generate_fallback_insights(
189
+ total_spending, total_rewards, optimization_score
190
+ )
191
+
192
+ def _generate_fallback_insights(
193
+ self,
194
+ total_spending: float,
195
+ total_rewards: float,
196
+ optimization_score: int
197
+ ) -> str:
198
+ """Generate rule-based insights when Gemini unavailable"""
199
+
200
+ rewards_rate = (total_rewards / total_spending * 100) if total_spending > 0 else 0
201
+
202
+ insights = f"You're earning **${total_rewards:.2f}** in rewards on **${total_spending:.2f}** of spending "
203
+ insights += f"(**{rewards_rate:.1f}%** effective rate). "
204
+
205
+ if optimization_score >= 80:
206
+ insights += "🌟 **Excellent optimization!** You're maximizing your rewards effectively. "
207
+ elif optimization_score >= 60:
208
+ insights += "πŸ‘ **Good progress!** Consider using our recommendations more consistently. "
209
+ else:
210
+ insights += "πŸ’‘ **Room for improvement!** Follow our card suggestions to boost your rewards. "
211
+
212
+ insights += "Keep tracking your spending to identify new optimization opportunities."
213
+
214
+ return insights
215
+
216
+
217
+ # Singleton instance
218
+ _gemini_explainer = None
219
 
220
+ def get_gemini_explainer() -> GeminiExplainer:
221
+ """Get or create singleton Gemini explainer instance"""
222
+ global _gemini_explainer
223
+
224
+ if _gemini_explainer is None:
225
+ _gemini_explainer = GeminiExplainer()
226
+
227
+ return _gemini_explainer