metalfrom.eu/docker-compose.yml
Nicolas Fryder 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

140 lines
4 KiB
YAML

services:
redis:
image: redis:7-alpine
command: ["redis-server", "--appendonly", "yes"]
volumes:
- bm_redis_data:/data
networks:
- coolify
geocoder-enqueue:
build:
context: apps/geocoder
working_dir: /app
environment:
DATABASE_URL: ${DATABASE_URL}
GEOCODE_ENQUEUE_BATCH: "100000"
command: ["python", "src/enqueue.py"]
networks:
- coolify
labels:
- traefik.enable=false
restart: "no"
geocoder-worker:
build:
context: apps/geocoder
working_dir: /app
environment:
DATABASE_URL: ${DATABASE_URL}
GEOAPIFY_API_KEY: ${GEOAPIFY_API_KEY}
GEOCODER_MIN_DELAY: "0.22"
GEOCODER_JITTER: "0.10"
GEOCODE_MAX_PER_RUN: "100000"
GEOCODE_MAX_GEO_TRIES: "3"
command: ["python", "src/worker.py"]
networks:
- coolify
labels:
- traefik.enable=false
restart: unless-stopped
groq-worker:
build:
context: apps/geocoder
working_dir: /app
environment:
DATABASE_URL: ${DATABASE_URL}
GROQ_API_KEY: ${GROQ_API_KEY}
GROQ_MAX_TRIES: "5"
GROQ_CALL_DELAY: "2.5"
command: ["python", "src/groq_worker.py"]
networks:
- coolify
labels:
- traefik.enable=false
restart: unless-stopped
pgadmin:
image: dpage/pgadmin4:8
environment:
PGADMIN_DEFAULT_EMAIL: ${PGADMIN_EMAIL}
PGADMIN_DEFAULT_PASSWORD: ${PGADMIN_PASSWORD}
PGADMIN_CONFIG_SERVER_MODE: "True"
volumes:
- pgadmin_data:/var/lib/pgadmin
networks:
- coolify
labels:
- traefik.enable=true
- traefik.docker.network=coolify
- traefik.http.routers.bm-pgadmin.rule=Host(`pgadmin.bm.nicolasfryder.ovh`)
- traefik.http.routers.bm-pgadmin.entrypoints=https
- traefik.http.routers.bm-pgadmin.tls=true
- traefik.http.routers.bm-pgadmin.tls.certresolver=letsencrypt
- traefik.http.services.bm-pgadmin.loadbalancer.server.port=80
api:
build:
context: apps/api
environment:
PORT: "3000"
DATABASE_URL: ${DATABASE_URL}
BM_IMPORT_TOKEN: ${BM_IMPORT_TOKEN}
CORS_ORIGINS: ${CORS_ORIGINS:-https://metalfrom.eu,https://www.metalfrom.eu}
ADMIN_JWT_SECRET: ${ADMIN_JWT_SECRET}
ADMIN_SEED_USERNAME: ${ADMIN_SEED_USERNAME}
ADMIN_SEED_PASSWORD_HASH: ${ADMIN_SEED_PASSWORD_HASH}
networks:
coolify:
aliases:
- bm-api-internal
labels:
- traefik.enable=true
- traefik.docker.network=coolify
- traefik.http.routers.bm-api.rule=Host(`bm.nicolasfryder.ovh`)
- traefik.http.routers.bm-api.entrypoints=https
- traefik.http.routers.bm-api.tls=true
- traefik.http.routers.bm-api.tls.certresolver=letsencrypt
- traefik.http.services.bm-api.loadbalancer.server.port=3000
admin:
build:
context: apps/admin
args:
API_UPSTREAM: http://bm-api-internal:3000
networks:
- coolify
labels:
- traefik.enable=true
- traefik.docker.network=coolify
- traefik.http.routers.bm-admin.rule=Host(`admin.metalfrom.eu`)
- traefik.http.routers.bm-admin.entrypoints=https
- traefik.http.routers.bm-admin.tls=true
- traefik.http.routers.bm-admin.tls.certresolver=letsencrypt
- traefik.http.services.bm-admin.loadbalancer.server.port=80
web:
build:
context: apps/web
networks:
- coolify
labels:
- traefik.enable=true
- traefik.docker.network=coolify
- traefik.http.routers.bm-web.rule=Host(`metalfrom.eu`) || Host(`www.metalfrom.eu`)
- traefik.http.routers.bm-web.entrypoints=https
- traefik.http.routers.bm-web.tls=true
- traefik.http.routers.bm-web.tls.certresolver=letsencrypt
- traefik.http.routers.bm-web.tls.domains[0].main=metalfrom.eu
- traefik.http.routers.bm-web.tls.domains[0].sans=www.metalfrom.eu
- traefik.http.services.bm-web.loadbalancer.server.port=80
networks:
coolify:
external: true
name: coolify
volumes:
bm_redis_data:
pgadmin_data: