spb/ora-ka Public
Ora-Ka — cinq agrégateurs Ka, une barre de recherche hybride (exact + sémantique)
Python 80%
TypeScript 12.9%
CSS 6.8%
1# Ora·Ka — Cinq agrégateurs. Une barre.23**Auteur : Simon-Pierre Boucher — contact@spboucher.ai**45[](https://www.ora-ka.com)6[](requirements.txt)7[](oraka/web.py)8[](apps)9[](apps)10[](oraka/semantic.py)11[](https://www.ora-ka.com/api/overview)12[](#production-maclustr--nœud-m4m64a-port-8200)1314Ora-Ka unifie les cinq agrégateurs automatisés de la famille Ka en une seule15plateforme : **une barre de recherche**, un moteur hybride exact + sémantique,16et les cinq applications d'origine **reproduites fidèlement** sous leur propre17préfixe — sans modifier une ligne de leurs backends.18192021## Métriques (prod, 2026-08-13)2223| Univers | Préfixe | Contenu | Inscriptions | Sources | Accent |24|-----------|-----------|--------------------------------|-------------:|--------:|-----------|25| Immo·Ka | `/immo/` | Propriétés à vendre (QC) | 48 487 | 33 | `#e23744` |26| Lou·Ka | `/lou/` | Logements à louer | 16 563 | 255 | `#d9f26b` |27| Fabri·Ka | `/fabri/` | Produits québécois | 291 132 | 3 224 boutiques | `#c4532e` |28| Auto·Ka | `/auto/` | Véhicules d'occasion | 17 997 | 138 | `#ff5a2a` |29| Food·Ka | `/food/` | Épicerie comparée | 26 319 | 30 | `#1f7a4d` |30| **Total** | | | **400 498** | | |3132| Dimension | Valeur |33|------------------------|--------|34| Index sémantique | 362 508 vecteurs · text-embedding-3-small · 256 d float16 · ≈ 164 Mo npz |35| Bases SQLite | ≈ 1,4 Go (5 bases + 2 bases quartier) |36| Moteur `oraka/` | 2 090 lignes Python (8 modules) |37| Backends embarqués | 339 fichiers Python · 65 852 lignes (inchangés) |38| Frontends | 5 SPA React 18 + Vite, rebuildées sous préfixe |39| Cadence d'ingestion | immo 180 min · lou 60 · auto 120 · fabri/food 360 |40| Latence recherche | brute-force numpy sur npz en RAM, hot-reload sur mtime |4142## La recherche hybride4344Une seule barre (`/api/search`) interroge les cinq univers avec un **score45unifié par candidat** — pas de cascade exact-puis-sémantique :4647- **Candidats** : correspondance exacte par jetons AND (LIKE/FTS5) ∪ top-k sémantique par univers.48- **Score** : cosinus (lookup par uid, même pour les hits exacts) + 0,22·couverture-jetons + 0,10·phrase + 0,05·exact + affinité d'univers data-driven.49- **Coupure dynamique** (best − 0,22) + **garantie de diversité** : chaque univers ≥ best − 0,30 est épinglé dans le top 12.50- **Affichage** : pertinence relative en % (score/best), jauge, surlignage des jetons (préfixe en début de mot, stopwords exclus).5152| « condo 2 chambres montréal » | « fromage du québec » |53|---|---|54|  |  |5556L'index (`oraka/semantic.py`) vit dans `data/semantic/<univers>.npz` ; le57serveur le recharge à chaud sur changement de mtime — un simple rsync des npz58suffit, sans redémarrage. Rebuild incrémental : `run.py index`59(~10 min, ~0,25 $ ; à relancer après les grosses syncs sinon l'index dérive).6061## Les cinq univers6263Chaque app est montée telle quelle sous son préfixe — mêmes fiches, mêmes64cartes, mêmes filtres que l'app d'origine :6566| | |67|---|---|68|  `/immo/` |  `/lou/` |69|  `/fabri/` |  `/auto/` |70|  `/food/` |  splash au boot |7172*Captures régénérables : `node scripts/screenshots.mjs` (playwright requis).*7374## Architecture7576```77ora-ka/78 run.py # serve [port] | sync [app ...] | watch | index79 oraka/80 web.py # app maîtresse : landing + /api/overview + /healthz + 5 mounts81 landing.py # landing « famille Ka × verre » (splash, ticker, cartes)82 search.py # /api/search — score unifié exact ∪ sémantique83 semantic.py # index npz par univers, hot-reload, OpenAI embeddings84 auth.py # SSO « KA ID » via le hub groupe-ka.com85 hubfav.py # favoris synchronisés au hub86 legal.py # conditions + confidentialité87 apps/88 immo/ { immoka/, data/{immoka.db, quartier.db, sources.json…}, frontend/ }89 lou/ { louka/, data/{louka.db, quartier.db, sources.json}, frontend/ }90 fabri/ { fabrika/, data/{fabrika.db, stores.json}, frontend/ }91 auto/ { autoka/, data/{autoka.db, sources.json}, frontend/ }92 food/ { foodka/, data/{foodka.db, sources.json}, frontend/ }93 data/semantic/ # <univers>.npz + .meta.json (non versionnés)94```9596Chaque app conserve son arborescence d'origine (`<package>/`, `data/`,97`frontend/dist/` frères) — ses chemins internes calculés via `__file__`98restent valides, **aucun code backend n'a été modifié**. Les frontends99React/Vite ont uniquement été rebuildés avec `base: '/<préfixe>/'` +100`basename` react-router + `API_BASE = import.meta.env.BASE_URL`101(+ cas spéciaux : worker MapLibre de lou, logos de food).102103Design de la landing : hybride « famille Ka × verre » — papier grainé104`#f5f3ee`, encre `#141814`, lime `#d9f26b`, JetBrains Mono uppercase,105bordures encre + ombres décalées dures, badge « Ka » incliné −2°, ticker,106splash Groupe KA (1,6 s, sessionStorage).107108## Lancement109110```bash111python3 -m venv .venv && .venv/bin/pip install -r requirements.txt112# builds frontend (une fois) : cd apps/<x>/frontend && npm install && npm run build113.venv/bin/python run.py serve 8200 # plateforme complète114.venv/bin/python run.py sync # ingestion des 5 apps (ou : sync immo lou …)115.venv/bin/python run.py watch # boucle permanente, cadence native par app116.venv/bin/python run.py index # (re)construit l'index sémantique117```118119`.env` (non versionné) : `OPENAI_API_KEY` (index sémantique),120`FIRECRAWL_API_KEY`, `SCRAPFLY_KEY`, `SCRAPFLY_API_KEY` (ingestion seulement,121jamais le serveur) ; `KA_SSO_SECRET`, `KA_HUB_URL` (SSO KA ID).122123## Production (MacLustr — nœud M4M64a, port 8200)124125```bash126pm2 start .venv/bin/python --name ora-ka-web --interpreter none --cwd ~/apps/ora-ka -- run.py serve 8200127pm2 start .venv/bin/python --name ora-ka-sync --interpreter none --cwd ~/apps/ora-ka -- run.py watch128pm2 start /opt/homebrew/bin/ngrok --name ora-ka-ngrok --interpreter none -- http --url=www.ora-ka.com 8200129```130131Healthcheck : `GET /healthz` — vérifie la présence des 5 bases SQLite.132Stats agrégées en direct : `GET /api/overview`.133134---135136© 2026 Groupe KA — Ora-Ka agrège des données publiques ; chaque inscription137reste la propriété de sa source.138