destinyebuka commited on
Commit
1306e79
·
1 Parent(s): 9b90b36
app/ai/agent/brain.py CHANGED
@@ -46,7 +46,21 @@ AVAILABLE_TOOLS = """
46
 
47
  1. update_listing(fields: dict)
48
  - Use this when user provides property details (price, bedrooms, location, etc.)
49
- - Fields: title, description, price, bedrooms, bathrooms, location, amenities (list), requirements (list), type (rent/sale)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
50
 
51
  2. search_properties(query: str, location: str, min_price: int, max_price: int, beds: int)
52
  - Use this when user wants to FIND/SEARCH for properties
 
46
 
47
  1. update_listing(fields: dict)
48
  - Use this when user provides property details (price, bedrooms, location, etc.)
49
+ - Fields: title, description, price, bedrooms, bathrooms, location, amenities (list), requirements (list), listing_type
50
+
51
+ LISTING TYPES (4 total):
52
+ - "rent" = Regular long-term rental (monthly/yearly payment)
53
+ - "sale" = Property for sale (one-time payment)
54
+ - "short-stay" = Short-term like Airbnb (daily/weekly/nightly)
55
+ - "roommate" = Someone ALREADY living in a place wants to find a person to SHARE the space with
56
+
57
+ ROOMMATE EXPLAINED: If user says "I want to share my apartment", "looking for someone to split rent",
58
+ "need a roommate", "want to find someone to live with" → listing_type = "roommate"
59
+
60
+ ROLE-BASED PERMISSIONS:
61
+ - Landlord: Can list ALL types (rent, sale, short-stay, roommate)
62
+ - Renter: Can ONLY list "roommate" type. If renter tries to list rent/sale/short-stay,
63
+ politely explain they can only list roommate listings.
64
 
65
  2. search_properties(query: str, location: str, min_price: int, max_price: int, beds: int)
66
  - Use this when user wants to FIND/SEARCH for properties
app/ai/agent/nodes/listing_collect.py CHANGED
@@ -689,6 +689,37 @@ Just return the message, no quotes."""
689
  state.temp_data["response_text"] = smart_response.get("response_text")
690
  state.temp_data["action"] = action
691
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
692
  logger.info("Continuing collection",
693
  action=action,
694
  missing_count=len(missing_required))
 
689
  state.temp_data["response_text"] = smart_response.get("response_text")
690
  state.temp_data["action"] = action
691
 
692
+ # ✅ NEW: Generate draft_ui for NEW listings if we have enough data to display
693
+ # This ensures users see a visual card, not just text, when providing images/fields
694
+ has_images = len(state.provided_fields.get("images", [])) > 0
695
+ has_key_fields = any([
696
+ state.provided_fields.get("location"),
697
+ state.provided_fields.get("bedrooms"),
698
+ state.provided_fields.get("price"),
699
+ ])
700
+
701
+ if has_images or has_key_fields:
702
+ from app.ai.agent.nodes.listing_validate import build_draft_ui_from_dict
703
+ draft_data = {
704
+ "title": state.provided_fields.get("title", "New Listing"),
705
+ "description": state.provided_fields.get("description", ""),
706
+ "location": state.provided_fields.get("location", ""),
707
+ "address": state.provided_fields.get("address", ""),
708
+ "bedrooms": state.provided_fields.get("bedrooms", 0),
709
+ "bathrooms": state.provided_fields.get("bathrooms", 0),
710
+ "price": state.provided_fields.get("price", 0),
711
+ "currency": state.provided_fields.get("currency", ""),
712
+ "price_type": state.provided_fields.get("price_type", "monthly"),
713
+ "listing_type": state.provided_fields.get("listing_type", "rent"),
714
+ "amenities": state.provided_fields.get("amenities", []),
715
+ "images": state.provided_fields.get("images", []),
716
+ "requirements": state.provided_fields.get("requirements", []),
717
+ }
718
+ draft_ui = build_draft_ui_from_dict(draft_data)
719
+ draft_ui["status"] = "draft" # Mark as draft (not editing existing)
720
+ state.temp_data["draft_ui"] = draft_ui
721
+ logger.info("Draft UI generated for new listing", has_images=has_images, image_count=len(draft_data.get("images", [])))
722
+
723
  logger.info("Continuing collection",
724
  action=action,
725
  missing_count=len(missing_required))
app/ai/tools/listing_tool.py CHANGED
@@ -415,15 +415,12 @@ async def auto_detect_listing_type(price_type: str, user_role: str, user_message
415
  if user_role in ["renter", "roommate"]:
416
  return "roommate"
417
 
418
- # If LLM explicitly extracted a valid type, trust it (but validate)
419
  if extracted_type:
420
  valid_types = ["rent", "sale", "short-stay", "roommate"]
421
  if extracted_type in valid_types:
422
- # Landlords can't list roommates usually, but if explicitly said...
423
- if extracted_type == "roommate" and user_role == "landlord":
424
- pass # Allow or block? Let's strictly block for now
425
- else:
426
- return extracted_type
427
 
428
  # LANDLORD: Detect from price_type as backup
429
  price_type_lower = (price_type or "").lower().strip()
@@ -470,21 +467,26 @@ def validate_listing_type_for_role(listing_type: str, user_role: str) -> tuple[b
470
  """
471
  Validate if user can create this listing type.
472
 
 
 
 
 
473
  Returns:
474
  (is_valid, error_message)
475
  """
 
 
 
 
476
 
477
  if user_role == "renter":
478
  if listing_type != "roommate":
479
- return False, "As a renter, you can only create roommate listings. Would you like to list a room for a roommate instead?"
480
  return True, ""
481
 
 
482
  if user_role == "landlord":
483
- if listing_type == "roommate":
484
- return False, "As a landlord, you cannot create roommate listings. You can list properties for rent, short-stay, or sale."
485
- if listing_type in ["rent", "short-stay", "sale"]:
486
- return True, ""
487
- return False, f"Invalid listing type: {listing_type}. Please choose rent, short-stay, or sale."
488
 
489
  # Default: allow
490
  return True, ""
 
415
  if user_role in ["renter", "roommate"]:
416
  return "roommate"
417
 
418
+ # If LLM explicitly extracted a valid type, trust it
419
  if extracted_type:
420
  valid_types = ["rent", "sale", "short-stay", "roommate"]
421
  if extracted_type in valid_types:
422
+ # Landlords can list ALL types including roommate
423
+ return extracted_type
 
 
 
424
 
425
  # LANDLORD: Detect from price_type as backup
426
  price_type_lower = (price_type or "").lower().strip()
 
467
  """
468
  Validate if user can create this listing type.
469
 
470
+ Permissions:
471
+ - Landlord: Can list ALL types (rent, sale, short-stay, roommate)
472
+ - Renter: Can ONLY list roommate
473
+
474
  Returns:
475
  (is_valid, error_message)
476
  """
477
+ valid_types = ["rent", "sale", "short-stay", "roommate"]
478
+
479
+ if listing_type not in valid_types:
480
+ return False, f"Invalid listing type: {listing_type}. Please choose rent, sale, short-stay, or roommate."
481
 
482
  if user_role == "renter":
483
  if listing_type != "roommate":
484
+ return False, "As a renter, you can only create roommate listings. Roommate listings are for finding someone to share your living space with. Would you like to list a room for a roommate instead?"
485
  return True, ""
486
 
487
+ # Landlord can list ANY type including roommate
488
  if user_role == "landlord":
489
+ return True, ""
 
 
 
 
490
 
491
  # Default: allow
492
  return True, ""