Créa·Ka — annuaire public cross-plateforme des créateurs de contenu québécois (crea-ka.com)
Python 73.6%
HTML 13.2%
TypeScript 6%
JavaScript 4.5%
CSS 1.7%
Dockerfile 0.6%
1# ==============================================================================2# Author: Simon-Pierre Boucher <contact@spboucher.ai>3# File: creaka/connectors/bio_liens.py4# Desc: Connecteur ENRICHISSEMENT « bio-liens » — découverte croisée5# inter-plateformes SANS AUCUNE requête : liaison conservatrice à6# partir des URLs COMPLÈTES déjà stockées dans les bios publiques.7# Palier 1 (§9) — passe en dernier (après link-in-bio).8# ==============================================================================9"""Liaison croisée à partir des bios déjà en base.1011Une bio publique contient souvent l'URL complète d'un autre compte du même12créateur (« youtube.com/@x », « patreon.com/x »…). C'est exactement le signal13`cross_link` §12.1 (0.90) : le créateur pointe lui-même vers son autre compte.1415Passe CONSERVATRICE (vague 2, §12) : uniquement les URLs complètes reconnues16par normalize.platform_from_url — jamais de simple « @handle » textuel17(ambigu), jamais d'inférence. Aucune requête réseau : tout vient des bios18déjà collectées par les autres connecteurs. Cap 5 nouveaux comptes par fiche19(garde-fou contre les bios-annuaires).20"""21from __future__ import annotations2223import re2425from ..identity import account26from ..normalize import platform_from_url27from ..schema import Creator28from .base import BaseConnector2930# URL complète (avec ou sans schéma) — les domaines nus type « exemple.com »31# sans chemin ne désignent pas un compte et sont ignorés par platform_from_url32_URL_RE = re.compile(r"(?:https?://|www\.)[^\s\"'<>()\[\]{}]+", re.I)3334MAX_NEW_PER_CREATOR = 5353637def extract_bio_accounts(bio: str, existing_keys: set[str]) -> list:38 """Bio publique → nouveaux comptes cross_link (URLs complètes seulement)."""39 accounts = []40 seen = set(existing_keys)41 for raw in _URL_RE.findall(bio or ""):42 url = raw.rstrip(".,;!?…")43 if not url.lower().startswith("http"):44 url = "https://" + url45 hit = platform_from_url(url)46 if not hit:47 continue48 platform, handle = hit49 key = f"{platform}:{handle}"50 if key in seen:51 continue52 seen.add(key)53 accounts.append(account(platform, handle, "cross_link", url=url))54 if len(accounts) >= MAX_NEW_PER_CREATOR:55 break56 return accounts575859class BioLiensConnector(BaseConnector):60 source_id = "bio-liens"61 kind = "enrichment"62 request_delay = 0.0 # AUCUNE requête réseau6364 def enrich(self, creators: list[Creator]) -> list[Creator]:65 enriched: list[Creator] = []66 for cr in creators:67 if not cr.bio:68 continue69 existing = {a.key for a in cr.platforms}70 # ne jamais relier une fiche vers son propre handle X/IG déjà connu71 new_accounts = extract_bio_accounts(cr.bio, existing)72 if not new_accounts:73 continue74 cr.platforms.extend(a.finalize() for a in new_accounts)75 enriched.append(cr)76 return enriched77