Vague 4 — expansion massive : twitch-decouverte + kick-decouverte (Scrapfly), YT 1361 requêtes (bloc EN, 13 thèmes×56 villes, +100 passe-temps), iTunes 146 requêtes, +5 catégories Wikipédia, enrichisseur region-bio (ville déclarée en bio → région §7)
+3 596 créateurs (5 841 → 9 437), +3 684 comptes (10 512). Twitch 292, Kick 122 comptes. region-bio : 1 391 fiches localisées. Avatars 96,5 %. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
28 changed files +1,053 −169
modified
creaka/connectors/balados_itunes.py
+19 −0
@@ -65,6 +65,25 @@ QUERIES = [ | |||||
| 65 | "balado papa québec", "balado éducation québec", "balado science québec", | 65 | "balado papa québec", "balado éducation québec", "balado science québec", | ||
| 66 | "balado littérature québec", "balado poésie québec", "balado bd québec", | 66 | "balado littérature québec", "balado poésie québec", "balado bd québec", | ||
| 67 | "balado jeux de société québec", "balado vin québec", "balado bière québec", | 67 | "balado jeux de société québec", "balado vin québec", "balado bière québec", | ||
| 68 | + # vague 4 : villes restantes + créneaux supplémentaires | ||||
| 69 | + "mascouche", "blainville balado", "brossard", "mirabel", "boucherville", | ||||
| 70 | + "chambly", "varennes balado", "sainte-julie", "beloeil", "mont-tremblant", | ||||
| 71 | + "sainte-adèle", "thetford mines", "la tuque", "gaspé", "roberval", | ||||
| 72 | + "dolbeau", "amqui", "montmagny", "saint-georges beauce", "cowansville", | ||||
| 73 | + "lachute", "salaberry-de-valleyfield", "sainte-thérèse", "l'assomption", | ||||
| 74 | + "rawdon", "baie-saint-paul", "la malbaie", "chibougamau", | ||||
| 75 | + "balado ia québec", "balado crypto québec", "balado marketing québec", | ||||
| 76 | + "balado droit québec", "balado médecine québec", "balado psycho québec", | ||||
| 77 | + "balado philosophie québec", "balado environnement québec", | ||||
| 78 | + "balado autochtone", "balado voyage québec", "balado spiritualité québec", | ||||
| 79 | + "balado true crime québec", "balado paranormal québec", | ||||
| 80 | + "balado nostalgie québec", "balado télé québec", "balado wrestling québec", | ||||
| 81 | + "balado lutte québec", "balado course québec", "balado vélo québec", | ||||
| 82 | + "balado golf québec", "balado pêche à la mouche québec", | ||||
| 83 | + "balado gestion québec", "balado rh québec", "balado photo québec", | ||||
| 84 | + "balado musique émergente québec", "balado métal québec", | ||||
| 85 | + "balado country québec", "balado horreur québec", "balado cinéma d'horreur", | ||||
| 86 | + "balado animation québec", "balado improvisation québec", | ||||
| 68 | ] | 87 | ] | ||
| 69 | 88 | ||||
| 70 | _GENRE_NICHE = { | 89 | _GENRE_NICHE = { | ||
added
creaka/connectors/kick_decouverte.py
+147 −0
@@ -0,0 +1,147 @@ | |||||
| 1 | +# ============================================================================== | ||||
| 2 | +# Author: Simon-Pierre Boucher <contact@spboucher.ai> | ||||
| 3 | +# File: creaka/connectors/kick_decouverte.py | ||||
| 4 | +# Desc: Connecteur DÉCOUVERTE — streamers Kick québécois via l'API publique | ||||
| 5 | +# de recherche du site (kick.com/api/search) + fiche v2 par chaîne | ||||
| 6 | +# (liens sociaux AUTO-DÉCLARÉS par le créateur → cross_link 0.90). | ||||
| 7 | +# Mode d'accès : Scrapfly ASP sans render_js (Cloudflare bloque les | ||||
| 8 | +# requêtes directes — 403). Palier 4 (§9/§10). | ||||
| 9 | +# ============================================================================== | ||||
| 10 | +"""Découverte des streamers Kick québécois. | ||||
| 11 | + | ||||
| 12 | +``kick.com/api/search?searched_word=…`` retourne pour chaque chaîne : slug, | ||||
| 13 | +abonnés, bio, photo de profil. ``kick.com/api/v2/channels/{slug}`` ajoute le | ||||
| 14 | +badge vérifié et surtout les LIENS SOCIAUX que le créateur a lui-même remplis | ||||
| 15 | +dans son profil (instagram/twitter/youtube/tiktok/facebook/discord) → signal | ||||
| 16 | +cross_link (0.90), la meilleure matière première du rattachement (§12.1). | ||||
| 17 | + | ||||
| 18 | +Filtre conservateur : marqueur québécois OBLIGATOIRE dans le pseudo, le slug | ||||
| 19 | +ou la bio (§7/§15). La fiche v2 n'est demandée QUE pour les chaînes retenues | ||||
| 20 | +(économie Scrapfly, §10 — chaque requête passe par l'ASP anti-bot). | ||||
| 21 | +""" | ||||
| 22 | +from __future__ import annotations | ||||
| 23 | + | ||||
| 24 | +import json | ||||
| 25 | +import sys | ||||
| 26 | + | ||||
| 27 | +from ..identity import account | ||||
| 28 | +from ..normalize import platform_from_url, slugify | ||||
| 29 | +from ..schema import Creator | ||||
| 30 | +from .base import BaseConnector | ||||
| 31 | +from .youtube_recherche import is_quebec | ||||
| 32 | + | ||||
| 33 | +SEARCH_URL = "https://kick.com/api/search?searched_word={term}" | ||||
| 34 | +CHANNEL_URL = "https://kick.com/api/v2/channels/{slug}" | ||||
| 35 | + | ||||
| 36 | +SEARCH_TERMS = [ | ||||
| 37 | + "quebec", "quebecois", "quebecoise", "queb", "montreal", "mtl", | ||||
| 38 | + "saguenay", "gaspesie", "mauricie", "estrie", "outaouais", "abitibi", | ||||
| 39 | + "gatineau", "sherbrooke", "levis", "longueuil", "rimouski", "chicoutimi", | ||||
| 40 | + "trois-rivieres", "drummondville", "lanaudiere", "laurentides", | ||||
| 41 | + "monteregie", "beauce", "charlevoix", "riv-nord", "rive-sud", | ||||
| 42 | +] | ||||
| 43 | + | ||||
| 44 | +# clés du profil v2 → plateformes §6.2 (liens auto-déclarés par le créateur) | ||||
| 45 | +_SOCIAL_KEYS = ("instagram", "twitter", "youtube", "tiktok", "facebook", | ||||
| 46 | + "discord") | ||||
| 47 | + | ||||
| 48 | + | ||||
| 49 | +class KickDecouverteConnector(BaseConnector): | ||||
| 50 | + source_id = "kick-decouverte" | ||||
| 51 | + kind = "discovery" | ||||
| 52 | + request_delay = 1.5 | ||||
| 53 | + max_details = 120 # fiches v2 par passage (budget Scrapfly, §10) | ||||
| 54 | + | ||||
| 55 | + def __init__(self) -> None: | ||||
| 56 | + super().__init__() | ||||
| 57 | + self.errors = 0 | ||||
| 58 | + | ||||
| 59 | + def _json(self, url: str) -> dict | list | None: | ||||
| 60 | + """GET via Scrapfly ASP (sans render_js — l'API répond en JSON).""" | ||||
| 61 | + result = self.scrapfly(url, render_js=False, asp=True) | ||||
| 62 | + if (result.get("status_code") or 0) != 200: | ||||
| 63 | + return None | ||||
| 64 | + try: | ||||
| 65 | + return json.loads(result.get("content") or "") | ||||
| 66 | + except Exception: | ||||
| 67 | + return None | ||||
| 68 | + | ||||
| 69 | + def _socials(self, user: dict) -> list: | ||||
| 70 | + """Liens sociaux auto-déclarés du profil v2 → comptes cross_link.""" | ||||
| 71 | + accounts = [] | ||||
| 72 | + for key in _SOCIAL_KEYS: | ||||
| 73 | + raw = (user.get(key) or "").strip() | ||||
| 74 | + if not raw: | ||||
| 75 | + continue | ||||
| 76 | + # le champ contient tantôt une URL, tantôt un simple handle | ||||
| 77 | + if "://" in raw or "." in raw.split("/")[0]: | ||||
| 78 | + parsed = platform_from_url(raw) | ||||
| 79 | + if parsed: | ||||
| 80 | + accounts.append(account(parsed[0], parsed[1], "cross_link")) | ||||
| 81 | + else: | ||||
| 82 | + platform = "x" if key == "twitter" else key | ||||
| 83 | + accounts.append(account(platform, raw, "cross_link")) | ||||
| 84 | + return accounts | ||||
| 85 | + | ||||
| 86 | + def fetch(self) -> list[Creator]: | ||||
| 87 | + # 1) recherche par termes QC → candidats (slug, bio, abonnés, avatar) | ||||
| 88 | + candidates: dict[str, dict] = {} | ||||
| 89 | + for term in SEARCH_TERMS: | ||||
| 90 | + try: | ||||
| 91 | + data = self._json(SEARCH_URL.format(term=term)) | ||||
| 92 | + except Exception: | ||||
| 93 | + self.errors += 1 | ||||
| 94 | + continue | ||||
| 95 | + for ch in (data or {}).get("channels") or []: | ||||
| 96 | + slug = (ch.get("slug") or "").strip().lower() | ||||
| 97 | + user = ch.get("user") or {} | ||||
| 98 | + name = (user.get("username") or slug).strip() | ||||
| 99 | + bio = (user.get("bio") or "").strip() | ||||
| 100 | + if not slug or slug in candidates or ch.get("is_banned"): | ||||
| 101 | + continue | ||||
| 102 | + # filtre conservateur : marqueur QC requis (pseudo/slug/bio) | ||||
| 103 | + if not is_quebec(f"{name} {slug} {bio}"): | ||||
| 104 | + continue | ||||
| 105 | + candidates[slug] = { | ||||
| 106 | + "name": name, "bio": bio, | ||||
| 107 | + "followers": ch.get("followers_count"), | ||||
| 108 | + "avatar": user.get("profilePic") or user.get("profile_pic"), | ||||
| 109 | + } | ||||
| 110 | + # 2) fiche v2 pour les retenus → badge + liens sociaux auto-déclarés | ||||
| 111 | + creators: list[Creator] = [] | ||||
| 112 | + for slug, cand in list(candidates.items())[:self.max_details]: | ||||
| 113 | + verified, socials = None, [] | ||||
| 114 | + try: | ||||
| 115 | + detail = self._json(CHANNEL_URL.format(slug=slug)) | ||||
| 116 | + except Exception: | ||||
| 117 | + self.errors += 1 | ||||
| 118 | + detail = None | ||||
| 119 | + if isinstance(detail, dict): | ||||
| 120 | + verified = bool(detail.get("verified")) or None | ||||
| 121 | + user = detail.get("user") or {} | ||||
| 122 | + socials = self._socials(user) | ||||
| 123 | + cand["bio"] = (user.get("bio") or cand["bio"] or "").strip() | ||||
| 124 | + cand["avatar"] = user.get("profile_pic") or cand["avatar"] | ||||
| 125 | + if detail.get("followers_count") is not None: | ||||
| 126 | + cand["followers"] = detail["followers_count"] | ||||
| 127 | + acc = account("kick", slug, "profil_source", | ||||
| 128 | + followers=cand["followers"], verified=verified) | ||||
| 129 | + avatar = cand.get("avatar") or "" | ||||
| 130 | + creators.append(Creator( | ||||
| 131 | + source=self.source_id, | ||||
| 132 | + external_id=slugify(cand["name"]), | ||||
| 133 | + display_name=cand["name"], | ||||
| 134 | + bio=(cand["bio"] or "")[:1200], | ||||
| 135 | + niches=["gaming"], | ||||
| 136 | + creator_type="streamer", | ||||
| 137 | + primary_platform="kick", | ||||
| 138 | + avatar_url=avatar if avatar.startswith("http") else None, | ||||
| 139 | + platforms=[acc, *socials], | ||||
| 140 | + source_ids=[f"{self.source_id}:{slug}"], | ||||
| 141 | + )) | ||||
| 142 | + dropped = len(candidates) - min(len(candidates), self.max_details) | ||||
| 143 | + if dropped > 0: | ||||
| 144 | + print(f"[crea-ka] kick-decouverte : {dropped} candidat(s) au-delà " | ||||
| 145 | + f"du budget v2 ({self.max_details}) — repris au prochain " | ||||
| 146 | + f"passage", file=sys.stderr) | ||||
| 147 | + return creators | ||||
added
creaka/connectors/region_bio.py
+166 −0
@@ -0,0 +1,166 @@ | |||||
| 1 | +# ============================================================================== | ||||
| 2 | +# Author: Simon-Pierre Boucher <contact@spboucher.ai> | ||||
| 3 | +# File: creaka/connectors/region_bio.py | ||||
| 4 | +# Desc: Connecteur ENRICHISSEMENT — région/ville depuis la localisation | ||||
| 5 | +# DÉCLARÉE dans la bio publique du créateur (« humoriste de | ||||
| 6 | +# Sherbrooke », « based in Montreal », « vlogueuse montréalaise »). | ||||
| 7 | +# Mode d'accès : AUCUNE requête (relit les bios déjà en base, comme | ||||
| 8 | +# bio-liens). Palier 1 (§9). Vague 4. | ||||
| 9 | +# ============================================================================== | ||||
| 10 | +"""Région/ville depuis la bio publique — prudence maximale (§7/§15). | ||||
| 11 | + | ||||
| 12 | +On n'infère JAMAIS : on ne retient une ville que si le créateur la déclare | ||||
| 13 | +lui-même dans sa bio avec une tournure locative sans ambiguïté (« de X », | ||||
| 14 | +« basé à X », « from X », gentilé comme « montréalais »). Villes au nom | ||||
| 15 | +piégeux exclues (Alma, Waterloo, Varennes… : prénoms, homonymes hors Québec, | ||||
| 16 | +particules de noms de famille). Si la bio mentionne des villes de RÉGIONS | ||||
| 17 | +différentes, on s'abstient (ambigu). Ne remplit que les champs VIDES. | ||||
| 18 | +""" | ||||
| 19 | +from __future__ import annotations | ||||
| 20 | + | ||||
| 21 | +import re | ||||
| 22 | + | ||||
| 23 | +from ..normalize import strip_accents | ||||
| 24 | +from ..schema import Creator | ||||
| 25 | +from .base import BaseConnector | ||||
| 26 | + | ||||
| 27 | +# villes SÛRES (clé sans accent) → (ville affichée, région §7). | ||||
| 28 | +# ⚠ liste volontairement restrictive : pas d'Alma (prénom), pas de Waterloo | ||||
| 29 | +# (Ontario), pas de Varennes (particule de nom), pas d'Anjou (France/quartier). | ||||
| 30 | +_SAFE_CITIES: dict[str, tuple[str, str]] = { | ||||
| 31 | + "montreal": ("Montréal", "Montréal"), | ||||
| 32 | + "verdun": ("Verdun", "Montréal"), | ||||
| 33 | + "lachine": ("Lachine", "Montréal"), | ||||
| 34 | + "outremont": ("Outremont", "Montréal"), | ||||
| 35 | + "westmount": ("Westmount", "Montréal"), | ||||
| 36 | + "ville de quebec": ("Québec", "Capitale-Nationale"), | ||||
| 37 | + "quebec city": ("Québec", "Capitale-Nationale"), | ||||
| 38 | + "baie-saint-paul": ("Baie-Saint-Paul", "Capitale-Nationale"), | ||||
| 39 | + "la malbaie": ("La Malbaie", "Capitale-Nationale"), | ||||
| 40 | + "laval": ("Laval", "Laval"), | ||||
| 41 | + "gatineau": ("Gatineau", "Outaouais"), | ||||
| 42 | + "sherbrooke": ("Sherbrooke", "Estrie"), | ||||
| 43 | + "magog": ("Magog", "Estrie"), | ||||
| 44 | + "granby": ("Granby", "Estrie"), | ||||
| 45 | + "trois-rivieres": ("Trois-Rivières", "Mauricie"), | ||||
| 46 | + "shawinigan": ("Shawinigan", "Mauricie"), | ||||
| 47 | + "la tuque": ("La Tuque", "Mauricie"), | ||||
| 48 | + "saguenay": ("Saguenay", "Saguenay–Lac-Saint-Jean"), | ||||
| 49 | + "chicoutimi": ("Chicoutimi", "Saguenay–Lac-Saint-Jean"), | ||||
| 50 | + "jonquiere": ("Jonquière", "Saguenay–Lac-Saint-Jean"), | ||||
| 51 | + "roberval": ("Roberval", "Saguenay–Lac-Saint-Jean"), | ||||
| 52 | + "dolbeau-mistassini": ("Dolbeau-Mistassini", "Saguenay–Lac-Saint-Jean"), | ||||
| 53 | + "rimouski": ("Rimouski", "Bas-Saint-Laurent"), | ||||
| 54 | + "riviere-du-loup": ("Rivière-du-Loup", "Bas-Saint-Laurent"), | ||||
| 55 | + "matane": ("Matane", "Bas-Saint-Laurent"), | ||||
| 56 | + "amqui": ("Amqui", "Bas-Saint-Laurent"), | ||||
| 57 | + "gaspe": ("Gaspé", "Gaspésie–Îles-de-la-Madeleine"), | ||||
| 58 | + "chandler": ("Chandler", "Gaspésie–Îles-de-la-Madeleine"), | ||||
| 59 | + "iles-de-la-madeleine": ("Îles-de-la-Madeleine", | ||||
| 60 | + "Gaspésie–Îles-de-la-Madeleine"), | ||||
| 61 | + "rouyn-noranda": ("Rouyn-Noranda", "Abitibi-Témiscamingue"), | ||||
| 62 | + "val-d'or": ("Val-d'Or", "Abitibi-Témiscamingue"), | ||||
| 63 | + "amos": ("Amos", "Abitibi-Témiscamingue"), | ||||
| 64 | + "la sarre": ("La Sarre", "Abitibi-Témiscamingue"), | ||||
| 65 | + "sept-iles": ("Sept-Îles", "Côte-Nord"), | ||||
| 66 | + "baie-comeau": ("Baie-Comeau", "Côte-Nord"), | ||||
| 67 | + "havre-saint-pierre": ("Havre-Saint-Pierre", "Côte-Nord"), | ||||
| 68 | + "chibougamau": ("Chibougamau", "Nord-du-Québec"), | ||||
| 69 | + "levis": ("Lévis", "Chaudière-Appalaches"), | ||||
| 70 | + "thetford mines": ("Thetford Mines", "Chaudière-Appalaches"), | ||||
| 71 | + "montmagny": ("Montmagny", "Chaudière-Appalaches"), | ||||
| 72 | + "saint-georges": ("Saint-Georges", "Chaudière-Appalaches"), | ||||
| 73 | + "drummondville": ("Drummondville", "Centre-du-Québec"), | ||||
| 74 | + "victoriaville": ("Victoriaville", "Centre-du-Québec"), | ||||
| 75 | + "longueuil": ("Longueuil", "Montérégie"), | ||||
| 76 | + "brossard": ("Brossard", "Montérégie"), | ||||
| 77 | + "boucherville": ("Boucherville", "Montérégie"), | ||||
| 78 | + "chambly": ("Chambly", "Montérégie"), | ||||
| 79 | + "beloeil": ("Belœil", "Montérégie"), | ||||
| 80 | + "sainte-julie": ("Sainte-Julie", "Montérégie"), | ||||
| 81 | + "saint-hyacinthe": ("Saint-Hyacinthe", "Montérégie"), | ||||
| 82 | + "sorel-tracy": ("Sorel-Tracy", "Montérégie"), | ||||
| 83 | + "chateauguay": ("Châteauguay", "Montérégie"), | ||||
| 84 | + "saint-jean-sur-richelieu": ("Saint-Jean-sur-Richelieu", "Montérégie"), | ||||
| 85 | + "salaberry-de-valleyfield": ("Salaberry-de-Valleyfield", "Montérégie"), | ||||
| 86 | + "vaudreuil-dorion": ("Vaudreuil-Dorion", "Montérégie"), | ||||
| 87 | + "cowansville": ("Cowansville", "Montérégie"), | ||||
| 88 | + "terrebonne": ("Terrebonne", "Lanaudière"), | ||||
| 89 | + "repentigny": ("Repentigny", "Lanaudière"), | ||||
| 90 | + "mascouche": ("Mascouche", "Lanaudière"), | ||||
| 91 | + "joliette": ("Joliette", "Lanaudière"), | ||||
| 92 | + "rawdon": ("Rawdon", "Lanaudière"), | ||||
| 93 | + "blainville": ("Blainville", "Laurentides"), | ||||
| 94 | + "boisbriand": ("Boisbriand", "Laurentides"), | ||||
| 95 | + "mirabel": ("Mirabel", "Laurentides"), | ||||
| 96 | + "saint-jerome": ("Saint-Jérôme", "Laurentides"), | ||||
| 97 | + "sainte-therese": ("Sainte-Thérèse", "Laurentides"), | ||||
| 98 | + "sainte-adele": ("Sainte-Adèle", "Laurentides"), | ||||
| 99 | + "sainte-agathe-des-monts": ("Sainte-Agathe-des-Monts", "Laurentides"), | ||||
| 100 | + "mont-laurier": ("Mont-Laurier", "Laurentides"), | ||||
| 101 | + "mont-tremblant": ("Mont-Tremblant", "Laurentides"), | ||||
| 102 | + "lachute": ("Lachute", "Laurentides"), | ||||
| 103 | +} | ||||
| 104 | + | ||||
| 105 | +# gentilés sans ambiguïté → ville (déclaration d'appartenance dans la bio) | ||||
| 106 | +_DEMONYMS: dict[str, str] = { | ||||
| 107 | + "montrealais": "montreal", "montrealaise": "montreal", | ||||
| 108 | + "trifluvien": "trois-rivieres", "trifluvienne": "trois-rivieres", | ||||
| 109 | + "sherbrookois": "sherbrooke", "sherbrookoise": "sherbrooke", | ||||
| 110 | + "gatinois": "gatineau", "gatinoise": "gatineau", | ||||
| 111 | + "lavallois": "laval", "lavalloise": "laval", | ||||
| 112 | + "longueuillois": "longueuil", "longueuilloise": "longueuil", | ||||
| 113 | + "rimouskois": "rimouski", "rimouskoise": "rimouski", | ||||
| 114 | + "gaspesien": "gaspe", "gaspesienne": "gaspe", | ||||
| 115 | +} | ||||
| 116 | + | ||||
| 117 | +# tournure locative OBLIGATOIRE devant le nom de ville : c'est elle qui fait | ||||
| 118 | +# de la mention une DÉCLARATION (« de Sherbrooke ») et non une anecdote | ||||
| 119 | +# (« j'ai visité Sherbrooke ») | ||||
| 120 | +_LOCATIVE = (r"(?:de|d'|du|a|au|from|in|based in|base(?:e)? a|situe(?:e)? a|" | ||||
| 121 | + r"originaire de|native de|natif de|vit a|vis a|habite a|" | ||||
| 122 | + r"direct(?:ement)? de|region de|coin de|ici a)") | ||||
| 123 | + | ||||
| 124 | +_CITY_RE = re.compile( | ||||
| 125 | + r"(?<![\w-])" + _LOCATIVE + r"\s+(?:la\s+|le\s+|l')?(" + | ||||
| 126 | + "|".join(sorted(map(re.escape, _SAFE_CITIES), key=len, reverse=True)) + | ||||
| 127 | + r")(?![\w-])") | ||||
| 128 | +_DEMONYM_RE = re.compile( | ||||
| 129 | + r"(?<![\w-])(" + "|".join(sorted(_DEMONYMS, key=len, reverse=True)) + | ||||
| 130 | + r")(?![\w-])") | ||||
| 131 | + | ||||
| 132 | + | ||||
| 133 | +def declared_cities(text: str) -> set[str]: | ||||
| 134 | + """Bio publique → clés de villes DÉCLARÉES (tournure locative ou gentilé).""" | ||||
| 135 | + blob = strip_accents(text or "").lower() | ||||
| 136 | + keys = set(_CITY_RE.findall(blob)) | ||||
| 137 | + keys |= {_DEMONYMS[d] for d in _DEMONYM_RE.findall(blob)} | ||||
| 138 | + return keys | ||||
| 139 | + | ||||
| 140 | + | ||||
| 141 | +class RegionBioConnector(BaseConnector): | ||||
| 142 | + source_id = "region-bio" | ||||
| 143 | + kind = "enrichment" | ||||
| 144 | + request_delay = 0.0 # aucune requête réseau | ||||
| 145 | + | ||||
| 146 | + def enrich(self, creators: list[Creator]) -> list[Creator]: | ||||
| 147 | + enriched: list[Creator] = [] | ||||
| 148 | + for cr in creators: | ||||
| 149 | + if cr.region and cr.city: | ||||
| 150 | + continue | ||||
| 151 | + keys = declared_cities(cr.bio) | ||||
| 152 | + if not keys: | ||||
| 153 | + continue | ||||
| 154 | + regions = {_SAFE_CITIES[k][1] for k in keys} | ||||
| 155 | + if len(regions) != 1: | ||||
| 156 | + continue # villes de régions différentes → ambigu, abstention | ||||
| 157 | + changed = False | ||||
| 158 | + if not cr.region: | ||||
| 159 | + cr.region = next(iter(regions)) | ||||
| 160 | + changed = True | ||||
| 161 | + if not cr.city and len(keys) == 1: | ||||
| 162 | + cr.city = _SAFE_CITIES[next(iter(keys))][0] | ||||
| 163 | + changed = True | ||||
| 164 | + if changed: | ||||
| 165 | + enriched.append(cr) | ||||
| 166 | + return enriched | ||||
added
creaka/connectors/twitch_decouverte.py
+206 −0
@@ -0,0 +1,206 @@ | |||||
| 1 | +# ============================================================================== | ||||
| 2 | +# Author: Simon-Pierre Boucher <contact@spboucher.ai> | ||||
| 3 | +# File: creaka/connectors/twitch_decouverte.py | ||||
| 4 | +# Desc: Connecteur DÉCOUVERTE — streamers Twitch québécois via l'API GQL | ||||
| 5 | +# publique du site officiel (Client-ID public, sans clé) : recherche | ||||
| 6 | +# de chaînes par termes QC + répertoire des diffusions en français. | ||||
| 7 | +# Palier 3 (§9). Filtre conservateur : marqueur québécois OBLIGATOIRE | ||||
| 8 | +# dans le nom, la bio ou le titre du stream. | ||||
| 9 | +# ============================================================================== | ||||
| 10 | +"""Découverte des streamers Twitch québécois — sans clé. | ||||
| 11 | + | ||||
| 12 | +Deux voies, mêmes conventions que l'enrichisseur `twitch` (vague 3) : | ||||
| 13 | + | ||||
| 14 | +1. ``searchFor`` (la recherche du site officiel) sur une liste de termes | ||||
| 15 | + québécois (province, régions, villes) → chaînes dont le profil PUBLIC | ||||
| 16 | + mentionne le Québec, avec abonnés, bio, avatar, statut partenaire ; | ||||
| 17 | +2. le répertoire des diffusions EN DIRECT en français (``streams``, | ||||
| 18 | + languages: [FR]) → longue traîne de streamers QC actifs, paginé ; la | ||||
| 19 | + couverture s'accumule à chaque passage (qui est en direct change chaque | ||||
| 20 | + jour, comme youtube-recherche). | ||||
| 21 | + | ||||
| 22 | +On ne crée une fiche QUE si un marqueur québécois figure dans le nom, la | ||||
| 23 | +description du profil ou le titre du stream (jamais d'inférence, §7/§15). | ||||
| 24 | +Le compte Twitch est le compte SOURCE de la fiche → signal profil_source | ||||
| 25 | +(0.98) ; l'enrichissement rattache ensuite ses autres plateformes. | ||||
| 26 | +""" | ||||
| 27 | +from __future__ import annotations | ||||
| 28 | + | ||||
| 29 | +import json | ||||
| 30 | +import subprocess | ||||
| 31 | +import sys | ||||
| 32 | +import time | ||||
| 33 | + | ||||
| 34 | +from ..identity import account | ||||
| 35 | +from ..normalize import slugify | ||||
| 36 | +from ..schema import Creator | ||||
| 37 | +from .base import USER_AGENT, BaseConnector | ||||
| 38 | +from .twitch import GQL_URL, WEB_CLIENT_ID | ||||
| 39 | +from .youtube_recherche import is_quebec | ||||
| 40 | + | ||||
| 41 | +# champs publics du profil (§15) — mêmes que l'enrichisseur twitch | ||||
| 42 | +_USER_FIELDS = ("login displayName description createdAt " | ||||
| 43 | + "followers { totalCount } profileImageURL(width: 300) " | ||||
| 44 | + "roles { isPartner isAffiliate } " | ||||
| 45 | + "lastBroadcast { startedAt game { displayName } }") | ||||
| 46 | + | ||||
| 47 | +# termes de recherche québécois (province, régions, villes, scène locale) | ||||
| 48 | +SEARCH_TERMS = [ | ||||
| 49 | + "québec", "québécois", "québécoise", "queb", "montréal", "mtl", | ||||
| 50 | + "ville de québec", "rive-sud", "rive-nord", "saguenay", "gaspésie", | ||||
| 51 | + "mauricie", "estrie", "outaouais", "abitibi", "témiscamingue", | ||||
| 52 | + "lanaudière", "laurentides", "montérégie", "charlevoix", "beauce", | ||||
| 53 | + "côte-nord", "bas-saint-laurent", "gatineau", "sherbrooke", "laval", | ||||
| 54 | + "longueuil", "lévis", "trois-rivières", "chicoutimi", "rimouski", | ||||
| 55 | + "drummondville", "granby", "victoriaville", "joliette", "terrebonne", | ||||
| 56 | + "repentigny", "brossard", "shawinigan", "rouyn-noranda", "alma", | ||||
| 57 | + "streamer québécois", "gamer québécois", "twitch québec", | ||||
| 58 | +] | ||||
| 59 | + | ||||
| 60 | +# jeu du stream → niche §6.1 (défaut : gaming — c'est Twitch) | ||||
| 61 | +_GAME_NICHE = { | ||||
| 62 | + "Just Chatting": "lifestyle", "Music": "musique", "Art": "arts", | ||||
| 63 | + "Food & Drink": "cuisine", "Sports": "sport-fitness", | ||||
| 64 | + "ASMR": "lifestyle", "Talk Shows & Podcasts": "actualite-opinion", | ||||
| 65 | + "Software and Game Development": "tech", "Science & Technology": "tech", | ||||
| 66 | + "Fitness & Health": "sport-fitness", "Travel & Outdoors": "plein-air", | ||||
| 67 | + "Makers & Crafting": "arts", "Beauty & Body Art": "beaute", | ||||
| 68 | + "Politics": "actualite-opinion", "DJs": "musique", | ||||
| 69 | +} | ||||
| 70 | + | ||||
| 71 | + | ||||
| 72 | +class TwitchDecouverteConnector(BaseConnector): | ||||
| 73 | + source_id = "twitch-decouverte" | ||||
| 74 | + kind = "discovery" | ||||
| 75 | + request_delay = 1.0 | ||||
| 76 | + search_limit = 25 # chaînes par page de recherche | ||||
| 77 | + search_pages = 4 # pages par terme (cursor searchFor) | ||||
| 78 | + stream_pages = 20 # pages du répertoire FR (30 streams/page) | ||||
| 79 | + | ||||
| 80 | + def __init__(self) -> None: | ||||
| 81 | + super().__init__() | ||||
| 82 | + self.errors = 0 | ||||
| 83 | + | ||||
| 84 | + # -- transport GQL (repli curl-binaire, même pattern que twitch.py) -------- | ||||
| 85 | + def _gql(self, query: str) -> dict: | ||||
| 86 | + payload = {"query": query} | ||||
| 87 | + try: | ||||
| 88 | + resp = self.post(GQL_URL, json=payload, | ||||
| 89 | + headers={"Client-Id": WEB_CLIENT_ID}) | ||||
| 90 | + return resp.json() | ||||
| 91 | + except Exception: | ||||
| 92 | + pass # 4xx/blocage TLS → repli curl | ||||
| 93 | + self._throttle() | ||||
| 94 | + try: | ||||
| 95 | + proc = subprocess.run( | ||||
| 96 | + ["curl", "-sS", "--fail", "--max-time", str(self.timeout), | ||||
| 97 | + "-A", USER_AGENT, "-H", f"Client-Id: {WEB_CLIENT_ID}", | ||||
| 98 | + "-H", "Content-Type: application/json", | ||||
| 99 | + "-d", json.dumps(payload), GQL_URL], | ||||
| 100 | + capture_output=True, text=True, timeout=self.timeout + 5) | ||||
| 101 | + finally: | ||||
| 102 | + self._last_request = time.time() | ||||
| 103 | + if proc.returncode != 0: | ||||
| 104 | + raise RuntimeError(f"curl {proc.returncode}: gql.twitch.tv") | ||||
| 105 | + return json.loads(proc.stdout) | ||||
| 106 | + | ||||
| 107 | + # -- fabrication d'une fiche ------------------------------------------------- | ||||
| 108 | + def _collect(self, user: dict, context: str, seen: set[str], | ||||
| 109 | + creators: list[Creator], niche: str = "gaming") -> None: | ||||
| 110 | + login = (user.get("login") or "").strip().lower() | ||||
| 111 | + name = (user.get("displayName") or login).strip() | ||||
| 112 | + bio = (user.get("description") or "").strip() | ||||
| 113 | + if not login or login in seen: | ||||
| 114 | + return | ||||
| 115 | + # filtre conservateur : marqueur QC dans nom + bio + titre du stream | ||||
| 116 | + if not is_quebec(f"{name} {bio} {context}"): | ||||
| 117 | + return | ||||
| 118 | + seen.add(login) | ||||
| 119 | + last = user.get("lastBroadcast") or {} | ||||
| 120 | + roles = user.get("roles") or {} | ||||
| 121 | + game = (last.get("game") or {}).get("displayName") | ||||
| 122 | + acc = account("twitch", login, "profil_source", | ||||
| 123 | + followers=(user.get("followers") or {}).get("totalCount"), | ||||
| 124 | + verified=bool(roles.get("isPartner")) or None) | ||||
| 125 | + acc.metrics = {k: v for k, v in { | ||||
| 126 | + "affiliate": bool(roles.get("isAffiliate")) or None, | ||||
| 127 | + "last_stream": last.get("startedAt"), | ||||
| 128 | + "game": game, | ||||
| 129 | + }.items() if v} | ||||
| 130 | + avatar = user.get("profileImageURL") or "" | ||||
| 131 | + creators.append(Creator( | ||||
| 132 | + source=self.source_id, | ||||
| 133 | + external_id=slugify(name), | ||||
| 134 | + display_name=name, | ||||
| 135 | + bio=bio[:1200], | ||||
| 136 | + niches=[_GAME_NICHE.get(game or "", niche)], | ||||
| 137 | + creator_type="streamer", | ||||
| 138 | + primary_platform="twitch", | ||||
| 139 | + avatar_url=avatar if avatar.startswith("http") else None, | ||||
| 140 | + platforms=[acc], | ||||
| 141 | + source_ids=[f"{self.source_id}:{login}"], | ||||
| 142 | + )) | ||||
| 143 | + | ||||
| 144 | + # -- voie 1 : recherche de chaînes par termes QC ----------------------------- | ||||
| 145 | + def _search(self, seen: set[str], creators: list[Creator]) -> None: | ||||
| 146 | + for term in SEARCH_TERMS: | ||||
| 147 | + cursor = "" | ||||
| 148 | + for _page in range(self.search_pages): | ||||
| 149 | + cur = f', cursor: {json.dumps(cursor)}' if cursor else "" | ||||
| 150 | + q = ("query { searchFor(userQuery: %s, platform: \"web\", " | ||||
| 151 | + "target: {index: CHANNEL, limit: %d%s}) " | ||||
| 152 | + "{ channels { cursor edges { item { ... on User { %s } } } } } }" | ||||
| 153 | + % (json.dumps(term), self.search_limit, cur, _USER_FIELDS)) | ||||
| 154 | + try: | ||||
| 155 | + data = self._gql(q) | ||||
| 156 | + channels = ((data.get("data") or {}).get("searchFor") | ||||
| 157 | + or {}).get("channels") or {} | ||||
| 158 | + except Exception: | ||||
| 159 | + self.errors += 1 | ||||
| 160 | + break | ||||
| 161 | + edges = channels.get("edges") or [] | ||||
| 162 | + for edge in edges: | ||||
| 163 | + user = edge.get("item") or {} | ||||
| 164 | + if user.get("login"): | ||||
| 165 | + self._collect(user, "", seen, creators) | ||||
| 166 | + cursor = channels.get("cursor") or "" | ||||
| 167 | + if not cursor or not edges: | ||||
| 168 | + break | ||||
| 169 | + | ||||
| 170 | + # -- voie 2 : répertoire des diffusions en français (longue traîne) ---------- | ||||
| 171 | + def _directory(self, seen: set[str], creators: list[Creator]) -> None: | ||||
| 172 | + after = "" | ||||
| 173 | + for _page in range(self.stream_pages): | ||||
| 174 | + aft = f', after: {json.dumps(after)}' if after else "" | ||||
| 175 | + q = ("query { streams(first: 30%s, options: {languages: [FR]}) " | ||||
| 176 | + "{ edges { cursor node { title broadcaster { %s } } } " | ||||
| 177 | + "pageInfo { hasNextPage } } }" % (aft, _USER_FIELDS)) | ||||
| 178 | + try: | ||||
| 179 | + data = self._gql(q) | ||||
| 180 | + streams = (data.get("data") or {}).get("streams") or {} | ||||
| 181 | + except Exception: | ||||
| 182 | + self.errors += 1 | ||||
| 183 | + return | ||||
| 184 | + edges = streams.get("edges") or [] | ||||
| 185 | + for edge in edges: | ||||
| 186 | + node = edge.get("node") or {} | ||||
| 187 | + user = node.get("broadcaster") or {} | ||||
| 188 | + if user.get("login"): | ||||
| 189 | + self._collect(user, node.get("title") or "", seen, creators) | ||||
| 190 | + if not edges or not (streams.get("pageInfo") or {}).get("hasNextPage"): | ||||
| 191 | + return | ||||
| 192 | + after = edges[-1].get("cursor") or "" | ||||
| 193 | + if not after: | ||||
| 194 | + return | ||||
| 195 | + | ||||
| 196 | + def fetch(self) -> list[Creator]: | ||||
| 197 | + creators: list[Creator] = [] | ||||
| 198 | + seen: set[str] = set() | ||||
| 199 | + self._search(seen, creators) | ||||
| 200 | + try: | ||||
| 201 | + self._directory(seen, creators) | ||||
| 202 | + except Exception as exc: # la voie 2 ne bloque jamais la voie 1 | ||||
| 203 | + self.errors += 1 | ||||
| 204 | + print(f"[crea-ka] ⚠ twitch-decouverte : répertoire FR en échec : " | ||||
| 205 | + f"{exc}", file=sys.stderr) | ||||
| 206 | + return creators | ||||
modified
creaka/connectors/wikipedia_qc.py
+9 −0
@@ -52,6 +52,15 @@ CATEGORIES: list[tuple[str, str, bool, str, str]] = [ | |||||
| 52 | ("en", "Category:Canadian Twitch (service) streamers", True, "gaming", | 52 | ("en", "Category:Canadian Twitch (service) streamers", True, "gaming", | ||
| 53 | "streamer"), | 53 | "streamer"), | ||
| 54 | ("en", "Category:Canadian TikTokers", True, "lifestyle", "createur-tiktok"), | 54 | ("en", "Category:Canadian TikTokers", True, "lifestyle", "createur-tiktok"), | ||
| 55 | + # vague 4 — catégories supplémentaires vérifiées (2026-08-18) | ||||
| 56 | + ("fr", "Catégorie:Blogueuse québécoise", False, "actualite-opinion", | ||||
| 57 | + "createur-ecrit"), | ||||
| 58 | + ("en", "Category:Canadian Internet celebrities", True, "lifestyle", | ||||
| 59 | + "influenceur"), | ||||
| 60 | + ("en", "Category:Canadian women podcasters", True, "actualite-opinion", | ||||
| 61 | + "podcasteur"), | ||||
| 62 | + ("en", "Category:Canadian video bloggers", True, "lifestyle", "youtubeur"), | ||||
| 63 | + ("en", "Category:Canadian gaming YouTubers", True, "gaming", "youtubeur"), | ||||
| 55 | ] | 64 | ] | ||
| 56 | 65 | ||||
| 57 | # propriétés Wikidata → plateformes §6.2 (handles curés par la communauté) | 66 | # propriétés Wikidata → plateformes §6.2 (handles curés par la communauté) | ||
modified
creaka/connectors/youtube_recherche.py
+101 −2
@@ -116,6 +116,34 @@ QUERIES: list[tuple[str, str]] = [ | |||||
| 116 | ("urbex québec", "autre"), ("faits divers québec", "actualite-opinion"), | 116 | ("urbex québec", "autre"), ("faits divers québec", "actualite-opinion"), | ||
| 117 | ("politique québécoise", "actualite-opinion"), | 117 | ("politique québécoise", "actualite-opinion"), | ||
| 118 | ("nouvelles québec", "actualite-opinion"), | 118 | ("nouvelles québec", "actualite-opinion"), | ||
| 119 | + # créateurs anglophones/bilingues (les marqueurs montreal/mtl/quebec | ||||
| 120 | + # figurent dans _QC_MARKERS — même filtre conservateur) | ||||
| 121 | + ("montreal vlog", "lifestyle"), ("montreal vlogger", "lifestyle"), | ||||
| 122 | + ("montreal youtuber", "lifestyle"), ("living in montreal", "lifestyle"), | ||||
| 123 | + ("montreal food", "bouffe-resto"), ("montreal foodie", "bouffe-resto"), | ||||
| 124 | + ("montreal restaurants", "bouffe-resto"), ("montreal cooking", "cuisine"), | ||||
| 125 | + ("montreal gaming", "gaming"), ("montreal streamer", "gaming"), | ||||
| 126 | + ("montreal comedy", "humour"), ("montreal standup", "humour"), | ||||
| 127 | + ("montreal music", "musique"), ("montreal rap", "musique"), | ||||
| 128 | + ("mtl rap", "musique"), ("montreal producer", "musique"), | ||||
| 129 | + ("montreal fitness", "sport-fitness"), ("montreal gym", "sport-fitness"), | ||||
| 130 | + ("montreal makeup", "beaute"), ("montreal beauty", "beaute"), | ||||
| 131 | + ("montreal fashion", "mode"), ("montreal streetwear", "mode"), | ||||
| 132 | + ("montreal thrift", "mode"), ("montreal barber", "beaute"), | ||||
| 133 | + ("montreal tech", "tech"), ("montreal developer", "tech"), | ||||
| 134 | + ("montreal photography", "arts"), ("montreal artist", "arts"), | ||||
| 135 | + ("montreal dance", "danse"), ("montreal travel", "voyage"), | ||||
| 136 | + ("montreal real estate", "finance-affaires"), | ||||
| 137 | + ("montreal finance", "finance-affaires"), | ||||
| 138 | + ("montreal podcast", "actualite-opinion"), | ||||
| 139 | + ("montreal family vlog", "famille-parentalite"), | ||||
| 140 | + ("quebec city vlog", "lifestyle"), ("quebec city food", "bouffe-resto"), | ||||
| 141 | + ("quebec gaming", "gaming"), ("quebec outdoors", "plein-air"), | ||||
| 142 | + ("quebec fishing", "plein-air"), ("quebec hunting", "plein-air"), | ||||
| 143 | + ("quebec snowboard", "plein-air"), ("quebec skiing", "plein-air"), | ||||
| 144 | + ("quebec history", "education"), ("learn french quebec", "education"), | ||||
| 145 | + ("quebec french lessons", "education"), ("anglo montreal", "lifestyle"), | ||||
| 146 | + ("laval vlogger", "lifestyle"), ("gatineau ottawa vlog", "lifestyle"), | ||||
| 119 | ] | 147 | ] | ||
| 120 | 148 | ||||
| 121 | # --- longue traîne : villes/MRC × créneaux (nano/micro créateurs locaux) -------- | 149 | # --- longue traîne : villes/MRC × créneaux (nano/micro créateurs locaux) -------- | ||
@@ -137,7 +165,13 @@ _TOWNS = [ | |||||
| 137 | ] | 165 | ] | ||
| 138 | _TOWN_THEMES = [("vlog", "lifestyle"), ("youtubeur", "lifestyle"), | 166 | _TOWN_THEMES = [("vlog", "lifestyle"), ("youtubeur", "lifestyle"), | ||
| 139 | ("gaming", "gaming"), ("chasse pêche", "plein-air"), | 167 | ("gaming", "gaming"), ("chasse pêche", "plein-air"), | ||
| 140 | − ("humour", "humour")] | 168 | + ("humour", "humour"), | ||
| 169 | + # vague 4 : la longue traîne locale couvre aussi la bouffe, la | ||||
| 170 | + # forme, la beauté, la musique, la famille et les balados | ||||
| 171 | + ("cuisine", "cuisine"), ("resto", "bouffe-resto"), | ||||
| 172 | + ("fitness", "sport-fitness"), ("beauté", "beaute"), | ||||
| 173 | + ("musique", "musique"), ("famille", "famille-parentalite"), | ||||
| 174 | + ("balado", "actualite-opinion"), ("plein air", "plein-air")] | ||||
| 141 | for _t in _TOWNS: | 175 | for _t in _TOWNS: | ||
| 142 | for _th, _n in _TOWN_THEMES: | 176 | for _th, _n in _TOWN_THEMES: | ||
| 143 | QUERIES.append((f"{_th} {_t}", _n)) | 177 | QUERIES.append((f"{_th} {_t}", _n)) | ||
@@ -189,6 +223,71 @@ _HOBBIES = [ | |||||
| 189 | ("frugal", "finance-affaires"), ("bourse dividendes", "finance-affaires"), | 223 | ("frugal", "finance-affaires"), ("bourse dividendes", "finance-affaires"), | ||
| 190 | ("intelligence artificielle", "tech"), ("cybersécurité", "tech"), | 224 | ("intelligence artificielle", "tech"), ("cybersécurité", "tech"), | ||
| 191 | ("impression 3d", "tech"), ("domotique", "tech"), ("drones", "tech"), | 225 | ("impression 3d", "tech"), ("domotique", "tech"), ("drones", "tech"), | ||
| 226 | + # vague 4 : encore plus de passe-temps, sports, métiers et scènes | ||||
| 227 | + ("escalade", "sport-fitness"), ("trail", "sport-fitness"), | ||||
| 228 | + ("triathlon", "sport-fitness"), ("powerlifting", "sport-fitness"), | ||||
| 229 | + ("arts martiaux", "sport-fitness"), ("jiu-jitsu", "sport-fitness"), | ||||
| 230 | + ("karaté", "sport-fitness"), ("boxe thaï", "sport-fitness"), | ||||
| 231 | + ("patinage", "sport-fitness"), ("ringuette", "sport-fitness"), | ||||
| 232 | + ("curling", "sport-fitness"), ("cheerleading", "sport-fitness"), | ||||
| 233 | + ("gymnastique", "sport-fitness"), ("natation", "sport-fitness"), | ||||
| 234 | + ("plongée", "plein-air"), ("voile", "plein-air"), | ||||
| 235 | + ("kayak de mer", "plein-air"), ("canot", "plein-air"), | ||||
| 236 | + ("raquette", "plein-air"), ("ski de fond", "plein-air"), | ||||
| 237 | + ("ski hors-piste", "plein-air"), ("escapade", "voyage"), | ||||
| 238 | + ("roadtrip", "voyage"), ("croisière", "voyage"), | ||||
| 239 | + ("aquariophilie", "autre"), ("reptiles", "autre"), | ||||
| 240 | + ("chiens", "autre"), ("chats", "autre"), ("chevaux", "plein-air"), | ||||
| 241 | + ("équitation", "plein-air"), ("fermette", "plein-air"), | ||||
| 242 | + ("poules", "plein-air"), ("potager", "plein-air"), | ||||
| 243 | + ("champignons", "plein-air"), ("mycologie", "plein-air"), | ||||
| 244 | + ("herboristerie", "sante-mieux-etre"), ("zéro déchet", "lifestyle"), | ||||
| 245 | + ("autosuffisance", "plein-air"), ("survivalisme", "plein-air"), | ||||
| 246 | + ("vinyle", "musique"), ("audiophile", "tech"), | ||||
| 247 | + ("home studio", "musique"), ("beatmaking", "musique"), | ||||
| 248 | + ("production musicale", "musique"), ("ukulélé", "musique"), | ||||
| 249 | + ("saxophone", "musique"), ("harmonica", "musique"), | ||||
| 250 | + ("accordéon", "musique"), ("chant", "musique"), | ||||
| 251 | + ("billard", "autre"), ("poker", "autre"), ("fléchettes", "autre"), | ||||
| 252 | + ("airsoft", "autre"), ("paintball", "autre"), | ||||
| 253 | + ("modélisme", "arts"), ("figurines", "arts"), ("bijoux", "arts"), | ||||
| 254 | + ("savonnerie", "arts"), ("chandelles", "arts"), | ||||
| 255 | + ("macramé", "arts"), ("scrapbooking", "arts"), | ||||
| 256 | + ("philatélie", "education"), ("numismatique", "education"), | ||||
| 257 | + ("antiquités", "autre"), ("brocante", "autre"), | ||||
| 258 | + ("horlogerie", "arts"), ("restauration meubles", "arts"), | ||||
| 259 | + ("ébénisterie", "arts"), ("charpenterie", "autre"), | ||||
| 260 | + ("maçonnerie", "autre"), ("toiture", "autre"), | ||||
| 261 | + ("mécanique diesel", "autre"), ("carrosserie", "autre"), | ||||
| 262 | + ("détailing", "autre"), ("camion lourd", "autre"), | ||||
| 263 | + ("agriculture laitière", "plein-air"), ("grandes cultures", "plein-air"), | ||||
| 264 | + ("boucherie", "cuisine"), ("charcuterie", "cuisine"), | ||||
| 265 | + ("fermentation", "cuisine"), ("kombucha", "cuisine"), | ||||
| 266 | + ("cidre", "bouffe-resto"), ("hydromel", "bouffe-resto"), | ||||
| 267 | + ("distillerie", "bouffe-resto"), ("torréfaction", "bouffe-resto"), | ||||
| 268 | + ("sommelier", "bouffe-resto"), ("cocktails", "bouffe-resto"), | ||||
| 269 | + ("orthopédagogie", "education"), ("orthophonie", "education"), | ||||
| 270 | + ("tdah", "sante-mieux-etre"), ("autisme", "sante-mieux-etre"), | ||||
| 271 | + ("kinésiologie", "sante-mieux-etre"), ("chiropratique", "sante-mieux-etre"), | ||||
| 272 | + ("dermatologie", "beaute"), ("nutritionniste", "sante-mieux-etre"), | ||||
| 273 | + ("sage-femme", "famille-parentalite"), ("doula", "famille-parentalite"), | ||||
| 274 | + ("homeschooling", "famille-parentalite"), ("école à la maison", "famille-parentalite"), | ||||
| 275 | + ("astuces ménage", "lifestyle"), ("décoration", "lifestyle"), | ||||
| 276 | + ("design intérieur", "lifestyle"), ("aménagement paysager", "autre"), | ||||
| 277 | + ("piscine", "autre"), ("spa", "autre"), | ||||
| 278 | + ("courtier hypothécaire", "finance-affaires"), | ||||
| 279 | + ("planificateur financier", "finance-affaires"), | ||||
| 280 | + ("assurance", "finance-affaires"), ("fiscalité", "finance-affaires"), | ||||
| 281 | + ("dropshipping", "finance-affaires"), ("commerce en ligne", "finance-affaires"), | ||||
| 282 | + ("marketing numérique", "finance-affaires"), ("freelance", "finance-affaires"), | ||||
| 283 | + ("linguistique", "education"), ("vulgarisation", "education"), | ||||
| 284 | + ("archéologie", "education"), ("géographie", "education"), | ||||
| 285 | + ("météo", "education"), ("aviation", "tech"), | ||||
| 286 | + ("simulateur de vol", "gaming"), ("trains", "autre"), | ||||
| 287 | + ("camping-car", "voyage"), ("vr roulotte", "voyage"), | ||||
| 288 | + ("pêche blanche", "plein-air"), ("trappage", "plein-air"), | ||||
| 289 | + ("taxidermie", "autre"), ("coutellerie", "arts"), | ||||
| 290 | + ("armes à feu", "plein-air"), ("tir à l'arc", "plein-air"), | ||||
| 192 | ] | 291 | ] | ||
| 193 | for _h, _n in _HOBBIES: | 292 | for _h, _n in _HOBBIES: | ||
| 194 | QUERIES.append((f"{_h} québec", _n)) | 293 | QUERIES.append((f"{_h} québec", _n)) | ||
@@ -275,7 +374,7 @@ class YouTubeRechercheConnector(BaseConnector): | |||||
| 275 | source_id = "youtube-recherche" | 374 | source_id = "youtube-recherche" | ||
| 276 | kind = "discovery" | 375 | kind = "discovery" | ||
| 277 | request_delay = 1.0 | 376 | request_delay = 1.0 | ||
| 278 | − max_queries = 800 | 377 | + max_queries = 2500 | ||
| 279 | max_pages_per_query = 4 # PROFONDEUR : pages de continuation (~20 chaînes/page) | 378 | max_pages_per_query = 4 # PROFONDEUR : pages de continuation (~20 chaînes/page) | ||
| 280 | 379 | ||||
| 281 | def _collect(self, channels: list[dict], niche: str, seen: set[str], | 380 | def _collect(self, channels: list[dict], niche: str, seen: set[str], | ||
modified
creaka/ingest.py
+1 −1
@@ -32,7 +32,7 @@ from .dedup import dedupe | |||||
| 32 | # tout dernier (il relit les bios enrichies, sans aucune requête) | 32 | # tout dernier (il relit les bios enrichies, sans aucune requête) | ||
| 33 | ENRICH_ORDER = ["instagram-profil", "tiktok-profil", "youtube", "twitch", | 33 | ENRICH_ORDER = ["instagram-profil", "tiktok-profil", "youtube", "twitch", | ||
| 34 | "x-profil", "balados-rss", "podcastindex", | 34 | "x-profil", "balados-rss", "podcastindex", | ||
| 35 | − "link-in-bio", "bio-liens"] | 35 | + "link-in-bio", "bio-liens", "region-bio"] | ||
| 36 | 36 | ||||
| 37 | 37 | ||||
| 38 | def _finalize_batch(creators: list) -> tuple[list, int]: | 38 | def _finalize_batch(creators: list) -> tuple[list, int]: | ||
modified
data/sources.json
+28 −1
@@ -148,6 +148,33 @@ | |||||
| 148 | "signal_identite": "cross_link (0.90) — le créateur pointe lui-même vers son autre compte", | 148 | "signal_identite": "cross_link (0.90) — le créateur pointe lui-même vers son autre compte", | ||
| 149 | "cadence": "quotidienne (watch), en dernier du pipeline", | 149 | "cadence": "quotidienne (watch), en dernier du pipeline", | ||
| 150 | "notes": "passe conservatrice §12 : patrons sûrs seulement, cap 5 nouveaux comptes par fiche" | 150 | "notes": "passe conservatrice §12 : patrons sûrs seulement, cap 5 nouveaux comptes par fiche" | ||
| 151 | + }, | ||||
| 152 | + { | ||||
| 153 | + "id": "twitch-decouverte", | ||||
| 154 | + "famille": "decouverte", | ||||
| 155 | + "palier": 3, | ||||
| 156 | + "acces": "API GQL publique du site officiel de Twitch (Client-ID public web, sans clé) : recherche searchFor par ~43 termes QC paginée + répertoire des diffusions EN DIRECT en français (streams languages:[FR], 20 pages)", | ||||
| 157 | + "signal_identite": "profil_source (0.98) — la chaîne est le compte d'origine de la fiche", | ||||
| 158 | + "cadence": "quotidienne (watch) — qui est en direct change chaque jour, la couverture s'accumule", | ||||
| 159 | + "notes": "vague 4 — marqueur québécois OBLIGATOIRE dans nom/bio/titre du stream ; abonnés, avatar, partenaire/affilié, dernier direct et jeu captés à la source ; niche déduite du jeu (Just Chatting → lifestyle, Music → musique…)" | ||||
| 160 | + }, | ||||
| 161 | + { | ||||
| 162 | + "id": "kick-decouverte", | ||||
| 163 | + "famille": "decouverte", | ||||
| 164 | + "palier": 4, | ||||
| 165 | + "acces": "Scrapfly ASP sans render_js (Cloudflare bloque le direct) : kick.com/api/search par ~27 termes QC + fiche v2 par chaîne retenue (cap 120/passage — budget Scrapfly)", | ||||
| 166 | + "signal_identite": "profil_source (0.98) pour la chaîne Kick ; cross_link (0.90) pour les liens sociaux AUTO-DÉCLARÉS du profil v2 (instagram/x/youtube/tiktok/facebook/discord)", | ||||
| 167 | + "cadence": "quotidienne (watch)", | ||||
| 168 | + "notes": "vague 4 — marqueur québécois requis dans pseudo/slug/bio ; la fiche v2 expose les liens sociaux remplis par le créateur lui-même : meilleure matière première du rattachement §12.1" | ||||
| 169 | + }, | ||||
| 170 | + { | ||||
| 171 | + "id": "region-bio", | ||||
| 172 | + "famille": "enrichissement", | ||||
| 173 | + "palier": 1, | ||||
| 174 | + "acces": "AUCUNE requête — relit les bios publiques déjà en base : ville DÉCLARÉE avec tournure locative (« de Sherbrooke », « based in Montreal ») ou gentilé (« montréalaise ») → région §7 + ville", | ||||
| 175 | + "signal_identite": "n/a (ne touche pas aux comptes)", | ||||
| 176 | + "cadence": "quotidienne (watch), tout dernier du pipeline", | ||||
| 177 | + "notes": "vague 4 — liste de ~70 villes SÛRES seulement (pas d'Alma/Waterloo/Varennes : prénoms, homonymes hors QC, particules) ; abstention si villes de régions différentes ; ne remplit que les champs vides" | ||||
| 151 | } | 178 | } | ||
| 152 | ] | 179 | ] | ||
| 153 | −} | 180 | +} | ||
| \ No newline at end of file | |||||
modified
docs/connecteurs/INDEX.md
+21 −18
@@ -1,24 +1,27 @@ | |||||
| 1 | # Créa-Ka — Index des connecteurs | 1 | # Créa-Ka — Index des connecteurs | ||
| 2 | 2 | ||||
| 3 | −_Généré automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 06:25 — ne pas éditer à la main, régénérer._ | 3 | +_Généré automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:01 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | −**16 sources au registre** · **5740 créateurs** et **6714 comptes** en BD. | 5 | +**19 sources au registre** · **9437 créateurs** et **10512 comptes** en BD. | ||
| 6 | 6 | ||||
| 7 | | Source | Famille | Palier | Type d'accès | Backend | Découverts | Comptes (plateforme) | État | Dernier passage | | 7 | | Source | Famille | Palier | Type d'accès | Backend | Découverts | Comptes (plateforme) | État | Dernier passage | | ||
| 8 | |---|---|---|---|---|---|---|---|---| | 8 | |---|---|---|---|---|---|---|---|---| | ||
| 9 | −| [`listes-medias`](listes-medias.md) | decouverte | P3 | dataset local compilé (data/seed) | direct | 310 | — | actif | 2026-08-18T06:23… | | 9 | +| [`listes-medias`](listes-medias.md) | decouverte | P3 | dataset local compilé (data/seed) | direct | 310 | — | actif | 2026-08-18T10:27… | | ||
| 10 | −| [`wikidata-qc`](wikidata-qc.md) | decouverte | P3 | API SPARQL publique (Wikidata) | direct | 73 | — | actif | 2026-08-18T06:27… | | 10 | +| [`wikidata-qc`](wikidata-qc.md) | decouverte | P3 | API SPARQL publique (Wikidata) | direct | 73 | — | actif | 2026-08-18T10:36… | | ||
| 11 | −| [`onlyqueb`](onlyqueb.md) | decouverte | P3 | sitemap XML + JSON-LD des pages profil (S… | direct | 253 | 248 (onlyfans) | actif | 2026-08-18T06:27… | | 11 | +| [`onlyqueb`](onlyqueb.md) | decouverte | P3 | sitemap XML + JSON-LD des pages profil (S… | direct | 253 | 248 (onlyfans) | actif | 2026-08-18T10:32… | | ||
| 12 | −| [`youtube-recherche`](youtube-recherche.md) | decouverte | P3 | API JSON | direct | 4595 | 4784 (youtube) | actif | 2026-08-18T07:22… | | 12 | +| [`youtube-recherche`](youtube-recherche.md) | decouverte | P3 | API JSON | direct | 7876 | 8084 (youtube) | actif | 2026-08-18T17:05… | | ||
| 13 | −| [`wikipedia-qc`](wikipedia-qc.md) | decouverte | P3 | API SPARQL publique (Wikidata) | direct | 76 | — | actif | 2026-08-18T10:07… | | 13 | +| [`wikipedia-qc`](wikipedia-qc.md) | decouverte | P3 | API SPARQL publique (Wikidata) | direct | 84 | — | actif | 2026-08-18T14:44… | | ||
| 14 | −| [`palmares-apple`](palmares-apple.md) | decouverte | P2 | API iTunes Search/Lookup (publique) | direct | 0 | 435 (podcast) | actif | 2026-08-18T09:58… | | 14 | +| [`palmares-apple`](palmares-apple.md) | decouverte | P2 | API iTunes Search/Lookup (publique) | direct | 0 | 462 (podcast) | actif | 2026-08-18T10:35… | | ||
| 15 | −| [`balados-itunes`](balados-itunes.md) | decouverte | P2 | API iTunes Search/Lookup (publique) | direct | 433 | 435 (podcast) | actif | 2026-08-18T06:23… | | 15 | +| [`balados-itunes`](balados-itunes.md) | decouverte | P2 | API iTunes Search/Lookup (publique) | direct | 460 | 462 (podcast) | actif | 2026-08-18T14:48… | | ||
| 16 | −| [`instagram-profil`](instagram-profil.md) | enrichissement | P4 | pages HTML publiques | Scrapfly | 0 | 476 (instagram) | actif | 2026-08-18T07:51… | | 16 | +| [`instagram-profil`](instagram-profil.md) | enrichissement | P4 | pages HTML publiques | Scrapfly | 0 | 495 (instagram) | actif | 2026-08-18T12:04… | | ||
| 17 | −| [`tiktok-profil`](tiktok-profil.md) | enrichissement | P4 | pages HTML publiques | Scrapfly | 0 | 199 (tiktok) | actif | 2026-08-18T09:16… | | 17 | +| [`tiktok-profil`](tiktok-profil.md) | enrichissement | P4 | pages HTML publiques | Scrapfly | 0 | 224 (tiktok) | actif | 2026-08-18T13:25… | | ||
| 18 | −| [`youtube`](youtube.md) | enrichissement | P2 | API JSON | direct | 0 | 4784 (youtube) | actif | 2026-08-18T10:24… | | 18 | +| [`youtube`](youtube.md) | enrichissement | P2 | API JSON | direct | 0 | 8084 (youtube) | actif | 2026-08-18T17:21… | | ||
| 19 | −| [`twitch`](twitch.md) | enrichissement | P2 | API JSON | direct | 0 | 28 (twitch) | actif | 2026-08-18T09:50… | | 19 | +| [`twitch`](twitch.md) | enrichissement | P2 | API JSON | direct | 0 | 292 (twitch) | actif | 2026-08-18T17:05… | | ||
| 20 | −| [`link-in-bio`](link-in-bio.md) | enrichissement | P1 | pages HTML publiques | Firecrawl | 0 | — | actif | 2026-08-18T09:57… | | 20 | +| [`link-in-bio`](link-in-bio.md) | enrichissement | P1 | pages HTML publiques | Firecrawl | 0 | — | actif | 2026-08-18T17:29… | | ||
| 21 | −| [`balados-rss`](balados-rss.md) | enrichissement | P1 | flux RSS publics | direct | 0 | 435 (podcast) | actif | 2026-08-18T09:55… | | 21 | +| [`balados-rss`](balados-rss.md) | enrichissement | P1 | flux RSS publics | direct | 0 | 462 (podcast) | actif | 2026-08-18T13:48… | | ||
| 22 | −| [`podcastindex`](podcastindex.md) | enrichissement | P2 | API JSON | direct | 0 | 435 (podcast) | prêt | — | | 22 | +| [`podcastindex`](podcastindex.md) | enrichissement | P2 | API JSON | direct | 0 | 462 (podcast) | prêt | — | | ||
| 23 | −| [`x-profil`](x-profil.md) | enrichissement | P3 | pages HTML publiques | direct | 0 | 209 (x) | actif | 2026-08-18T09:55… | | 23 | +| [`x-profil`](x-profil.md) | enrichissement | P3 | pages HTML publiques | direct | 0 | 228 (x) | actif | 2026-08-18T17:27… | | ||
| 24 | −| [`bio-liens`](bio-liens.md) | enrichissement | P1 | pages HTML publiques | direct | 0 | — | actif | 2026-08-18T09:57… | | 24 | +| [`bio-liens`](bio-liens.md) | enrichissement | P1 | pages HTML publiques | direct | 0 | — | actif | 2026-08-18T17:29… | | ||
| 25 | +| [`twitch-decouverte`](twitch-decouverte.md) | decouverte | P3 | pages HTML publiques | direct | 262 | — | actif | 2026-08-18T14:33… | | ||||
| 26 | +| [`kick-decouverte`](kick-decouverte.md) | decouverte | P4 | pages HTML publiques | Scrapfly | 119 | — | actif | 2026-08-18T14:42… | | ||||
| 27 | +| [`region-bio`](region-bio.md) | enrichissement | P1 | pages HTML publiques | direct | 0 | — | actif | 2026-08-18T17:29… | | ||||
modified
docs/connecteurs/balados-itunes.md
+12 −12
@@ -1,8 +1,8 @@ | |||||
| 1 | # `balados-itunes` — connecteur decouverte (palier 2) | 1 | # `balados-itunes` — connecteur decouverte (palier 2) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 06:25 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:01 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | −**État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 433 · touchés : 433 | 5 | +**État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 460 · touchés : 460 | ||
| 6 | 6 | ||||
| 7 | ## Description de la source | 7 | ## Description de la source | ||
| 8 | 8 | ||||
@@ -25,14 +25,14 @@ Connecteur DÉCOUVERTE — balados québécois via l'API de recherche iTunes/App | |||||
| 25 | 25 | ||||
| 26 | ## Champs récupérés → schéma cible | 26 | ## Champs récupérés → schéma cible | ||
| 27 | 27 | ||||
| 28 | −Source de **découverte** : produit des fiches `Creator` (tables `creators` + `accounts`). Complétude mesurée sur les 433 créateurs découverts par cette source (champ `doc.source`) ; exemple tiré d'une fiche réelle. | 28 | +Source de **découverte** : produit des fiches `Creator` (tables `creators` + `accounts`). Complétude mesurée sur les 460 créateurs découverts par cette source (champ `doc.source`) ; exemple tiré d'une fiche réelle. | ||
| 29 | 29 | ||||
| 30 | | Champ du doc créateur | Contenu | Renseigné | Exemple réel | | 30 | | Champ du doc créateur | Contenu | Renseigné | Exemple réel | | ||
| 31 | |---|---|---|---| | 31 | |---|---|---|---| | ||
| 32 | | `display_name` | Nom public | 100 % | Québec Nostalgie : le podcast | | 32 | | `display_name` | Nom public | 100 % | Québec Nostalgie : le podcast | | ||
| 33 | | `bio` | Bio | 97 % | Fidèle à la page Instagram du même nom, Québec Nostalgie : le podcast est un véritable vo… | | 33 | | `bio` | Bio | 97 % | Fidèle à la page Instagram du même nom, Québec Nostalgie : le podcast est un véritable vo… | | ||
| 34 | −| `region` | Région | 0 % | — | | 34 | +| `region` | Région | 8 % | — | | ||
| 35 | −| `city` | Ville | 0 % | — | | 35 | +| `city` | Ville | 8 % | — | | ||
| 36 | | `niches` | Niches (liste) | 100 % | actualite-opinion | | 36 | | `niches` | Niches (liste) | 100 % | actualite-opinion | | ||
| 37 | | `languages` | Langues (liste) | 100 % | fr | | 37 | | `languages` | Langues (liste) | 100 % | fr | | ||
| 38 | | `creator_type` | Type de créateur | 100 % | podcasteur | | 38 | | `creator_type` | Type de créateur | 100 % | podcasteur | | ||
@@ -42,7 +42,7 @@ Source de **découverte** : produit des fiches `Creator` (tables `creators` + `a | |||||
| 42 | | `total_reach` | Portée totale (abonnés cumulés) | 0 % | 109744 | | 42 | | `total_reach` | Portée totale (abonnés cumulés) | 0 % | 109744 | | ||
| 43 | | `link_in_bio_url` | Lien-en-bio | 0 % | https://linktr.ee/QuebecNostalgie | | 43 | | `link_in_bio_url` | Lien-en-bio | 0 % | https://linktr.ee/QuebecNostalgie | | ||
| 44 | 44 | ||||
| 45 | −Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `podcast` (435 comptes en BD, confiance moyenne 0.98). | 45 | +Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `podcast` (462 comptes en BD, confiance moyenne 0.98). | ||
| 46 | 46 | ||||
| 47 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | 47 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | ||
| 48 | |---|---|---|---| | 48 | |---|---|---|---| | ||
@@ -58,16 +58,16 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 58 | ## Fréquence & budget | 58 | ## Fréquence & budget | ||
| 59 | 59 | ||||
| 60 | - **Cadence déclarée (registre)** : quotidienne (watch) | 60 | - **Cadence déclarée (registre)** : quotidienne (watch) | ||
| 61 | −- **Cadence observée** (médiane sync_log) : ≈ 24 min | 61 | +- **Cadence observée** (médiane sync_log) : ≈ 40 min | ||
| 62 | −- **Dernier passage** : 2026-08-18T06:23:00Z — 433 créateurs, 433 comptes, +0 / ~433, 0 erreur(s), 131 s | 62 | +- **Dernier passage** : 2026-08-18T14:48:10Z — 460 créateurs, 460 comptes, +27 / ~433, 0 erreur(s), 241 s | ||
| 63 | - **Throttling** : 1.5 s entre requêtes (`request_delay`) | 63 | - **Throttling** : 1.5 s entre requêtes (`request_delay`) | ||
| 64 | 64 | ||||
| 65 | ## Volumétrie & complétude | 65 | ## Volumétrie & complétude | ||
| 66 | 66 | ||||
| 67 | −- **Créateurs découverts par la source** (`doc.source`) : 433 · **fiches touchées** (`source_ids`) : 433 | 67 | +- **Créateurs découverts par la source** (`doc.source`) : 460 · **fiches touchées** (`source_ids`) : 460 | ||
| 68 | −- **Complétude clé (découverts)** : niches 100 % · avatar 100 % · portée 0 % · région 0 % | 68 | +- **Complétude clé (découverts)** : niches 100 % · avatar 100 % · portée 0 % · région 8 % | ||
| 69 | −- **Comptes `podcast` en BD** : 435 — abonnés 0 % · métriques 100 % · dernière vérification 2026-08-18T09:56:23Z | 69 | +- **Comptes `podcast` en BD** : 462 — abonnés 0 % · métriques 100 % · dernière vérification 2026-08-18T17:28:28Z | ||
| 70 | −- **Runs journalisés (60 derniers)** : 7, dont 0 avec erreurs | 70 | +- **Runs journalisés (60 derniers)** : 9, dont 0 avec erreurs | ||
| 71 | 71 | ||||
| 72 | ## Erreurs connues & dépannage | 72 | ## Erreurs connues & dépannage | ||
| 73 | 73 | ||||
modified
docs/connecteurs/balados-rss.md
+7 −6
@@ -1,6 +1,6 @@ | |||||
| 1 | # `balados-rss` — connecteur enrichissement (palier 1) | 1 | # `balados-rss` — connecteur enrichissement (palier 1) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 06:25 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:01 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -25,7 +25,7 @@ Connecteur ENRICHISSEMENT « balados-rss » — lecture directe des flux RSS aut | |||||
| 25 | 25 | ||||
| 26 | ## Champs récupérés → schéma cible | 26 | ## Champs récupérés → schéma cible | ||
| 27 | 27 | ||||
| 28 | −Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `podcast` (435 comptes en BD, confiance moyenne 0.98). | 28 | +Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `podcast` (462 comptes en BD, confiance moyenne 0.98). | ||
| 29 | 29 | ||||
| 30 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | 30 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | ||
| 31 | |---|---|---|---| | 31 | |---|---|---|---| | ||
@@ -41,20 +41,21 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 41 | ## Fréquence & budget | 41 | ## Fréquence & budget | ||
| 42 | 42 | ||||
| 43 | - **Cadence déclarée (registre)** : quotidienne (watch) — rotation complète des 433 balados en ~3 jours, puis hebdomadaire | 43 | - **Cadence déclarée (registre)** : quotidienne (watch) — rotation complète des 433 balados en ~3 jours, puis hebdomadaire | ||
| 44 | −- **Cadence observée** (médiane sync_log) : ≈ 2.0 h | 44 | +- **Cadence observée** (médiane sync_log) : ≈ 3.6 h | ||
| 45 | −- **Dernier passage** : 2026-08-18T09:55:43Z — 8 créateurs, 36 comptes, +0 / ~8, 5 erreur(s), 12 s | 45 | +- **Dernier passage** : 2026-08-18T13:48:02Z — 8 créateurs, 36 comptes, +0 / ~8, 5 erreur(s), 12 s | ||
| 46 | - **Throttling** : 0.2 s entre requêtes (`request_delay`) | 46 | - **Throttling** : 0.2 s entre requêtes (`request_delay`) | ||
| 47 | 47 | ||||
| 48 | ## Volumétrie & complétude | 48 | ## Volumétrie & complétude | ||
| 49 | 49 | ||||
| 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 51 | −- **Comptes `podcast` en BD** : 435 — abonnés 0 % · métriques 100 % · dernière vérification 2026-08-18T09:56:23Z | 51 | +- **Comptes `podcast` en BD** : 462 — abonnés 0 % · métriques 100 % · dernière vérification 2026-08-18T17:28:28Z | ||
| 52 | −- **Runs journalisés (60 derniers)** : 5, dont 4 avec erreurs | 52 | +- **Runs journalisés (60 derniers)** : 6, dont 5 avec erreurs | ||
| 53 | 53 | ||||
| 54 | ## Erreurs connues & dépannage | 54 | ## Erreurs connues & dépannage | ||
| 55 | 55 | ||||
| 56 | | Passage | Erreurs | Alerte (sync_log) | | 56 | | Passage | Erreurs | Alerte (sync_log) | | ||
| 57 | |---|---|---| | 57 | |---|---|---| | ||
| 58 | +| 2026-08-18T13:48:02Z | 5 | — | | ||||
| 58 | | 2026-08-18T09:55:43Z | 5 | — | | 59 | | 2026-08-18T09:55:43Z | 5 | — | | ||
| 59 | | 2026-08-18T06:17:19Z | 5 | — | | 60 | | 2026-08-18T06:17:19Z | 5 | — | | ||
| 60 | | 2026-08-18T06:17:07Z | 5 | — | | 61 | | 2026-08-18T06:17:07Z | 5 | — | | ||
modified
docs/connecteurs/bio-liens.md
+7 −5
@@ -1,6 +1,6 @@ | |||||
| 1 | # `bio-liens` — connecteur enrichissement (palier 1) | 1 | # `bio-liens` — connecteur enrichissement (palier 1) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 06:25 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:01 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -29,19 +29,21 @@ Aucune donnée attribuable à cette source en BD pour l'instant (clés manquante | |||||
| 29 | ## Fréquence & budget | 29 | ## Fréquence & budget | ||
| 30 | 30 | ||||
| 31 | - **Cadence déclarée (registre)** : quotidienne (watch), en dernier du pipeline | 31 | - **Cadence déclarée (registre)** : quotidienne (watch), en dernier du pipeline | ||
| 32 | −- **Cadence observée** (médiane sync_log) : — | 32 | +- **Cadence observée** (médiane sync_log) : ≈ 3.7 h | ||
| 33 | −- **Dernier passage** : 2026-08-18T09:57:40Z — 1 créateurs, 2 comptes, +0 / ~1, 0 erreur(s), 0 s | 33 | +- **Dernier passage** : 2026-08-18T17:29:45Z — 14 créateurs, 30 comptes, +0 / ~14, 0 erreur(s), 0 s | ||
| 34 | - **Caps / budgets du module** : `MAX_NEW_PER_CREATOR` = 5 | 34 | - **Caps / budgets du module** : `MAX_NEW_PER_CREATOR` = 5 | ||
| 35 | - **Throttling** : 0.0 s entre requêtes (`request_delay`) | 35 | - **Throttling** : 0.0 s entre requêtes (`request_delay`) | ||
| 36 | 36 | ||||
| 37 | ## Volumétrie & complétude | 37 | ## Volumétrie & complétude | ||
| 38 | 38 | ||||
| 39 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 39 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 40 | −- **Runs journalisés (60 derniers)** : 2, dont 0 avec erreurs | 40 | +- **Runs journalisés (60 derniers)** : 4, dont 0 avec erreurs | ||
| 41 | 41 | ||||
| 42 | ## Erreurs connues & dépannage | 42 | ## Erreurs connues & dépannage | ||
| 43 | 43 | ||||
| 44 | −Aucune erreur ni alerte dans les 60 derniers runs journalisés. | 44 | +| Passage | Erreurs | Alerte (sync_log) | | ||
| 45 | +|---|---|---| | ||||
| 46 | +| 2026-08-18T13:50:07Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 45 | 47 | ||||
| 46 | Rejouer la source seule : `python3 run.py sync bio-liens` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='bio-liens' ORDER BY ts DESC LIMIT 5;`). | 48 | Rejouer la source seule : `python3 run.py sync bio-liens` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='bio-liens' ORDER BY ts DESC LIMIT 5;`). | ||
| 47 | 49 | ||||
modified
docs/connecteurs/instagram-profil.md
+8 −8
@@ -1,6 +1,6 @@ | |||||
| 1 | # `instagram-profil` — connecteur enrichissement (palier 4) | 1 | # `instagram-profil` — connecteur enrichissement (palier 4) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 06:25 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:01 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : Scrapfly · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : Scrapfly · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -25,31 +25,31 @@ Connecteur ENRICHISSEMENT Instagram — profil public par créateur : abonnés, | |||||
| 25 | 25 | ||||
| 26 | ## Champs récupérés → schéma cible | 26 | ## Champs récupérés → schéma cible | ||
| 27 | 27 | ||||
| 28 | −Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `instagram` (476 comptes en BD, confiance moyenne 0.88). | 28 | +Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `instagram` (495 comptes en BD, confiance moyenne 0.88). | ||
| 29 | 29 | ||||
| 30 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | 30 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | ||
| 31 | |---|---|---|---| | 31 | |---|---|---|---| | ||
| 32 | | `handle` | Handle | 100 % | catherinepaiz | | 32 | | `handle` | Handle | 100 % | catherinepaiz | | ||
| 33 | | `url` | URL du profil | 100 % | https://www.instagram.com/catherinepaiz/ | | 33 | | `url` | URL du profil | 100 % | https://www.instagram.com/catherinepaiz/ | | ||
| 34 | −| `followers` | Abonnés | 70 % | 7023547 | | 34 | +| `followers` | Abonnés | 70 % | 7023251 | | ||
| 35 | | `verified` | Badge vérifié | 58 % | 1 | | 35 | | `verified` | Badge vérifié | 58 % | 1 | | ||
| 36 | | `confidence` | Confiance d'identité | 100 % | 0.85 | | 36 | | `confidence` | Confiance d'identité | 100 % | 0.85 | | ||
| 37 | | `signal` | Signal d'identité | 100 % | base_publique | | 37 | | `signal` | Signal d'identité | 100 % | base_publique | | ||
| 38 | | `metrics` | Métriques détaillées (JSON) | 58 % | {"following": 248, "posts": 667, "is_business": false} | | 38 | | `metrics` | Métriques détaillées (JSON) | 58 % | {"following": 248, "posts": 667, "is_business": false} | | ||
| 39 | −| `last_checked` | Dernière vérification | 100 % | 2026-08-18T07:23:10Z | | 39 | +| `last_checked` | Dernière vérification | 100 % | 2026-08-18T11:35:29Z | | ||
| 40 | 40 | ||||
| 41 | ## Fréquence & budget | 41 | ## Fréquence & budget | ||
| 42 | 42 | ||||
| 43 | - **Cadence déclarée (registre)** : hebdomadaire (gros créateurs) / mensuelle | 43 | - **Cadence déclarée (registre)** : hebdomadaire (gros créateurs) / mensuelle | ||
| 44 | −- **Cadence observée** (médiane sync_log) : ≈ 2.1 h | 44 | +- **Cadence observée** (médiane sync_log) : ≈ 3.2 h | ||
| 45 | −- **Dernier passage** : 2026-08-18T07:51:39Z — 274 créateurs, 698 comptes, +0 / ~274, 0 erreur(s), 1724 s | 45 | +- **Dernier passage** : 2026-08-18T12:04:24Z — 288 créateurs, 789 comptes, +0 / ~288, 0 erreur(s), 1756 s | ||
| 46 | - **Throttling** : 1.5 s entre requêtes (`request_delay`) | 46 | - **Throttling** : 1.5 s entre requêtes (`request_delay`) | ||
| 47 | 47 | ||||
| 48 | ## Volumétrie & complétude | 48 | ## Volumétrie & complétude | ||
| 49 | 49 | ||||
| 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 51 | −- **Comptes `instagram` en BD** : 476 — abonnés 70 % · métriques 58 % · dernière vérification 2026-08-18T10:07:33Z | 51 | +- **Comptes `instagram` en BD** : 495 — abonnés 70 % · métriques 58 % · dernière vérification 2026-08-18T17:29:45Z | ||
| 52 | −- **Runs journalisés (60 derniers)** : 4, dont 0 avec erreurs | 52 | +- **Runs journalisés (60 derniers)** : 5, dont 0 avec erreurs | ||
| 53 | 53 | ||||
| 54 | ## Erreurs connues & dépannage | 54 | ## Erreurs connues & dépannage | ||
| 55 | 55 | ||||
added
docs/connecteurs/kick-decouverte.md
+73 −0
@@ -0,0 +1,73 @@ | |||||
| 1 | +# `kick-decouverte` — connecteur decouverte (palier 4) | ||||
| 2 | + | ||||
| 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:01 — ne pas éditer à la main, régénérer._ | ||||
| 4 | + | ||||
| 5 | +**État : actif** · Famille : decouverte (discovery) · Backend : Scrapfly · Créateurs découverts : 119 · touchés : 119 | ||||
| 6 | + | ||||
| 7 | +## Description de la source | ||||
| 8 | + | ||||
| 9 | +Connecteur DÉCOUVERTE — streamers Kick québécois via l'API publique de recherche du site (kick.com/api/search) + fiche v2 par chaîne (liens sociaux AUTO-DÉCLARÉS par le créateur → cross_link 0.90). Mode d'accès : Scrapfly ASP sans render_js (Cloudflare bloque les requêtes directes — 403). Palier 4 (§9/§10). | ||||
| 10 | + | ||||
| 11 | +- **Notes (registre)** : vague 4 — marqueur québécois requis dans pseudo/slug/bio ; la fiche v2 expose les liens sociaux remplis par le créateur lui-même : meilleure matière première du rattachement §12.1 | ||||
| 12 | +- **Signal d'identité** : profil_source (0.98) pour la chaîne Kick ; cross_link (0.90) pour les liens sociaux AUTO-DÉCLARÉS du profil v2 (instagram/x/youtube/tiktok/facebook/discord) (colonne `accounts.signal` / `confidence`) | ||||
| 13 | +- **Module** : `creaka/connectors/kick_decouverte.py` — classe `KickDecouverteConnector` (`kind = "discovery"`) | ||||
| 14 | + | ||||
| 15 | +## Accès | ||||
| 16 | + | ||||
| 17 | +- **Accès (registre)** : Scrapfly ASP sans render_js (Cloudflare bloque le direct) : kick.com/api/search par ~27 termes QC + fiche v2 par chaîne retenue (cap 120/passage — budget Scrapfly) | ||||
| 18 | +- **Type d'accès (code)** : pages HTML publiques | ||||
| 19 | +- **Endpoint de base** : https://kick.com/api/search?searched_word={term} | ||||
| 20 | +- **URLs du module** : https://kick.com/api/search?searched_word={term} · https://kick.com/api/v2/channels/{slug} | ||||
| 21 | +- **Pagination** : réponse unique (pas de pagination) | ||||
| 22 | +- **Backend anti-bot / rendu** : Scrapfly (asp + render_js — contournement anti-bot) | ||||
| 23 | +- **Politesse** : 1.5 s entre requêtes, timeout 30 s, UA `CreaKaBot/1.0 (+https://www.crea-ka.com/bot)` | ||||
| 24 | +- **Authentification** : aucune — contenu public / API anonyme | ||||
| 25 | + | ||||
| 26 | +## Champs récupérés → schéma cible | ||||
| 27 | + | ||||
| 28 | +Source de **découverte** : produit des fiches `Creator` (tables `creators` + `accounts`). Complétude mesurée sur les 119 créateurs découverts par cette source (champ `doc.source`) ; exemple tiré d'une fiche réelle. | ||||
| 29 | + | ||||
| 30 | +| Champ du doc créateur | Contenu | Renseigné | Exemple réel | | ||||
| 31 | +|---|---|---|---| | ||||
| 32 | +| `display_name` | Nom public | 100 % | valquebrada | | ||||
| 33 | +| `bio` | Bio | 25 % | Meu nome é Valmir Lima, tenho 32 anos de idade, curto jogar GTA RP. Vou mostrar um pouco … | | ||||
| 34 | +| `region` | Région | 0 % | — | | ||||
| 35 | +| `city` | Ville | 0 % | — | | ||||
| 36 | +| `niches` | Niches (liste) | 100 % | gaming | | ||||
| 37 | +| `languages` | Langues (liste) | 100 % | fr | | ||||
| 38 | +| `creator_type` | Type de créateur | 100 % | streamer | | ||||
| 39 | +| `primary_platform` | Plateforme principale | 100 % | twitch | | ||||
| 40 | +| `platforms` | Comptes sociaux (liste) | 100 % | twitch:@valquebrada, kick:@valquebrada, instagram:@val_quebrada | | ||||
| 41 | +| `avatar_url` | Avatar | 40 % | https://files.kick.com/images/user/15480678/profile_image/conversion/f1cf1446-e43a-478d-8… | | ||||
| 42 | +| `total_reach` | Portée totale (abonnés cumulés) | 56 % | 2772 | | ||||
| 43 | +| `link_in_bio_url` | Lien-en-bio | 0 % | — | | ||||
| 44 | + | ||||
| 45 | +## Fréquence & budget | ||||
| 46 | + | ||||
| 47 | +- **Cadence déclarée (registre)** : quotidienne (watch) | ||||
| 48 | +- **Cadence observée** (médiane sync_log) : — | ||||
| 49 | +- **Dernier passage** : 2026-08-18T14:42:46Z — 120 créateurs, 188 comptes, +119 / ~1, 0 erreur(s), 573 s | ||||
| 50 | +- **Throttling** : 1.5 s entre requêtes (`request_delay`) | ||||
| 51 | + | ||||
| 52 | +## Volumétrie & complétude | ||||
| 53 | + | ||||
| 54 | +- **Créateurs découverts par la source** (`doc.source`) : 119 · **fiches touchées** (`source_ids`) : 119 | ||||
| 55 | +- **Complétude clé (découverts)** : niches 100 % · avatar 40 % · portée 56 % · région 0 % | ||||
| 56 | +- **Runs journalisés (60 derniers)** : 1, dont 0 avec erreurs | ||||
| 57 | + | ||||
| 58 | +## Erreurs connues & dépannage | ||||
| 59 | + | ||||
| 60 | +Aucune erreur ni alerte dans les 60 derniers runs journalisés. | ||||
| 61 | + | ||||
| 62 | +Rejouer la source seule : `python3 run.py sync kick-decouverte` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='kick-decouverte' ORDER BY ts DESC LIMIT 5;`). | ||||
| 63 | + | ||||
| 64 | +## Licence, attribution & conditions | ||||
| 65 | + | ||||
| 66 | +- **Cadre d'accès (registre)** : Scrapfly ASP sans render_js (Cloudflare bloque le direct) : kick.com/api/search par ~27 termes QC + fiche v2 par chaîne retenue (cap 120/passage — budget Scrapfly) | ||||
| 67 | +- **Profils publics uniquement** : UA identifiable `CreaKaBot/1.0 (+https://www.crea-ka.com/bot; contact@spboucher.ai)`, throttling poli, respect des opt-out (`data/optout.json`) et du volet éthique (`creaka/ethics.py` — mineurs exclus via `is_minor`). | ||||
| 68 | +- Retrait sur demande : contact@spboucher.ai (opt-out honoré à la prochaine ingestion). | ||||
| 69 | + | ||||
| 70 | +## Historique | ||||
| 71 | + | ||||
| 72 | +- 2026-08-18 — plus ancien passage journalisé dans `sync_log` (fenêtre des 60 derniers). | ||||
| 73 | +- 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | ||||
modified
docs/connecteurs/link-in-bio.md
+4 −4
@@ -1,6 +1,6 @@ | |||||
| 1 | # `link-in-bio` — connecteur enrichissement (palier 1) | 1 | # `link-in-bio` — connecteur enrichissement (palier 1) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 06:25 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:01 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : Firecrawl · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : Firecrawl · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -29,14 +29,14 @@ Aucune donnée attribuable à cette source en BD pour l'instant (clés manquante | |||||
| 29 | ## Fréquence & budget | 29 | ## Fréquence & budget | ||
| 30 | 30 | ||||
| 31 | - **Cadence déclarée (registre)** : mensuelle | 31 | - **Cadence déclarée (registre)** : mensuelle | ||
| 32 | −- **Cadence observée** (médiane sync_log) : ≈ 4.4 h | 32 | +- **Cadence observée** (médiane sync_log) : ≈ 3.8 h | ||
| 33 | −- **Dernier passage** : 2026-08-18T09:57:40Z — 78 créateurs, 302 comptes, +0 / ~78, 0 erreur(s), 116 s | 33 | +- **Dernier passage** : 2026-08-18T17:29:45Z — 83 créateurs, 333 comptes, +0 / ~83, 0 erreur(s), 126 s | ||
| 34 | - **Throttling** : 1.2 s entre requêtes (`request_delay`) | 34 | - **Throttling** : 1.2 s entre requêtes (`request_delay`) | ||
| 35 | 35 | ||||
| 36 | ## Volumétrie & complétude | 36 | ## Volumétrie & complétude | ||
| 37 | 37 | ||||
| 38 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 38 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 39 | −- **Runs journalisés (60 derniers)** : 3, dont 0 avec erreurs | 39 | +- **Runs journalisés (60 derniers)** : 5, dont 0 avec erreurs | ||
| 40 | 40 | ||||
| 41 | ## Erreurs connues & dépannage | 41 | ## Erreurs connues & dépannage | ||
| 42 | 42 | ||||
modified
docs/connecteurs/listes-medias.md
+10 −10
@@ -1,6 +1,6 @@ | |||||
| 1 | # `listes-medias` — connecteur decouverte (palier 3) | 1 | # `listes-medias` — connecteur decouverte (palier 3) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 06:25 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:01 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 310 · touchés : 310 | 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 310 · touchés : 310 | ||
| 6 | 6 | ||||
@@ -29,30 +29,30 @@ Source de **découverte** : produit des fiches `Creator` (tables `creators` + `a | |||||
| 29 | | Champ du doc créateur | Contenu | Renseigné | Exemple réel | | 29 | | Champ du doc créateur | Contenu | Renseigné | Exemple réel | | ||
| 30 | |---|---|---|---| | 30 | |---|---|---|---| | ||
| 31 | | `display_name` | Nom public | 100 % | Enola Bédard | | 31 | | `display_name` | Nom public | 100 % | Enola Bédard | | ||
| 32 | −| `bio` | Bio | 72 % | Énola Bédard (born September 14, 2000) is a Canadian dancer, singer, and social media per… | | 32 | +| `bio` | Bio | 73 % | Énola Bédard (born September 14, 2000) is a Canadian dancer, singer, and social media per… | | ||
| 33 | −| `region` | Région | 49 % | — | | 33 | +| `region` | Région | 51 % | Capitale-Nationale | | ||
| 34 | −| `city` | Ville | 49 % | — | | 34 | +| `city` | Ville | 51 % | Québec | | ||
| 35 | | `niches` | Niches (liste) | 100 % | danse, lifestyle | | 35 | | `niches` | Niches (liste) | 100 % | danse, lifestyle | | ||
| 36 | | `languages` | Langues (liste) | 100 % | en, fr | | 36 | | `languages` | Langues (liste) | 100 % | en, fr | | ||
| 37 | | `creator_type` | Type de créateur | 100 % | createur-tiktok | | 37 | | `creator_type` | Type de créateur | 100 % | createur-tiktok | | ||
| 38 | | `primary_platform` | Plateforme principale | 100 % | tiktok | | 38 | | `primary_platform` | Plateforme principale | 100 % | tiktok | | ||
| 39 | | `platforms` | Comptes sociaux (liste) | 100 % | tiktok:@enola.bedard, youtube:@enola.bedard, instagram:@enola.bedard | | 39 | | `platforms` | Comptes sociaux (liste) | 100 % | tiktok:@enola.bedard, youtube:@enola.bedard, instagram:@enola.bedard | | ||
| 40 | −| `avatar_url` | Avatar | 74 % | https://scontent-lga3-2.cdninstagram.com/v/t51.82787-19/515154150_18510310135012441_32506… | | 40 | +| `avatar_url` | Avatar | 75 % | https://scontent-lga3-2.cdninstagram.com/v/t51.82787-19/515154150_18510310135012441_32506… | | ||
| 41 | −| `total_reach` | Portée totale (abonnés cumulés) | 90 % | 25307536 | | 41 | +| `total_reach` | Portée totale (abonnés cumulés) | 90 % | 24917522 | | ||
| 42 | | `link_in_bio_url` | Lien-en-bio | 24 % | — | | 42 | | `link_in_bio_url` | Lien-en-bio | 24 % | — | | ||
| 43 | 43 | ||||
| 44 | ## Fréquence & budget | 44 | ## Fréquence & budget | ||
| 45 | 45 | ||||
| 46 | - **Cadence déclarée (registre)** : mensuelle (recompilation du dataset) | 46 | - **Cadence déclarée (registre)** : mensuelle (recompilation du dataset) | ||
| 47 | −- **Cadence observée** (médiane sync_log) : ≈ 22 min | 47 | +- **Cadence observée** (médiane sync_log) : ≈ 28 min | ||
| 48 | −- **Dernier passage** : 2026-08-18T06:23:00Z — 310 créateurs, 448 comptes, +0 / ~310, 0 erreur(s), 0 s | 48 | +- **Dernier passage** : 2026-08-18T10:27:45Z — 310 créateurs, 448 comptes, +0 / ~310, 0 erreur(s), 0 s | ||
| 49 | - **Throttling** : 0.8 s entre requêtes (`request_delay`) | 49 | - **Throttling** : 0.8 s entre requêtes (`request_delay`) | ||
| 50 | 50 | ||||
| 51 | ## Volumétrie & complétude | 51 | ## Volumétrie & complétude | ||
| 52 | 52 | ||||
| 53 | - **Créateurs découverts par la source** (`doc.source`) : 310 · **fiches touchées** (`source_ids`) : 310 | 53 | - **Créateurs découverts par la source** (`doc.source`) : 310 · **fiches touchées** (`source_ids`) : 310 | ||
| 54 | −- **Complétude clé (découverts)** : niches 100 % · avatar 74 % · portée 90 % · région 49 % | 54 | +- **Complétude clé (découverts)** : niches 100 % · avatar 75 % · portée 90 % · région 51 % | ||
| 55 | −- **Runs journalisés (60 derniers)** : 11, dont 0 avec erreurs | 55 | +- **Runs journalisés (60 derniers)** : 12, dont 0 avec erreurs | ||
| 56 | 56 | ||||
| 57 | ## Erreurs connues & dépannage | 57 | ## Erreurs connues & dépannage | ||
| 58 | 58 | ||||
modified
docs/connecteurs/onlyqueb.md
+9 −9
@@ -1,6 +1,6 @@ | |||||
| 1 | # `onlyqueb` — connecteur decouverte (palier 3) | 1 | # `onlyqueb` — connecteur decouverte (palier 3) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 06:25 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:01 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 253 · touchés : 253 | 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 253 · touchés : 253 | ||
| 6 | 6 | ||||
@@ -31,15 +31,15 @@ Source de **découverte** : produit des fiches `Creator` (tables `creators` + `a | |||||
| 31 | |---|---|---|---| | 31 | |---|---|---|---| | ||
| 32 | | `display_name` | Nom public | 100 % | Jade Lavoie | | 32 | | `display_name` | Nom public | 100 % | Jade Lavoie | | ||
| 33 | | `bio` | Bio | 98 % | Deviens mon prochain acteur! 🔥 Je fais littéralement TOUT. Demande ce que tu veux et trou… | | 33 | | `bio` | Bio | 98 % | Deviens mon prochain acteur! 🔥 Je fais littéralement TOUT. Demande ce que tu veux et trou… | | ||
| 34 | −| `region` | Région | 0 % | — | | 34 | +| `region` | Région | 2 % | — | | ||
| 35 | −| `city` | Ville | 0 % | — | | 35 | +| `city` | Ville | 2 % | — | | ||
| 36 | | `niches` | Niches (liste) | 100 % | autre | | 36 | | `niches` | Niches (liste) | 100 % | autre | | ||
| 37 | | `languages` | Langues (liste) | 100 % | fr | | 37 | | `languages` | Langues (liste) | 100 % | fr | | ||
| 38 | | `creator_type` | Type de créateur | 100 % | influenceur | | 38 | | `creator_type` | Type de créateur | 100 % | influenceur | | ||
| 39 | | `primary_platform` | Plateforme principale | 100 % | instagram | | 39 | | `primary_platform` | Plateforme principale | 100 % | instagram | | ||
| 40 | | `platforms` | Comptes sociaux (liste) | 100 % | instagram:@jadelavoie, x:@missjadelavoie, onlyfans:@misslavoie | | 40 | | `platforms` | Comptes sociaux (liste) | 100 % | instagram:@jadelavoie, x:@missjadelavoie, onlyfans:@misslavoie | | ||
| 41 | | `avatar_url` | Avatar | 100 % | https://storage.googleapis.com/onlyqueb/MQZBiXsbMQa31zxj9P_mabNxNITFBxa6 | | 41 | | `avatar_url` | Avatar | 100 % | https://storage.googleapis.com/onlyqueb/MQZBiXsbMQa31zxj9P_mabNxNITFBxa6 | | ||
| 42 | −| `total_reach` | Portée totale (abonnés cumulés) | 18 % | 1571106 | | 42 | +| `total_reach` | Portée totale (abonnés cumulés) | 20 % | 1571053 | | ||
| 43 | | `link_in_bio_url` | Lien-en-bio | 2 % | — | | 43 | | `link_in_bio_url` | Lien-en-bio | 2 % | — | | ||
| 44 | 44 | ||||
| 45 | Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `onlyfans` (248 comptes en BD, confiance moyenne 0.90). | 45 | Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `onlyfans` (248 comptes en BD, confiance moyenne 0.90). | ||
@@ -58,16 +58,16 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 58 | ## Fréquence & budget | 58 | ## Fréquence & budget | ||
| 59 | 59 | ||||
| 60 | - **Cadence déclarée (registre)** : hebdomadaire | 60 | - **Cadence déclarée (registre)** : hebdomadaire | ||
| 61 | −- **Cadence observée** (médiane sync_log) : ≈ 24 min | 61 | +- **Cadence observée** (médiane sync_log) : ≈ 32 min | ||
| 62 | −- **Dernier passage** : 2026-08-18T06:27:32Z — 253 créateurs, 611 comptes, +0 / ~253, 0 erreur(s), 272 s | 62 | +- **Dernier passage** : 2026-08-18T10:32:17Z — 253 créateurs, 611 comptes, +0 / ~253, 0 erreur(s), 272 s | ||
| 63 | - **Throttling** : 1.0 s entre requêtes (`request_delay`) | 63 | - **Throttling** : 1.0 s entre requêtes (`request_delay`) | ||
| 64 | 64 | ||||
| 65 | ## Volumétrie & complétude | 65 | ## Volumétrie & complétude | ||
| 66 | 66 | ||||
| 67 | - **Créateurs découverts par la source** (`doc.source`) : 253 · **fiches touchées** (`source_ids`) : 253 | 67 | - **Créateurs découverts par la source** (`doc.source`) : 253 · **fiches touchées** (`source_ids`) : 253 | ||
| 68 | −- **Complétude clé (découverts)** : niches 100 % · avatar 100 % · portée 18 % · région 0 % | 68 | +- **Complétude clé (découverts)** : niches 100 % · avatar 100 % · portée 20 % · région 2 % | ||
| 69 | −- **Comptes `onlyfans` en BD** : 248 — abonnés 0 % · métriques 0 % · dernière vérification 2026-08-18T09:57:40Z | 69 | +- **Comptes `onlyfans` en BD** : 248 — abonnés 0 % · métriques 0 % · dernière vérification 2026-08-18T17:29:45Z | ||
| 70 | −- **Runs journalisés (60 derniers)** : 7, dont 0 avec erreurs | 70 | +- **Runs journalisés (60 derniers)** : 8, dont 0 avec erreurs | ||
| 71 | 71 | ||||
| 72 | ## Erreurs connues & dépannage | 72 | ## Erreurs connues & dépannage | ||
| 73 | 73 | ||||
modified
docs/connecteurs/palmares-apple.md
+7 −6
@@ -1,6 +1,6 @@ | |||||
| 1 | # `palmares-apple` — connecteur decouverte (palier 2) | 1 | # `palmares-apple` — connecteur decouverte (palier 2) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 06:25 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:01 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -25,7 +25,7 @@ Connecteur DÉCOUVERTE — balados québécois dans le TOP 100 canadien d'Apple | |||||
| 25 | 25 | ||||
| 26 | ## Champs récupérés → schéma cible | 26 | ## Champs récupérés → schéma cible | ||
| 27 | 27 | ||||
| 28 | −Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `podcast` (435 comptes en BD, confiance moyenne 0.98). | 28 | +Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `podcast` (462 comptes en BD, confiance moyenne 0.98). | ||
| 29 | 29 | ||||
| 30 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | 30 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | ||
| 31 | |---|---|---|---| | 31 | |---|---|---|---| | ||
@@ -41,20 +41,21 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 41 | ## Fréquence & budget | 41 | ## Fréquence & budget | ||
| 42 | 42 | ||||
| 43 | - **Cadence déclarée (registre)** : quotidienne (watch) — le palmarès bouge chaque jour | 43 | - **Cadence déclarée (registre)** : quotidienne (watch) — le palmarès bouge chaque jour | ||
| 44 | −- **Cadence observée** (médiane sync_log) : — | 44 | +- **Cadence observée** (médiane sync_log) : ≈ 21 min | ||
| 45 | −- **Dernier passage** : 2026-08-18T09:58:54Z — 0 créateurs, 0 comptes, +0 / ~0, 0 erreur(s), 211 s | 45 | +- **Dernier passage** : 2026-08-18T10:35:47Z — 0 créateurs, 0 comptes, +0 / ~0, 0 erreur(s), 209 s | ||
| 46 | - **Throttling** : 1.0 s entre requêtes (`request_delay`) | 46 | - **Throttling** : 1.0 s entre requêtes (`request_delay`) | ||
| 47 | 47 | ||||
| 48 | ## Volumétrie & complétude | 48 | ## Volumétrie & complétude | ||
| 49 | 49 | ||||
| 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 51 | −- **Comptes `podcast` en BD** : 435 — abonnés 0 % · métriques 100 % · dernière vérification 2026-08-18T09:56:23Z | 51 | +- **Comptes `podcast` en BD** : 462 — abonnés 0 % · métriques 100 % · dernière vérification 2026-08-18T17:28:28Z | ||
| 52 | −- **Runs journalisés (60 derniers)** : 2, dont 0 avec erreurs | 52 | +- **Runs journalisés (60 derniers)** : 3, dont 0 avec erreurs | ||
| 53 | 53 | ||||
| 54 | ## Erreurs connues & dépannage | 54 | ## Erreurs connues & dépannage | ||
| 55 | 55 | ||||
| 56 | | Passage | Erreurs | Alerte (sync_log) | | 56 | | Passage | Erreurs | Alerte (sync_log) | | ||
| 57 | |---|---|---| | 57 | |---|---|---| | ||
| 58 | +| 2026-08-18T10:35:47Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||||
| 58 | | 2026-08-18T09:58:54Z | 0 | 0 créateur retourné — source possiblement bloquée | | 59 | | 2026-08-18T09:58:54Z | 0 | 0 créateur retourné — source possiblement bloquée | | ||
| 59 | 60 | ||||
| 60 | Rejouer la source seule : `python3 run.py sync palmares-apple` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='palmares-apple' ORDER BY ts DESC LIMIT 5;`). | 61 | Rejouer la source seule : `python3 run.py sync palmares-apple` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='palmares-apple' ORDER BY ts DESC LIMIT 5;`). | ||
modified
docs/connecteurs/podcastindex.md
+3 −3
@@ -1,6 +1,6 @@ | |||||
| 1 | # `podcastindex` — connecteur enrichissement (palier 2) | 1 | # `podcastindex` — connecteur enrichissement (palier 2) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 06:25 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:01 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : prêt — clés requises** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | 5 | **État : prêt — clés requises** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -25,7 +25,7 @@ Connecteur ENRICHISSEMENT « podcastindex » — API Podcast Index (OFFICIELLE, | |||||
| 25 | 25 | ||||
| 26 | ## Champs récupérés → schéma cible | 26 | ## Champs récupérés → schéma cible | ||
| 27 | 27 | ||||
| 28 | −Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `podcast` (435 comptes en BD, confiance moyenne 0.98). | 28 | +Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `podcast` (462 comptes en BD, confiance moyenne 0.98). | ||
| 29 | 29 | ||||
| 30 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | 30 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | ||
| 31 | |---|---|---|---| | 31 | |---|---|---|---| | ||
@@ -47,7 +47,7 @@ Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les platefo | |||||
| 47 | ## Volumétrie & complétude | 47 | ## Volumétrie & complétude | ||
| 48 | 48 | ||||
| 49 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 49 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 50 | −- **Comptes `podcast` en BD** : 435 — abonnés 0 % · métriques 100 % · dernière vérification 2026-08-18T09:56:23Z | 50 | +- **Comptes `podcast` en BD** : 462 — abonnés 0 % · métriques 100 % · dernière vérification 2026-08-18T17:28:28Z | ||
| 51 | - **Runs journalisés (60 derniers)** : 0, dont 0 avec erreurs | 51 | - **Runs journalisés (60 derniers)** : 0, dont 0 avec erreurs | ||
| 52 | 52 | ||||
| 53 | ## Erreurs connues & dépannage | 53 | ## Erreurs connues & dépannage | ||
added
docs/connecteurs/region-bio.md
+56 −0
@@ -0,0 +1,56 @@ | |||||
| 1 | +# `region-bio` — connecteur enrichissement (palier 1) | ||||
| 2 | + | ||||
| 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:01 — ne pas éditer à la main, régénérer._ | ||||
| 4 | + | ||||
| 5 | +**État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | ||||
| 6 | + | ||||
| 7 | +## Description de la source | ||||
| 8 | + | ||||
| 9 | +Connecteur ENRICHISSEMENT — région/ville depuis la localisation DÉCLARÉE dans la bio publique du créateur (« humoriste de Sherbrooke », « based in Montreal », « vlogueuse montréalaise »). Mode d'accès : AUCUNE requête (relit les bios déjà en base, comme bio-liens). Palier 1 (§9). Vague 4. | ||||
| 10 | + | ||||
| 11 | +- **Notes (registre)** : vague 4 — liste de ~70 villes SÛRES seulement (pas d'Alma/Waterloo/Varennes : prénoms, homonymes hors QC, particules) ; abstention si villes de régions différentes ; ne remplit que les champs vides | ||||
| 12 | +- **Signal d'identité** : n/a (ne touche pas aux comptes) (colonne `accounts.signal` / `confidence`) | ||||
| 13 | +- **Module** : `creaka/connectors/region_bio.py` — classe `RegionBioConnector` (`kind = "enrichment"`) | ||||
| 14 | + | ||||
| 15 | +## Accès | ||||
| 16 | + | ||||
| 17 | +- **Accès (registre)** : AUCUNE requête — relit les bios publiques déjà en base : ville DÉCLARÉE avec tournure locative (« de Sherbrooke », « based in Montreal ») ou gentilé (« montréalaise ») → région §7 + ville | ||||
| 18 | +- **Type d'accès (code)** : pages HTML publiques | ||||
| 19 | +- **Endpoint de base** : — | ||||
| 20 | +- **Pagination** : réponse unique (pas de pagination) | ||||
| 21 | +- **Backend anti-bot / rendu** : requests direct | ||||
| 22 | +- **Politesse** : 0.0 s entre requêtes, timeout 30 s, UA `CreaKaBot/1.0 (+https://www.crea-ka.com/bot)` | ||||
| 23 | +- **Authentification** : aucune — contenu public / API anonyme | ||||
| 24 | + | ||||
| 25 | +## Champs récupérés → schéma cible | ||||
| 26 | + | ||||
| 27 | +Aucune donnée attribuable à cette source en BD pour l'instant (clés manquantes ou source en attente) — schéma cible : `creators` + `accounts`. | ||||
| 28 | + | ||||
| 29 | +## Fréquence & budget | ||||
| 30 | + | ||||
| 31 | +- **Cadence déclarée (registre)** : quotidienne (watch), tout dernier du pipeline | ||||
| 32 | +- **Cadence observée** (médiane sync_log) : — | ||||
| 33 | +- **Dernier passage** : 2026-08-18T17:29:46Z — 1391 créateurs, 1507 comptes, +0 / ~1391, 0 erreur(s), 0 s | ||||
| 34 | +- **Throttling** : 0.0 s entre requêtes (`request_delay`) | ||||
| 35 | + | ||||
| 36 | +## Volumétrie & complétude | ||||
| 37 | + | ||||
| 38 | +- **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||||
| 39 | +- **Runs journalisés (60 derniers)** : 1, dont 0 avec erreurs | ||||
| 40 | + | ||||
| 41 | +## Erreurs connues & dépannage | ||||
| 42 | + | ||||
| 43 | +Aucune erreur ni alerte dans les 60 derniers runs journalisés. | ||||
| 44 | + | ||||
| 45 | +Rejouer la source seule : `python3 run.py sync region-bio` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='region-bio' ORDER BY ts DESC LIMIT 5;`). | ||||
| 46 | + | ||||
| 47 | +## Licence, attribution & conditions | ||||
| 48 | + | ||||
| 49 | +- **Cadre d'accès (registre)** : AUCUNE requête — relit les bios publiques déjà en base : ville DÉCLARÉE avec tournure locative (« de Sherbrooke », « based in Montreal ») ou gentilé (« montréalaise ») → région §7 + ville | ||||
| 50 | +- **Profils publics uniquement** : UA identifiable `CreaKaBot/1.0 (+https://www.crea-ka.com/bot; contact@spboucher.ai)`, throttling poli, respect des opt-out (`data/optout.json`) et du volet éthique (`creaka/ethics.py` — mineurs exclus via `is_minor`). | ||||
| 51 | +- Retrait sur demande : contact@spboucher.ai (opt-out honoré à la prochaine ingestion). | ||||
| 52 | + | ||||
| 53 | +## Historique | ||||
| 54 | + | ||||
| 55 | +- 2026-08-18 — plus ancien passage journalisé dans `sync_log` (fenêtre des 60 derniers). | ||||
| 56 | +- 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | ||||
modified
docs/connecteurs/tiktok-profil.md
+10 −10
@@ -1,6 +1,6 @@ | |||||
| 1 | # `tiktok-profil` — connecteur enrichissement (palier 4) | 1 | # `tiktok-profil` — connecteur enrichissement (palier 4) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 06:25 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:01 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : Scrapfly · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : Scrapfly · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -25,31 +25,31 @@ Connecteur ENRICHISSEMENT TikTok — profil public par créateur : abonnés, bad | |||||
| 25 | 25 | ||||
| 26 | ## Champs récupérés → schéma cible | 26 | ## Champs récupérés → schéma cible | ||
| 27 | 27 | ||||
| 28 | −Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `tiktok` (199 comptes en BD, confiance moyenne 0.90). | 28 | +Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `tiktok` (224 comptes en BD, confiance moyenne 0.90). | ||
| 29 | 29 | ||||
| 30 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | 30 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | ||
| 31 | |---|---|---|---| | 31 | |---|---|---|---| | ||
| 32 | | `handle` | Handle | 100 % | enola.bedard | | 32 | | `handle` | Handle | 100 % | enola.bedard | | ||
| 33 | | `url` | URL du profil | 100 % | https://www.tiktok.com/@enola.bedard | | 33 | | `url` | URL du profil | 100 % | https://www.tiktok.com/@enola.bedard | | ||
| 34 | −| `followers` | Abonnés | 65 % | 17100000 | | 34 | +| `followers` | Abonnés | 63 % | 17000000 | | ||
| 35 | −| `verified` | Badge vérifié | 55 % | 1 | | 35 | +| `verified` | Badge vérifié | 59 % | 1 | | ||
| 36 | | `confidence` | Confiance d'identité | 100 % | 0.85 | | 36 | | `confidence` | Confiance d'identité | 100 % | 0.85 | | ||
| 37 | | `signal` | Signal d'identité | 100 % | base_publique | | 37 | | `signal` | Signal d'identité | 100 % | base_publique | | ||
| 38 | −| `metrics` | Métriques détaillées (JSON) | 55 % | {"following": 813, "likes": 438100000, "videos": 2847} | | 38 | +| `metrics` | Métriques détaillées (JSON) | 59 % | {"following": 813, "likes": 438100000, "videos": 2847} | | ||
| 39 | −| `last_checked` | Dernière vérification | 100 % | 2026-08-18T10:07:33Z | | 39 | +| `last_checked` | Dernière vérification | 100 % | 2026-08-18T14:44:09Z | | ||
| 40 | 40 | ||||
| 41 | ## Fréquence & budget | 41 | ## Fréquence & budget | ||
| 42 | 42 | ||||
| 43 | - **Cadence déclarée (registre)** : hebdomadaire (gros créateurs) / mensuelle | 43 | - **Cadence déclarée (registre)** : hebdomadaire (gros créateurs) / mensuelle | ||
| 44 | −- **Cadence observée** (médiane sync_log) : — | 44 | +- **Cadence observée** (médiane sync_log) : ≈ 6.4 h | ||
| 45 | −- **Dernier passage** : 2026-08-18T09:16:06Z — 76 créateurs, 257 comptes, +0 / ~76, 0 erreur(s), 5067 s | 45 | +- **Dernier passage** : 2026-08-18T13:25:43Z — 67 créateurs, 255 comptes, +0 / ~67, 0 erreur(s), 4880 s | ||
| 46 | - **Throttling** : 1.5 s entre requêtes (`request_delay`) | 46 | - **Throttling** : 1.5 s entre requêtes (`request_delay`) | ||
| 47 | 47 | ||||
| 48 | ## Volumétrie & complétude | 48 | ## Volumétrie & complétude | ||
| 49 | 49 | ||||
| 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 51 | −- **Comptes `tiktok` en BD** : 199 — abonnés 65 % · métriques 55 % · dernière vérification 2026-08-18T10:07:33Z | 51 | +- **Comptes `tiktok` en BD** : 224 — abonnés 63 % · métriques 59 % · dernière vérification 2026-08-18T17:29:45Z | ||
| 52 | −- **Runs journalisés (60 derniers)** : 2, dont 0 avec erreurs | 52 | +- **Runs journalisés (60 derniers)** : 3, dont 0 avec erreurs | ||
| 53 | 53 | ||||
| 54 | ## Erreurs connues & dépannage | 54 | ## Erreurs connues & dépannage | ||
| 55 | 55 | ||||
added
docs/connecteurs/twitch-decouverte.md
+72 −0
@@ -0,0 +1,72 @@ | |||||
| 1 | +# `twitch-decouverte` — connecteur decouverte (palier 3) | ||||
| 2 | + | ||||
| 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:01 — ne pas éditer à la main, régénérer._ | ||||
| 4 | + | ||||
| 5 | +**État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 262 · touchés : 262 | ||||
| 6 | + | ||||
| 7 | +## Description de la source | ||||
| 8 | + | ||||
| 9 | +Connecteur DÉCOUVERTE — streamers Twitch québécois via l'API GQL publique du site officiel (Client-ID public, sans clé) : recherche de chaînes par termes QC + répertoire des diffusions en français. Palier 3 (§9). Filtre conservateur : marqueur québécois OBLIGATOIRE dans le nom, la bio ou le titre du stream. | ||||
| 10 | + | ||||
| 11 | +- **Notes (registre)** : vague 4 — marqueur québécois OBLIGATOIRE dans nom/bio/titre du stream ; abonnés, avatar, partenaire/affilié, dernier direct et jeu captés à la source ; niche déduite du jeu (Just Chatting → lifestyle, Music → musique…) | ||||
| 12 | +- **Signal d'identité** : profil_source (0.98) — la chaîne est le compte d'origine de la fiche (colonne `accounts.signal` / `confidence`) | ||||
| 13 | +- **Module** : `creaka/connectors/twitch_decouverte.py` — classe `TwitchDecouverteConnector` (`kind = "discovery"`) | ||||
| 14 | + | ||||
| 15 | +## Accès | ||||
| 16 | + | ||||
| 17 | +- **Accès (registre)** : API GQL publique du site officiel de Twitch (Client-ID public web, sans clé) : recherche searchFor par ~43 termes QC paginée + répertoire des diffusions EN DIRECT en français (streams languages:[FR], 20 pages) | ||||
| 18 | +- **Type d'accès (code)** : pages HTML publiques | ||||
| 19 | +- **Endpoint de base** : — | ||||
| 20 | +- **Pagination** : curseur / continuation | ||||
| 21 | +- **Backend anti-bot / rendu** : requests direct (session UA CreaKaBot, throttling poli) | ||||
| 22 | +- **Politesse** : 1.0 s entre requêtes, timeout 30 s, UA `CreaKaBot/1.0 (+https://www.crea-ka.com/bot)` | ||||
| 23 | +- **Authentification** : clé(s) API requise(s) — voir statut/registre | ||||
| 24 | + | ||||
| 25 | +## Champs récupérés → schéma cible | ||||
| 26 | + | ||||
| 27 | +Source de **découverte** : produit des fiches `Creator` (tables `creators` + `accounts`). Complétude mesurée sur les 262 créateurs découverts par cette source (champ `doc.source`) ; exemple tiré d'une fiche réelle. | ||||
| 28 | + | ||||
| 29 | +| Champ du doc créateur | Contenu | Renseigné | Exemple réel | | ||||
| 30 | +|---|---|---|---| | ||||
| 31 | +| `display_name` | Nom public | 100 % | PlaqueBoyMax | | ||||
| 32 | +| `bio` | Bio | 55 % | for business inquiries: [retiré] | | ||||
| 33 | +| `region` | Région | 4 % | — | | ||||
| 34 | +| `city` | Ville | 4 % | — | | ||||
| 35 | +| `niches` | Niches (liste) | 100 % | lifestyle | | ||||
| 36 | +| `languages` | Langues (liste) | 100 % | fr | | ||||
| 37 | +| `creator_type` | Type de créateur | 100 % | streamer | | ||||
| 38 | +| `primary_platform` | Plateforme principale | 100 % | twitch | | ||||
| 39 | +| `platforms` | Comptes sociaux (liste) | 100 % | twitch:@plaqueboymax | | ||||
| 40 | +| `avatar_url` | Avatar | 100 % | https://static-cdn.jtvnw.net/jtv_user_pictures/14f0fcfd-00d4-4004-9379-93e0c6336f5e-profi… | | ||||
| 41 | +| `total_reach` | Portée totale (abonnés cumulés) | 74 % | 2841225 | | ||||
| 42 | +| `link_in_bio_url` | Lien-en-bio | 0 % | — | | ||||
| 43 | + | ||||
| 44 | +## Fréquence & budget | ||||
| 45 | + | ||||
| 46 | +- **Cadence déclarée (registre)** : quotidienne (watch) — qui est en direct change chaque jour, la couverture s'accumule | ||||
| 47 | +- **Cadence observée** (médiane sync_log) : — | ||||
| 48 | +- **Dernier passage** : 2026-08-18T14:33:13Z — 262 créateurs, 262 comptes, +262 / ~0, 0 erreur(s), 147 s | ||||
| 49 | +- **Throttling** : 1.0 s entre requêtes (`request_delay`) | ||||
| 50 | + | ||||
| 51 | +## Volumétrie & complétude | ||||
| 52 | + | ||||
| 53 | +- **Créateurs découverts par la source** (`doc.source`) : 262 · **fiches touchées** (`source_ids`) : 262 | ||||
| 54 | +- **Complétude clé (découverts)** : niches 100 % · avatar 100 % · portée 74 % · région 4 % | ||||
| 55 | +- **Runs journalisés (60 derniers)** : 1, dont 0 avec erreurs | ||||
| 56 | + | ||||
| 57 | +## Erreurs connues & dépannage | ||||
| 58 | + | ||||
| 59 | +Aucune erreur ni alerte dans les 60 derniers runs journalisés. | ||||
| 60 | + | ||||
| 61 | +Rejouer la source seule : `python3 run.py sync twitch-decouverte` · vérifier `sync_log` (`SELECT * FROM sync_log WHERE source='twitch-decouverte' ORDER BY ts DESC LIMIT 5;`). | ||||
| 62 | + | ||||
| 63 | +## Licence, attribution & conditions | ||||
| 64 | + | ||||
| 65 | +- **Cadre d'accès (registre)** : API GQL publique du site officiel de Twitch (Client-ID public web, sans clé) : recherche searchFor par ~43 termes QC paginée + répertoire des diffusions EN DIRECT en français (streams languages:[FR], 20 pages) | ||||
| 66 | +- **API publique** utilisée selon ses conditions (pas de clé détournée, throttling poli) ; données limitées aux profils publics. | ||||
| 67 | +- Retrait sur demande : contact@spboucher.ai (opt-out honoré à la prochaine ingestion). | ||||
| 68 | + | ||||
| 69 | +## Historique | ||||
| 70 | + | ||||
| 71 | +- 2026-08-18 — plus ancien passage journalisé dans `sync_log` (fenêtre des 60 derniers). | ||||
| 72 | +- 2026-08-18 — vague d'enrichissement : standardisation de la documentation des connecteurs (fiche générée par `scripts/gen_connector_docs.py`). | ||||
modified
docs/connecteurs/twitch.md
+10 −10
@@ -1,6 +1,6 @@ | |||||
| 1 | # `twitch` — connecteur enrichissement (palier 2) | 1 | # `twitch` — connecteur enrichissement (palier 2) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 06:25 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:01 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | 5 | **État : actif** · Famille : enrichissement (enrichment) · Backend : direct · Créateurs découverts : 0 · touchés : 0 | ||
| 6 | 6 | ||||
@@ -25,31 +25,31 @@ Connecteur ENRICHISSEMENT Twitch — profil public par créateur SANS clé via l | |||||
| 25 | 25 | ||||
| 26 | ## Champs récupérés → schéma cible | 26 | ## Champs récupérés → schéma cible | ||
| 27 | 27 | ||||
| 28 | −Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `twitch` (28 comptes en BD, confiance moyenne 0.89). | 28 | +Cible d'**enrichissement** : colonnes de la table `accounts` pour la/les plateforme(s) `twitch` (292 comptes en BD, confiance moyenne 0.97). | ||
| 29 | 29 | ||||
| 30 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | 30 | | Colonne `accounts` | Contenu | Renseignée | Exemple réel | | ||
| 31 | |---|---|---|---| | 31 | |---|---|---|---| | ||
| 32 | | `handle` | Handle | 100 % | xqc | | 32 | | `handle` | Handle | 100 % | xqc | | ||
| 33 | | `url` | URL du profil | 100 % | https://www.twitch.tv/xqc | | 33 | | `url` | URL du profil | 100 % | https://www.twitch.tv/xqc | | ||
| 34 | −| `followers` | Abonnés | 75 % | 12535964 | | 34 | +| `followers` | Abonnés | 98 % | 12535878 | | ||
| 35 | −| `verified` | Badge vérifié | 39 % | 1 | | 35 | +| `verified` | Badge vérifié | 6 % | 1 | | ||
| 36 | | `confidence` | Confiance d'identité | 100 % | 0.85 | | 36 | | `confidence` | Confiance d'identité | 100 % | 0.85 | | ||
| 37 | | `signal` | Signal d'identité | 100 % | base_publique | | 37 | | `signal` | Signal d'identité | 100 % | base_publique | | ||
| 38 | −| `metrics` | Métriques détaillées (JSON) | 68 % | {"last_stream": "2026-08-18T08:03:23.924661Z", "game": "Just Chatting"} | | 38 | +| `metrics` | Métriques détaillées (JSON) | 79 % | {"last_stream": "2026-08-18T08:03:23.924661Z", "game": "Just Chatting"} | | ||
| 39 | −| `last_checked` | Dernière vérification | 100 % | 2026-08-18T10:07:33Z | | 39 | +| `last_checked` | Dernière vérification | 100 % | 2026-08-18T17:05:24Z | | ||
| 40 | 40 | ||||
| 41 | ## Fréquence & budget | 41 | ## Fréquence & budget | ||
| 42 | 42 | ||||
| 43 | - **Cadence déclarée (registre)** : hebdomadaire | 43 | - **Cadence déclarée (registre)** : hebdomadaire | ||
| 44 | −- **Cadence observée** (médiane sync_log) : — | 44 | +- **Cadence observée** (médiane sync_log) : ≈ 3.9 h | ||
| 45 | −- **Dernier passage** : 2026-08-18T09:50:40Z — 24 créateurs, 90 comptes, +0 / ~24, 0 erreur(s), 1 s | 45 | +- **Dernier passage** : 2026-08-18T17:05:40Z — 289 créateurs, 372 comptes, +0 / ~289, 0 erreur(s), 16 s | ||
| 46 | - **Throttling** : 1.0 s entre requêtes (`request_delay`) | 46 | - **Throttling** : 1.0 s entre requêtes (`request_delay`) | ||
| 47 | 47 | ||||
| 48 | ## Volumétrie & complétude | 48 | ## Volumétrie & complétude | ||
| 49 | 49 | ||||
| 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | 50 | - **Créateurs découverts par la source** (`doc.source`) : 0 · **fiches touchées** (`source_ids`) : 0 | ||
| 51 | −- **Comptes `twitch` en BD** : 28 — abonnés 75 % · métriques 68 % · dernière vérification 2026-08-18T10:07:33Z | 51 | +- **Comptes `twitch` en BD** : 292 — abonnés 98 % · métriques 79 % · dernière vérification 2026-08-18T17:28:20Z | ||
| 52 | −- **Runs journalisés (60 derniers)** : 2, dont 0 avec erreurs | 52 | +- **Runs journalisés (60 derniers)** : 4, dont 0 avec erreurs | ||
| 53 | 53 | ||||
| 54 | ## Erreurs connues & dépannage | 54 | ## Erreurs connues & dépannage | ||
| 55 | 55 | ||||
modified
docs/connecteurs/wikidata-qc.md
+10 −10
@@ -1,6 +1,6 @@ | |||||
| 1 | # `wikidata-qc` — connecteur decouverte (palier 3) | 1 | # `wikidata-qc` — connecteur decouverte (palier 3) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 06:25 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:01 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 73 · touchés : 73 | 5 | **État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 73 · touchés : 73 | ||
| 6 | 6 | ||||
@@ -30,30 +30,30 @@ Source de **découverte** : produit des fiches `Creator` (tables `creators` + `a | |||||
| 30 | | Champ du doc créateur | Contenu | Renseigné | Exemple réel | | 30 | | Champ du doc créateur | Contenu | Renseigné | Exemple réel | | ||
| 31 | |---|---|---|---| | 31 | |---|---|---|---| | ||
| 32 | | `display_name` | Nom public | 100 % | xQc | | 32 | | `display_name` | Nom public | 100 % | xQc | | ||
| 33 | −| `bio` | Bio | 75 % | Félix Lengyel, mieux connu sous le pseudonyme « xQc » (Félix Québec), né le 12 novembre 1… | | 33 | +| `bio` | Bio | 77 % | Félix Lengyel, mieux connu sous le pseudonyme « xQc » (Félix Québec), né le 12 novembre 1… | | ||
| 34 | −| `region` | Région | 0 % | — | | 34 | +| `region` | Région | 18 % | Laval | | ||
| 35 | −| `city` | Ville | 0 % | — | | 35 | +| `city` | Ville | 18 % | Laval | | ||
| 36 | | `niches` | Niches (liste) | 100 % | gaming, lifestyle | | 36 | | `niches` | Niches (liste) | 100 % | gaming, lifestyle | | ||
| 37 | | `languages` | Langues (liste) | 100 % | en, fr | | 37 | | `languages` | Langues (liste) | 100 % | en, fr | | ||
| 38 | | `creator_type` | Type de créateur | 100 % | influenceur | | 38 | | `creator_type` | Type de créateur | 100 % | influenceur | | ||
| 39 | | `primary_platform` | Plateforme principale | 100 % | twitch | | 39 | | `primary_platform` | Plateforme principale | 100 % | twitch | | ||
| 40 | | `platforms` | Comptes sociaux (liste) | 99 % | twitch:@xqc, youtube:@UCmDTrq0LNgPodDOFZiSbsww, x:@xqc | | 40 | | `platforms` | Comptes sociaux (liste) | 99 % | twitch:@xqc, youtube:@UCmDTrq0LNgPodDOFZiSbsww, x:@xqc | | ||
| 41 | −| `avatar_url` | Avatar | 71 % | https://scontent-yyz1-1.cdninstagram.com/v/t51.2885-19/387770319_137990486044045_21612287… | | 41 | +| `avatar_url` | Avatar | 73 % | https://scontent-yyz1-1.cdninstagram.com/v/t51.2885-19/387770319_137990486044045_21612287… | | ||
| 42 | −| `total_reach` | Portée totale (abonnés cumulés) | 64 % | 17220047 | | 42 | +| `total_reach` | Portée totale (abonnés cumulés) | 64 % | 17219949 | | ||
| 43 | | `link_in_bio_url` | Lien-en-bio | 19 % | — | | 43 | | `link_in_bio_url` | Lien-en-bio | 19 % | — | | ||
| 44 | 44 | ||||
| 45 | ## Fréquence & budget | 45 | ## Fréquence & budget | ||
| 46 | 46 | ||||
| 47 | - **Cadence déclarée (registre)** : hebdomadaire | 47 | - **Cadence déclarée (registre)** : hebdomadaire | ||
| 48 | −- **Cadence observée** (médiane sync_log) : ≈ 30 min | 48 | +- **Cadence observée** (médiane sync_log) : ≈ 32 min | ||
| 49 | −- **Dernier passage** : 2026-08-18T06:27:51Z — 83 créateurs, 172 comptes, +0 / ~83, 0 erreur(s), 18 s | 49 | +- **Dernier passage** : 2026-08-18T10:36:26Z — 83 créateurs, 172 comptes, +0 / ~83, 0 erreur(s), 39 s | ||
| 50 | - **Throttling** : 2.0 s entre requêtes (`request_delay`) | 50 | - **Throttling** : 2.0 s entre requêtes (`request_delay`) | ||
| 51 | 51 | ||||
| 52 | ## Volumétrie & complétude | 52 | ## Volumétrie & complétude | ||
| 53 | 53 | ||||
| 54 | - **Créateurs découverts par la source** (`doc.source`) : 73 · **fiches touchées** (`source_ids`) : 73 | 54 | - **Créateurs découverts par la source** (`doc.source`) : 73 · **fiches touchées** (`source_ids`) : 73 | ||
| 55 | −- **Complétude clé (découverts)** : niches 100 % · avatar 71 % · portée 64 % · région 0 % | 55 | +- **Complétude clé (découverts)** : niches 100 % · avatar 73 % · portée 64 % · région 18 % | ||
| 56 | −- **Runs journalisés (60 derniers)** : 9, dont 1 avec erreurs | 56 | +- **Runs journalisés (60 derniers)** : 10, dont 1 avec erreurs | ||
| 57 | 57 | ||||
| 58 | ## Erreurs connues & dépannage | 58 | ## Erreurs connues & dépannage | ||
| 59 | 59 | ||||
modified
docs/connecteurs/wikipedia-qc.md
+19 −19
@@ -1,8 +1,8 @@ | |||||
| 1 | # `wikipedia-qc` — connecteur decouverte (palier 3) | 1 | # `wikipedia-qc` — connecteur decouverte (palier 3) | ||
| 2 | 2 | ||||
| 3 | −_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 06:25 — ne pas éditer à la main, régénérer._ | 3 | +_Fiche générée automatiquement par `scripts/gen_connector_docs.py` le 2026-08-18 14:01 — ne pas éditer à la main, régénérer._ | ||
| 4 | 4 | ||||
| 5 | −**État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 76 · touchés : 76 | 5 | +**État : actif** · Famille : decouverte (discovery) · Backend : direct · Créateurs découverts : 84 · touchés : 84 | ||
| 6 | 6 | ||||
| 7 | ## Description de la source | 7 | ## Description de la source | ||
| 8 | 8 | ||||
@@ -25,35 +25,35 @@ Connecteur DÉCOUVERTE — créateurs de contenu québécois recensés dans les | |||||
| 25 | 25 | ||||
| 26 | ## Champs récupérés → schéma cible | 26 | ## Champs récupérés → schéma cible | ||
| 27 | 27 | ||||
| 28 | −Source de **découverte** : produit des fiches `Creator` (tables `creators` + `accounts`). Complétude mesurée sur les 76 créateurs découverts par cette source (champ `doc.source`) ; exemple tiré d'une fiche réelle. | 28 | +Source de **découverte** : produit des fiches `Creator` (tables `creators` + `accounts`). Complétude mesurée sur les 84 créateurs découverts par cette source (champ `doc.source`) ; exemple tiré d'une fiche réelle. | ||
| 29 | 29 | ||||
| 30 | | Champ du doc créateur | Contenu | Renseigné | Exemple réel | | 30 | | Champ du doc créateur | Contenu | Renseigné | Exemple réel | | ||
| 31 | |---|---|---|---| | 31 | |---|---|---|---| | ||
| 32 | −| `display_name` | Nom public | 100 % | Adib Alkhalidey | | 32 | +| `display_name` | Nom public | 100 % | Evil Uno | | ||
| 33 | −| `bio` | Bio | 100 % | Adib Alkhalidey est un humoriste, auteur-compositeur-interprète, réalisateur et acteur qu… | | 33 | +| `bio` | Bio | 100 % | Nicolas Dansereau (born July 20, 1987), better known by the ring name Evil Uno, is a Cana… | | ||
| 34 | −| `region` | Région | 0 % | — | | 34 | +| `region` | Région | 49 % | — | | ||
| 35 | −| `city` | Ville | 0 % | — | | 35 | +| `city` | Ville | 48 % | — | | ||
| 36 | −| `niches` | Niches (liste) | 100 % | humour | | 36 | +| `niches` | Niches (liste) | 100 % | lifestyle | | ||
| 37 | | `languages` | Langues (liste) | 100 % | fr | | 37 | | `languages` | Langues (liste) | 100 % | fr | | ||
| 38 | −| `creator_type` | Type de créateur | 100 % | humoriste | | 38 | +| `creator_type` | Type de créateur | 100 % | youtubeur | | ||
| 39 | −| `primary_platform` | Plateforme principale | 100 % | site-web | | 39 | +| `primary_platform` | Plateforme principale | 100 % | x | | ||
| 40 | −| `platforms` | Comptes sociaux (liste) | 100 % | site-web:@adibalkhalidey.com | | 40 | +| `platforms` | Comptes sociaux (liste) | 100 % | x:@eviluno, instagram:@evil.uno, twitch:@eviluno | | ||
| 41 | −| `avatar_url` | Avatar | 75 % | https://upload.wikimedia.org/wikipedia/commons/thumb/9/9c/IGP6508.jpg/500px-IGP6508.jpg?u… | | 41 | +| `avatar_url` | Avatar | 80 % | https://upload.wikimedia.org/wikipedia/commons/thumb/a/a6/Unoenjoy.jpg/500px-Unoenjoy.jpg… | | ||
| 42 | −| `total_reach` | Portée totale (abonnés cumulés) | 0 % | — | | 42 | +| `total_reach` | Portée totale (abonnés cumulés) | 12 % | 268165 | | ||
| 43 | −| `link_in_bio_url` | Lien-en-bio | 0 % | — | | 43 | +| `link_in_bio_url` | Lien-en-bio | 5 % | http://linktr.ee/eviluno | | ||
| 44 | 44 | ||||
| 45 | ## Fréquence & budget | 45 | ## Fréquence & budget | ||
| 46 | 46 | ||||
| 47 | - **Cadence déclarée (registre)** : hebdomadaire | 47 | - **Cadence déclarée (registre)** : hebdomadaire | ||
| 48 | −- **Cadence observée** (médiane sync_log) : — | 48 | +- **Cadence observée** (médiane sync_log) : ≈ 30 min | ||
| 49 | −- **Dernier passage** : 2026-08-18T10:07:33Z — 111 créateurs, 247 comptes, +76 / ~35, 0 erreur(s), 58 s | 49 | +- **Dernier passage** : 2026-08-18T14:44:09Z — 120 créateurs, 262 comptes, +8 / ~112, 0 erreur(s), 83 s | ||
| 50 | - **Throttling** : 1.0 s entre requêtes (`request_delay`) | 50 | - **Throttling** : 1.0 s entre requêtes (`request_delay`) | ||
| 51 | 51 | ||||
| 52 | ## Volumétrie & complétude | 52 | ## Volumétrie & complétude | ||
| 53 | 53 | ||||
| 54 | −- **Créateurs découverts par la source** (`doc.source`) : 76 · **fiches touchées** (`source_ids`) : 76 | 54 | +- **Créateurs découverts par la source** (`doc.source`) : 84 · **fiches touchées** (`source_ids`) : 84 | ||
| 55 | −- **Complétude clé (découverts)** : niches 100 % · avatar 75 % · portée 0 % · région 0 % | 55 | +- **Complétude clé (découverts)** : niches 100 % · avatar 80 % · portée 12 % · région 49 % | ||
| 56 | −- **Runs journalisés (60 derniers)** : 2, dont 0 avec erreurs | 56 | +- **Runs journalisés (60 derniers)** : 4, dont 0 avec erreurs | ||
| 57 | 57 | ||||
| 58 | ## Erreurs connues & dépannage | 58 | ## Erreurs connues & dépannage | ||
| 59 | 59 | ||||
modified
docs/connecteurs/x-profil.md
+11 −10
Large diff (57 lines) is not loaded by default to keep the page fast.Load diff
modified
docs/connecteurs/youtube-recherche.md
+17 −17
Large diff (71 lines) is not loaded by default to keep the page fast.Load diff
modified
docs/connecteurs/youtube.md
+10 −8
Large diff (50 lines) is not loaded by default to keep the page fast.Load diff