Update app.py
Browse files
app.py
CHANGED
|
@@ -7,6 +7,7 @@ from collections import Counter
|
|
| 7 |
import plotly.express as px
|
| 8 |
import plotly.graph_objects as go
|
| 9 |
import networkx as nx
|
|
|
|
| 10 |
|
| 11 |
# プロフィール画像を取得するヘルパー関数
|
| 12 |
def get_profile_info(client, did_or_handle):
|
|
@@ -51,6 +52,10 @@ def analyze_and_output(my_id, my_pw, target_id, freq_type, progress=gr.Progress(
|
|
| 51 |
for feed_view in response.feed:
|
| 52 |
post = feed_view.post
|
| 53 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
# A. 投稿データの保存(本人のポストのみ)
|
| 55 |
if post.author.handle == target_handle:
|
| 56 |
created_at_raw = getattr(post.record, 'created_at', None)
|
|
@@ -65,9 +70,7 @@ def analyze_and_output(my_id, my_pw, target_id, freq_type, progress=gr.Progress(
|
|
| 65 |
})
|
| 66 |
|
| 67 |
# B. リポストのカウント
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
if feed_view.reason and isinstance(post, PostView):
|
| 71 |
u = post.author.handle
|
| 72 |
if u != target_handle:
|
| 73 |
if u not in interaction_data: interaction_data[u] = Counter()
|
|
@@ -78,12 +81,15 @@ def analyze_and_output(my_id, my_pw, target_id, freq_type, progress=gr.Progress(
|
|
| 78 |
# C. リプライのカウント
|
| 79 |
elif post.author.handle == target_handle:
|
| 80 |
if getattr(feed_view, 'reply', None) and feed_view.reply.parent:
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
|
|
|
|
|
|
|
|
|
| 87 |
|
| 88 |
cursor = response.cursor
|
| 89 |
if not cursor: break
|
|
@@ -91,18 +97,15 @@ def analyze_and_output(my_id, my_pw, target_id, freq_type, progress=gr.Progress(
|
|
| 91 |
# --- 3. いいねのカウント ---
|
| 92 |
try:
|
| 93 |
likes_resp = client.get_actor_likes(actor=profile.did, limit=50)
|
| 94 |
-
|
| 95 |
for l in likes_resp.feed:
|
| 96 |
# 投稿が削除されていない(PostViewである)ことを確認
|
| 97 |
if isinstance(l.post, PostView):
|
| 98 |
u = l.post.author.handle
|
| 99 |
-
|
| 100 |
-
|
| 101 |
-
|
| 102 |
-
|
| 103 |
-
|
| 104 |
-
# いいねもネットワークの線として考慮する
|
| 105 |
-
interactions_for_network.append((target_handle, u))
|
| 106 |
except: pass
|
| 107 |
|
| 108 |
# --- 4. 解析とHTML作成 ---
|
|
@@ -154,7 +157,6 @@ def analyze_and_output(my_id, my_pw, target_id, freq_type, progress=gr.Progress(
|
|
| 154 |
# --- 6. アイコン付きネットワーク図の生成 ---
|
| 155 |
progress(0.8, desc="ネットワーク図を生成中...")
|
| 156 |
G = nx.Graph()
|
| 157 |
-
# 交流のある上位ユーザーを抽出
|
| 158 |
top_interactors = [u for u, c in Counter(reply_users_list + repost_users_list + like_users_list).most_common(12)]
|
| 159 |
nodes = list(set([target_handle] + top_interactors))
|
| 160 |
|
|
@@ -173,7 +175,7 @@ def analyze_and_output(my_id, my_pw, target_id, freq_type, progress=gr.Progress(
|
|
| 173 |
edge_y += [pos[edge[0]][1], pos[edge[1]][1], None]
|
| 174 |
fig_net.add_trace(go.Scatter(x=edge_x, y=edge_y, mode='lines', line=dict(color='#ccc', width=1), hoverinfo='none'))
|
| 175 |
|
| 176 |
-
# ホバー用の透明な点
|
| 177 |
node_hover_texts = []
|
| 178 |
for node in G.nodes():
|
| 179 |
if node == target_handle:
|
|
|
|
| 7 |
import plotly.express as px
|
| 8 |
import plotly.graph_objects as go
|
| 9 |
import networkx as nx
|
| 10 |
+
from atproto_client.models.app.bsky.feed.defs import PostView
|
| 11 |
|
| 12 |
# プロフィール画像を取得するヘルパー関数
|
| 13 |
def get_profile_info(client, did_or_handle):
|
|
|
|
| 52 |
for feed_view in response.feed:
|
| 53 |
post = feed_view.post
|
| 54 |
|
| 55 |
+
# 投稿が正常に取得できている場合のみ処理 (NotFoundPost対策)
|
| 56 |
+
if not isinstance(post, PostView):
|
| 57 |
+
continue
|
| 58 |
+
|
| 59 |
# A. 投稿データの保存(本人のポストのみ)
|
| 60 |
if post.author.handle == target_handle:
|
| 61 |
created_at_raw = getattr(post.record, 'created_at', None)
|
|
|
|
| 70 |
})
|
| 71 |
|
| 72 |
# B. リポストのカウント
|
| 73 |
+
if feed_view.reason:
|
|
|
|
|
|
|
| 74 |
u = post.author.handle
|
| 75 |
if u != target_handle:
|
| 76 |
if u not in interaction_data: interaction_data[u] = Counter()
|
|
|
|
| 81 |
# C. リプライのカウント
|
| 82 |
elif post.author.handle == target_handle:
|
| 83 |
if getattr(feed_view, 'reply', None) and feed_view.reply.parent:
|
| 84 |
+
# 親ポストが削除されている可能性をチェック
|
| 85 |
+
parent_post = feed_view.reply.parent
|
| 86 |
+
if isinstance(parent_post, PostView):
|
| 87 |
+
u = parent_post.author.handle
|
| 88 |
+
if u != target_handle:
|
| 89 |
+
if u not in interaction_data: interaction_data[u] = Counter()
|
| 90 |
+
interaction_data[u]['reply'] += 1
|
| 91 |
+
reply_users_list.append(u)
|
| 92 |
+
interactions_for_network.append((target_handle, u))
|
| 93 |
|
| 94 |
cursor = response.cursor
|
| 95 |
if not cursor: break
|
|
|
|
| 97 |
# --- 3. いいねのカウント ---
|
| 98 |
try:
|
| 99 |
likes_resp = client.get_actor_likes(actor=profile.did, limit=50)
|
|
|
|
| 100 |
for l in likes_resp.feed:
|
| 101 |
# 投稿が削除されていない(PostViewである)ことを確認
|
| 102 |
if isinstance(l.post, PostView):
|
| 103 |
u = l.post.author.handle
|
| 104 |
+
if u != target_handle:
|
| 105 |
+
if u not in interaction_data: interaction_data[u] = Counter()
|
| 106 |
+
interaction_data[u]['like'] += 1
|
| 107 |
+
like_users_list.append(u)
|
| 108 |
+
interactions_for_network.append((target_handle, u))
|
|
|
|
|
|
|
| 109 |
except: pass
|
| 110 |
|
| 111 |
# --- 4. 解析とHTML作成 ---
|
|
|
|
| 157 |
# --- 6. アイコン付きネットワーク図の生成 ---
|
| 158 |
progress(0.8, desc="ネットワーク図を生成中...")
|
| 159 |
G = nx.Graph()
|
|
|
|
| 160 |
top_interactors = [u for u, c in Counter(reply_users_list + repost_users_list + like_users_list).most_common(12)]
|
| 161 |
nodes = list(set([target_handle] + top_interactors))
|
| 162 |
|
|
|
|
| 175 |
edge_y += [pos[edge[0]][1], pos[edge[1]][1], None]
|
| 176 |
fig_net.add_trace(go.Scatter(x=edge_x, y=edge_y, mode='lines', line=dict(color='#ccc', width=1), hoverinfo='none'))
|
| 177 |
|
| 178 |
+
# ホバー用の透明な点
|
| 179 |
node_hover_texts = []
|
| 180 |
for node in G.nodes():
|
| 181 |
if node == target_handle:
|