AI Real Estate Bot

Correlation to CPT

User Input

  • The user can input their prompt to the bot and click a button to submit the prompt.
<form id="input-form">
    <input id="input-field" type="text" placeholder="Type your message here">
    <button id="submit-button" type="submit">Send</button>
</form>
  • To get an answer, the user must input the access code to the bot.
    const accessCode = prompt("Please enter your access code:");
    if (!accessCode) return; // Don't proceed without access code
    

Use of at least 1 list

  • I use a database to store all the properties available. This database has over 800 properties This makes my program easier to develop and easier to maintain.
class House(db.Model, UserMixin):
    __tablename__ = 'houses'

    id = db.Column(db.Integer, primary_key=True)
    address = db.Column(db.String(256), index=True)
    city = db.Column(db.String(64), index=True, nullable=True)
    state = db.Column(db.String(8), index=True, nullable=True)
    zip = db.Column(db.Integer, index=True, nullable=True)
    latitude = db.Column(db.Float, index=True, nullable=True)
    longitude = db.Column(db.Float, index=True, nullable=True)
    price = db.Column(db.Integer, index=True, nullable=True)
    bathrooms = db.Column(db.Float, index=True, nullable=True)
    bedrooms = db.Column(db.Integer, index=True, nullable=True)
    livingarea = db.Column(db.Integer, index=True, nullable=True)
    homeType = db.Column(db.String(64), index=True, nullable=True)
    priceEstimate = db.Column(db.Integer, index=True, nullable=True)
    rentEstimate = db.Column(db.Integer, index=True, nullable=True)
    imgSRC = db.Column(db.String, index=True, nullable=True)
    favorites = db.relationship('Favorite', backref='House', uselist=True, lazy='dynamic')

    def __init__(self, address, city, state, zip, latitude, longitude, price, bathrooms, bedrooms, livingarea, homeType, priceEstimate, rentEstimate, imgSRC):
        self.address = address
        self.city = city
        self.state = state
        self.zip = zip
        self.latitude = latitude
        self.longitude = longitude
        self.price = price
        self.bathrooms = bathrooms
        self.bedrooms = bedrooms
        self.livingarea = livingarea
        self.homeType = homeType
        self.priceEstimate = priceEstimate
        self.rentEstimate = rentEstimate
        self.imgSRC = imgSRC

def initHouses():
    with app.app_context():
        """Create database and tables"""
        db.create_all()
        house_count = db.session.query(House).count()
        if house_count > 0:
            return

        basedir = os.path.abspath(os.path.dirname(__file__))
        # Specify the file path
        file_path = basedir + "/../static/data/RealEstateData.csv"
        # Load the CSV file into a DataFrame
        df = pd.read_csv(file_path)

        for index, row in df.iterrows():
            try:
                house = House(
                    address=row['address'] if pd.notna(row['address']) else None,
                    city=row['city'] if pd.notna(row['city']) else None,
                    state=row['state'] if pd.notna(row['state']) else None,
                    zip=row['zipcode'] if pd.notna(row['zipcode']) else None,
                    latitude=row['latitude'] if pd.notna(row['latitude']) else None,
                    longitude=row['longitude'] if pd.notna(row['longitude']) else None,
                    price=row['price'] if pd.notna(row['price']) else None,
                    bathrooms=row['bathrooms'] if pd.notna(row['bathrooms']) else None,
                    bedrooms=row['bedrooms'] if pd.notna(row['bedrooms']) else None,
                    livingarea=row['livingArea'] if pd.notna(row['livingArea']) else None,
                    homeType=row['homeType'] if pd.notna(row['homeType']) else None,
                    priceEstimate=row['PriceEstimate'] if pd.notna(row['PriceEstimate']) else None,
                    rentEstimate=row['RentEstimate'] if pd.notna(row['RentEstimate']) else None,
                    imgSRC=row['imgSrc'] if pd.notna(row['imgSrc']) else None
                )
                db.session.add(house)
                db.session.commit()
            except IntegrityError:
                '''fails with bad or duplicate data'''
                db.session.remove()
                print(f"Records exist, duplicate house, or error: {house.name}")
            except Exception as e_inner:
                print(f"Error adding house at index {index}: {str(e_inner)}")

One procedure that contributes to the program’s intended purpose

  • This procedure is used to get the user’s input and return the bot’s response. This is the main procedure that allows the bot to function.
