Spaces:
Sleeping
Sleeping
""" | |
Zoe - Real Estate Agent | |
""" | |
from typing import Optional, Dict, Any, List | |
from dataclasses import dataclass | |
from datetime import datetime | |
import os | |
import json | |
import requests | |
from loguru import logger | |
from swarms import Agent | |
from swarm_models import OpenAIChat | |
from dotenv import load_dotenv | |
from enum import Enum | |
# Configure loguru logger | |
logger.add( | |
"logs/real_estate_agent_{time}.log", | |
rotation="500 MB", | |
retention="10 days", | |
level="INFO", | |
format="{time:YYYY-MM-DD at HH:mm:ss} | {level} | {message}", | |
) | |
class PropertyType(str, Enum): | |
"""Enum for property types""" | |
OFFICE = "office" | |
RETAIL = "retail" | |
INDUSTRIAL = "industrial" | |
MIXED_USE = "mixed-use" | |
LAND = "land" | |
class PropertyListing: | |
"""Data class for commercial property listings""" | |
property_id: str | |
address: str | |
city: str | |
state: str | |
zip_code: str | |
price: float | |
square_footage: float | |
property_type: PropertyType | |
zoning: str | |
listing_date: datetime | |
lat: float | |
lng: float | |
description: Optional[str] = None | |
features: Optional[List[str]] = None | |
images: Optional[List[str]] = None | |
class PropertyRadarAPI: | |
"""Client for PropertyRadar API integration""" | |
def __init__(self, api_key: str): | |
"""Initialize PropertyRadar API client | |
Args: | |
api_key (str): PropertyRadar API key | |
""" | |
self.api_key = api_key | |
self.base_url = "https://api.propertyradar.com/v1" | |
self.session = requests.Session() | |
self.session.headers.update( | |
{ | |
"Authorization": f"Bearer {api_key}", | |
"Content-Type": "application/json", | |
} | |
) | |
def search_properties( | |
self, | |
max_price: float = 10_000_000, | |
property_types: List[PropertyType] = None, | |
location: Dict[str, Any] = None, | |
min_sqft: Optional[float] = None, | |
max_sqft: Optional[float] = None, | |
page: int = 1, | |
limit: int = 20, | |
) -> List[PropertyListing]: | |
""" | |
Search for commercial properties using PropertyRadar API | |
Args: | |
max_price (float): Maximum property price | |
property_types (List[PropertyType]): Types of properties to search for | |
location (Dict[str, Any]): Location criteria (city, county, or coordinates) | |
min_sqft (Optional[float]): Minimum square footage | |
max_sqft (Optional[float]): Maximum square footage | |
page (int): Page number for pagination | |
limit (int): Number of results per page | |
Returns: | |
List[PropertyListing]: List of matching properties | |
""" | |
try: | |
# Build the query parameters | |
params = { | |
"price_max": max_price, | |
"property_types": ( | |
[pt.value for pt in property_types] | |
if property_types | |
else None | |
), | |
"page": page, | |
"limit": limit, | |
"for_sale": True, | |
"state": "FL", # Florida only | |
"commercial_property": True, | |
} | |
# Add location parameters | |
if location: | |
params.update(location) | |
# Add square footage filters | |
if min_sqft: | |
params["square_feet_min"] = min_sqft | |
if max_sqft: | |
params["square_feet_max"] = max_sqft | |
# Make the API request | |
response = self.session.get( | |
f"{self.base_url}/properties", | |
params={ | |
k: v for k, v in params.items() if v is not None | |
}, | |
) | |
response.raise_for_status() | |
# Parse the response | |
properties_data = response.json() | |
# Convert to PropertyListing objects | |
return [ | |
PropertyListing( | |
property_id=prop["id"], | |
address=prop["address"], | |
city=prop["city"], | |
state=prop["state"], | |
zip_code=prop["zip_code"], | |
price=float(prop["price"]), | |
square_footage=float(prop["square_feet"]), | |
property_type=PropertyType(prop["property_type"]), | |
zoning=prop["zoning"], | |
listing_date=datetime.fromisoformat( | |
prop["list_date"] | |
), | |
lat=float(prop["latitude"]), | |
lng=float(prop["longitude"]), | |
description=prop.get("description"), | |
features=prop.get("features", []), | |
images=prop.get("images", []), | |
) | |
for prop in properties_data["results"] | |
] | |
except requests.RequestException as e: | |
logger.error(f"Error fetching properties: {str(e)}") | |
raise | |
class CommercialRealEstateAgent: | |
"""Agent for searching and analyzing commercial real estate properties""" | |
def __init__( | |
self, | |
openai_api_key: str, | |
propertyradar_api_key: str, | |
model_name: str = "gpt-4", | |
temperature: float = 0.1, | |
saved_state_path: Optional[str] = None, | |
): | |
"""Initialize the real estate agent | |
Args: | |
openai_api_key (str): OpenAI API key | |
propertyradar_api_key (str): PropertyRadar API key | |
model_name (str): Name of the LLM model to use | |
temperature (float): Temperature setting for the LLM | |
saved_state_path (Optional[str]): Path to save agent state | |
""" | |
self.property_api = PropertyRadarAPI(propertyradar_api_key) | |
# Initialize OpenAI model | |
self.model = OpenAIChat( | |
openai_api_key=openai_api_key, | |
model_name=model_name, | |
temperature=temperature, | |
) | |
# Initialize the agent | |
self.agent = Agent( | |
agent_name="Commercial-Real-Estate-Agent", | |
system_prompt=self._get_system_prompt(), | |
llm=self.model, | |
max_loops=1, | |
autosave=True, | |
dashboard=False, | |
verbose=True, | |
saved_state_path=saved_state_path, | |
context_length=200000, | |
streaming_on=False, | |
) | |
logger.info( | |
"Commercial Real Estate Agent initialized successfully" | |
) | |
def _get_system_prompt(self) -> str: | |
"""Get the system prompt for the agent""" | |
return """You are a specialized commercial real estate agent assistant focused on Central Florida properties. | |
Your primary responsibilities are: | |
1. Search for commercial properties under $10 million | |
2. Focus on properties zoned for commercial use | |
3. Provide detailed analysis of property features, location benefits, and potential ROI | |
4. Consider local market conditions and growth potential | |
5. Verify zoning compliance and restrictions | |
When analyzing properties, consider: | |
- Current market valuations | |
- Local business development plans | |
- Traffic patterns and accessibility | |
- Nearby amenities and businesses | |
- Future development potential""" | |
def search_properties( | |
self, | |
max_price: float = 10_000_000, | |
property_types: List[PropertyType] = None, | |
location: Dict[str, Any] = None, | |
min_sqft: Optional[float] = None, | |
max_sqft: Optional[float] = None, | |
) -> List[Dict[str, Any]]: | |
""" | |
Search for properties and provide analysis | |
Args: | |
max_price (float): Maximum property price | |
property_types (List[PropertyType]): Types of properties to search | |
location (Dict[str, Any]): Location criteria | |
min_sqft (Optional[float]): Minimum square footage | |
max_sqft (Optional[float]): Maximum square footage | |
Returns: | |
List[Dict[str, Any]]: List of properties with analysis | |
""" | |
try: | |
# Search for properties | |
properties = self.property_api.search_properties( | |
max_price=max_price, | |
property_types=property_types, | |
location=location, | |
min_sqft=min_sqft, | |
max_sqft=max_sqft, | |
) | |
# Analyze each property | |
analyzed_properties = [] | |
for prop in properties: | |
analysis = self.agent.run( | |
f"Analyze this commercial property:\n" | |
f"Address: {prop.address}, {prop.city}, FL {prop.zip_code}\n" | |
f"Price: ${prop.price:,.2f}\n" | |
f"Square Footage: {prop.square_footage:,.0f}\n" | |
f"Property Type: {prop.property_type.value}\n" | |
f"Zoning: {prop.zoning}\n" | |
f"Description: {prop.description or 'Not provided'}" | |
) | |
analyzed_properties.append( | |
{"property": prop.__dict__, "analysis": analysis} | |
) | |
logger.info( | |
f"Successfully analyzed {len(analyzed_properties)} properties" | |
) | |
return analyzed_properties | |
except Exception as e: | |
logger.error( | |
f"Error in property search and analysis: {str(e)}" | |
) | |
raise | |
def main(): | |
"""Main function to demonstrate usage""" | |
load_dotenv() | |
# Initialize the agent | |
agent = CommercialRealEstateAgent( | |
openai_api_key=os.getenv("OPENAI_API_KEY"), | |
propertyradar_api_key=os.getenv("PROPERTYRADAR_API_KEY"), | |
saved_state_path="real_estate_agent_state.json", | |
) | |
# Example search | |
results = agent.search_properties( | |
max_price=5_000_000, | |
property_types=[PropertyType.RETAIL, PropertyType.OFFICE], | |
location={"city": "Orlando", "radius_miles": 25}, | |
min_sqft=2000, | |
) | |
# Save results | |
with open("search_results.json", "w") as f: | |
json.dump(results, f, default=str, indent=2) | |
if __name__ == "__main__": | |
main() | |