back to work
AI · Geospatial

WohnIQ

Personal Project

Jun 2026Full-Stack AI Engineer (Solo)
WohnIQ

A production-grade AI-assisted apartment search platform for Berlin that parses natural-language queries, ranks listings deterministically, enriches results with live commute and POI data, and flags suspicious listings through a hybrid scam detection engine with measurable evals.

FastAPINext.js 14TypeScriptPythonGemini FlashSupabasePostgreSQLpgvectorSQLAlchemyAlembicPydanticTailwind CSSshadcn/uiLeafletimagehashBVG/VBB APIOSM OverpassRailwayVercel

  • Architected and shipped a full-stack AI search platform end-to-end — NLP query parsing, pgvector semantic retrieval, deterministic ranking, real-time enrichment, hybrid scam detection, and deployment.
  • Built a central LLM client around Gemini Flash with Pydantic-validated structured output, one re-prompt on failure, and a deterministic fallback — ensuring no unvalidated model text reaches business logic or the user.
  • Designed a hybrid scam detection engine fusing three signal sources into an explainable 0–100 risk score: deterministic price z-score rules, perceptual-hash (pHash) duplicate photo detection, and an LLM text pass extracting verbatim evidence quotes.
  • Implemented real-time commute enrichment via the keyless BVG/VBB transport.rest API and neighborhood POI enrichment via OSM Overpass, cached per listing and integrated into the ranking score.
  • Built a measurable eval harness (parser, ranking, scam) with threshold gates that run in CI, providing ground-truth precision/recall/F1 metrics over a synthetic dataset with labeled scam types and hard negatives.
  • Deployed backend on Railway (Docker + FastAPI) and frontend on Vercel (Next.js 14), with Supabase Postgres + pgvector as the single data store for listings, embeddings, and risk assessments.
  • Enforced a strict language-vs-logic separation: the LLM is limited to three single-shot stateless calls (parse query, read scam text, write explanation). All ranking, scoring, and ordering is deterministic code — same input always produces the same output, making explanations trustworthy by construction.
  • Chose a hybrid scam detector over a pure LLM classifier: fusing rule signals, pHash image duplicates, and a structured LLM text pass produces an explainable score with evidence, rather than an opaque verdict.
  • Used synthetic listings with ground-truth scam labels by design, enabling a proper confusion matrix eval with per-type recall and hard-negative clearance — something impossible with scraped real-world data.
  • Called the Gemini SDK directly behind a thin injectable transport rather than adopting LangChain/LangGraph — three stateless calls don't justify an orchestration framework, and the injectable boundary keeps tests fully offline.
  • Kept all schema changes through SQLAlchemy 2.0 models + Alembic migrations with strict guardrails after a near-miss with an accidental drop_table.
Result

Deployed and live. Accepts plain-language Berlin apartment queries and returns ranked results with natural-language explanations grounded in score breakdowns, real-time commute times, neighborhood POI counts, and per-listing scam risk badges. Scam eval achieves measurable precision/recall over four scam types with hard-negative clearance tracked in CI.