Commit graph

8 commits

Author SHA1 Message Date
88f6f2bff9 fix(geocoder): rejeter la confiance <= seuil (0.7 et moins → LLM)
is_reliable exige strictement > MIN_CONFIDENCE : une confiance de 0.7 pile
(ou moins) n'est plus acceptée et part vers le LLM.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 20:34:42 +02:00
72a52a8d3b feat(geocoder): seuil de confiance strict, dedup, purge ancien pipeline
Durcissement fiabilité (suite audit).

Confiance & granularité
- worker: un résultat n'est accepté ('done') que si confiance >= GEOCODE_MIN_CONFIDENCE
  (0.7) ET granularité non-grossière (rejette country/state/county/region). Sinon
  on continue les fallbacks, puis -> llm_needed.
- fix majeur: sur cache hit la confiance était écrite 0.5 en dur (97% des lignes
  faussées). Elle est désormais lue depuis geocode_cache (recalculée du raw).
- migration 012: colonnes confidence+granularity sur geocode_cache (recalcul des
  entrées Geoapify depuis le raw), geocode_granularity sur band_locations.

Dedup (7x moins de travail)
- fast-path: un band_location dont le (lieu,pays) est déjà 'done' copie le
  résultat sans appel API. Index fonctionnel lower(location_raw).

Ancien pipeline retiré
- geocode_queue n'est plus lu nulle part (endpoints /geocoding/reset-errors et
  /requeue-all supprimés, /live et /geocoding et Monitor basculés sur
  band_locations, panneau admin "ancien pipeline" retiré).

Boutons reset (onglet Géocodage, zone dangereuse)
- POST /admin/api/locations/reset-all: remet tout en queue + efface coords
- POST /admin/api/geocode-cache/purge-nominatim: purge le cache Nominatim

Divers
- groq_worker: coût calculé par modèle (70B vs 8B) au lieu du tarif 70B fixe
- GEOCODE_MIN_CONFIDENCE ajouté aux deux compose

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 20:32:16 +02:00
2b871584e9 feat(admin): observabilité & provenance du géocodage + fix parser
Objectif: pouvoir debugger la fiabilité des données depuis l'admin.

Parser
- fix split "and": _CITY_SPLIT ne coupe plus sur " and "/"&" (cassait
  "Tyne and Wear", "Bosnia and Herzegovina", "Newcastle upon Tyne"). Garde
  uniquement "/" et "\" (séparateurs canoniques Metal Archives).

Traçabilité LLM
- migration 011: llm_cache reçoit ma_id + location_raw + country (+ index) pour
  relier chaque appel Groq au groupe déclencheur
- groq_worker: renseigne ces colonnes à l'insertion

Admin — lecture par groupe
- GET /admin/api/bands/:ma_id renvoie désormais aussi les band_locations (steps,
  statut, provider, confiance, coords, essais, erreur, query) et les appels LLM
  (modèle, extraction, tokens, coût, prompt/réponse)
- modal band: section "Provenance & géocodage" (crawl MA / géocodage / LLM +
  champs verrouillés manuels)

Admin — stats & debug LLM
- GET /admin/api/geocoding: breakdown par provider (avg confiance) + par modèle
  LLM (dont city=null); nouvelle carte "LLM null"
