| # Documentation |
|
|
| ## 1. Project Summary |
|
|
| **Short description of your app:** |
| The app accepts a German apartment request in free text and uses an LLM to extract structured information. It then predicts the estimated monthly rent in CHF with a saved scikit-learn model and municipality data from the BFS dataset. A second LLM step turns the prediction into a short German explanation with an uncertainty note. |
|
|
| --- |
|
|
| ## 2. Files Used |
|
|
| List the main files you worked with. |
|
|
| | File | Purpose | |
| |------|---------| |
| | `ai_applications_exercise2.ipynb` | Notebook work and testing | |
| | `app_student.py` | Student implementation | |
| | `app.py` | Final deployable app | |
| | `model.pkl` | Saved gradient boosting model used by the app | |
| | `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?** |
| `model.pkl` |
|
|
| **What does the model predict?** |
| The model predicts the estimated monthly rent in CHF for a given apartment request. |
|
|
| **Which input features are used for prediction?** |
| The model uses 14 input features in this order: |
|
|
| 1. `rooms` |
| 2. `area` |
| 3. `pop` |
| 4. `pop_dens` |
| 5. `frg_pct` |
| 6. `emp` |
| 7. `tax_income` |
| 8. `rooms_per_sqm` |
| 9. `wealth_index` |
| 10. `is_zurich_city` |
| 11. `pop_emp_ratio` |
| 12. `log_area` |
| 13. `log_pop` |
| 14. `log_tax_income` |
|
|
| ### 3.2 Prediction Logic |
|
|
| The app first extracts `rooms`, `area_m2`, and `town` from the user text. Then it looks up the corresponding municipality row in `bfs_municipality_and_tax_data.csv` and builds the full feature row from the user values and BFS attributes. Additional engineered features such as `rooms_per_sqm`, `wealth_index`, `is_zurich_city`, `pop_emp_ratio`, and log-transformed values are computed before the model prediction. |
|
|
| --- |
|
|
| ## 4. LLM Extraction Part |
|
|
| ### 4.1 Goal |
|
|
| The LLM had to extract three structured values from the free-text request: the number of rooms, the living area in square meters, and the town or municipality name. |
|
|
| ### 4.2 Prompt Design |
|
|
| The prompt uses a German system instruction that tells the model to convert apartment wishes into structured data. It requires strict JSON only, with the keys `rooms`, `area_m2`, and `town`, and the request text is also in German so Swiss place names are matched more reliably. |
|
|
| ### 4.3 Expected Output Format |
|
|
| ```json |
| {"rooms": 3.5, "area_m2": 85, "town": "Winterthur"} |
| ``` |
|
|
| ### 4.4 Validation |
|
|
| After the LLM response, the code parses the JSON and checks that all required keys exist. The town name is then normalized with `match_town(...)` and validated against the dataset before the prediction step continues. |
|
|
| --- |
|
|
| ## 5. LLM Explanation Part |
|
|
| ### 5.1 Goal |
|
|
| The second LLM step explains the prediction in simple German. It should not calculate a new price; it should only describe the already predicted result and mention a limitation or uncertainty. |
|
|
| ### 5.2 Prompt Design |
|
|
| The explanation prompt includes the extracted apartment request and the predicted CHF value. It asks for a short German answer, includes an uncertainty note, and requires JSON output with an `answer` key. |
|
|
| ### 5.3 Expected Output Format |
|
|
| ```json |
| {"answer": "Für eine 3.5-Zimmer-Wohnung in Winterthur schätzt das Modell rund 2800 CHF pro Monat. Eine Unsicherheit ist, dass Zustand und Mikrolage nicht direkt im Modell enthalten sind."} |
| ``` |
|
|
| --- |
|
|
| ## 6. End-to-End Pipeline |
|
|
| End-to-end pipeline: |
| Suggested order: |
| 1. User enters a German apartment request. |
| 2. The LLM extracts `rooms`, `area_m2`, and `town`. |
| 3. Python validates the extracted values and maps the town to BFS data. |
| 4. The app builds the 14 model features from user input and municipality data. |
| 5. The saved gradient boosting model predicts the monthly rent. |
| 6. The LLM generates a short explanation. |
| 7. The app returns structured input, prediction, and final answer. |
|
|
| --- |
|
|
| ## 7. Test Cases |
|
|
| Document at least 3 test inputs. |
|
|
| | Test Input | Extracted Output Correct? | Prediction Returned? | Explanation Returned? | Notes | |
| |------------|----------------------------|----------------------|-----------------------|-------| |
| | `Ich suche eine 3.5-Zimmer-Wohnung mit 85 m2 in Winterthur.` | Yes | Yes | Yes | Valid extraction and prediction | |
| | `Ich brauche eine 2-Zimmer-Wohnung mit etwa 55 m2 in Kloten.` | Yes | Yes | Yes | Different town and smaller apartment | |
| | `Ich suche eine 5.5-Zimmer-Wohnung mit etwa 180 m2 in Zürich.` | Yes | Yes | Yes | Larger apartment and Zürich-specific feature | |
|
|
| ## 8. Errors and Problems |
|
|
| I had one major problem during the implementation: the first version of the app returned almost the same rental value for many different apartment requests. The cause was that I was still using the older regression model instead of the newer model file, so the prediction was too coarse and not sufficiently differentiated. |
|
|
| - **Problem**: The predicted monthly rent was not precise enough and often stayed at the same value. |
| - **Cause**: The app used the older regression model instead of the newer saved model with richer features. |
| - **Fix**: I switched the app to the new model file and adapted the prediction pipeline to the correct feature set, which improved the variation in the results. |
|
|
| I also had smaller setup-related issues when connecting the OpenAI variables and the model file path, but these were resolved by aligning the file names and environment variable names with the app code. |
|
|
| --- |
|
|
| ## 9. Deployment Notes |
|
|
| ### 9.1 Files included |
|
|
| I uploaded the files manually to Hugging Face. The deployed files were: |
|
|
| - `app.py` |
| - `README.md` |
| - `bfs_municipality_and_tax_data.csv` |
| - `model.pkl` |
| - `requirements.txt` |
| - `.gitattributes` |
| - `.documentation.md` |
|
|
| ### 9.2 Secrets / Environment Variables |
|
|
| The Space required the following variables: |
|
|
| - `OPENAI_API_KEY` |
| - `OPENAI_MODEL` |
|
|
| The app reads these names directly, so they must match the code exactly. |
|
|
| ### 9.3 Deployment Result |
|
|
| The Space works without problems. The app loads correctly, the LLM extraction runs, the prediction is returned, and the final explanation is displayed as expected. |
|
|
| ### 9.4 Screenshots |
|
|
|  |
| Extraktion der JSON-Antwort und die vorhergesagte Miete wurden korrekt angezeigt. |
|
|
|  |
| Anderes Beispiel mit verändertem Prompt; Modell liefert eine passende Schätzung und eine kurze Erklärung. |
|
|
| --- |
|
|
| ## 10. Reflection |
|
|
| This exercise showed me that the combination of a structured regression model and an LLM can work well when both parts are aligned correctly. The LLM is useful for converting natural language into usable model input, but the overall quality of the app depends heavily on the underlying model and the features it was trained on. At the beginning I saw that the output was too repetitive, which made it clear that the older model was not suitable for the final solution. After switching to the newer model file, the predictions became more plausible and more varied. In a next step, I would improve the app further by adding more apartment-specific features such as exact location quality, condition, and amenities. |
|
|
| ## 11. Responsible Use Note |
|
|
| The predicted rent is only an estimate and should not be treated as a final market price. The model still works with a limited set of structured features, so it cannot capture every factor that influences real rental prices. The LLM can also make extraction errors if the user input is unclear or incomplete. For responsible use, the result should always be presented as a rough guidance value rather than a guaranteed rental price. |
|
|