First Initialization

This commit is contained in:
aliakbar
2026-06-29 15:32:24 +03:30
commit 29c2add74e
105 changed files with 13177 additions and 0 deletions
+216
View File
@@ -0,0 +1,216 @@
import networkx as nx
from pyvis.network import Network
import textwrap
import ast
import re
class Visualizer:
def __init__(self):
pass
def build_graph(self, propositions, relations, scores, output_path):
"""
دریافت ۳ ساختار مجزا (گزاره‌ها، روابط، امتیازها) و رسم گراف
"""
net = Network(height="100vh", width="100%", bgcolor="#1a1a1a", font_color="white", directed=True,
cdn_resources="in_line")
# ساخت دیکشنری‌های کمکی برای جستجوی سریع
prop_dict = {p['proposition_id']: p['proposition_text'] for p in propositions}
score_dict = {s['relation_id']: s['score'] for s in scores}
# 1. اضافه کردن نودها (گزاره‌ها)
for p_id, text in prop_dict.items():
wrapped_text = "\n".join(textwrap.wrap(text, width=40))
net.add_node(
p_id,
label=f"گزاره {p_id}",
title=wrapped_text, # نمایش متن کامل هنگام هاور پیش‌فرض
shape="box",
color={"background": "#264653", "border": "#1b3039", "highlight": {"background": "#2a9d8f"}},
font={"face": "B Nazanin, Tahoma, Arial", "size": 16, "color": "white"}
)
# 2. اضافه کردن یال‌ها (روابط)
for rel in relations:
source = rel['source_proposition_id']
target = rel['target_proposition_id']
rel_id = rel['relation_id']
rel_type = rel['relation_type']
score = score_dict.get(rel_id, 0)
wrapped_rel = "\n".join(textwrap.wrap(rel_type, width=40))
edge_title = f"امتیاز: {score}\n\nنوع رابطه:\n{wrapped_rel}"
if source in prop_dict and target in prop_dict:
net.add_edge(
source,
target,
label=str(score),
title=edge_title, # نمایش متن در سایدبار از طریق رویداد
width=max(2, int(score) / 2), # ضخامت خط بر اساس امتیاز
color={"color": "#e9c46a", "highlight": "#f4a261"},
font={"align": "middle", "color": "#ffea00", "background": "#1a1a1a"},
arrows={"to": {"enabled": True, "scaleFactor": 1.2}}
)
# تنظیمات گراف و فعال‌سازی هاور
net.set_options("""
{
"physics": {
"forceAtlas2Based": {
"gravitationalConstant": -50,
"centralGravity": 0.01,
"springLength": 150,
"springConstant": 0.08
},
"minVelocity": 0.75,
"solver": "forceAtlas2Based"
},
"interaction": { "hover": true, "navigationButtons": true }
}
""")
html_content = net.generate_html(output_path)
# تزریق اسکریپت برای ارسال اطلاعات هاور به سایدبار صفحه وب
hover_js = """
<script type="text/javascript">
network.on("hoverEdge", function (params) {
var edgeData = edges.get(params.edge);
window.parent.postMessage({ type: 'hoverEdge', info: edgeData.title }, '*');
});
network.on("hoverNode", function (params) {
var nodeData = nodes.get(params.node);
window.parent.postMessage({ type: 'hoverNode', info: nodeData.title }, '*');
});
network.on("blurEdge", function (params) {
window.parent.postMessage({ type: 'blur', info: '' }, '*');
});
network.on("blurNode", function (params) {
window.parent.postMessage({ type: 'blur', info: '' }, '*');
});
</script>
</body>
"""
html_content = html_content.replace('</body>', hover_js)
with open(output_path, "w", encoding="utf-8") as f:
f.write(html_content)
return output_path
def build_tree(self, tree_data_list, output_path):
net = Network(height="100vh", width="100%", bgcolor="#1a1a1a", font_color="white", directed=True,
cdn_resources="in_line")
valid_node_ids = set()
for node_data in tree_data_list:
node_id = str(node_data.get('segment_id', '')).strip()
valid_node_ids.add(node_id)
level = int(node_data.get('level', 0))
full_text = node_data.get('semantic_unit', 'بدون متن')
wrapped_text = "\n".join(textwrap.wrap(full_text, width=40))
raw_sentences = node_data.get('original_sentences', [])
if isinstance(raw_sentences, str):
try:
raw_sentences = ast.literal_eval(raw_sentences)
except (ValueError, SyntaxError):
pass
if isinstance(raw_sentences, list):
sentences_str = "<br><br>".join(raw_sentences)
num_sentences = len(raw_sentences)
else:
sentences_str = str(raw_sentences)
num_sentences = len([s for s in sentences_str.split('.') if s.strip()]) if sentences_str else 0
# متمایز کردن رنگ برگ‌ها (سطح 0) از نودهای میانی
bg_color = "#e76f51" if level == 0 else "#2a9d8f"
net.add_node(
node_id,
label=f"سطح {level}\n{node_id}",
title=wrapped_text,
level=level,
shape="box",
sentences=sentences_str,
num_sentences=num_sentences,
color={"background": bg_color, "border": "#1f6e64", "highlight": {"background": "#3bc2b4"}},
font={"face": "B Nazanin, Tahoma, Arial", "size": 16}
)
for node_data in tree_data_list:
node_id = str(node_data.get('segment_id', '')).strip()
parent_val = node_data.get('parent_segment_id')
if parent_val and str(parent_val).strip() != "":
clean_parents_str = re.sub(r"[\[\]\'\"\s]", "", str(parent_val))
parents_list = clean_parents_str.split(',')
for p_id in parents_list:
if p_id in valid_node_ids:
net.add_edge(
p_id,
node_id,
width=3,
color={"color": "#e9c46a", "highlight": "#f4a261"},
arrows={"to": {"enabled": True, "scaleFactor": 1.2}},
smooth={'type': 'cubicBezier', 'forceDirection': 'vertical', 'roundness': 0.4}
)
net.set_options("""
{
"layout": {
"hierarchical": {
"enabled": true,
"direction": "DU",
"sortMethod": "directed",
"nodeSpacing": 250,
"levelSeparation": 150
}
},
"physics": {
"hierarchicalRepulsion": {
"centralGravity": 0.0,
"springLength": 100,
"springConstant": 0.01,
"nodeDistance": 250,
"damping": 0.09
},
"solver": "hierarchicalRepulsion"
},
"interaction": { "hover": true, "navigationButtons": true }
}
""")
html_content = net.generate_html(output_path)
# تزریق اسکریپت کلیک درخت
click_js = """
<script type="text/javascript">
network.on("click", function (params) {
if (params.nodes.length > 0) {
var nodeId = params.nodes[0];
var clickedNode = nodes.get(nodeId);
window.parent.postMessage({
type: 'node_click',
id: nodeId,
label: clickedNode.label,
summary: clickedNode.title,
sentences: clickedNode.sentences || 'اطلاعات جملات موجود نیست.',
num_sentences: clickedNode.num_sentences || 0
}, '*');
}
});
</script>
</body>
"""
html_content = html_content.replace('</body>', click_js)
with open(output_path, "w", encoding="utf-8") as f:
f.write(html_content)
return output_path