Ora·Ka
Five aggregators, 400,498 listings, one search bar: Ora·Ka merges the whole Ka data family into a single hybrid search platform.
Live at www.ora-ka.com, it mounts Immo·Ka, Lou·Ka, Fabri·Ka, Auto·Ka, and Food·Ka under one roof without modifying a single line of their backends.
400,498
Listings across five universes
5
Aggregators unified
362,508
Semantic embedding vectors
~1.4 GB
SQLite databases
2,090
Lines of Python in the engine
65,852
Backend lines embedded unchanged
Overview
Ora·Ka unifies the five automated aggregators of the Ka family (Immo·Ka for Québec properties for sale, Lou·Ka for rentals, Fabri·Ka for Québec-made products, Auto·Ka for used vehicles, and Food·Ka for grocery price comparison) into one platform totalling 400,498 listings. Each original app is mounted as-is under its own prefix (/immo/, /lou/, /fabri/, /auto/, /food/) with the same listing pages, cards, and filters, while a shared landing page presents a single search bar, a live ticker, and aggregate stats served by /api/overview.
The heart of the platform is a hybrid search engine at /api/search that scores every candidate with one unified formula rather than an exact-then-semantic cascade. Candidates come from exact AND-token matching (LIKE/FTS5) union top-k semantic hits per universe; the score combines cosine similarity over 362,508 OpenAI text-embedding-3-small vectors (256-dimension float16, about 164 MB of npz files) with token-coverage, phrase, and exact bonuses plus data-driven universe affinity. A dynamic cutoff and a diversity guarantee pin every competitive universe into the top 12, and the in-RAM numpy index hot-reloads whenever an npz file's mtime changes.
A 2,090-line Python engine (8 modules, FastAPI) orchestrates everything: run.py serves the platform, syncs the five apps on their native ingestion cadences (immo every 180 minutes, lou 60, auto 120, fabri and food 360), and rebuilds the semantic index in about 10 minutes for roughly $0.25. The embedded backends (339 Python files, 65,852 lines) run unchanged over roughly 1.4 GB of SQLite, and the five React 18 + Vite SPAs were only rebuilt under their prefixes. Production runs on MacLustr node M4M64a port 8200 under pm2, exposed by ngrok at www.ora-ka.com.
Key Features
One hybrid search bar
A single /api/search endpoint queries all five universes at once, merging exact AND-token matches with top-k semantic hits under one unified score per candidate.
Semantic index
362,508 OpenAI text-embedding-3-small vectors at 256 dimensions in float16, about 164 MB of npz files, one index per universe.
Five apps, zero backend changes
Each original app is mounted under its own prefix with its full tree intact; 339 Python files and 65,852 lines run completely unmodified.
Automated ingestion
run.py watch keeps every universe fresh on its native cadence: immo every 180 minutes, lou every 60, auto every 120, fabri and food every 360.
Hot-reloading in-RAM index
Brute-force numpy search over npz files held in RAM, reloaded automatically on mtime change, so a simple rsync updates the index with no restart.
KA ID SSO and hub favorites
Signs members in through the groupe-ka.com hub's KA ID single sign-on and syncs favorites back to the central hub store.
How It Works
Ingestion
run.py watch runs a permanent loop that syncs each of the five apps on its native cadence (immo 180 min, lou 60, auto 120, fabri and food 360), using the apps' own unmodified ingestion code.
Storage
Each universe keeps its original SQLite database (immoka.db, louka.db, fabrika.db, autoka.db, foodka.db, plus two neighborhood databases), about 1.4 GB in total with no database server.
Indexing
run.py index incrementally rebuilds one npz semantic index per universe with OpenAI text-embedding-3-small at 256 dimensions, taking about 10 minutes and roughly $0.25 per run.
Search
/api/search unions exact AND-token candidates with per-universe semantic top-k, scores everything with cosine plus 0.22 token-coverage, 0.10 phrase, and 0.05 exact bonuses, then applies a dynamic cutoff and a diversity guarantee.
Serving
The FastAPI master app in oraka/web.py serves the landing, /api/overview, and /healthz, and mounts the five apps under their prefixes; pm2 runs web, sync, and ngrok processes on M4M64a:8200 behind www.ora-ka.com.
Tech Stack
Engine & Backend
Data & Frontend
Deployment
Highlights
- 400,498 listings unified: 291,132 Québec products, 48,487 properties, 26,319 grocery items, 17,997 vehicles, and 16,563 rentals.
- Not a single line of the five embedded backends was modified: 339 Python files and 65,852 lines run as-is under their prefixes.
- One unified score per candidate (cosine + 0.22 token coverage + 0.10 phrase + 0.05 exact) replaces the usual exact-then-semantic cascade.
- A diversity guarantee pins every universe scoring within 0.30 of the best hit into the top 12 results.
- The semantic index hot-reloads on file mtime, so rsyncing fresh npz files updates search without restarting the server.
- GET /healthz verifies all five SQLite databases and GET /api/overview serves live aggregate statistics.
Explore Ora·Ka
Five Ka aggregators behind one search bar — the full source is on GitHub.