apartment-predictor / documentation.md
durovali's picture
Upload documentation.md
b5f371d verified
|
Raw
History Blame Contribute Delete
9.26 kB

A newer version of the Gradio SDK is available: 6.22.0

Upgrade

Documentation

Week 2: Apartment Predictor (Saved Regression Model + LLM Workflow)


1. Project Summary

The app accepts a free-text German apartment request from the user, for example "Ich suche eine 3.5-Zimmer-Wohnung mit 85 m2 in Winterthur." A first LLM call extracts the rooms, area in m2, and town from the text and returns them as structured JSON. The extracted values are then combined with municipality statistics from a CSV file and fed into a pre-trained Random Forest regression model, which predicts the monthly rent in CHF. A second LLM call generates a short German explanation of the prediction, including an uncertainty note.


2. Files Used

File Purpose
ai_applications_exercise2.ipynb Notebook work and testing
app_student.py Student implementation (template)
app.py Final deployable app
random_forest_regression.pkl Saved regression model
bfs_municipality_and_tax_data.csv Municipality features used for prediction
requirements.txt Python dependencies
documentation.md Written documentation for the submission

3. Numeric Prediction Part

3.1 Reused Model

Which saved model did you use? random_forest_regression.pkl

What does the model predict? The model predicts the monthly rent in CHF for a Swiss apartment based on structural features (rooms, area) and municipality-level statistics (population, population density, foreigner percentage, employment, tax income).

Which input features are used for prediction?

  1. rooms
  2. area_m2
  3. pop
  4. pop_dens
  5. frg_pct
  6. emp
  7. tax_income

3.2 Prediction Logic

The user's town name is matched to the BFS municipality database using exact lowercase matching first, then a relaxed contains-match as fallback. Once matched, the corresponding municipality row is looked up to retrieve the five statistical features. These are combined with the user-provided rooms and area values into a NumPy array with shape (1, 7) and passed to the scikit-learn Random Forest model via model.predict().


4. LLM Extraction Part

4.1 Goal

The LLM had to extract three structured values from free German text: the number of rooms (rooms), the apartment size in square meters (area_m2), and the town name (town).

4.2 Prompt Design

A system prompt instructed the LLM to act as an assistant that extracts apartment information from German text. The prompt required strict JSON output without any Markdown, code blocks, or explanations. It specified the exact output format and told the model to set null for any value it could not find.

  • System instruction was used
  • Strict JSON output was required
  • Required keys: rooms, area_m2, town
  • German input was expected
  • No Markdown or code fences allowed

4.3 Expected Output Format

{"rooms": 3.5, "area_m2": 85, "town": "Winterthur"}

4.4 Validation

After receiving the LLM response, a parse_json_response() function strips any accidental Markdown fences, then parses the text with json.loads(). If parsing fails a ValueError is raised with the raw response. After successful parsing the function checks that all required keys are present and raises a ValueError listing any missing keys. The run_pipeline() function additionally checks that none of the three extracted values are null before proceeding.


5. LLM Explanation Part

5.1 Goal

The second LLM step generates a short German explanation of the predicted rent. The LLM must mention the key input factors (rooms, area, town) and add an uncertainty note about factors not captured by the model. The LLM must not calculate or suggest a different price.

5.2 Prompt Design

The system prompt instructed the LLM to act as a helpful Swiss apartment assistant, explain the prediction in plain German, mention rooms, area and location as key factors, add one uncertainty note (e.g. condition, exact location, amenities), and explicitly not recalculate the price. Output was required as strict JSON with a single answer key.

5.3 Expected Output Format

{"answer": "Fuer eine 2.5-Zimmer-Wohnung mit 55 m2 in Zuerich schaetzt das Modell rund 2639 CHF pro Monat. Eine Unsicherheit ist, dass Zustand und Mikrolage nicht direkt im Modell enthalten sind."}

