| <!doctype html> |
| <html> |
| <head> |
| <meta charset="utf-8"> |
| <title>Neo4j Graph Comparison Visualization</title> |
| <style> |
| html, body { |
| font: 16pt Arial; |
| margin: 0; |
| padding: 0; |
| overflow: hidden; |
| } |
| #viz { |
| width: 100vw; |
| height: 100vh; |
| border: 1px solid; |
| background: #f7f9fc; |
| } |
| </style> |
| <script src="neovis.js/dist/neovis.js"></script> |
| <script |
| src="http://code.jquery.com/jquery-3.2.1.min.js" |
| integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" |
| crossorigin="anonymous"> |
| </script> |
| </head> |
| <body onload="draw()"> |
| <div id="viz"></div> |
|
|
| <script> |
| |
| function normalizeLabel(str) { |
| return str.replace(/\\/g, '').replace(/\r?\n/g,' ').replace(/\s+/g,' ').trim() |
| } |
| |
| |
| async function fetchDiff(doc) { |
| const url = doc ? `graph_diff_${doc}.json` : 'graph_diff.json' |
| try { |
| const r = await fetch(url) |
| if (!r.ok) throw new Error(r.statusText) |
| return await r.json() |
| } catch { |
| return { missing_nodes:[], extra_nodes:[], missing_edges:[], extra_edges:[] } |
| } |
| } |
| |
| |
| function draw() { |
| const params = new URLSearchParams(window.location.search) |
| const doc = params.get('doc') |
| |
| |
| const cypher = doc |
| ? `MATCH p=(n:Entity {doc:'${doc}'})-[r:RELATED_TO {doc:'${doc}'}]->(m:Entity {doc:'${doc}'}) RETURN p` |
| : `MATCH p=()-[r:RELATED_TO]->() RETURN p` |
| |
| const viz = new NeoVis.default({ |
| containerId: 'viz', |
| neo4j: { serverUrl:'bolt://localhost:7687', serverUser:'neo4j', serverPassword:'123456789' }, |
| labels: { Entity:{ label:'name' } }, |
| relationships:{ RELATED_TO:{ label:true } }, |
| visConfig: { |
| nodes:{ |
| shape: 'box', |
| size: 25, |
| font: { |
| face: 'arial', |
| size: 20, |
| color: 'black', |
| align: 'center' |
| }, |
| margin: 10, |
| widthConstraint: { |
| minimum: 80, |
| maximum: 200 |
| }, |
| heightConstraint: { |
| minimum: 40 |
| } |
| }, |
| edges:{ |
| arrows: { to: { enabled: true, scaleFactor: 0.8 } }, |
| smooth: { type: 'cubicBezier', roundness: 0.4 }, |
| length: 250, |
| font: { |
| size: 12, |
| align: 'horizontal' |
| } |
| }, |
| layout: { |
| hierarchical: { |
| enabled: true, |
| direction: 'UD', |
| sortMethod: 'directed', |
| levelSeparation: 200, |
| nodeSpacing: 150, |
| treeSpacing: 200, |
| blockShifting: true, |
| edgeMinimization: true, |
| parentCentralization: true |
| } |
| }, |
| physics: { |
| enabled: false, |
| hierarchicalRepulsion: { |
| nodeDistance: 150 |
| } |
| }, |
| interaction: { |
| dragNodes: true, |
| dragView: true, |
| zoomView: true |
| } |
| }, |
| initialCypher: cypher |
| }) |
| |
| viz.registerOnEvent('completed', async () => { |
| const diff = await fetchDiff(doc) |
| const net = viz.network || viz._network |
| if (!net) return |
| |
| |
| |
| |
| const FP_nodes = new Set(diff.extra_nodes.map(normalizeLabel)) |
| const FN_nodes = new Set(diff.missing_nodes.map(normalizeLabel)) |
| const FP_edges = new Set(diff.extra_edges.map(([s,t])=>normalizeLabel(s)+'||'+normalizeLabel(t))) |
| const FN_edges = new Set(diff.missing_edges.map(([s,t])=>normalizeLabel(s)+'||'+normalizeLabel(t))) |
| |
| |
| console.log('📊 Données du fichier graph_diff.json:') |
| console.log('🔴 FP_nodes (hallucinations - ROUGE):', Array.from(FP_nodes)) |
| console.log('🟠 FN_nodes (non détectés - ORANGE):', Array.from(FN_nodes)) |
| console.log('FP_edges:', Array.from(FP_edges)) |
| console.log('FN_edges:', Array.from(FN_edges)) |
| |
| |
| const nodesArr = net.body.data.nodes.get() |
| const edgesArr = net.body.data.edges.get() |
| |
| const testNodeSet = new Set(nodesArr.map(n=>normalizeLabel(n.label))) |
| const testEdgeSet = new Set(edgesArr.map(e => { |
| const f = normalizeLabel(nodesArr.find(n=>n.id===e.from).label) |
| const t = normalizeLabel(nodesArr.find(n=>n.id===e.to).label) |
| return f+'||'+t |
| })) |
| |
| |
| console.log('📈 Nœuds affichés dans le graphe:', Array.from(testNodeSet)) |
| |
| |
| |
| const TP_nodes = new Set([...testNodeSet].filter(lbl => !FP_nodes.has(lbl) && !FN_nodes.has(lbl))) |
| const TP_edges = new Set([...testEdgeSet].filter(key => !FP_edges.has(key) && !FN_edges.has(key))) |
| |
| |
| console.log('✅ TP_nodes (corrects - VERT):', Array.from(TP_nodes)) |
| console.log('🔴 FP_nodes (hallucinations - ROUGE):', Array.from(FP_nodes)) |
| console.log('🟠 FN_nodes (non détectés - ORANGE):', Array.from(FN_nodes)) |
| |
| |
| |
| nodesArr.forEach(n => { |
| const lbl = normalizeLabel(n.label) |
| let bg, bd |
| |
| if (FP_nodes.has(lbl)) { |
| |
| bg = 'red' |
| bd = '#c62828' |
| } else if (FN_nodes.has(lbl)) { |
| |
| bg = 'orange' |
| bd = '#f9a825' |
| } else if (TP_nodes.has(lbl)) { |
| |
| bg = 'green' |
| bd = '#1B5E20' |
| } else { |
| |
| bg = 'gray' |
| bd = '#777' |
| } |
| |
| net.body.data.nodes.update({ |
| id: n.id, |
| color: { background: bg, border: bd }, |
| font: { color: 'black', size: 20 } |
| }) |
| }) |
| |
| |
| FN_nodes.forEach(lbl => { |
| if (!testNodeSet.has(lbl)) { |
| net.body.data.nodes.add({ |
| id: 'FN_node_'+lbl, |
| label: lbl, |
| color: { background: 'orange', border: '#f9a825' }, |
| font: { color: 'black', size: 20 }, |
| shape: 'box', |
| physics: false, |
| x: Math.random() * 500, |
| y: Math.random() * 500 |
| }) |
| } |
| }) |
| |
| |
| edgesArr.forEach(e => { |
| const f = normalizeLabel(nodesArr.find(n=>n.id===e.from).label) |
| const t = normalizeLabel(nodesArr.find(n=>n.id===e.to).label) |
| const key = f+'||'+t |
| let col |
| |
| if (FP_edges.has(key)) { |
| |
| col = 'red' |
| } else if (FN_edges.has(key)) { |
| |
| col = 'orange' |
| } else if (TP_edges.has(key)) { |
| |
| col = 'green' |
| } else { |
| |
| col = 'gray' |
| } |
| |
| net.body.data.edges.update({ |
| id: e.id, |
| color: { color: col }, |
| arrows: { to: { color: col } }, |
| width: 2 |
| }) |
| }) |
| |
| |
| let idx=0 |
| FN_edges.forEach(key => { |
| if (!testEdgeSet.has(key)) { |
| const [fs,ts] = key.split('||') |
| const fromN = nodesArr.find(n=>normalizeLabel(n.label)===fs) |
| const toN = nodesArr.find(n=>normalizeLabel(n.label)===ts) |
| const fromId= fromN?fromN.id:'FN_node_'+fs |
| const toId = toN?toN.id:'FN_node_'+ts |
| net.body.data.edges.add({ |
| id: 'FN_edge_'+(idx++), |
| from: fromId, to: toId, |
| color: { color: 'orange' }, |
| dashes: true, |
| arrows: { to: { color: 'orange' } }, |
| width: 2 |
| }) |
| } |
| }) |
| }) |
| |
| viz.render() |
| } |
| </script> |
| </body> |
| </html> |