A production-grade, containerized AI system that automates the creation of multilingual, SEO-optimized real estate property listings. This solution leverages Google Gemini 2.5 Flash-Lite for high-speed content generation and LanguageTool for grammar verification, wrapped in a FastAPI backend with an interactive Streamlit frontend.
It includes a robust LLM-as-a-Judge evaluation suite to automatically verify content quality against strict linguistic and structural criteria.
- π― Problem Statement
- β¨ Key Features
- π οΈ Tech Stack
- π Project Structure
- βοΈ Setup & Installation
- π Usage
- π§ͺ Automated Evaluation Suite
- ποΈ Architecture & Design Decisions
β οΈ Assumptions & Limitations- π License
Real estate companies manage hundreds of property listings across different cities and need to:
- Generate consistent, high-quality content at scale
- Support multiple languages and market tones
- Ensure strict SEO compliance
- Maintain a specific HTML structure for website integration
This system solves these challenges by transforming structured property data (JSON) into complete, ready-to-publish listing descriptions with guaranteed structural compliance.
- π Structured Output: Generates 7 distinct content sections (Title, Meta Description, H1, Description, Key Features, Neighborhood, CTA) with proper HTML tagging.
- π Multilingual & Regional:
- Languages: English, Portuguese, Spanish, French.
- Regional Localization: US vs. UK English (e.g., "Elevator" vs. "Lift"), PT vs. BR Portuguese.
- π Tone Customization: Professional, Friendly, Luxury, or Investor-focused writing styles.
- π SEO Optimization: Built-in keyword verification, dynamic city translation, and meta tag length validation.
- β Quality Assurance: Grammar checking via LanguageTool (Java-based) and logic validation (e.g., ensuring "Studio" is used for 1-bedroom units < 40sqm).
- LLM-as-a-Judge: A built-in testing suite that uses a separate LLM instance to grade generated content against a "Golden Dataset".
- Criteria Verification: Automatically checks for correct vocabulary (e.g., "Flat" vs "Apartment"), currency symbols, and tone compliance.
- Deterministic HTML Generation: LLM outputs pure JSON; Python constructs HTML (100% structural compliance).
- Async Processing: FastAPI with async/await for high-throughput batch operations.
- Docker-Optimized: LanguageTool models pre-downloaded during image build (no runtime delays).
| Component | Technology | Purpose |
|---|---|---|
| API Framework | FastAPI 0.121.3 | Async REST API with OpenAPI docs |
| LLM | Google Gemini 2.5 Flash-Lite | Cost-effective, low-latency content generation |
| Grammar Check | language-tool-python 3.0.0 | Multi-language grammar verification |
| Frontend | Streamlit 1.51.0 | Interactive testing UI |
| Validation | Pydantic 2.12.4 | Type-safe request/response models |
| Translation | deep-translator 1.11.4 | Dynamic city name localization |
| Testing | Google GenAI + Pytest | LLM-as-a-Judge evaluation framework |
| Containerization | Docker + Docker Compose | Reproducible deployment |
real-estate-ai/
βββ app/
β βββ api/
β β βββ routes.py # FastAPI endpoints (/generate, /batch)
β βββ core/
β β βββ config.py # Settings & environment variables
β βββ models/
β β βββ schemas.py # Pydantic models (input/output)
β βββ services/
β βββ generator.py # LLM orchestration & HTML construction
β βββ prompt.py # Dynamic prompt builder with localization
β βββ quality.py # Grammar checking & SEO validation
βββ tests/
β βββ evaluation_suite.py # LLM-as-a-Judge runner
β βββ golden_dataset.json # Test cases with strict criteria
β βββ evaluation_results.json # Output logs of the last test run
βββ frontend.py # Streamlit UI for interactive testing
βββ main.py # FastAPI app with lifespan management
βββ preload.py # Downloads LanguageTool models (Docker build step)
βββ docker-compose.yml # Multi-container orchestration
βββ Dockerfile # Optimized image with Java + Python
βββ requirements.txt # Python dependencies
βββ .env # API keys (DO NOT COMMIT)
- Docker (β₯ 20.10) and Docker Compose (β₯ 2.0)
- Google Gemini API Key β Get one here
- At least 2GB RAM allocated to Docker (for LanguageTool)
git clone https://github.com/jgurakuqi/real-estate-ai-content-generator.git
cd real-estate-ai-generatorCreate a .env file in the root directory:
# .env
GEMINI_API_KEY=your_actual_api_key_hereThis command builds the image, pre-downloads grammar models, and starts the services.
docker-compose up --buildService URLs:
- Frontend (Streamlit): http://localhost:8501
- Backend API: http://localhost:8000
- API Documentation: http://localhost:8000/docs
- Navigate to http://localhost:8501.
- Select Language (e.g., English) and Region (e.g., π¬π§ UK vs πΊπΈ US).
- Fill in property details.
- Click "β¨ Generate Content".
- View results in tabs: Preview, SEO & Quality (Grammar/Keywords), and Raw HTML.
Endpoint: POST /api/v1/generate
curl -X POST "http://localhost:8000/api/v1/generate" \
-H "Content-Type: application/json" \
-d '{
"title": "Modern Flat in London",
"location": { "city": "London", "neighborhood": "Shoreditch" },
"features": { "bedrooms": 2, "bathrooms": 1, "area_sqm": 60, "elevator": true },
"price": 500000,
"listing_type": "sale",
"language": "en",
"region": "GB",
"tone": "professional"
}'This project includes a sophisticated LLM-as-a-Judge script to verify that the AI adheres to complex instructions (e.g., "Use British English spelling" or "Don't sound like an investment pitch").
- Loads test cases from
tests/golden_dataset.json. - Generates content using the current system.
- Sends the output + grading criteria to a separate LLM instance (Judge).
- The Judge evaluates Pass/Fail and provides reasoning.
You can run the evaluation suite locally (requires Python installed locally):
# Install dependencies locally
pip install -r requirements.txt
# Run the suite
python -m tests.evaluation_suiteSample Output:
βΆοΈ Running Case: TEST_001_UK_REGION...
β
PASS
βΆοΈ Running Case: TEST_002_LUXURY_TONE...
β
PASS
π SUMMARY: 4/4 Tests Passed
π Ready for Production!
Results are saved to tests/evaluation_results.json.
Problem: LLMs often break HTML tags. Solution: The LLM outputs pure JSON. Python handles the HTML wrapping. This guarantees 100% valid HTML structure every time.
Problem: LanguageTool is heavy (Java-based) and slow to load. Solution:
- Models are downloaded during
docker buildviapreload.py. - The
QualityCheckerclass is loaded as a singleton on app startup (lifespanevent) and injected into routes.
Problem: "Apartment" (US) vs "Flat" (UK); "Elevator" vs "Lift".
Solution: A PromptBuilder injects region-specific vocabulary rules into the system prompt based on the region input, ensuring the LLM adopts the correct persona (e.g., "British Estate Agent").
- Studio Logic: The system automatically detects studios based on bedroom count (1) and keywords/size (<40sqm), adjusting the title to "Studio" or "T0".
- Translation: City names are translated via Google Translate API (deep-translator). In a high-load production environment, a static dictionary or caching layer (Redis) would be preferred.
- Memory: Requires ~2GB RAM due to the Java-based LanguageTool server running alongside the Python app.
This project is licensed under the MIT License. See the LICENSE file for details.