Skip to content

Commit 200c60b

Browse files
authored
feat: ワードクラウド生成時に装飾を外し削除されたメッセージを除外 (#3)
* fix: strip_decorationを使用してワードクラウド生成時のテキストを整形 * feat: メッセージ削除時のデータベース更新とギルド退出時のメッセージデータ削除機能を追加 * fix: ギルド削除時に関連設定をデータベースから削除する機能を追加 * fix: メッセージコレクションのtimestampインデックスを削除 * fix: メッセージIDのインデックス設定を修正し、メッセージ削除イベントハンドラーの名前を変更 * feat: メッセージ削除時のデータベース更新機能を追加し、複数メッセージ削除イベントハンドラーを実装 * fix: メッセージ削除時のデータベース処理を改善し、ギルドとチャンネル名の取得を安全に行うよう修正
1 parent 91c2820 commit 200c60b

3 files changed

Lines changed: 100 additions & 3 deletions

File tree

src/cogs/wordcloud.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from datetime import datetime, timedelta
55
from typing import Optional
66
from zoneinfo import ZoneInfo
7-
from libs.visualize import generate_wordcloud_image
7+
from libs.visualize import generate_wordcloud_image, strip_decoration
88
from libs.embed import EmbedHelper
99

1010

@@ -125,7 +125,7 @@ async def wordcloud(
125125
await interaction.followup.send(embed=embed)
126126
return
127127

128-
raw_text = " ".join(doc.get("content", "") for doc in docs)
128+
raw_text = " ".join(strip_decoration(doc.get("content", "")) for doc in docs)
129129

130130
try:
131131
image_buffer = generate_wordcloud_image(raw_text)
@@ -482,7 +482,9 @@ async def _execute_scheduled_wordcloud(
482482
self._update_last_executed(guild_id, channel_id, frequency)
483483
return
484484

485-
raw_text = " ".join(doc.get("content", "") for doc in docs)
485+
raw_text = " ".join(
486+
strip_decoration(doc.get("content", "")) for doc in docs
487+
)
486488

487489
try:
488490
image_buffer = generate_wordcloud_image(raw_text)

src/libs/visualize.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,32 @@ def normalize_text(text: str) -> str:
7575
return unicodedata.normalize("NFKC", normalized)
7676

7777

78+
def strip_decoration(text: str) -> str:
79+
"""テキスト中のコードブロック(```...```, ~~~...~~~)とインラインコード(`...`)、取り消し線(~~...~~)、スポイラー(||...||)を除去して返す。
80+
81+
意図: ワードクラウド生成時にコードのトークンがノイズになるため除去する。
82+
"""
83+
if not text:
84+
return ""
85+
86+
# フェンス付きコードブロック(```...``` や ~~~...~~~)を削除
87+
text = re.sub(r"```.*?```", " ", text, flags=re.S)
88+
text = re.sub(r"~~~.*?~~~", " ", text, flags=re.S)
89+
90+
# インラインコード `...` を削除
91+
text = re.sub(r"`[^`]*`", " ", text)
92+
93+
# 取り消し線 ~~...~~ を削除
94+
text = re.sub(r"~~[^~]*~~", " ", text)
95+
96+
# スポイラー ||...|| を削除
97+
text = re.sub(r"\|\|[^|]*\|\|", " ", text)
98+
99+
# 複数空白を単一空白に
100+
text = re.sub(r"\s+", " ", text)
101+
return text.strip()
102+
103+
78104
def extract_nouns(text: str, tokenizer: Tokenizer | None = None) -> str:
79105
t = tokenizer or Tokenizer()
80106
words_list: list[str] = []

src/main.py

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,11 @@ def setup_db():
3434
bot.db.messages.create_index("user_id")
3535
bot.db.messages.create_index("channel_id")
3636
bot.db.messages.create_index("guild_id")
37+
bot.db.messages.create_index(
38+
"message_id",
39+
unique=True,
40+
partialFilterExpression={"message_id": {"$exists": True}},
41+
)
3742

3843
# TTL Index: 30日後に自動的に削除
3944
bot.db.messages.create_index("timestamp", expireAfterSeconds=30 * 24 * 60 * 60)
@@ -85,6 +90,7 @@ async def on_message(message):
8590
roles = message.author.roles
8691

8792
data = {
93+
"message_id": str(message.id),
8894
"guild_id": str(message.guild.id),
8995
"guild_name": message.guild.name,
9096
"user_id": str(message.author.id),
@@ -101,6 +107,69 @@ async def on_message(message):
101107
await bot.process_commands(message)
102108

103109

110+
def _delete_message_records(message_ids):
111+
normalized_ids = [str(message_id) for message_id in message_ids]
112+
result = bot.db.messages.delete_many({"message_id": {"$in": normalized_ids}})
113+
return result.deleted_count
114+
115+
116+
@bot.event
117+
async def on_guild_remove(guild):
118+
print(f"Left guild: {guild.name} (ID: {guild.id})")
119+
# サーバーから退出した際に、そのサーバーのメッセージデータを削除する
120+
result = bot.db.messages.delete_many({"guild_id": str(guild.id)})
121+
print(
122+
f"Deleted {result.deleted_count} messages from the database for guild {guild.name}"
123+
)
124+
# 設定の削除
125+
settings_result = bot.db.guild_settings.delete_many({"guild_id": str(guild.id)})
126+
print(
127+
f"Deleted {settings_result.deleted_count} guild settings from the database for guild {guild.name}"
128+
)
129+
channel_settings_result = bot.db.channel_settings.delete_many(
130+
{"guild_id": str(guild.id)}
131+
)
132+
print(
133+
f"Deleted {channel_settings_result.deleted_count} channel settings from the database for guild {guild.name}"
134+
)
135+
136+
137+
@bot.event
138+
async def on_raw_message_delete(payload):
139+
"""
140+
メッセージが削除された際のイベントハンドラー
141+
"""
142+
if payload.guild_id is None:
143+
return
144+
145+
deleted_count = _delete_message_records([payload.message_id])
146+
if deleted_count > 0:
147+
guild = bot.get_guild(payload.guild_id)
148+
channel = bot.get_channel(payload.channel_id)
149+
guild_name = guild.name if guild is not None else "Unknown Guild"
150+
channel_name = channel.name if channel is not None else "Unknown Channel"
151+
print(
152+
f"Deleted {deleted_count} message records from the database for deleted message in guild '{guild_name}' (ID: {payload.guild_id}), channel '{channel_name}' (ID: {payload.channel_id})"
153+
)
154+
155+
156+
@bot.event
157+
async def on_raw_bulk_message_delete(payload):
158+
"""
159+
複数メッセージが一度に削除された際のイベントハンドラー
160+
"""
161+
if payload.guild_id is None:
162+
return
163+
164+
deleted_count = _delete_message_records(payload.message_ids)
165+
if deleted_count > 0:
166+
guild = bot.get_guild(payload.guild_id)
167+
guild_name = guild.name if guild is not None else "Unknown Guild"
168+
print(
169+
f"Deleted {deleted_count} message records from the database for bulk deleted messages in guild '{guild_name}' (ID: {payload.guild_id})"
170+
)
171+
172+
104173
@bot.event
105174
async def on_guild_join(guild):
106175
print(f"Joined guild: {guild.name} (ID: {guild.id})")

0 commit comments

Comments
 (0)