Update recommender/recommender.py
Browse files- recommender/recommender.py +153 -153
recommender/recommender.py
CHANGED
|
@@ -1,154 +1,154 @@
|
|
| 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 data 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 |
)
|
|
|
|
| 1 |
+
import ast
|
| 2 |
+
import re
|
| 3 |
+
import pandas as 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 data 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 |
)
|