Spaces:
Sleeping
Sleeping
File size: 3,863 Bytes
ef78361 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | """UMAP ํ ํฝ ๋งต ์๊ฐํ (Plotly scatter).
snapshot.coordinates: [{cluster_id, x, y, size, label}]
clusters: [{id, cluster_label, attention_score, citation_density, opportunity_score, fanout_count, ...}]
"""
import streamlit as st
import plotly.graph_objects as go
def render_topic_map(clusters: list[dict], snapshot: dict | None, frame: str = "all"):
"""Render UMAP 2D scatter from snapshot coordinates + cluster metadata."""
if not snapshot or not snapshot.get("coordinates"):
st.info("UMAP ์ขํ ๋ฐ์ดํฐ๊ฐ ์์ต๋๋ค. ํด๋ฌ์คํฐ๋ง ์คํ ํ ์์ฑ๋ฉ๋๋ค.")
return
# Frame-specific guide
if frame == "demand":
st.markdown("""
๊ฐ ์ ์ ํ๋์ **Demand ํ ํฝ** (ChatGPT sub-query ๊ทธ๋ฃน)์
๋๋ค.
- **์ ํฌ๊ธฐ**: ํด๋น ํ ํฝ์ fanout ์ (ํด์๋ก ์๋น์๊ฐ ์์ฃผ ๋ฌป๋ ํ ํฝ)
- **์ ์์**: ๊ธฐํ ์ ์ (๋นจ๊ฐ = ๊ธฐํ ํผ, ๋
ธ๋ = ๋ณดํต)
- **๊ฐ๊น์ด ์๋ ์ **: ์ ์ฌํ ๊ฒ์ ์๋์ ํ ํฝ
""")
elif frame == "supply":
st.markdown("""
๊ฐ ์ ์ ํ๋์ **Supply ํ ํฝ** (Gemini citation quote ๊ทธ๋ฃน)์
๋๋ค.
- **์ ํฌ๊ธฐ**: ํด๋น ํ ํฝ์ ์ธ์ฉ ์ (ํด์๋ก AI๊ฐ ์์ฃผ ์ธ์ฉํ๋ ํ ํฝ)
- **์ ์์**: ๊ธฐํ ์ ์ (๋นจ๊ฐ = ๊ธฐํ ํผ, ๋
ธ๋ = ๋ณดํต)
- **๊ฐ๊น์ด ์๋ ์ **: ์ ์ฌํ ์ธ์ฉ ์ฃผ์ ์ ํ ํฝ
""")
else:
st.markdown("""
๊ฐ ์ ์ ํ๋์ **ํ ํฝ**(AI ์ถ๊ฐ ์ง๋ฌธ ๊ทธ๋ฃน)์
๋๋ค.
- **์ ํฌ๊ธฐ**: ํด๋น ํ ํฝ์ AI ์ถ๊ฐ ์ง๋ฌธ ์ (ํด์๋ก AI๊ฐ ์์ฃผ ๋ฌป๋ ํ ํฝ)
- **์ ์์**: ๊ธฐํ ์ ์ (๋นจ๊ฐ = ๊ธฐํ ํผ, ๋
ธ๋ = ๋ณดํต)
- **๊ฐ๊น์ด ์๋ ์ **: ์ ์ฌํ ์ฃผ์ ์ ํ ํฝ
""")
count_label = "Citations" if frame == "supply" else "Fanouts"
coords = snapshot["coordinates"]
# Build cluster lookup by id
cluster_map = {c["id"]: c for c in clusters}
# Merge coordinate data with cluster metadata
xs, ys, sizes, colors, hover_texts = [], [], [], [], []
for pt in coords:
cid = pt.get("cluster_id")
meta = cluster_map.get(cid, {})
xs.append(pt["x"])
ys.append(pt["y"])
fanout_count = pt.get("size", meta.get("fanout_count", 10))
# Normalize size for display (min 5, max 40)
norm_size = max(5, min(40, fanout_count / 5))
sizes.append(norm_size)
opp = float(meta.get("opportunity_score", 0) or 0)
colors.append(opp)
label = meta.get("cluster_label") or f"Cluster {pt.get('label', '?')}"
attn = float(meta.get("attention_score", 0) or 0)
density = float(meta.get("citation_density", 0) or 0)
hover_texts.append(
f"<b>{label}</b><br>"
f"Attention: {attn:.4f}<br>"
f"Density: {density:.4f}<br>"
f"Opportunity: {opp:.4f}<br>"
f"{count_label}: {fanout_count}"
)
fig = go.Figure()
fig.add_trace(go.Scatter(
x=xs,
y=ys,
mode="markers",
marker=dict(
size=sizes,
color=colors,
colorscale="YlOrRd",
colorbar=dict(title="Opportunity"),
opacity=0.7,
line=dict(width=0.5, color="#333"),
),
text=hover_texts,
hoverinfo="text",
))
fig.update_layout(
title="AI ํ ํฝ ๋งต (UMAP 2D Projection)",
xaxis=dict(title="UMAP-1", showgrid=False, zeroline=False),
yaxis=dict(title="UMAP-2", showgrid=False, zeroline=False),
height=600,
template="plotly_white",
hoverlabel=dict(bgcolor="white", font_size=12),
)
st.plotly_chart(fig, use_container_width=True, config={"displayModeBar": False})
# Algorithm params info
params = snapshot.get("algorithm_params")
if params:
with st.expander("๋ถ์ ์ค์ (๊ธฐ์ ์์ธ)"):
st.json(params)
|