def get_openai_answer(user_input):
        encrypted_app_token = 'gAAAAABlOLQoLplaL2-lfD1T4VkBXnkKxq1XK_VlVHiEm7MaftNJmZ4f-7rQlUws-NIMHjpWOMtevkwB5NX7f4kqknvrVtwH3ccAsOHB_Yg9dzksRxh5yVuuIXRD3hov8yU6BSXwd-HLTnBRLX5ARDOqzxJoK6M15A=='

        basedir = os.path.abspath(os.path.dirname(__file__))

        # Specify the file path
        file_path = basedir + "/../static/data/RealEsateDataforOpenAI.csv"

        dataset = pd.read_csv(file_path, header=0).to_string()

        houses = db.session.query(House).all()
        dataset = []
        for house in houses:
            dataset.append(house.all_details())
        jsondata = jsonify(dataset)

        crypto_key = os.getenv("CRYPTO_KEY")
        if crypto_key is None:
            raise ValueError("CRYPTO_KEY environment variable is not set.")
        
        cipher_suite = Fernet(crypto_key)
        api_key = cipher_suite.decrypt(encrypted_app_token).decode()
        os.environ["OPENAI_API_KEY"] = api_key
        
        summary_template = """
            {user_input}, answer using this: {jsondata} If unable able to answer, use your own information.
        """

        summary_prompt_template = PromptTemplate(
            input_variables=["user_input", "dataset"], template=summary_template
        )

        llm = ChatOpenAI(temperature=0, model_name="gpt-3.5-turbo-16k", api_key=api_key)

        chain = LLMChain(llm=llm, prompt=summary_prompt_template)
        response = chain.run(user_input=user_input, dataset=dataset)
        
        return response

An algorithm that includes sequencing, selection, and iteration

  • The loop or iteration extracts all information on all properties, which is vital for the bot to properly answer prompts. The sequencing is important in checking if the user has the access code to the bot. If not an error will be thrown
houses = db.session.query(House).all()
        dataset = []
        for house in houses:
            dataset.append(house.all_details())
        jsondata = jsonify(dataset)

        crypto_key = os.getenv("CRYPTO_KEY")
        if crypto_key is None:
            raise ValueError("CRYPTO_KEY environment variable is not set.")

Calls to your student-developed procedure

  • This calls the AI bot api to get the response to the user’s prompt.
document.addEventListener("DOMContentLoaded", function () {
        const conversation = document.getElementById("conversation");
        const inputField = document.getElementById("input-field");
        const submitButton = document.getElementById("submit-button");
        submitButton.addEventListener("click", function (e) {
            e.preventDefault();
            const userQuestion = inputField.value.trim();
            if (!userQuestion) return; // Don't send empty questions
            const accessCode = prompt("Please enter your access code:");
            if (!accessCode) return; // Don't proceed without access code
            // Display the user's prompt in a different style and position
            const userMessage = document.createElement("div");
            userMessage.classList.add("user-message"); // New class for user messages
            const userText = document.createElement("div");
            userText.classList.add("user-text"); // New class for user text
            userText.textContent = userQuestion;
            userMessage.appendChild(userText);
            conversation.appendChild(userMessage);
            // Send the user's question to the API
            const url = uri + '/api/house/openai';
            fetch(url + `?question=${encodeURIComponent(userQuestion)}&code=${accessCode}`, {method: 'GET', mode: 'cors'}).then((response) => response.json()).then((data) => {
                    // Display the chatbot's response
                    const chatbotMessage = document.createElement("div");
                    chatbotMessage.classList.add("chatbot-message");
                    const chatbotText = document.createElement("div");
                    chatbotText.classList.add("chatbot-text");
                    chatbotText.textContent = data;
                    chatbotMessage.appendChild(chatbotText);
                    conversation.appendChild(chatbotMessage);
                    conversation.scrollTop = conversation.scrollHeight;
                    inputField.value = "";
                    inputField.focus();
                })
                .catch((error) => {
                    console.error("Error fetching data from the API:", error);
                });
        });
    });

Instructions for output

  • The AI bot ouputs the answer to the user’s prompt and displays it in the chat window.
fetch(url + `?question=${encodeURIComponent(userQuestion)}&code=${accessCode}`, {method: 'GET', mode: 'cors'}).then((response) => response.json()).then((data) => {
    // Display the chatbot's response
    const chatbotMessage = document.createElement("div");
    chatbotMessage.classList.add("chatbot-message");
    const chatbotText = document.createElement("div");
    chatbotText.classList.add("chatbot-text");
    chatbotText.textContent = data;
    chatbotMessage.appendChild(chatbotText);
    conversation.appendChild(chatbotMessage);
    conversation.scrollTop = conversation.scrollHeight;
    inputField.value = "";
    inputField.focus();
})
.catch((error) => {
    console.error("Error fetching data from the API:", error);
});

CPT Video

  • Contains examples of user interactions with the AI bot
  • Contains examples of the bot’s responses to user prompts
  • Has no voice and only captions
  • Meets length at 1 minute exactly