Sulaiman8 commited on
Commit
0691955
·
verified ·
1 Parent(s): 77d12df

Delete recommender

Browse files
recommender/graph_retrieval_vectordb.py DELETED
@@ -1,226 +0,0 @@
1
- import google.generativeai as genai
2
- from neo4j import GraphDatabase
3
- import os
4
- import numpy as np
5
- import faiss
6
- from app import card_descriptions,eligibility_df
7
-
8
- #neo4j credentials
9
- NEO4J_URI = os.environ.get("NEO4J_URI")
10
- NEO4J_USER = os.environ.get("NEO4J_USER")
11
- NEO4J_PASS = os.environ.get("NEO4J_PASS")
12
- driver = GraphDatabase.driver(NEO4J_URI, auth=(NEO4J_USER, NEO4J_PASS))
13
-
14
- #generating cypher query
15
- def generate_cypher(user_query, query_intent, include_cobranded):
16
- genai.configure(api_key='AIzaSyAHoi9xbYAThtjXlyF_IKFtruoWYoUCjJQ')
17
- model3 = genai.GenerativeModel('gemini-1.5-flash-latest')
18
- print("inside cypher query gen")
19
-
20
- context_note = f"""
21
- Contextual Flags:
22
- - FD Card intent: {query_intent}
23
- - Include co-branded cards: {include_cobranded}
24
- """
25
-
26
- cypher_prompt = f"""
27
- You are an expert Neo4j Cypher query generator.
28
-
29
- Given a user’s question, graph schema, and **contextual flags**, generate the correct Cypher query. The query should return only the cards `c`.
30
-
31
- ONLY output the Cypher query. Do NOT explain anything.
32
-
33
- ---
34
-
35
- Graph Schema:
36
- - Nodes:
37
- - (Card): Properties = name, bank_name, card_type, premium, co_branded
38
- - (Feature): Properties = name
39
- - Relationships:
40
- - (Card)-[:HAS_FEATURE]->(Feature)
41
-
42
- Feature Inclusion Rules:
43
- - Only include relevant features based on user query.
44
- - Forex markup fee and foreign transaction fee are the same.
45
- - If FD Card intent is true then include the features if the query contains any and also include “General Cashback” or “General Reward Points”
46
- - Don’t add “General Cashback” or “General Reward Points” if it is not required.
47
- - If fuel is mentioned, include both `Fuel Benefits` and `Fuel Surcharge Waiver`.
48
- - **ALWAYS** match features using: `f.name IN [...]` — even if there is only **one** feature.
49
-
50
-
51
- Valid values:
52
- - card_type: 'FD Card' or 'Regular'
53
- - premium: true (no concept of false — just include it if applicable)
54
- - co_branded: true (no concept of false — just include it if applicable)
55
-
56
- MANDATORY Condition Rules:
57
- - If FD Card intent is true → include: `c.card_type = 'FD Card'`
58
- - Else → include: `c.card_type = 'Regular'`
59
- - If the query is based on beginners or students or people with no or low credit history then use FD Card.
60
- - If the query uses words like "premium", "elite", "luxury", "exclusive", "infinia", "black", etc. → include: `AND c.premium = true`
61
- - If the query includes low spending, without high spending or budget → include: `(c.premium IS NULL OR c.premium = false)`
62
- - If include co-branded is false → include: `AND (c.co_branded IS NULL OR c.co_branded = false)`
63
- - Use exact values for `bank_name` as in the database: ["SBI", "HDFC", "Axis", "ICICI", "YES", "HSBC", "IDFC", "American Express", "SMB", "Federal Bank", "AU Bank", "IDBI", "Kotak Mahindra Bank","IndusInd","RBL"]
64
- - Do not add bank after the name of the bank if it is not mentioned in the datase list.
65
- - These conditions are **MANDATORY**. If they apply, include them in the `WHERE` clause. Do not skip them.
66
-
67
- ---
68
-
69
- Available features:
70
- "General Cashback", "Fuel Surcharge Waiver", "Fuel Benefits", "Welcome Bonus",
71
- "Airport Lounge Access", "General Reward Points", "Domestic Travel Benefits",
72
- "Movie Benefits", "Flight Discounts", "International Travel Benefits",
73
- "Hotel Benefits", "Dining Benefits", "Daily Spends (Grocery)", "Railway Benefits",
74
- "Travel Benefits", "Railway Lounge", "Insurance", "Utility",
75
- "E-commerce Platform Benefits", "Air Miles", "Spa Access Benefits",
76
- "Lifestyle & Luxury Perks", "Golf Access & Perks", "Online Shopping Benefits",
77
- "UPI Transaction Support", "Health Benefits", "EMI Conversion Options",
78
- "No Forex Markup Fee", "Roadside Assistance", "Rupay Network Support",Super Premium Cards
79
-
80
- ---
81
-
82
- Few-shot Examples:
83
-
84
- User Query: Show premium cards with airport lounge access
85
- Cypher:
86
- MATCH (c:Card)-[:HAS_FEATURE]->(f:Feature)
87
- WHERE f.name IN ["Airport Lounge Access"]
88
- AND c.card_type = 'Regular'
89
- AND c.premium = true
90
- RETURN c
91
-
92
- User Query: I want FD cards with spa access and golf perks
93
- Cypher:
94
- MATCH (c:Card)-[:HAS_FEATURE]->(f:Feature)
95
- WHERE f.name IN ["Spa Access Benefits", "Golf Access & Perks"]
96
- AND c.card_type = 'FD Card'
97
- RETURN c
98
-
99
- User Query: Cards that support UPI but are not co-branded
100
- Cypher:
101
- MATCH (c:Card)-[:HAS_FEATURE]->(f:Feature)
102
- WHERE f.name IN ["UPI Transaction Support"]
103
- AND c.card_type = 'Regular'
104
- AND (c.co_branded IS NULL OR c.co_branded = false)
105
- RETURN c
106
-
107
- ---
108
-
109
- {context_note}
110
-
111
- User Query: {user_query}
112
- Cypher:
113
- """
114
-
115
- response = model3.generate_content(cypher_prompt.strip())
116
- cypher_code = response.text.strip()
117
-
118
- if cypher_code.startswith("```cypher"):
119
- cypher_code = cypher_code[len("```cypher"):].strip()
120
- elif cypher_code.startswith("```"):
121
- cypher_code = cypher_code[len("```"):].strip()
122
- if cypher_code.endswith("```"):
123
- cypher_code = cypher_code[:-3].strip()
124
-
125
- return cypher_code
126
-
127
- #generating embeddings (run only once)
128
- def chunk_text(text, chunk_size=1):
129
- sentences = text.split("; ")
130
- return ["; ".join(sentences[i:i+chunk_size]) for i in range(0, len(sentences), chunk_size)]
131
-
132
- def get_gemini_embeddings(text_list):
133
- embeddings = []
134
- print("Generating embeddings with Gemini...")
135
- for text in text_list:
136
- response = genai.embed_content(
137
- model=model_name,
138
- content=text,
139
- task_type="RETRIEVAL_DOCUMENT")
140
- embeddings.append(np.array(response["embedding"], dtype=np.float32))
141
- return np.vstack(embeddings)
142
-
143
- # Chunk all card descriptions
144
- chunk_texts = []
145
- chunk_name_mapping = {}
146
- for card_idx, (card_name, desc) in enumerate(card_descriptions.items()):
147
- chunks = chunk_text(desc)
148
- for chunk in chunks:
149
- chunk_index = len(chunk_texts)
150
- chunk_texts.append(chunk)
151
- chunk_name_mapping[chunk_index] = card_name
152
-
153
- genai.configure(api_key=os.environ.get("api_key_2"))
154
- model_name = "models/text-embedding-004"
155
-
156
- #Generating embeddings
157
- chunk_embeddings = get_gemini_embeddings(chunk_texts)
158
- faiss.normalize_L2(chunk_embeddings)
159
-
160
- print(f"Prepared {len(chunk_texts)} total chunks and embeddings.")
161
-
162
- #eligibility filter
163
- def eligibility_filter(cards, user_income, user_cibil, user_age,min_joining_fee, max_joining_fee,
164
- min_annual_fee, max_annual_fee):
165
- eligible_cards = []
166
- print("inside filter")
167
- for card_name in cards:
168
- # print(eligibility_df.columns)
169
-
170
- eligibility = eligibility_df[eligibility_df["Name"] == card_name]
171
-
172
- if not eligibility.empty:
173
- min_income = eligibility.iloc[0]["Minimum Income (LPA)"]
174
- min_cibil = eligibility.iloc[0]["Minimum Credit Score"]
175
- min_age = eligibility.iloc[0]["Minimum Age"]
176
- max_age = eligibility.iloc[0]["Maximum Age"]
177
- joining_fee=eligibility.iloc[0]["Joining fee"]
178
- annual_fee=eligibility.iloc[0]["Annual fee"]
179
- if (user_income >= min_income and
180
- user_cibil >= min_cibil and
181
- min_age <= user_age <= max_age and
182
- min_joining_fee<=joining_fee<=max_joining_fee and
183
- min_annual_fee<=annual_fee<=max_annual_fee):
184
- eligible_cards.append(card_name)
185
-
186
- return eligible_cards
187
-
188
-
189
-
190
- #function for retrieving cards from knowledge graph
191
- class Neo4jConnectionError(Exception):
192
- pass
193
-
194
- def run_cypher_query(user_query, query, use_eligibility, user_income, user_cibil, user_age,
195
- min_joining_fee, max_joining_fee, min_annual_fee, max_annual_fee):
196
-
197
- try:
198
- with driver.session() as session:
199
-
200
- result = session.run(query)
201
- matched_cards = [record["c"] for record in result]
202
- filtered_cards = [card["name"] for card in matched_cards]
203
-
204
- except Exception as e:
205
- raise Neo4jConnectionError("Failed to connect to the Neo4j database.") from e
206
-
207
- if use_eligibility:
208
- filtered_cards = eligibility_filter(filtered_cards, user_income, user_cibil, user_age,
209
- min_joining_fee, max_joining_fee,
210
- min_annual_fee, max_annual_fee)
211
-
212
- # for card in filtered_cards:
213
- # print("error")
214
- # print(card["name"])
215
- relevant_indexes = [i for i, name in chunk_name_mapping.items() if name in filtered_cards]
216
- filtered_embeddings = chunk_embeddings[relevant_indexes]
217
- filtered_texts = [chunk_texts[i] for i in relevant_indexes]
218
- filtered_mapping = {i: chunk_name_mapping[idx] for i, idx in enumerate(relevant_indexes)}
219
-
220
- # Build FAISS index
221
- dim = filtered_embeddings.shape[1]
222
- faiss_index = faiss.IndexFlatIP(dim)
223
- faiss_index.add(filtered_embeddings)
224
-
225
- print(f"FAISS index created with {len(filtered_embeddings)} filtered chunks.")
226
- return faiss_index, filtered_mapping
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
recommender/recommender.py DELETED
@@ -1,154 +0,0 @@
1
- import ast
2
- import re
3
- import pd
4
- import tempfile
5
- import os
6
- from intent_classification.fd_classification import find_intent
7
- from intent_classification.retrieval_classification import handle_query_classification,find_matching_card,generate_card_response_with_context
8
- from recommender.retrieval_ranking import generate_multi_queries,convert_to_direct_query_gradio,retrieve_and_rank_cards,generate_credit_card_recommendation_gemini,cross_encoder
9
- from app import eligibility_lookup,card_features_lookup
10
- from recommender.graph_retrieval_vectordb import generate_cypher,run_cypher_query,Neo4jConnectionError
11
-
12
- #function to pass the retrieved cards and generated response to the UI
13
- def recommend_cards_gradio(user_query, preferences, income, cibil, age,
14
- min_joining_fee, max_joining_fee,
15
- min_annual_fee, max_annual_fee,
16
- use_eligibility=True,include_cobranded=True):
17
- try:
18
- # print(user_query)
19
- if(user_query):
20
- result = handle_query_classification(user_query)
21
-
22
- if result["intent"] == "no_retrieval":
23
- return (
24
- f"<div style='background-color:#e3f2fd;padding:20px;border-radius:10px;'>"
25
- f"<pre style='white-space:pre-wrap;font-size:13px;color:#212121;'>{result['response']}</pre></div>",
26
- [["No retrieval required", "Answered using LLM"]],
27
- None,
28
- [],
29
- {},
30
- "Answered without retrieval"
31
- )
32
- elif result["intent"] == "specific":
33
- matched_card = find_matching_card(user_query)
34
- if matched_card:
35
- gemini_answer = generate_card_response_with_context(user_query, matched_card)
36
- card_name = matched_card["name"]
37
- card_desc = matched_card["description"]
38
- card_lookup = {card_name: card_desc}
39
-
40
- # Constructing eligibility info if available
41
- eligibility_info = eligibility_lookup.get(card_name, "No eligibility or fee information available.")
42
- chat_history_entry = f"{card_name}:\n{card_desc}\n\nEligibility & Fees:\n{eligibility_info}"
43
-
44
- return (
45
- f"<div style='background-color:#fffde7;padding:20px;border-radius:10px;'>"
46
- f"<pre style='white-space:pre-wrap;font-size:13px;color:#212121;'>{gemini_answer}</pre></div>",
47
- [["Specific card detected", card_name]],
48
- None,
49
- [],
50
- card_lookup,
51
- user_query
52
- )
53
- else:
54
- return (
55
- "<b style='color:red;'>Card mentioned not found in database.</b>",
56
- [["Card not found", "Try another card name."]],
57
- None,
58
- [],
59
- {},
60
- "Card not found"
61
- )
62
- direct_query = convert_to_direct_query_gradio(user_query, preferences)
63
- queries = generate_multi_queries(direct_query)
64
-
65
- if cibil < 700 and use_eligibility:
66
- query_intent = True
67
- else:
68
- query_intent = find_intent(user_query)
69
- print(query_intent)
70
- cypher_query = generate_cypher(direct_query, query_intent,include_cobranded)
71
- print("Generated Cypher:\n", cypher_query)
72
-
73
- try:
74
- faiss_index, filtered_mapping = run_cypher_query(
75
- user_query, cypher_query, use_eligibility,
76
- income, cibil, age,
77
- min_joining_fee, max_joining_fee,
78
- min_annual_fee, max_annual_fee
79
- )
80
- except Neo4jConnectionError as graph_err:
81
- return (
82
- "<b style='color:red;'>Graph database connection failed. Please try again later.</b>",
83
- [["Graph database error", str(graph_err)]],
84
- None,
85
- [],
86
- {},
87
- "Graph DB connection error"
88
- )
89
-
90
- cards = retrieve_and_rank_cards(faiss_index, filtered_mapping, direct_query, queries, top_k=10)
91
- gemini_summary = generate_credit_card_recommendation_gemini(user_query, direct_query, cards)
92
-
93
- if not cards:
94
- return (
95
- "<b style='color:red;'>No eligible cards found.</b>",
96
- [["No eligible cards found", "Please try a different query or check your input values."]],
97
- None,
98
- [],
99
- {},
100
- "No eligible card found"
101
- )
102
-
103
- match = re.search(r"f\.name IN (\[.*?\])", cypher_query)
104
- query_features = set(ast.literal_eval(match.group(1))) if match else set()
105
-
106
- card_rows = []
107
- for score, card in sorted(
108
- zip(cross_encoder.predict([[direct_query, card["description"]] for card in cards]), cards),
109
- reverse=True,
110
- key=lambda x: x[0]
111
- ):
112
- card_name = card["name"]
113
- card_desc = card["description"]
114
- matched_features = query_features.intersection(card_features_lookup.get(card_name, set()))
115
- feature_str = ", ".join(matched_features) if matched_features else "None"
116
- card_rows.append([card_name, feature_str, card_desc])
117
-
118
-
119
- card_names = [row[0] for row in card_rows]
120
- card_lookup = {row[0]: row[2] for row in card_rows}
121
- top_card_html = f"""
122
- <div style="
123
- background-color: #fff3e0;
124
- color: #212121;
125
- border-radius: 16px;
126
- padding: 20px;
127
- border: 2px solid #ffa726;
128
- box-shadow: 2px 2px 8px rgba(0,0,0,0.1);
129
- margin-bottom: 16px;
130
- font-family: sans-serif;
131
- font-size: 8px;
132
- ">
133
- <pre style="white-space: pre-wrap; font-size: 13px; color: #212121;">{gemini_summary}</pre>
134
- </div>
135
- """
136
-
137
- df_cards = pd.DataFrame(card_rows, columns=["Card Name", "Matched Features", "Description"])
138
- filename = "recommended_cards.csv"
139
- temp_dir = tempfile.gettempdir()
140
- file_path = os.path.join(temp_dir, filename)
141
- df_cards.to_csv(file_path, index=False)
142
-
143
- return top_card_html, card_rows, file_path, card_names, card_lookup, direct_query
144
-
145
- except Exception as e:
146
- print("Error:", e)
147
- return (
148
- "An unexpected error occurred. Please try again in a few minutes.",
149
- [["Something went wrong", "Please try again."]],
150
- None,
151
- [],
152
- {},
153
- "Unexpected error occurred, please try again in a while"
154
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
recommender/retrieval_ranking.py DELETED
@@ -1,215 +0,0 @@
1
- import numpy as np
2
- import faiss
3
- from collections import defaultdict
4
- import os
5
- import google.generativeai as genai
6
- from sentence_transformers import CrossEncoder
7
-
8
- # Function to generate direct query using Gemini
9
- def convert_to_direct_query_gradio(user_query,preferences):
10
- genai.configure(api_key=os.environ.get("api_key_2"))
11
- model2 = genai.GenerativeModel('gemini-1.5-flash-latest')
12
-
13
- preferences_text = ""
14
- if preferences:
15
- preferences_text = "User selected preferences: " + ", ".join(preferences) + "."
16
- # Prompt with examples for indirect-to-direct conversion
17
- prompt = f"""
18
- You are an AI assistant that refines user queries to make them optimized for information retrieval while keeping the original intent.
19
-
20
- Instructions:
21
- - Identify the main focus from the query.
22
- - Reformat the query in a structured way for better retrieval.
23
- - Ensure the most important feature appears first.
24
- - Use precise keywords that match credit card benefits.
25
- - Include the preferences also in the final query.
26
- - Do NOT introduce new benefits not mentioned by the user.
27
- - If the user uses vague terms like "vacation", interpret it as travel-related benefits including: airport lounge access, international/domestic travel, hotel benefits, forex waiver.
28
- - If the query includes terms like "beginner", "entry-level", or "low credit score", include essential features such as cashback, reward points, and basic offers.
29
- - If the query is empty, generate a useful retrieval-focused query based solely on preferences.
30
-
31
- Examples:
32
-
33
- Example 1
34
- - User Query: "I drive a lot for work and want a credit card with good fuel rewards and travel perks."
35
- - Optimized Query: "Category: Fuel Rewards | Best credit cards for high fuel spending with maximum rewards & fuel surcharge waiver. Travel perks preferred but secondary."
36
-
37
- Example 2
38
- - User Query: "I mostly shop online and want a card that gives high cashback on e-commerce purchases. Food delivery perks would be nice."
39
- - Optimized Query: "Category: Online Shopping | Credit cards with best cashback on e-commerce platforms like Amazon, Flipkart. Food delivery benefits secondary."
40
-
41
- Example 3
42
- - User Query: "I eat out a lot and also order food from Swiggy/Zomato. I want the best dining discounts and food delivery cashback."
43
- - Optimized Query: "Category: Dining & Food Delivery | Top credit cards offering the best dining discounts at restaurants and cashback on Swiggy/Zomato orders."
44
-
45
- Now, optimize the following preferences and user query:
46
-
47
- Preferences: "{preferences_text}"
48
- User Query: "{user_query}"
49
- """
50
-
51
- print("rewriting")
52
- response = model2.generate_content(prompt)
53
-
54
- print(response.text)
55
- return response.text
56
-
57
- # Function to generate multiple focused subqueries from a user query
58
- def generate_multi_queries(direct_query, n=3):
59
- genai.configure(api_key=os.environ.get("api_key_2"))
60
- model2 = genai.GenerativeModel('gemini-1.5-flash-latest')
61
- prompt = f"""
62
- The following is a detailed credit card search query:
63
- "{direct_query}"
64
- Generate {n} distinct subqueries that **collectively cover all the important features** from the original query.
65
- Each subquery should emphasize a **different combination** of the features (e.g., lounge access, travel insurance, low foreign transaction fees, hotel discounts, etc.).
66
- Keep the same format: "Category: ... | ...". Make sure all features from the original query are represented across the {n} queries.
67
- Output only the subqueries, one per line. Do not include any explanations, numbering, or formatting — just plain queries separated by newline characters.
68
- """
69
- response = model2.generate_content(prompt)
70
- # print(response.text)
71
- queries = [q.strip() for q in response.text.strip().split('\n') if q.strip()]
72
-
73
- return queries
74
-
75
- #retrieval
76
- #Cross-Encoder Model
77
- cross_encoder = CrossEncoder("cross-encoder/ms-marco-MiniLM-L6-v2")
78
-
79
- def rerank_cards_mini(query, cards, top_n=5):
80
- card_descriptions = [card["description"] for card in cards]
81
- query_card_pairs = [[query, desc] for desc in card_descriptions]
82
- scores = cross_encoder.predict(query_card_pairs)
83
-
84
- #Normalizing
85
- if len(scores) == 0 or (max(scores) - min(scores)) == 0:
86
- scores = [1.0] * len(cards)
87
- else:
88
- scores = np.array(scores)
89
- scores = (scores - scores.min()) / (scores.max() - scores.min())
90
-
91
- # Sort cards by descending score
92
- ranked_cards = sorted(zip(scores, cards), key=lambda x: x[0], reverse=True)
93
- top_cards = [card for _, card in ranked_cards[:top_n]]
94
-
95
- return top_cards
96
-
97
- def retrieve_relevant_cards(user_query, index, chunk_name_mapping, df, top_k=15):
98
- genai.configure(api_key=os.environ.get("api_key_2"))
99
- model_name = "models/text-embedding-004"
100
- print(f"\nUser Query: {user_query}")
101
-
102
- # Generate and normalize query embedding
103
- query_embedding = genai.embed_content(
104
- model=model_name,
105
- content=user_query,
106
- task_type="RETRIEVAL_QUERY"
107
- )["embedding"]
108
- # query_embedding=model.encode(user_query)
109
- query_embedding = np.array(query_embedding, dtype=np.float32)
110
- faiss.normalize_L2(query_embedding.reshape(1, -1))
111
-
112
- # Search FAISS index for top-k chunks
113
- D, I = index.search(np.expand_dims(query_embedding, axis=0), top_k * 5)
114
- similarity_scores = D[0]
115
-
116
- # Map chunks back to unique card names with highest similarity per card
117
- card_similarity = defaultdict(float)
118
- card_dict = {card["name"]: card for card in df.to_dict(orient="records")}
119
- unique_cards = {}
120
-
121
- for i, chunk_idx in enumerate(I[0]):
122
- if chunk_idx == -1:
123
- continue
124
- card_name = chunk_name_mapping[chunk_idx]
125
- if card_name not in unique_cards or similarity_scores[i] > card_similarity[card_name]:
126
- card_similarity[card_name] = similarity_scores[i]
127
- unique_cards[card_name] = {
128
- "name": card_name,
129
- "description": card_dict[card_name]["description"],
130
- "similarity": similarity_scores[i]
131
- }
132
-
133
- # Sort by similarity and take top_k
134
- ordered_cards = sorted(unique_cards.values(), key=lambda x: x["similarity"], reverse=True)[:top_k]
135
-
136
- print("\nTop Recommended Cards:")
137
- for card in ordered_cards:
138
- print(f"- {card['name']} (Similarity: {card['similarity']:.4f})")
139
-
140
- return ordered_cards
141
-
142
- def retrieve_and_rank_cards(faiss_index,filtered_mapping,direct_query, queries, top_k=10):
143
- all_retrieved=[]
144
- for query in queries:
145
- results = retrieve_relevant_cards(
146
- query, faiss_index, filtered_mapping, df, 10
147
- )
148
-
149
- reranked_cards = results[:5]
150
-
151
- all_retrieved.extend(reranked_cards)
152
-
153
- # Removing duplicates
154
- seen = set()
155
- unique_cards = []
156
- for card in all_retrieved:
157
- if card["name"] not in seen:
158
- seen.add(card["name"])
159
- unique_cards.append(card)
160
- if not unique_cards:
161
- return unique_cards
162
- reranked_cards = rerank_cards_mini(direct_query, unique_cards, top_n=5)
163
- return reranked_cards
164
-
165
-
166
- def generate_credit_card_recommendation_gemini(indirect_query,user_query,retrieved_cards, max_new_tokens=500):
167
- genai.configure(api_key=os.environ.get("api_key_3"))
168
- model3 = genai.GenerativeModel('gemini-1.5-flash-latest')
169
- print("using gemini")
170
- if not retrieved_cards:
171
- return "Unfortunately, no credit cards match your eligibility criteria."
172
- for card in retrieved_cards:
173
- print(f"Name: {card['name']}")
174
- print(f"Description: {card['description']}\n")
175
-
176
- # Formatting retrieved cards for input context
177
- cards_info = "\n\n".join([
178
- f"{card['name']}\n"
179
- f"- Description: {card['description']}\n\n"
180
- for card in retrieved_cards
181
- ])
182
-
183
- # Gemini Prompt
184
- gemini_prompt = f"""
185
- You are a financial analyst specializing in credit cards and rewards optimization.
186
- Your task is to analyze and select the best credit card based on user priorities.
187
-
188
- ### User's Query:
189
- {indirect_query+user_query}
190
-
191
- ### Available Credit Cards:
192
- {cards_info}
193
-
194
- ### Instructions:
195
- 1️ Analyze the user's need from the given query .
196
- 2️ Select the best card based on that primary need and only from the details present in the desctiption.Do not include details which are not explicitly mentioned.
197
- 3️ Explain why it's the best choice (list benefits concisely).
198
- 4 Do not assume and include benefits or features which is nor explicitly mentioned in the card description.
199
- 5 Mention the benefits only if it explicitly mentioned in the card description and if it is not mentioned just skip it and do not mention anything about it.
200
- 6 Do not include extra symbols like * or #, just generate a textual response maybe with numbers for points.
201
- 7️ If the user mentions they need FD-based cards or cards for students or if they have low credit score, assume all the provided cards are FD-based. Just compare them based on benefits and choose the best one.
202
- 8 If user asks for fd based cards and the descriptions do not mention it just pick a best card from the given list.
203
-
204
- ### Expected Output Format:
205
- Best Card: [Card Name]
206
- Why It’s the Best:
207
- 1️ [Primary Benefit] : [Explanation]
208
- 2️ [Additional Perks] : [Explanation]
209
- 3️ [Final Justification] : [Why it's the best fit]
210
- """
211
-
212
- # Generate response using Gemini
213
- response = model3.generate_content(gemini_prompt)
214
-
215
- return response.text