taslim19 commited on
Commit
13fb449
·
1 Parent(s): c44833a

Add NSFW plugin, requirements, and admin-only /nsfw command

Browse files
DragMusic/plugins/plugins/nsfw.py ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import tempfile
3
+ import subprocess
4
+ from PIL import Image, UnidentifiedImageError
5
+ import torch
6
+ import torch.nn.functional as F
7
+ from pyrogram import Client, filters
8
+ from pyrogram.types import Message
9
+ from transformers import AutoModelForImageClassification, ViTImageProcessor
10
+ from DragMusic import app
11
+ from motor.motor_asyncio import AsyncIOMotorClient
12
+ from pyrogram.errors import PeerIdInvalid, UserNotParticipant
13
+ from config import MONGO_DB_URI
14
+
15
+ # Initialize MongoDB client and select database & collection
16
+ db_client = AsyncIOMotorClient(MONGO_DB_URI)
17
+ db = db_client['AnonXDatabase']
18
+ nsfw_chats_collection = db['nsfw_chats']
19
+
20
+ # Logger setup
21
+ LOGGER_ID = -1002471976725
22
+ LOGGER_TOPIC_ID = 6314
23
+
24
+ # Load model and processor
25
+ model = AutoModelForImageClassification.from_pretrained("Falconsai/nsfw_image_detection")
26
+ processor = ViTImageProcessor.from_pretrained("Falconsai/nsfw_image_detection")
27
+
28
+ async def is_nsfw_enabled(chat_id: int) -> bool:
29
+ chat = await nsfw_chats_collection.find_one({"chat_id": chat_id})
30
+ return bool(chat)
31
+
32
+ async def enable_nsfw(chat_id: int):
33
+ await nsfw_chats_collection.update_one({"chat_id": chat_id}, {"$set": {"chat_id": chat_id}}, upsert=True)
34
+
35
+ async def disable_nsfw(chat_id: int):
36
+ await nsfw_chats_collection.delete_one({"chat_id": chat_id})
37
+
38
+ @app.on_message(filters.command("nsfw") & filters.group)
39
+ async def toggle_nsfw_scan(_, message: Message):
40
+ if len(message.command) != 2:
41
+ return await message.reply("Usage: /nsfw enable or /nsfw disable")
42
+
43
+ try:
44
+ member = await app.get_chat_member(message.chat.id, message.from_user.id)
45
+ if not (member.status in ["administrator", "owner"]):
46
+ return await message.reply("Only group admins and the group owner can use this command.")
47
+ except (PeerIdInvalid, UserNotParticipant):
48
+ return await message.reply("You must be a group member to use this command.")
49
+
50
+ arg = message.command[1].lower()
51
+ if arg == "enable":
52
+ await enable_nsfw(message.chat.id)
53
+ await message.reply("Enabled NSFW scanning for this group.")
54
+ elif arg == "disable":
55
+ await disable_nsfw(message.chat.id)
56
+ await message.reply("Disabled NSFW scanning for this group.")
57
+ else:
58
+ await message.reply("Invalid argument. Use /nsfw enable or /nsfw disable.")
59
+
60
+ @app.on_message(filters.command("scan") & filters.reply)
61
+ async def scan_command(_, message: Message):
62
+ if not message.reply_to_message:
63
+ return await message.reply("Reply to an image, video, or sticker to scan.")
64
+ await scan_media(message.reply_to_message, message)
65
+
66
+ @app.on_message(filters.group & (filters.photo | filters.video | filters.sticker))
67
+ async def auto_nsfw_scan(client: Client, message: Message):
68
+ if await is_nsfw_enabled(message.chat.id):
69
+ await scan_media(message, message)
70
+
71
+ async def scan_media(media_msg: Message, reply_msg: Message):
72
+ media = media_msg.photo or media_msg.video or media_msg.sticker
73
+ path = None
74
+ image_path = None
75
+
76
+ try:
77
+ ext = ".jpg"
78
+ if media_msg.video:
79
+ ext = ".mp4"
80
+ elif media_msg.sticker:
81
+ ext = ".webp"
82
+
83
+ with tempfile.NamedTemporaryFile(suffix=ext, delete=False) as temp:
84
+ path = temp.name
85
+
86
+ if hasattr(media, "download"):
87
+ await media.download(file_name=path)
88
+ elif media.file_id:
89
+ await media_msg.download(file_name=path)
90
+ else:
91
+ return await reply_msg.reply("Unable to download media.")
92
+
93
+ if path.endswith((".webm", ".mp4", ".webp")):
94
+ image_path = path + ".png"
95
+ subprocess.run(["ffmpeg", "-i", path, "-frames:v", "1", image_path, "-y"],
96
+ stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
97
+ if not os.path.exists(image_path) or os.path.getsize(image_path) == 0:
98
+ return await reply_msg.reply("Failed to extract image frame.")
99
+ img = Image.open(image_path).convert("RGB")
100
+ else:
101
+ if os.path.getsize(path) == 0:
102
+ return await reply_msg.reply("Downloaded file is empty, cannot scan.")
103
+ img = Image.open(path).convert("RGB")
104
+
105
+ inputs = processor(images=img, return_tensors="pt")
106
+ with torch.no_grad():
107
+ outputs = model(**inputs)
108
+ probs = F.softmax(outputs.logits, dim=1)
109
+ confidence = round(probs[0][1].item() * 100, 2)
110
+ label = "NSFW" if confidence > 50 else "SFW"
111
+
112
+ if label == "NSFW":
113
+ try:
114
+ await media_msg.delete()
115
+ except Exception as e:
116
+ print(f"[NSFW] Failed to delete message: {e}")
117
+
118
+ if confidence > 50:
119
+ await reply_msg.reply(f"NSFW Detected ({confidence}%) — Message deleted.")
120
+ log_text = (
121
+ f"NSFW Content Detected\n"
122
+ f"Chat: {reply_msg.chat.title} ({reply_msg.chat.id})\n"
123
+ f"User: {media_msg.from_user.mention if media_msg.from_user else 'Unknown'}\n"
124
+ f"Confidence: {confidence}%"
125
+ )
126
+ try:
127
+ await app.send_message(
128
+ chat_id=LOGGER_ID,
129
+ text=log_text,
130
+ message_thread_id=LOGGER_TOPIC_ID
131
+ )
132
+ except Exception as log_err:
133
+ print(f"[NSFW Logger Error] {log_err}")
134
+ elif confidence > 50:
135
+ await reply_msg.reply(f"Scan Result: {label} ({confidence}%)")
136
+
137
+ except UnidentifiedImageError:
138
+ print(f"[NSFW Detection Error] cannot identify image file '{path or image_path}'")
139
+ await reply_msg.reply("Failed to read image for scanning.")
140
+ except Exception as e:
141
+ print(f"[NSFW Detection Error] {e}")
142
+ await reply_msg.reply("Error occurred during NSFW scan.")
143
+ finally:
144
+ if path and os.path.exists(path):
145
+ os.remove(path)
146
+ if image_path and os.path.exists(image_path):
147
+ os.remove(image_path)
requirements.txt CHANGED
@@ -41,3 +41,8 @@ bing_image_downloader
41
  openai==0.28
42
  uvicorn
43
  fastapi
 
 
 
 
 
 
41
  openai==0.28
42
  uvicorn
43
  fastapi
44
+ torch
45
+ transformers
46
+ pillow
47
+ # ffmpeg is installed at the system level, but if you want a Python wrapper, uncomment the next line:
48
+ # ffmpeg-python