feat(value_rank): 社交边标签改为昵称并增加恶搞关系文案

- 关系图边标签新增双向@次数明细,并在边中点展示

- 标签从 wxid 改为群昵称显示,提升可读性

- 增加恶搞关系标签规则(如双向奔赴、单向上头、单箭头输出等)
This commit is contained in:
liuwei
2026-04-21 15:47:52 +08:00
parent 1742f19120
commit 6f4efcfa72
2 changed files with 64 additions and 4 deletions

View File

@@ -1247,10 +1247,37 @@ class ValueRankPlugin(MessagePluginInterface):
if len(selected_nodes) < 2:
return None
selected_edges: List[Tuple[str, str, float, float]] = []
# 记录每条无向边对应的双向明细次数:
# pair_dir_count[(a,b)] = {"a_to_b": x, "b_to_a": y}
# 这样在图上可以直接标注“双向@次数”,避免只看总互动分看不出方向关系。
pair_dir_count: Dict[Tuple[str, str], Dict[str, int]] = {}
for row in edge_rows:
uid_a = str(row.get("from_user_id") or "").strip()
uid_b = str(row.get("to_user_id") or "").strip()
if not uid_a or not uid_b or uid_a == uid_b:
continue
a, b = (uid_a, uid_b) if uid_a < uid_b else (uid_b, uid_a)
mention_count = int(float(row.get("mention_count_window") or 0.0))
bucket = pair_dir_count.setdefault((a, b), {"a_to_b": 0, "b_to_a": 0})
if uid_a == a and uid_b == b:
bucket["a_to_b"] += mention_count
else:
bucket["b_to_a"] += mention_count
selected_edges: List[Tuple[str, str, float, float, int, int]] = []
for (a, b), data in edge_map.items():
if a in selected_set and b in selected_set:
selected_edges.append((a, b, float(data.get("mention_count", 0.0)), float(data.get("score", 0.0))))
dir_bucket = pair_dir_count.get((a, b), {"a_to_b": 0, "b_to_a": 0})
selected_edges.append(
(
a,
b,
float(data.get("mention_count", 0.0)),
float(data.get("score", 0.0)),
int(dir_bucket.get("a_to_b", 0)),
int(dir_bucket.get("b_to_a", 0)),
)
)
if not selected_edges:
return None
@@ -1274,7 +1301,7 @@ class ValueRankPlugin(MessagePluginInterface):
self,
group_id: str,
selected_nodes: List[str],
selected_edges: List[Tuple[str, str, float, float]],
selected_edges: List[Tuple[str, str, float, float, int, int]],
partner_map: Dict[str, set],
node_score_map: Dict[str, float],
) -> str:
@@ -1303,7 +1330,11 @@ class ValueRankPlugin(MessagePluginInterface):
cm = ContactManager.get_instance()
edge_svg_parts: List[str] = []
for a, b, mention_count, score in selected_edges:
# 双向@标签层:
# 1. 每条边中点标注“a->b / b->a”
# 2. 使用白底半透明标签提升可读性,避免与连线重叠难辨识。
edge_label_parts: List[str] = []
for a, b, mention_count, score, a_to_b_count, b_to_a_count in selected_edges:
ax, ay = pos_map[a]
bx, by = pos_map[b]
normalized = max(0.12, min(score / max_edge_score, 1.0))
@@ -1313,6 +1344,33 @@ class ValueRankPlugin(MessagePluginInterface):
f'<line x1="{ax:.1f}" y1="{ay:.1f}" x2="{bx:.1f}" y2="{by:.1f}" '
f'stroke="rgba(33, 150, 243, {opacity:.3f})" stroke-width="{stroke_width:.2f}" />'
)
# 通过字典序固定方向,确保同一条边每次渲染文案方向一致。
# 标签文案改为“昵称 + 双向次数 + 恶搞关系标签”,不再展示 wxid。
mx, my = (ax + bx) / 2.0, (ay + by) / 2.0
nick_a = cm.get_group_name(group_id, a) or a
nick_b = cm.get_group_name(group_id, b) or b
total_count = int(a_to_b_count) + int(b_to_a_count)
diff_count = abs(int(a_to_b_count) - int(b_to_a_count))
if total_count >= 12 and diff_count <= 2:
relation_tag = "双向奔赴"
elif diff_count >= 8 and max(int(a_to_b_count), int(b_to_a_count)) >= 10:
relation_tag = "单向上头"
elif total_count <= 2:
relation_tag = "点头之交"
elif int(a_to_b_count) == 0 or int(b_to_a_count) == 0:
relation_tag = "单箭头输出"
else:
relation_tag = "互相捧场"
label_text = f"{nick_a}{nick_b} {a_to_b_count}/{b_to_a_count} {relation_tag}"
safe_label = html.escape(label_text)
edge_label_parts.append(
f'<g transform="translate({mx:.1f},{my:.1f})">'
f'<rect x="-170" y="-12" width="340" height="24" rx="8" ry="8" fill="rgba(255,255,255,0.82)"></rect>'
f'<text x="0" y="5" text-anchor="middle" font-size="12" fill="#4E5F7D">{safe_label}</text>'
f'</g>'
)
# 节点头像层拆分为 defs + body 两段:
# 1. defs 内定义每个节点的裁剪路径,避免头像越界;
@@ -1399,6 +1457,7 @@ class ValueRankPlugin(MessagePluginInterface):
"__GROUP_TITLE__": group_title,
"__SUMMARY_TEXT__": summary_text,
"__EDGE_SVG__": "".join(edge_svg_parts),
"__EDGE_LABELS__": "".join(edge_label_parts),
"__NODE_DEFS__": "".join(node_defs_parts),
"__NODE_SVG__": "".join(node_svg_parts),
}

View File

@@ -53,6 +53,7 @@
__NODE_DEFS__
</defs>
__EDGE_SVG__
__EDGE_LABELS__
__NODE_SVG__
</svg>
</div>