A newer version of the Gradio SDK is available: 6.15.2
Construire une visualisation de sous-graphe JDM
Spécification pour transformer la démarche en outil MCP. Le fichier de référence est plat_asiatique_subgraph.html.
1. Source des données — outils MCP jdm
Tout est construit en interrogeant les outils du serveur MCP jdm (basés sur le dump JeuxDeMots du LIRMM/CNRS). Pour un terme racine T :
Profondeur 1 — voisins directs de T, un appel par relation
disambiguate(T)→ si polysémique, on choisit unsense_idà explorerget_hypernyms(T)→r_isa(catégories)get_hyponyms(T)→r_hypo(exemples)get_synonyms(T)→r_synget_antonyms(T)→r_antoget_characteristics(T)→r_caracget_parts(T)→r_has_partget_locations(T)→r_lieuget_actions_on(T)→r_patient-1(verbes dont T est COD)get_relations_of_type(T, "r_domain")etget_relations_of_type(T, "r_associated")
Chaque appel renvoie une liste {source, relation, target, w, polarity}.
À conserver tel quel :
target: déjà décodé en français lisible — ne pas re-transformer.w: poids consensuel ; sert à filtrer (w ≥ 25) et à épaissir les arêtes.polarity:"affirmation"ou"négation"— à ne pas mélanger.
Profondeur 2 — voisins de voisins
Pour chaque voisin sélectionné N (typiquement top-K par poids), relancer un sous-ensemble des mêmes outils — généralement get_parts, get_locations, get_characteristics — selon le type de N (un nom de plat → ingrédients + lieux ; un ingrédient → caractéristiques ; etc.).
2. Structure du graphe en mémoire
Nœuds
Un par terme unique rencontré.
{
"id": "Y1",
"label": "curry",
"depth": 1,
"kind": "hypo"
}
kindest dérivé de la relation entrante :center | isa | hypo | syn | anto | carac | part | lieu | verb | domain | assoc.
Arêtes
{
"from": "P",
"to": "Y1",
"relation": "r_hypo",
"weight": 70,
"polarity": "affirmation",
"depth": 1
}
- Le
labelaffiché concatène relation et poids, ex."r_hypo 70". depth === 2→ tracer en pointillés gris.polarity === "négation"→ préfixer le label « NON » et/ou utiliser une couleur dédiée (rouge). Ne jamais traiter une négation comme une affirmation.
Filtrage
- Top-K par relation (ici K = 4 à 9 selon la relation).
w ≥ 25par défaut (le seuil JDM standard pour exclure le bruit).- Évite l'explosion combinatoire à profondeur 2.
3. Rendu (vis-network)
Lib
vis-network via CDN (https://unpkg.com/vis-network@9.1.9/standalone/umd/vis-network.min.js). Moteur force-directed prêt à l'emploi, alternative possible : Cytoscape.js (même format JSON).
Centre épinglé
Le nœud racine est fixé au centre :
{ id:'P', x:0, y:0, fixed:{x:true,y:true}, mass:5 }
Les autres nœuds gravitent autour via le solver forceAtlas2Based.
Paramètres physiques clés (à ajuster selon densité)
forceAtlas2Based: {
gravitationalConstant: -90, // répulsion entre nœuds
centralGravity: 0.05, // attire l'ensemble vers le centre
springLength: 110, // longueur d'arête au repos — petit = compact
springConstant: 0.12,
avoidOverlap: 1
}
Physique désactivée après stabilisation
network.once('stabilizationIterationsDone', () => {
network.setOptions({ physics:{ enabled:false } });
network.fit({ animation:{ duration:400 } });
});
Le layout fige une fois calculé, ce qui rend les nœuds draggables sans rebondissement.
Palette par type de relation
| Relation | Couleur (fond / bordure) |
|---|---|
| centre | #212121 / #000 (texte blanc) |
r_isa |
#e3f2fd / #1976d2 (bleu) |
r_hypo |
#e8f5e9 / #388e3c (vert) |
r_carac |
#f3e5f5 / #7b1fa2 (violet) |
r_has_part |
#fff3e0 / #ef6c00 (orange) |
r_lieu |
#e0f7fa / #00838f (cyan) |
r_patient-1 |
#fce4ec / #ad1457 (rose) |
| profondeur 2 | #fafafa / #bdbdbd (gris, arêtes pointillées) |
4. Interactions
Zoom
- Molette : zoom natif vis-network (
zoomSpeed: 0.6,minZoom: 0.1,maxZoom: 4). - Boutons
Zoom +/−:network.moveTo({ scale: network.getScale() * factor }). - Bouton
Recentrer:network.fit({ animation:true }).
Hover — mise en évidence des voisins
network.on('hoverNode', p => highlight(p.node));
network.on('blurNode', resetHighlight);
Dans highlight(focusId) :
const connected = new Set(network.getConnectedNodes(focusId))+ ajouterfocusId.network.getConnectedEdges(focusId)→ set des arêtes voisines.nodes.update(...): opacité 0.2 et texte gris pour tout ce qui n'est pas connecté.edges.update(...): couleur gris très clair pour les arêtes hors voisinage.
resetHighlight restaure les couleurs d'origine en relisant l'attribut dashes (profondeur 2) de chaque arête.
5. Recette pour en faire un outil MCP
API proposée
build_subgraph(
term: str,
depth: int = 2,
top_k_per_relation: int = 6,
min_weight: float = 25,
relations: list[str] | None = None, # défaut : jeu standard ci-dessus
output: Literal["json", "html"] = "html"
) -> str
Étapes
- Désambiguïsation :
disambiguate(term). Si plusieurs sens forts, prendre le top par poids ou exposer un paramètresense_id. - Profondeur 1 : appels parallèles des ~10 outils listés en §1. Agréger en
{nodes, edges}. - Profondeur 2 : pour chaque voisin retenu (top-K par poids), choisir le sous-ensemble d'outils pertinent selon
kind, relancer. Marquer les nœuds/arêtesdepth: 2. - Sérialisation :
output="json"→ retourner{nodes, edges, root, stats}.output="html"→ injecter lesDataSetdans le template de plat_asiatique_subgraph.html et retourner un fichier autonome.
Format vis-network (cible)
const nodes = new vis.DataSet([
{ id:'P', label:'plat asiatique', x:0, y:0, fixed:{x:true,y:true}, mass:5,
color:{ background:'#212121', border:'#000' }, font:{ color:'#fff', size:28 } },
{ id:'Y1', label:'curry', color:{ background:'#e8f5e9', border:'#388e3c' },
font:{ size:22 } },
// ...
]);
const edges = new vis.DataSet([
{ from:'P', to:'Y1', label:'r_hypo 70', arrows:'to',
color:{ color:'#9e9e9e' }, font:{ size:14 } },
// depth 2 : dashes: true
]);
6. Pièges à connaître
- Polysémie : toujours
disambiguateen premier. Pour les termes très ambigus (avocat,souris,police), interroger sur lesense_idplutôt que sur le terme nu — sinon on mélange des branches sans rapport. Cf. mémoirefeedback_jdm_disambiguate_first. - Polarité négative :
polarity === "négation"est fréquente et porteuse de sens. Exemple réel :plat asiatique | r_isa | cuisine asiatiqueavecw = -30, polarity="négation"— JDM marque ici que le plat n'EST PAS la cuisine. La traiter comme une affirmation = erreur factuelle. - Artefacts d'héritage :
canard laqué | r_has_part | plumage (w=146)est hérité du canard vivant — incohérent avec le plat. Un filtre heuristique par cohérence sémantique aide, mais reste un travail manuel ou nécessite un LLM en post-traitement. - Lourdeur de profondeur 3 : limiter
depthà 2 par défaut. Profondeur 3 → graphes illisibles et latence multipliée. - Doublons en français/anglais : JDM mélange parfois
en:music,en:chorusdans les résultats — filtrer le préfixeen:si on veut rester monolingue.