#!/usr/bin/env python3 """ user_role_context_handler.py - Handle different user roles and rental models Supports: Airbnb (host/guest), African rentals (landlord/renter/tenant) """ import logging from typing import Dict, Tuple, Optional from enum import Enum import re logger = logging.getLogger(__name__) class RentalModel(Enum): """Different rental models""" AIRBNB = "airbnb" # Short-stay, host/guest model AFRICAN_RENTAL = "african" # Long-term rent, landlord/tenant model ROOMMATE = "roommate" # Room sharing in existing space MIXED = "mixed" # Both types possible UNKNOWN = "unknown" class UserRole: """Handle different user roles across rental models""" # Airbnb roles AIRBNB_HOST = "airbnb_host" AIRBNB_GUEST = "airbnb_guest" # African rental roles LANDLORD = "landlord" RENTER = "renter" TENANT = "tenant" # Alias for renter # Roommate roles HOMEOWNER_SEEKING_ROOMMATE = "homeowner_seeking_roommate" # Has space, looking for roommate ROOMMATE_SEEKER = "roommate_seeker" # Looking for a room to share # Generic OWNER = "owner" BUYER = "buyer" SELLER = "seller" class UserRoleDetector: """Intelligently detect user role from context""" def __init__(self): # Keywords for role detection self.host_keywords = { "airbnb": ["host", "hosting", "list my property", "list my place", "rent out", "share"], "african": ["landlord", "owner", "property owner", "im renting out", "im listing"] } self.guest_keywords = { "airbnb": ["guest", "book", "looking for place", "need accommodation", "airbnb"], "african": ["renter", "tenant", "looking to rent", "seeking", "want to rent", "im looking for"] } self.buyer_keywords = ["buy", "purchase", "for sale", "selling", "acquire"] self.seller_keywords = ["sell", "selling", "sale", "list for sale"] # Roommate keywords self.homeowner_seeking_roommate_keywords = [ "looking for a roommate", "need a roommate", "seeking roommate", "want to share my", "have a spare room", "room available", "looking to share", "share my apartment", "share my house", "my place is too big", "extra room", "can share" ] self.roommate_seeker_keywords = [ "looking for a room", "seeking a room", "need a room", "looking for roommate", "want to share a place", "room for rent", "share accommodation", "shared apartment", "shared house", "need accommodation", "looking for a place to share" ] logger.info("🔍 User Role Detector initialized") def detect_rental_model(self, user_message: str, location: str = None) -> RentalModel: """Detect which rental model user is in""" msg_lower = user_message.lower().strip() # Keywords indicating Airbnb model airbnb_indicators = ["airbnb", "short stay", "nightly", "daily", "vacation rental", "host"] # Keywords indicating African rental model african_indicators = ["landlord", "tenant", "renter", "monthly rent", "long term", "furnished room"] # Keywords indicating roommate model roommate_indicators = ["roommate", "share my", "spare room", "share apartment", "shared house", "share a place"] # Check for explicit indicators for indicator in roommate_indicators: if indicator in msg_lower: logger.info(f"🏘️ Detected roommate model: '{indicator}'") return RentalModel.ROOMMATE for indicator in airbnb_indicators: if indicator in msg_lower: logger.info(f"🏨 Detected Airbnb model: '{indicator}'") return RentalModel.AIRBNB for indicator in african_indicators: if indicator in msg_lower: logger.info(f"🏢 Detected African rental model: '{indicator}'") return RentalModel.AFRICAN_RENTAL # Location-based inference (African locations more likely = African model) if location: african_countries = ["benin", "nigeria", "kenya", "ghana", "south africa", "uganda", "senegal"] if any(country in location.lower() for country in african_countries): logger.info(f"📍 African location detected: {location}") return RentalModel.AFRICAN_RENTAL # Default to mixed return RentalModel.MIXED def detect_user_role(self, user_message: str, rental_model: RentalModel = None) -> Tuple[str, float]: """ Detect user role from message Returns: (role, confidence) """ msg_lower = user_message.lower().strip() if rental_model is None: rental_model = self.detect_rental_model(user_message) # ==================== SELLER / LANDLORD ==================== # Check for explicit landlord/owner language landlord_explicit = ["im a landlord", "im the landlord", "i own", "i own this", "as a landlord"] for phrase in landlord_explicit: if phrase in msg_lower: logger.info(f"✅ Explicit landlord detected: '{phrase}'") return UserRole.LANDLORD, 0.99 # Check for listing/rental language if rental_model == RentalModel.AFRICAN_RENTAL: landlord_signals = [ "im listing", "list my", "im renting out", "property for rent", "available for rent", "i have a", "i own a" ] for signal in landlord_signals: if signal in msg_lower: logger.info(f"🏠 African landlord signal: '{signal}'") return UserRole.LANDLORD, 0.90 if rental_model == RentalModel.AIRBNB: host_signals = ["im hosting", "im a host", "list on airbnb", "airbnb host", "share my place"] for signal in host_signals: if signal in msg_lower: logger.info(f"🏨 Airbnb host signal: '{signal}'") return UserRole.AIRBNB_HOST, 0.90 # ==================== BUYER / SELLER (SALE) ==================== # Explicit sale language seller_signals = ["im selling", "for sale", "sell my", "selling property", "list for sale"] for signal in seller_signals: if signal in msg_lower: logger.info(f"💰 Seller detected: '{signal}'") return UserRole.SELLER, 0.95 buyer_signals = ["want to buy", "looking to purchase", "im buying", "purchase property"] for signal in buyer_signals: if signal in msg_lower: logger.info(f"💳 Buyer detected: '{signal}'") return UserRole.BUYER, 0.95 # ==================== RENTER / GUEST ==================== # Check for explicit renter language renter_explicit = ["im a tenant", "im a renter", "im looking to rent", "looking for a place to rent"] for phrase in renter_explicit: if phrase in msg_lower: logger.info(f"✅ Explicit renter/tenant detected: '{phrase}'") if rental_model == RentalModel.AFRICAN_RENTAL: return UserRole.TENANT, 0.99 else: return UserRole.AIRBNB_GUEST, 0.99 # ==================== ROOMMATE ROLES ==================== # Homeowner seeking roommate for keyword in self.homeowner_seeking_roommate_keywords: if keyword in msg_lower: logger.info(f"✅ Homeowner seeking roommate detected: '{keyword}'") return UserRole.HOMEOWNER_SEEKING_ROOMMATE, 0.90 # Roommate seeker for keyword in self.roommate_seeker_keywords: if keyword in msg_lower: logger.info(f"✅ Roommate seeker detected: '{keyword}'") return UserRole.ROOMMATE_SEEKER, 0.90 # Guest/renter signals if rental_model == RentalModel.AFRICAN_RENTAL: renter_signals = [ "looking for a", "need a", "seeking", "want to rent", "im looking for", "show me", "what do you have", "available rooms" ] for signal in renter_signals: if signal in msg_lower: logger.info(f"🔍 African renter signal: '{signal}'") return UserRole.RENTER, 0.80 if rental_model == RentalModel.AIRBNB: guest_signals = [ "looking for accommodation", "need a place", "book", "where can i stay", "available places", "show me listings" ] for signal in guest_signals: if signal in msg_lower: logger.info(f"🔍 Airbnb guest signal: '{signal}'") return UserRole.AIRBNB_GUEST, 0.80 logger.warning(f"⚠️ Could not determine user role from: {user_message}") return None, 0.0 def validate_role_consistency(self, user_role: str, rental_model: RentalModel) -> bool: """Validate that role matches rental model""" valid_combinations = { RentalModel.AIRBNB: [UserRole.AIRBNB_HOST, UserRole.AIRBNB_GUEST], RentalModel.AFRICAN_RENTAL: [UserRole.LANDLORD, UserRole.RENTER, UserRole.TENANT], RentalModel.ROOMMATE: [UserRole.HOMEOWNER_SEEKING_ROOMMATE, UserRole.ROOMMATE_SEEKER], RentalModel.MIXED: [UserRole.LANDLORD, UserRole.RENTER, UserRole.TENANT, UserRole.AIRBNB_HOST, UserRole.AIRBNB_GUEST, UserRole.HOMEOWNER_SEEKING_ROOMMATE, UserRole.ROOMMATE_SEEKER], } valid = valid_combinations.get(rental_model, []) if user_role in valid: logger.info(f"✅ Role {user_role} valid for {rental_model.value}") return True logger.warning(f"⚠️ Role {user_role} may not match {rental_model.value}") return False class RoleBasedInferenceEngine: """Adapt inference based on user role and rental model""" def __init__(self): self.role_detector = UserRoleDetector() logger.info("🧠 Role-based Inference Engine initialized") def infer_listing_type(self, state: Dict, user_message: str, rental_model: RentalModel = None) -> Tuple[str, float]: """ Infer listing type based on user role and rental model Returns: (listing_type, confidence) """ # Detect rental model if rental_model is None: rental_model = self.role_detector.detect_rental_model(user_message, state.get("location")) # Detect user role user_role, role_confidence = self.role_detector.detect_user_role(user_message, rental_model) logger.info(f"🔍 Rental Model: {rental_model.value}") logger.info(f"👤 User Role: {user_role} (confidence: {role_confidence:.0%})") # Store in state for later use state["rental_model"] = rental_model.value state["user_role"] = user_role # ==================== AIRBNB MODEL ==================== if rental_model == RentalModel.AIRBNB: # Host listing = short-stay if user_role == UserRole.AIRBNB_HOST: logger.info("📍 Host → short-stay listing") return "short-stay", 0.98 # Guest searching = just needs to search if user_role == UserRole.AIRBNB_GUEST: logger.info("📍 Guest → searching for short-stay") return "short-stay", 0.95 # ==================== AFRICAN RENTAL MODEL ==================== elif rental_model == RentalModel.AFRICAN_RENTAL: # Landlord listing = rent listing if user_role in [UserRole.LANDLORD, UserRole.OWNER]: logger.info("📍 Landlord → rent listing") return "rent", 0.98 # Renter/tenant searching = rent listing if user_role in [UserRole.RENTER, UserRole.TENANT]: logger.info("📍 Tenant/Renter → searching for rent") return "rent", 0.95 # ==================== ROOMMATE MODEL ==================== elif rental_model == RentalModel.ROOMMATE: # Homeowner seeking roommate = roommate listing if user_role == UserRole.HOMEOWNER_SEEKING_ROOMMATE: logger.info("📍 Homeowner → roommate listing") return "roommate", 0.98 # Roommate seeker = searching roommate if user_role == UserRole.ROOMMATE_SEEKER: logger.info("📍 Roommate seeker → searching for roommate") return "roommate", 0.95 # ==================== SALE MODEL (both) ==================== if user_role == UserRole.SELLER: logger.info("📍 Seller → sale listing") return "sale", 0.98 if user_role == UserRole.BUYER: logger.info("📍 Buyer → searching for sale") return "sale", 0.95 # Fallback: check explicit listing_type explicit_type = state.get("listing_type") if explicit_type: logger.info(f"📍 Using explicit listing_type: {explicit_type}") return explicit_type, 0.85 logger.warning("⚠️ Could not infer listing_type, defaulting to rent") return "rent", 0.5 def adapt_field_extraction(self, state: Dict, user_message: str) -> Dict: """ Adapt field extraction based on user role and rental model """ rental_model = self.role_detector.detect_rental_model(user_message, state.get("location")) user_role, _ = self.role_detector.detect_user_role(user_message, rental_model) extraction_config = { "rental_model": rental_model.value, "user_role": user_role, "required_fields": [], "price_type_suggestions": [], "amenity_focus": [], "validation_rules": [] } # ==================== AIRBNB HOST ==================== if user_role == UserRole.AIRBNB_HOST: extraction_config["required_fields"] = [ "location", "bedrooms", "bathrooms", "price", "amenities" ] extraction_config["price_type_suggestions"] = ["nightly", "daily", "weekly"] extraction_config["amenity_focus"] = ["wifi", "parking", "pool", "kitchen", "ac"] extraction_config["validation_rules"] = [ "price must be per night (nightly/daily)", "bedrooms minimum 1", "bathrooms can be shared" ] # ==================== AIRBNB GUEST ==================== elif user_role == UserRole.AIRBNB_GUEST: extraction_config["required_fields"] = ["location", "check_in", "check_out"] extraction_config["price_type_suggestions"] = ["nightly"] extraction_config["amenity_focus"] = ["wifi", "kitchen", "parking"] extraction_config["validation_rules"] = [ "check dates for availability", "show prices in nightly rates" ] # ==================== LANDLORD (African) ==================== elif user_role == UserRole.LANDLORD: extraction_config["required_fields"] = [ "location", "bedrooms", "bathrooms", "price", "price_type", "furnished" ] extraction_config["price_type_suggestions"] = ["monthly", "yearly"] extraction_config["amenity_focus"] = [ "furnished", "kitchen", "water", "electricity", "security" ] extraction_config["validation_rules"] = [ "price must be monthly or yearly", "specify if furnished/unfurnished", "include utility info if available", "bedrooms and bathrooms required" ] # ==================== RENTER/TENANT (African) ==================== elif user_role in [UserRole.RENTER, UserRole.TENANT]: extraction_config["required_fields"] = [ "location", "budget", "bedrooms", "price_type" ] extraction_config["price_type_suggestions"] = ["monthly", "yearly"] extraction_config["amenity_focus"] = [ "furnished", "security", "water", "electricity", "parking" ] extraction_config["validation_rules"] = [ "show monthly/yearly prices", "filter by budget", "highlight furnished options", "show security features" ] # ==================== HOMEOWNER SEEKING ROOMMATE ==================== elif user_role == UserRole.HOMEOWNER_SEEKING_ROOMMATE: extraction_config["required_fields"] = [ "location", "bedrooms_available", "bathrooms_available", "price", "price_type" ] extraction_config["price_type_suggestions"] = ["monthly", "yearly"] extraction_config["amenity_focus"] = [ "furnished", "utilities_included", "kitchen_access", "laundry", "internet", "parking", "living_room_access" ] extraction_config["validation_rules"] = [ "price must be monthly or yearly", "specify which rooms are available", "describe house/apartment condition", "list utilities included", "mention house rules" ] # ==================== ROOMMATE SEEKER ==================== elif user_role == UserRole.ROOMMATE_SEEKER: extraction_config["required_fields"] = [ "location", "budget", "move_in_date" ] extraction_config["price_type_suggestions"] = ["monthly", "yearly"] extraction_config["amenity_focus"] = [ "furnished", "utilities_included", "kitchen_access", "internet", "parking", "proximity_to_work" ] extraction_config["validation_rules"] = [ "show monthly/yearly prices", "filter by budget", "check roommate compatibility", "show lease terms" ] # ==================== SELLER ==================== elif user_role == UserRole.SELLER: extraction_config["required_fields"] = [ "location", "bedrooms", "bathrooms", "price", "property_type" ] extraction_config["price_type_suggestions"] = ["fixed"] extraction_config["amenity_focus"] = ["land size", "property type", "condition"] extraction_config["validation_rules"] = [ "price is total sale price", "property type required (apartment, house, etc)", "include land/property size if known" ] # ==================== BUYER ==================== elif user_role == UserRole.BUYER: extraction_config["required_fields"] = [ "location", "budget", "bedrooms", "property_type" ] extraction_config["price_type_suggestions"] = [] extraction_config["amenity_focus"] = ["property type", "land size", "condition"] extraction_config["validation_rules"] = [ "show total sale prices", "filter by budget range", "group by property type" ] logger.info(f"✅ Extraction config adapted for {user_role}") return extraction_config def get_role_context_prompt(self, user_role: str, rental_model: str) -> str: """Get AI prompt context based on role""" prompts = { UserRole.AIRBNB_HOST: """ You are helping an Airbnb host list their property. - Focus on: short-stay rental features, nightly rates, guest amenities - Price type: nightly/daily/weekly - Emphasize: WiFi, kitchen, parking, cleanliness """, UserRole.AIRBNB_GUEST: """ You are helping someone find an Airbnb accommodation. - Focus on: guest experience, amenities, location convenience - Price type: show nightly rates - Emphasize: cleanliness, safety, host responsiveness """, UserRole.LANDLORD: """ You are helping an African landlord/property owner list a rental. - Focus on: long-term rental (monthly/yearly), tenant features, property durability - Price type: monthly or yearly - Emphasize: furnished/unfurnished, utilities, security, maintenance - Include: lease terms, deposit requirements """, UserRole.RENTER: """ You are helping a tenant/renter find an apartment or room. - Focus on: long-term rental suitability, affordability, amenities for living - Price type: monthly or yearly budget - Emphasize: security, utilities included, furnished options, commute - Ask about: move-in date, lease length, budget """, UserRole.TENANT: """ You are helping a tenant/renter find an apartment or room. - Focus on: long-term rental suitability, affordability, amenities for living - Price type: monthly or yearly budget - Emphasize: security, utilities included, furnished options, commute - Ask about: move-in date, lease length, budget """, UserRole.SELLER: """ You are helping someone sell a property. - Focus on: property value, unique features, condition, potential - Price type: total sale price - Emphasize: location, size, renovations, investment potential - Include: property history, legal documents status """, UserRole.BUYER: """ You are helping someone find and purchase a property. - Focus on: property value, investment potential, location - Price type: show total purchase price - Emphasize: property condition, neighborhood, future value - Include: financing options, inspection recommendations """, UserRole.HOMEOWNER_SEEKING_ROOMMATE: """ You are helping someone find a roommate to share their home with. - Focus on: compatibility, house/apartment details, shared spaces - Price type: monthly or yearly - Emphasize: house rules, utilities included, available rooms, amenities - Include: lease terms, deposit, move-in date, roommate preferences - Ask about: their lifestyle, work schedule, cleanliness standards """, UserRole.ROOMMATE_SEEKER: """ You are helping someone find a room to share with a roommate. - Focus on: affordability, roommate compatibility, location, utilities - Price type: monthly or yearly budget - Emphasize: house rules, amenities, commute, lifestyle fit - Include: move-in date, lease length, deposit requirements - Ask about: budget, preferred location, work/study location, lifestyle """ } return prompts.get(user_role, "") # ==================== EXAMPLE USAGE ==================== if __name__ == "__main__": logging.basicConfig(level=logging.INFO) engine = RoleBasedInferenceEngine() # Test cases test_cases = [ # Airbnb host ("I'm a host on Airbnb and want to list my apartment in Lagos", "Lagos"), # Airbnb guest ("I'm looking for accommodation on Airbnb in Accra next week", "Accra"), # African landlord ("I'm a landlord in Cotonou with a 2-bedroom apartment for monthly rent", "Cotonou"), # African tenant ("I'm looking to rent a furnished room in Nairobi, my budget is 30000 KES per month", "Nairobi"), # Homeowner seeking roommate ("My house in Lagos is too big for just me. I have 2 extra bedrooms and want to share", "Lagos"), # Roommate seeker ("I'm looking for a room to share in Accra, somewhere near my workplace", "Accra"), # Seller ("I want to sell my house in Lagos for 50 million NGN", "Lagos"), # Buyer ("I'm looking to buy a 3-bedroom apartment in Cape Town", "Cape Town"), ] print("\n" + "="*70) print("🧠 ROLE-BASED INFERENCE ENGINE TEST") print("="*70 + "\n") for message, location in test_cases: print(f"📝 Message: {message}") print(f"📍 Location: {location}\n") state = {"location": location} listing_type, confidence = engine.infer_listing_type(state, message) print(f"✅ Listing Type: {listing_type} (confidence: {confidence:.0%})") config = engine.adapt_field_extraction(state, message) print(f"📋 Required fields: {', '.join(config['required_fields'])}") print(f"💰 Price types: {', '.join(config['price_type_suggestions'])}") prompt = engine.get_role_context_prompt(config['user_role'], config['rental_model']) print(f"🎯 AI Context:\n{prompt}") print("-" * 70 + "\n")