zenaight commited on
Commit
22f2680
·
1 Parent(s): 9dfa030

Enhance debugging and property search logic in AI chat

Browse files

- Added debug print statements in `chat_with_session_memory` and `extract_and_search_properties` to log the number of properties found, specific property details, and search filters applied, improving traceability during the property search process.
- Implemented logic to clear restrictive filters for general area searches, enhancing the flexibility of property recommendations based on user intent.
- Refined the property search query in `search_properties` to prioritize city matches before falling back to location searches, optimizing the search process and improving user experience.

Files changed (2) hide show
  1. ai_chat.py +21 -0
  2. database.py +15 -7
ai_chat.py CHANGED
@@ -39,7 +39,9 @@ def chat_with_session_memory(state):
39
 
40
  # Direct listing summary (bypass LLM when properties are found)
41
  props = state.get("properties", [])
 
42
  if props:
 
43
  # a) Build a direct summary string
44
  response_text = ""
45
  # include any search status
@@ -247,10 +249,24 @@ async def extract_and_update_intent(state):
247
  except Exception as e:
248
  extracted = {}
249
 
 
 
 
 
 
 
250
  for field in intent_fields:
251
  new_val = extracted.get(field)
252
  old_val = intent.get(field)
253
 
 
 
 
 
 
 
 
 
254
  if new_val is not None and new_val != old_val:
255
  # Handle must_have field as array (LLM decides the logic)
256
  if field == "must_have" and new_val:
@@ -289,12 +305,14 @@ async def extract_and_search_properties(state):
289
  Search for properties based on user intent and store results in state.
290
  """
291
  intent = state.get("intent", {})
 
292
 
293
  # Check if we have the minimum required field for property search
294
  location = intent.get("location_preference")
295
 
296
  if not location:
297
  # Missing location, skip property search
 
298
  return {"response": None}
299
 
300
  # Prepare filters for property search
@@ -314,11 +332,14 @@ async def extract_and_search_properties(state):
314
  filters["must_have"] = must_have
315
 
316
  # Search for properties
 
317
  properties = await search_properties(filters)
318
  state["properties"] = properties
 
319
 
320
  # Pass 1: strict filters
321
  if properties:
 
322
  return {"response": None}
323
 
324
  # Pass 2: drop must-haves
 
39
 
40
  # Direct listing summary (bypass LLM when properties are found)
41
  props = state.get("properties", [])
42
+ print(f"DEBUG - chat_with_session_memory: {len(props)} properties in state")
43
  if props:
44
+ print(f"DEBUG - first property: {props[0].get('title')} in {props[0].get('city')}")
45
  # a) Build a direct summary string
46
  response_text = ""
47
  # include any search status
 
249
  except Exception as e:
250
  extracted = {}
251
 
252
+ # Check if this is a general area search (like "what do you have in [area]")
253
+ is_general_area_search = (
254
+ "what do you have" in user_message.lower() and
255
+ any(word in user_message.lower() for word in ["in ", "area", "jhb", "johannesburg", "cape town", "durban"])
256
+ )
257
+
258
  for field in intent_fields:
259
  new_val = extracted.get(field)
260
  old_val = intent.get(field)
261
 
262
+ # For general area searches, clear restrictive filters
263
+ if is_general_area_search and field in ["budget", "size_preference_sqm", "must_have"]:
264
+ if old_val is not None:
265
+ print(f"DEBUG - Clearing restrictive field {field} for general area search")
266
+ await update_user_intent(session_id, {field: None})
267
+ intent[field] = None
268
+ continue
269
+
270
  if new_val is not None and new_val != old_val:
271
  # Handle must_have field as array (LLM decides the logic)
272
  if field == "must_have" and new_val:
 
305
  Search for properties based on user intent and store results in state.
306
  """
307
  intent = state.get("intent", {})
308
+ print(f"DEBUG - extract_and_search_properties intent: {intent}")
309
 
310
  # Check if we have the minimum required field for property search
311
  location = intent.get("location_preference")
312
 
313
  if not location:
314
  # Missing location, skip property search
315
+ print("DEBUG - No location found, skipping property search")
316
  return {"response": None}
317
 
318
  # Prepare filters for property search
 
332
  filters["must_have"] = must_have
333
 
334
  # Search for properties
335
+ print(f"DEBUG - Searching with filters: {filters}")
336
  properties = await search_properties(filters)
337
  state["properties"] = properties
338
+ print(f"DEBUG - Found {len(properties)} properties with strict filters")
339
 
340
  # Pass 1: strict filters
341
  if properties:
342
+ print("DEBUG - Properties found, returning None to continue to chat")
343
  return {"response": None}
344
 
345
  # Pass 2: drop must-haves
database.py CHANGED
@@ -294,18 +294,21 @@ async def search_properties(filters: dict) -> list:
294
  return []
295
 
296
  try:
 
297
  query = supabase.table("properties").select("*").eq("is_active", True)
298
 
299
  # a. Location: try city first, then location field
300
  loc = filters.get("location_preference")
301
  if loc:
302
- query = query.ilike("city", f"%{loc}%")
303
- resp = query.execute()
304
- if not resp.data:
305
- # fallback to suburb/area match
306
- query = supabase.table("properties").select("*")\
307
- .eq("is_active", True)\
308
- .ilike("location", f"%{loc}%")
 
 
309
 
310
  # b. Budget cap
311
  budget = filters.get("budget")
@@ -327,7 +330,12 @@ async def search_properties(filters: dict) -> list:
327
 
328
  # f. Execute and return
329
  resp = query.execute()
 
 
 
 
330
  return resp.data or []
331
 
332
  except Exception as e:
 
333
  return []
 
294
  return []
295
 
296
  try:
297
+ # Start with base query
298
  query = supabase.table("properties").select("*").eq("is_active", True)
299
 
300
  # a. Location: try city first, then location field
301
  loc = filters.get("location_preference")
302
  if loc:
303
+ # Try city match first
304
+ city_query = query.ilike("city", f"%{loc}%")
305
+ city_resp = city_query.execute()
306
+
307
+ if city_resp.data:
308
+ query = city_query
309
+ else:
310
+ # Fallback to location field
311
+ query = supabase.table("properties").select("*").eq("is_active", True).ilike("location", f"%{loc}%")
312
 
313
  # b. Budget cap
314
  budget = filters.get("budget")
 
330
 
331
  # f. Execute and return
332
  resp = query.execute()
333
+ print(f"DEBUG - search_properties filters: {filters}")
334
+ print(f"DEBUG - properties returned: {len(resp.data) if resp.data else 0}")
335
+ if resp.data:
336
+ print(f"DEBUG - first property: {resp.data[0].get('title')} in {resp.data[0].get('city')}")
337
  return resp.data or []
338
 
339
  except Exception as e:
340
+ print(f"DEBUG - search_properties error: {e}")
341
  return []