# Documentation ## Week 2: Apartment Predictor (Saved Regression Model + LLM Workflow) This file documents the apartment rent prediction app that I built, tested, and deployed on Hugging Face Spaces. --- ## 1. Project Summary The app accepts a German natural language apartment request. The user writes a sentence that includes the number of rooms, the apartment size and the town. The LLM extracts the structured values `rooms`, `area_m2` and `town` from the user text. A saved Random Forest regression model then predicts the estimated monthly rent in CHF. Finally, the LLM generates a short German explanation of the prediction and mentions that the result is only an estimate. --- ## 2. Files Used | File | Purpose | |---|---| | `app.py` | Final deployable app used by Hugging Face Spaces | | `app_student.py` | Student implementation with the completed TODOs | | `random_forest_regression.pkl` | Saved Random Forest regression model | | `bfs_municipality_and_tax_data.csv` | Municipality data used for prediction | | `requirements.txt` | Python dependencies for Hugging Face Spaces | | `README.md` | Hugging Face Space configuration and short app description | | `documentation.md` | Written documentation for the submission | | `screenshot1.png` | Screenshot of the first working app test | | `screenshot2.png` | Screenshot of the second working app test | --- ## 3. Numeric Prediction Part ### 3.1 Reused Model I used the saved model file: `random_forest_regression.pkl` The model predicts the estimated monthly apartment rent in CHF. The model uses apartment information and municipality information for the prediction. ### 3.2 Input Features The model uses these features: 1. `rooms` 2. `area` 3. `pop` 4. `pop_dens` 5. `frg_pct` 6. `emp` 7. `tax_income` In the user interface and in the LLM extraction step, the apartment size is called `area_m2`. For the model input, I map `area_m2` to the trained model feature `area`, because the saved model expects the feature name `area`. ### 3.3 Prediction Logic First, the LLM extracts the number of rooms, the apartment area and the town from the German user text. Then the app matches the extracted town to the municipality data in `bfs_municipality_and_tax_data.csv`. After that, the app combines the apartment values with the municipality values and passes them to the saved Random Forest model. The model returns a monthly rent prediction in CHF. --- ## 4. LLM Extraction Part ### 4.1 Goal The goal of the first LLM step is to transform a free German apartment request into structured JSON. The LLM extracts: - `rooms` - `area_m2` - `town` ### 4.2 Prompt Design The system prompt tells the LLM to extract apartment preferences from German text. It requires strict JSON output only, without Markdown or additional explanation. The required JSON keys are: - `rooms` - `area_m2` - `town` The prompt also tells the model to use `null` if a value is missing. ### 4.3 Expected Output Format Example: ```json { "rooms": 3.5, "area_m2": 85, "town": "Winterthur" } ``` ### 4.4 Validation The app validates the LLM response before using it. It checks whether the response is valid JSON and whether all required keys are present. It also checks that rooms, area and town are not missing. The town is matched against the BFS municipality data before the prediction is made. --- ## 5. LLM Explanation Part ### 5.1 Goal The second LLM step generates a short German explanation of the model prediction. The LLM does not calculate the rent itself. It only explains the numeric prediction returned by the Random Forest model. ### 5.2 Prompt Design The explanation prompt includes the extracted apartment preferences and the predicted monthly rent. The LLM is instructed to answer in German, mention the predicted rent in CHF and include one short uncertainty note. The response is also required to be valid JSON with the key `answer`. ### 5.3 Expected Output Format Example: ```json { "answer": "Die Wohnung mit 3.5 Zimmern und 85 m² in Winterthur hat eine geschätzte Monatsmiete von etwa 2117 CHF. Diese Schätzung basiert auf einem numerischen Modell und kommunalen Daten. Bitte beachten Sie, dass es leichte Abweichungen geben kann." } ``` --- ## 6. End-to-End Pipeline The full pipeline works like this: 1. The user enters a German apartment request. 2. The LLM extracts `rooms`, `area_m2` and `town`. 3. Python validates the extracted JSON. 4. The app matches the town to the municipality data. 5. The app builds the model input features. 6. The Random Forest model predicts the estimated monthly rent. 7. The LLM generates a short German explanation. 8. The app returns the extracted JSON, the predicted rent and the final explanation. --- ## 7. Test Cases | Test Input | Extracted Output Correct? | Prediction Returned? | Explanation Returned? | Notes | |---|---|---|---|---| | `Ich suche eine 3.5-Zimmer-Wohnung mit etwa 85 m2 in Winterthur.` | Yes | Yes | Yes | Extracted 3.5 rooms, 85 m² and Winterthur. Prediction and explanation were returned successfully. | | `Ich möchte eine 2-Zimmer-Wohnung mit ungefähr 60 m2 in Zürich mieten.` | Yes | Yes | Yes | Extracted 2 rooms, 60 m² and Zürich. Prediction and explanation were returned successfully. | | `Ich suche eine 4.5-Zimmer-Wohnung mit 110 m2 in Bern.` | Yes | Yes | Yes | This was used as an additional German test prompt to check another Swiss city. | --- ## 8. Errors and Problems ### Problem 1: Missing API key At first, the app returned an error saying that the API key was missing. The reason was that the OpenAI API key was not set as an environment variable. I fixed this by adding the API key as a Hugging Face secret named `OPENAI_API_KEY`. ### Problem 2: Wrong or invalid API key On Hugging Face, the app returned an error saying that the API key was incorrect. The reason was that the API key was copied incorrectly or an invalid key was used. I fixed this by replacing the secret with a valid key and restarting the Space. ### Problem 3: Model feature name mismatch The model returned an error because it expected the feature name `area`, but the app originally passed `area_m2`. The saved model was trained with the feature name `area`. I fixed this by mapping the extracted value `area_m2` to the model feature `area`. ### Problem 4: Model version warning A warning appeared because the Random Forest model was saved with a different scikit-learn version. This warning did not stop the app. The model still loaded and returned predictions. --- ## 9. Deployment Notes ### 9.1 Files included The following files were uploaded to Hugging Face Spaces: - `app.py` - `app_student.py` - `requirements.txt` - `README.md` - `documentation.md` - `bfs_municipality_and_tax_data.csv` - `random_forest_regression.pkl` - `screenshot1.png` - `screenshot2.png` ### 9.2 Secrets / Environment Variables The app requires these Hugging Face secrets: - `OPENAI_API_KEY` - `OPENAI_MODEL` The model name used was: `gpt-4.1-mini` ### 9.3 Deployment Result The Hugging Face Space ran successfully. The app accepted German apartment requests, extracted structured JSON, returned a rent prediction and generated a German explanation. --- ## 10. Screenshots ### Example 1 ![Example 1](https://huggingface.co/spaces/vasanthi8134/apartment-predictor/resolve/main/screenshot1.jpeg) In this example, the app extracted 3.5 rooms, 85 m² and Winterthur from the German input. It returned a monthly rent prediction and a short German explanation. ### Example 2 ![Example 2](https://huggingface.co/spaces/vasanthi8134/apartment-predictor/resolve/main/screenshot2.jpeg) In this example, the app extracted 2 rooms, 60 m² and Zürich from the German input. It returned a monthly rent prediction and explained that the result is an estimate. --- ## 11. Reflection The combination of a regression model and an LLM worked well because both parts have a clear role. The LLM is useful for understanding natural language and extracting structured values. The regression model is useful for making the numeric prediction. The system is still fragile because the LLM could extract values incorrectly or the town might not match the municipality data. I would improve the app by adding better town suggestions and more apartment features. --- ## 12. Responsible Use Note The prediction is only an estimate and should not be used as a guaranteed rental price. Real rental prices depend on many additional factors, such as location quality, building condition, floor, balcony, renovation status and market situation. The LLM may also extract values incorrectly, so the extracted JSON should always be checked. The app is useful as a learning prototype, but not as a final real estate pricing tool.