- nouveau GET /admin/api/llm + onglet "LLM": liste filtrable des appels Groq,
  prompt/réponse dépliables, lien vers le groupe

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 20:10:18 +02:00
f145188d1f fix(geocoder): band_locations.ma_id en BIGINT — débloque 62k bands
bands.ma_id est BIGINT (crawler génère jusqu'à ~3.5e9) mais band_locations.ma_id
avait été créé en INTEGER (max 2.1e9). Tout INSERT pour un band à ma_id élevé
échouait en "integer out of range", erreur avalée silencieusement par l'enqueue.
62 239 bands (sur 96 143 localisables) n'entraient donc jamais dans le pipeline,
d'où 0 llm_needed / 0 erreur trompeurs.

- migration 008: ma_id BIGINT (installs neuves)
- migration 009: ALTER COLUMN ma_id TYPE BIGINT (DB existante)
- enqueue.py: compte les inserts échoués (failed=) au lieu de les avaler
- worker.py: sync_bands_primary prend le lieu d'ORIGINE (step 0) et non la
  dernière localisation — garde les groupes européens en Europe
- admin app.js: coût LLM robuste au NaN (NUMERIC accepte la valeur spéciale NaN)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-02 19:47:30 +02:00
dba6b9f730 feat(geocoding): boutons UI pour déclencher l'enqueue band_locations
- enqueue.py devient un daemon qui poll job_triggers (type geocoder_enqueue)
  toutes les 15s — plus de commande manuelle à lancer
- API : geocoder_enqueue ajouté aux job types autorisés
- Admin UI page Géocodage : bouton "Lancer l'enqueue" (vert)
- Admin UI Centre de commandes : même bouton dans la section Géocodeur
- docker-compose : geocoder-enqueue passe à restart: unless-stopped

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-01 21:55:40 +02:00
c39a8513f8 feat(geocoding): pipeline multi-étapes avec LLM Groq free tier
- Migration 008 : tables band_locations (N steps × M villes par band)
  et llm_cache (évite les double-appels LLM par sha256)
- parser.py : parse location_text en steps structurés, gère N/A/Unknown,
  villes multiples (Bergen / Oslo), hiérarchies admin, codes pays
- enqueue.py rewrite : peuple band_locations depuis bands, résout les
  is_country_only avec centroïdes hardcodés (confidence=0.1)
- worker.py rewrite : fallbacks progressifs Geoapify (plus spécifique
  → plus vague), sync bands.lat/lon depuis le step le plus récent,
  bascule en llm_needed après 3 échecs
- groq_worker.py (nouveau) : Groq free tier JSON mode, llm_cache,
  rate-limit par modèle, backoff exponentiel, fallback 8B si 70B saturé
- docker-compose : geocoder-enqueue (one-shot), groq-worker (continu),
  geocoder-worker devient unless-stopped
- Admin API : /geocoding retourne stats band_locations + llm_cache ;
  nouvelles routes /locations/reset-errors /reset-llm /requeue-all
- Admin UI : page Géocodage affiche les deux pipelines en parallèle

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-01 21:49:22 +02:00
3dc483bc4f feat: geocoder Geoapify + fixes crawler + améliorations admin dashboard
Geocoder → Geoapify (bcb790b9007644d1a44ff2391118479c) :
- Remplace Nominatim par Geoapify dans apps/geocoder/src/worker.py
- Délai réduit à 0.22s (5 req/s vs 1 req/s Nominatim) → bien plus rapide
- Même logique de cache geocode_cache, même fallback backoff progressif
- Env vars : GEOAPIFY_API_KEY (obligatoire), GEOCODER_MIN_DELAY/JITTER

Fix crawler incremental_modified (Expecting value: line 1 column 1) :
- ma_http.get_json() retenait sans retry sur JSONDecodeError (corps vide =
  session Chrome morte). Désormais : refresh session + retry, comme pour
  les erreurs 403/429.

Admin dashboard :
- Bands : colonne Lieu, champ recherche lieu séparé (location_q), filtres
  "Géocodé oui/non" (has_lat) et "Lieu vide/renseigné" (has_location)
- Queue : bouton "Annuler runs bloqués >30min" (POST /admin/api/crawl-runs/
  cleanup), auto-refresh 15s, colonne Progression avec durée elapsed pour
  les runs actifs
- Dashboard : toutes les listes pays/genre/statut sans limite (scroll interne)
- Progression live : crawler écrit les stats dans crawl_run toutes les 50
  bands (update_crawl_run_progress), visible dans Queue en temps réel

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-30 22:44:28 +02:00
d4e1bf2e15 chore: initial commit — snapshot VPS 2026-06-27
- apps/api      : API REST Node.js/Fastify + PostgreSQL/PostGIS
- apps/geocoder : Worker Python géocodage Nominatim
- apps/worker   : Scraper Python Metal-Archives
- apps/web      : Frontend statique Leaflet/clustering/heatmap
- infra/        : docker-compose + init.sql

Déployé via Coolify + Traefik sur VPS OVH.
2026-06-27 08:53:39 +00:00