ETHOS / argument_visualizer.py
NextGenC's picture
Upload 10 files
98c2b46 verified
raw
history blame
5.99 kB
# argument_visualizer.py (V2/V3 - Adım 3.1: Düşük Eşik Denemesi)
import networkx as nx
from typing import List, Dict
import data_models
from rich.console import Console
import textwrap
import torch
import torch.nn.functional as F
console = Console()
# Anlamsal Benzerlik Eşiği DÜŞÜRÜLDÜ!
LINKING_SIMILARITY_THRESHOLD = 0.55 # Önceki 0.65 idi, şimdi 0.55 deneyelim
# --- Yardımcı Fonksiyon: Benzerlik Hesaplama (Aynı) ---
def calculate_similarity(emb1: torch.Tensor | None, emb2: torch.Tensor | None) -> float | None:
if emb1 is None or emb2 is None: return None
emb1 = emb1.cpu(); emb2 = emb2.cpu()
if emb1.dim() == 1: emb1 = emb1.unsqueeze(0)
if emb2.dim() == 1: emb2 = emb2.unsqueeze(0)
try: return F.cosine_similarity(emb1, emb2).item()
except Exception as e: console.print(f"[yellow]Warn: Cosine similarity failed: {e}[/yellow]"); return None
# --- Ana Grafik Oluşturma Fonksiyonu (Aynı) ---
def build_argument_graph(
components: List[data_models.ArgumentComponent],
sentence_embeddings: List[torch.Tensor | None]
) -> nx.DiGraph | None:
# ... (Fonksiyonun geri kalanı bir önceki mesajdakiyle aynı)...
if not components: return None
G = nx.DiGraph()
claims = []; premises = []
for i, comp in enumerate(components):
node_id = f"{comp.component_type[0]}{i+1}"
conf_str = f" (Conf: {comp.confidence:.2f})" if comp.confidence is not None else ""
node_label = f"\"{textwrap.shorten(comp.text, width=35, placeholder='...')}\"{conf_str}"
node_shape = "()" if comp.component_type == "Claim" else "[]"
G.add_node(node_id, label=node_label, type=comp.component_type, shape=node_shape, component_index=i, sentence_index=comp.sentence_index)
if comp.component_type == "Claim": claims.append((i, node_id, comp.sentence_index))
else: premises.append((i, node_id, comp.sentence_index))
if not claims or not premises:
console.print(" -> Argument graph requires at least one claim and one premise to show structure.", style="dim")
return G
edges_added = 0
for p_comp_idx, p_node_id, p_sent_idx in premises:
if not (0 <= p_sent_idx < len(sentence_embeddings)): continue
premise_embedding = sentence_embeddings[p_sent_idx]
if premise_embedding is None: continue
for c_comp_idx, c_node_id, c_sent_idx in claims:
if not (0 <= c_sent_idx < len(sentence_embeddings)): continue
claim_embedding = sentence_embeddings[c_sent_idx]
if claim_embedding is None: continue
similarity = calculate_similarity(premise_embedding, claim_embedding)
if similarity is not None and similarity >= LINKING_SIMILARITY_THRESHOLD: # Eşik kontrolü
console.print(f" -> Linking {p_node_id} to {c_node_id} (Similarity: {similarity:.2f})", style="dim")
G.add_edge(p_node_id, c_node_id, relation="supports", similarity=similarity)
edges_added += 1
if edges_added == 0:
console.print(f" -> Could not link any premises to claims based on similarity threshold ({LINKING_SIMILARITY_THRESHOLD}).", style="dim")
console.print(f" -> Built argument graph with {G.number_of_nodes()} nodes and {G.number_of_edges()} edges (Semantic Linking).", style="dim")
return G
# Grafik Formatlama Fonksiyonu (Aynı)
def format_graph_text(graph: nx.DiGraph | None) -> str:
# ... (Fonksiyonun içeriği öncekiyle aynı) ...
if graph is None: return " Argument graph could not be built."
if graph.number_of_nodes() == 0: return " No argument components identified to build a graph."
output_lines = [" Argument Structure (Linked by Semantic Similarity):"]
isolated_nodes = [node for node, degree in graph.degree() if degree == 0 and graph.in_degree(node)==0 and graph.out_degree(node)==0 ]
connected_nodes = set()
if graph.number_of_edges() == 0:
if not isolated_nodes: output_lines.append(" No argument structure links could be determined.")
else:
output_lines.append(" Detected Links (Premise --Supports (Similarity)--> Claim):")
for u, v, data in graph.edges(data=True):
connected_nodes.add(u); connected_nodes.add(v)
u_data = graph.nodes[u]; v_data = graph.nodes[v]
u_shape = u_data.get('shape', '[]'); v_shape = v_data.get('shape', '()')
u_label = u_data.get('label', u); v_label = v_data.get('label', v)
similarity = data.get('similarity')
sim_str = f"(Sim: {similarity:.2f})" if similarity is not None else ""
output_lines.append(f" {u_shape[0]}{u}{u_shape[1]}: {u_label}")
output_lines.append(f" {' ' * len(u)} --Supports {sim_str}--> {v_shape[0]}{v}{v_shape[1]}: {v_label}")
output_lines.append("")
really_isolated = set(isolated_nodes) # Tüm izoleler
if really_isolated:
# Eğer kenar varsa ve izole düğüm varsa başlık ekle
if graph.number_of_edges() > 0:
output_lines.append(" Nodes without determined links:")
# Kenar yoksa zaten yukarıda başlık vardı
elif not isolated_nodes and graph.number_of_edges() == 0 : # Hata durumu, yukarıda handle edildi
pass
elif isolated_nodes and graph.number_of_edges() == 0: # Sadece izole düğümler varsa
output_lines.append(" Nodes (No links determined):")
for node_id in sorted(list(really_isolated)):
data = graph.nodes[node_id]
shape = data.get('shape', '??')
label = data.get('label', node_id)
output_lines.append(f" {shape[0]}{node_id}{shape[1]}: {label}")
output_lines.append(f" [dim](Links based on similarity >= {LINKING_SIMILARITY_THRESHOLD})[/dim]")
return "\n".join(output_lines)