6. End-to-End Pipeline

  1. User enters a German apartment request in the Gradio text box.
  2. The first LLM call extracts rooms, area_m2, and town from the text and returns strict JSON.
  3. Python validates the extracted values: checks for valid JSON, required keys, and non-null values.
  4. The town name is matched to the BFS municipality database to retrieve population and tax statistics.
  5. The seven features are assembled into a NumPy array and passed to the Random Forest model, which returns the predicted monthly rent in CHF.
  6. The second LLM call receives the preferences and prediction and returns a short German explanation with an uncertainty note as JSON.
  7. The app displays the extracted JSON, the predicted rent, and the final explanation to the user.

7. Test Cases

Test Input Extracted Output Correct? Prediction Returned? Explanation Returned? Notes
2.5 Zimmer, 55m2, Zuerich Yes Yes Yes rooms=2.5, area_m2=55, town=Zuerich extracted correctly. Prediction: 2639.47 CHF
Ich suche eine 4.5-Zimmer-Wohnung mit 120 m2 in Bern. Yes Yes Yes rooms=4.5, area_m2=120, town=Bern extracted correctly. Prediction: 2827.90 CHF
Ich brauche etwas Guenstiges in Luzern, ca. 60m2 und 2 Zimmer. Yes Yes Yes LLM correctly identified rooms=2, area_m2=60, town=Luzern from informal text

8. Errors and Problems

Problem: scikit-learn version warning on startup Cause: The model was pickled with scikit-learn 1.6.1 but Hugging Face Spaces runs 1.8.0 Fix: Pinned scikit-learn==1.6.1 in requirements.txt to ensure version compatibility

Problem: LLM occasionally returns JSON wrapped in Markdown code fences Cause: Some LLM responses include json ... formatting despite instructions Fix: The parse_json_response() function strips Markdown fences before parsing

Problem: Town names with umlauts (e.g. Zuerich vs Zuerich) sometimes failed matching Cause: Case and umlaut differences between user input and BFS database Fix: Implemented relaxed contains-matching as fallback after exact lowercase match


9. Deployment Notes

9.1 Files included

  • app.py
  • requirements.txt
  • random_forest_regression.pkl
  • bfs_municipality_and_tax_data.csv
  • documentation.md

9.2 Secrets / Environment Variables

  • OPENAI_API_KEY
  • OPENAI_MODEL (optional, defaults to gpt-4.1-mini)

9.3 Deployment Result

The Space ran successfully after pinning the scikit-learn version. Both LLM calls and the regression model work correctly. The app correctly handles German free-text input and returns structured extraction, a numeric prediction, and a natural language explanation.

9.4 Screenshots

Example 1

Test 1: The user entered "2.5 Zimmer, 55m2, Zuerich". The LLM correctly extracted all three values and the model predicted a monthly rent of 2639.47 CHF. The explanation mentions the key factors and includes an uncertainty note about condition and amenities.

Example 2

Test 2: The user entered "Ich suche eine 4.5-Zimmer-Wohnung mit 120 m2 in Bern." The LLM correctly extracted rooms=4.5, area_m2=120, town=Bern and the model predicted 2827.90 CHF. The explanation correctly references all input factors and notes potential price variation.


10. Reflection

The combination of a regression model and an LLM worked well: the structured model provides a reliable numeric estimate based on objective features, while the LLM bridges the gap between free text and structured input. The most fragile part of the system is the LLM extraction step, since the model may misread ambiguous German phrasing or fail to produce valid JSON. German input is important because Swiss renters naturally write in German, and forcing English would create an unnecessary barrier. Important apartment information still missing from the model includes floor level, building age, renovation status, and proximity to public transport. As a next step, adding more structured features or allowing the LLM to also estimate qualitative factors could improve the prediction quality.


11. Responsible Use Note

The predicted rent is only an estimate based on a limited set of structural and municipality-level features and should not be used as a binding price reference. The regression model does not capture all factors that influence real rental prices, such as apartment condition, exact micro-location, or current market demand. The LLM extraction step may occasionally misinterpret user input, leading to incorrect features being passed to the model. Users should treat the output as a rough orientation and consult official rental platforms or a professional for accurate pricing information.