from data import debug_print,eligibility_lookup,llm1
from nodes.intent import get_pretty_state_string,CreditCardState
from langchain_core.messages import SystemMessage, HumanMessage
#comparison node
async def compare_node_fn(state: CreditCardState) -> CreditCardState:
debug_print("NODE", f"Entering compare_node_fn with state:\n {get_pretty_state_string(state)}\n")
selected_cards = state.get("selected_cards", [])
card_lookup = state.get("card_lookup", {})
debug_print("COMPARE_NODE", f"Selected cards: {selected_cards}")
debug_print("COMPARE_NODE", f"Card lookup keys: {list(card_lookup.keys())}")
if not selected_cards or len(selected_cards) < 2:
debug_print("COMPARE_NODE", "Not enough cards selected for comparison")
state["comparison_result"] = "Please select at least two cards to compare."
return state
comparison_details = []
for name in selected_cards:
eligibility_info = eligibility_lookup.get(name, "No eligibility or fee information available.")
desc = card_lookup.get(name, "No description available.")
full_desc = f"{desc}\n\nEligibility & Fees:\n{eligibility_info}"
comparison_details.append(f"{name}: {full_desc}")
debug_print("COMPARE_NODE", f"Added card '{name}' with description length: {len(desc)}")
use_table_format = len(selected_cards) <= 3
#prompts for tabular and normal markdwon responses
if use_table_format:
header_row = "| Feature | " + " | ".join(selected_cards) + " |"
separator_row = "|---|" + "---|" * len(selected_cards)
benefits_structure = "| Benefits | " + " | ".join(["[3-4 key benefits]
[as concise bullet points]"] * len(selected_cards)) + " |"
fees_structure = "| Fees & Eligibility | " + " | ".join(["[Key fees & eligibility as bullet points]"] * len(selected_cards)) + " |"
limitations_structure = "| Limitations | " + " | ".join(["[List any limitations as bullet points]"] * len(selected_cards)) + " |"
ideal_user_structure = "| Ideal User | " + " | ".join(["[A single short sentence]"] * len(selected_cards)) + " |"
dynamic_table_blueprint = (
f"{header_row}\n"
f"{separator_row}\n"
f"{benefits_structure}\n"
f"{fees_structure}\n"
f"{limitations_structure}\n"
f"{ideal_user_structure}\n"
)
comparison_prompt = (
"Compare the following credit cards using the exact and complete **markdown table** structure provided below.\n\n"
f"{dynamic_table_blueprint}\n"
"Instructions:\n"
"1. **STRICTLY adhere to the table structure.**\n"
"2. **DO NOT GUESS OR HALLUCINATE.** Use only the card data provided below.\n"
"3. For `Benefits`, extract and list **ONLY** the 3-4 most important benefits. Keep each bullet point very short.\n"
"4. For `Fees & Eligibility`, list the key fees (joining/annual) and income/age as separate concise bullet points.\n"
"5. For `Limitations`, extract only the top 1-2 limitations. If none are listed, write 'None listed in the provided data.'.\n"
"6. For `Ideal User`, provide a single sentence describing the best fit for the card.\n"
"7. After the table, give a brief, one-sentence recommendation.\n"
"8. Use `
` for line breaks inside table cells. Do not use newline characters (`\\n`) or extra `|` inside any cell.\n\n"
"CARD DATA:\n\n"
+ "\n\n".join(comparison_details)
)
else:
comparison_prompt = (
"Compare the following credit cards based on their benefits, fees, eligibility, and ideal use cases.\n\n"
"Instructions:\n"
"1. **STRICTLY** use only the card data provided below. Do NOT guess, assume, or hallucinate any information.\n"
"2. Keep the output short, structured, and highly readable.\n"
"3. Use markdown format with clear section headers like 'Comparison' and 'Recommendation'.\n"
"4. Use a concise list of bullet points for each card's benefits, fees, and limitations.\n"
"5. Conclude with a recommendation on which card suits which type of user.\n\n"
"CARD DATA:\n\n"
+ "\n\n".join(comparison_details)
)
debug_print("COMPARE_NODE", "Calling Llama for comparison")
try:
messages = [
SystemMessage(content="You are an expert in comparing credit card products."),
HumanMessage(content=comparison_prompt)
]
response_obj = await llm1.ainvoke(
messages,
config={"max_tokens": 2048, "temperature": 0.0}
)
response_content = response_obj.content
debug_print("COMPARE_NODE", f"Response received with length: {len(response_content)}")
print(response_content)
state["comparison_result"] = response_content
except Exception as e:
debug_print("ERROR", f"Error during comparison: {e}")
state["comparison_result"] = "An error occurred while comparing the cards. Please try again."
return state