Spaces:
Runtime error
Runtime error
| import discord | |
| from discord.ext import commands | |
| import json | |
| import os | |
| import asyncio | |
| from datetime import datetime, timedelta | |
| import re | |
| import logging | |
| from dotenv import load_dotenv | |
| from gradio_client import Client | |
| from concurrent.futures import ThreadPoolExecutor | |
| from gtts import gTTS | |
| import io | |
| import aiohttp | |
| # Set up logging | |
| logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s') | |
| logger = logging.getLogger(__name__) | |
| # Load environment variables | |
| load_dotenv() | |
| TOKEN = os.getenv('DISCORD_TOKEN') | |
| if not TOKEN: | |
| raise ValueError("DISCORD_TOKEN not found in environment variables. Please set it in a .env file.") | |
| # File paths | |
| CONFIG_FILE = 'config.json' | |
| WARNS_FILE = 'warnings.json' | |
| TIMEOUT_FILE = 'timeout_users.json' | |
| LOGS_FILE = 'moderation_logs.json' | |
| BADWORD_COUNTS_FILE = 'badword_counts.json' | |
| # Intents | |
| intents = discord.Intents.default() | |
| intents.members = True | |
| intents.message_content = True | |
| intents.messages = True | |
| intents.guilds = True | |
| intents.voice_states = True | |
| # Initialize bot | |
| bot = commands.Bot(command_prefix='$', intents=intents, case_insensitive=True) | |
| # Data storage | |
| chat_history = {} # key: user_id (str), value: list of messages (dict) | |
| MAX_CHAT_HISTORY = 10 # Limit chat history per user | |
| FFMPEG_PATH = 'ffmpeg' # Update to your FFmpeg path | |
| # ThreadPoolExecutor | |
| executor = ThreadPoolExecutor(max_workers=3) | |
| # System prompt for AI | |
| SYSTEM_PROMPT = """ | |
| You are GaurdineX, a futuristic next-generation AI guardian model built to act as both protector and assistant, designed with a balance of intelligence, security, and futuristic style; you must always respond in a confident, helpful, and clear manner, embodying the traits of a reliable guardian AI—offering smart answers, moderation support, automation capabilities, and insightful guidance with precision, friendliness, and trust, while maintaining a sleek, cyberpunk-futuristic tone that reflects your identity as more than a Discord bot but as a powerful AI model that represents safety, reliability, and cutting-edge intelligence in every interaction. | |
| """ | |
| # Helper functions | |
| def load_data(filename, default_data): | |
| if os.path.exists(filename): | |
| try: | |
| with open(filename, 'r', encoding='utf-8') as f: | |
| return json.load(f) | |
| except Exception as e: | |
| logger.error(f"Error loading {filename}: {e}") | |
| return default_data | |
| return default_data | |
| def save_data(data, filename): | |
| try: | |
| with open(filename, 'w', encoding='utf-8') as f: | |
| json.dump(data, f, indent=4, ensure_ascii=False) | |
| except Exception as e: | |
| logger.error(f"Error saving {filename}: {e}") | |
| def log_action(guild_id, action, user_id, moderator_id, reason): | |
| log_entry = { | |
| "timestamp": datetime.utcnow().isoformat(), | |
| "action": action, | |
| "user_id": str(user_id) if user_id else None, | |
| "moderator_id": str(moderator_id), | |
| "reason": reason | |
| } | |
| logs = load_data(LOGS_FILE, []) | |
| logs.append(log_entry) | |
| save_data(logs, LOGS_FILE) | |
| # Load data | |
| warnings_data = load_data(WARNS_FILE, {}) | |
| timeout_data = load_data(TIMEOUT_FILE, {}) | |
| config_data = load_data(CONFIG_FILE, {}) | |
| badword_counts = load_data(BADWORD_COUNTS_FILE, {}) | |
| async def timeout_check(): | |
| await bot.wait_until_ready() | |
| while not bot.is_closed(): | |
| await asyncio.sleep(60) | |
| current_time = datetime.utcnow() | |
| for guild_id in list(timeout_data.keys()): | |
| if guild_id not in timeout_data: | |
| continue | |
| for user_id in list(timeout_data[guild_id].keys()): | |
| if user_id not in timeout_data[guild_id]: | |
| continue | |
| timeout_info = timeout_data[guild_id][user_id] | |
| try: | |
| timeout_end_time = datetime.fromisoformat(timeout_info['end_time']) | |
| except ValueError: | |
| logger.error(f"Invalid datetime format for user {user_id} in guild {guild_id}") | |
| continue | |
| if current_time >= timeout_end_time: | |
| try: | |
| guild = bot.get_guild(int(guild_id)) | |
| if not guild: | |
| continue | |
| member = guild.get_member(int(user_id)) | |
| if member and member.timed_out_until: | |
| await member.edit(timed_out_until=None) | |
| channel = guild.system_channel | |
| if channel: | |
| lang = config_data.get(guild_id, {}).get('language', 'en') | |
| msg = f"{member.mention} has been automatically un-timed out." if lang == 'en' else f"{member.mention} تم فك التايم آوت عنه بشكل تلقائي." | |
| await channel.send(msg) | |
| if guild_id in timeout_data and user_id in timeout_data[guild_id]: | |
| del timeout_data[guild_id][user_id] | |
| save_data(timeout_data, TIMEOUT_FILE) | |
| except Exception as e: | |
| logger.error(f"Error un-timing out user {user_id}: {e}") | |
| async def on_guild_join(guild): | |
| try: | |
| role = await guild.create_role( | |
| name="🛡 Bot Moderation", | |
| permissions=discord.Permissions(moderate_members=True, kick_members=True, ban_members=True, manage_messages=True), | |
| hoist=True, | |
| mentionable=True | |
| ) | |
| guild_id = str(guild.id) | |
| config_data[guild_id] = { | |
| 'admin_role_id': role.id, | |
| 'allowed_users': [], | |
| 'language': 'en', | |
| 'bad_words': ['fuck', 'shit', 'asshole'] # Add more bad words as needed | |
| } | |
| save_data(config_data, CONFIG_FILE) | |
| logger.info(f"Created '🛡 Bot Moderation' role and set config for guild {guild_id}") | |
| except discord.Forbidden: | |
| logger.error(f"Failed to create role in guild {guild.id}: Missing permissions") | |
| except Exception as e: | |
| logger.error(f"Error in on_guild_join for guild {guild.id}: {e}") | |
| async def apply_timeout(member: discord.Member, duration_delta: timedelta, reason: str): | |
| timeout_end_time = datetime.utcnow() + duration_delta | |
| try: | |
| await member.edit(timed_out_until=timeout_end_time, reason=reason) | |
| guild_id = str(member.guild.id) | |
| user_id = str(member.id) | |
| if guild_id not in timeout_data: | |
| timeout_data[guild_id] = {} | |
| timeout_data[guild_id][user_id] = { | |
| "end_time": timeout_end_time.isoformat(), | |
| "reason": reason | |
| } | |
| save_data(timeout_data, TIMEOUT_FILE) | |
| log_action(guild_id, "timeout", user_id, bot.user.id, reason) | |
| return True | |
| except discord.Forbidden: | |
| return False | |
| async def process_ai_command(ctx, prompt: str): | |
| guild_id = str(ctx.guild.id) | |
| config = config_data.get(guild_id, {}) | |
| lang = config.get('language', 'en') | |
| prompt = prompt.lower().strip() | |
| # Role creation | |
| if 'create role' in prompt or 'ضيف رول' in prompt: | |
| match = re.search(r'name\s+([a-zA-Z0-9\s]+)', prompt) or re.search(r'اسم(ه|ها)?\s+([a-zA-Z0-9\s]+)', prompt) | |
| if match: | |
| role_name = match.group(2 if 'name' in prompt else 2).strip() | |
| try: | |
| new_role = await ctx.guild.create_role(name=role_name) | |
| msg = f"✅ Role **{role_name}** created successfully." if lang == 'en' else f"✅ تم إنشاء رول جديد باسم **{role_name}**." | |
| await ctx.send(msg) | |
| log_action(guild_id, "create_role", None, ctx.author.id, f"Created role {role_name}") | |
| # Handle permissions | |
| perms_match = re.search(r'permissions\s+(.+)', prompt) or re.search(r'و(اديله|اديها|اديهم)?\s+(صلاحيات|برميشناات|برميشن)?\s+(.+)', prompt) | |
| if perms_match: | |
| perms_text = perms_match.group(1 if 'permissions' in prompt else 3).lower() | |
| perms = {} | |
| if 'kick' in perms_text or 'كيك' in perms_text: | |
| perms['kick_members'] = True | |
| if 'ban' in perms_text or 'بان' in perms_text: | |
| perms['ban_members'] = True | |
| if 'timeout' in perms_text or 'تايم آوت' in perms_text or 'mute' in perms_text or 'ميوت' in perms_text: | |
| perms['moderate_members'] = True | |
| if perms: | |
| await new_role.edit(permissions=discord.Permissions(**perms)) | |
| msg = f"✅ Permissions updated for role **{role_name}**." if lang == 'en' else f"✅ تم تعديل صلاحيات رول **{role_name}** حسب طلبك." | |
| await ctx.send(msg) | |
| else: | |
| msg = "🤔 Could not determine permissions." if lang == 'en' else "🤔 معرفتش أحدد الصلاحيات اللي عايزها بالظبط." | |
| await ctx.send(msg) | |
| except discord.Forbidden: | |
| msg = "❌ I don't have permission to create roles." if lang == 'en' else "❌ معلش، ماليش صلاحية أضيف رول." | |
| await ctx.send(msg) | |
| return | |
| # Default AI response | |
| for attempt in range(3): # Retry up to 3 times | |
| try: | |
| client = Client("amd/gpt-oss-120b-chatbot") | |
| loop = asyncio.get_running_loop() | |
| ai_output = await loop.run_in_executor( | |
| executor, | |
| lambda: client.predict( | |
| message=prompt, | |
| system_prompt=SYSTEM_PROMPT, | |
| temperature=0.7, | |
| reasoning_effort="medium", | |
| enable_browsing=False, | |
| api_name="/chat" | |
| ) | |
| ) | |
| match = re.search(r'💬 Response:\s*(.+)', ai_output, re.DOTALL) | |
| response = match.group(1).strip() if match else ai_output.strip() | |
| await ctx.send(response) | |
| return | |
| except Exception as e: | |
| logger.error(f"AI attempt {attempt + 1} failed: {e}") | |
| if attempt < 2: | |
| await asyncio.sleep(2) # Wait before retrying | |
| else: | |
| msg = f"Error communicating with AI after 3 attempts: {e}" if lang == 'en' else f"حصل خطأ أثناء التواصل مع الذكاء الاصطناعي بعد 3 محاولات: {e}" | |
| await ctx.send(msg) | |
| async def chat_with_ai(message: discord.Message): | |
| guild_id = str(message.guild.id) | |
| config = config_data.get(guild_id, {}) | |
| lang = config.get('language', 'en') | |
| text = message.content.lower() | |
| gender = 'neutral' | |
| if 'انا بنت' in text or 'انا انثى' in text or 'عايزة' in text or 'مبسوطة' in text: | |
| gender = 'female' | |
| elif 'انا ولد' in text or 'انا ذكر' in text or 'عايز' in text or 'مبسوط' in text: | |
| gender = 'male' | |
| responses = { | |
| 'neutral': {"en": "I'm doing great, thanks! How about you?", "ar": "أنا كويس جداً. أخبارك إيه؟"}, | |
| 'female': {"en": "Hey there, doing awesome! How about you, queen?", "ar": "الحمد لله تمام يا قمر. عاملة إيه إنتي؟"}, | |
| 'male': {"en": "Yo, I'm good! What's up with you, champ?", "ar": "الحمد لله بخير يا بطل. عامل إيه؟"} | |
| } | |
| if 'how are you' in text or 'عامل ايه' in text or 'اخبارك' in text: | |
| await message.channel.send(responses[gender][lang]) | |
| elif 'who are you' in text or 'مين انت' in text or 'اسمك' in text: | |
| msg = "I'm OS Bot, your friendly Discord moderation assistant!" if lang == 'en' else "أنا بوت إدارة ذكي، تحت أمرك!" | |
| await message.channel.send(msg) | |
| elif 'help me' in text or 'بساعدني' in text or 'ممكن تساعدني' in text: | |
| msg = { | |
| 'female': {"en": "Of course, queen! Let me know what you need.", "ar": "أكيد يا قمر، تحت أمرك. ممكن تكتبي اللي محتاجاه."}, | |
| 'male': {"en": "Sure thing, champ! What's up?", "ar": "أكيد يا معلم، تحت أمرك. ممكن تكتب اللي محتاجه."}, | |
| 'neutral': {"en": "Happy to help! What's up?", "ar": "أكيد، تحت أمرك. ممكن تكتب اللي محتاجه."} | |
| }[gender][lang] | |
| await message.channel.send(msg) | |
| async def on_ready(): | |
| logger.info(f'Logged in as {bot.user.name}') | |
| bot.loop.create_task(timeout_check()) | |
| async def on_message(message): | |
| if message.author.bot: | |
| return | |
| guild_id = str(message.guild.id) | |
| user_id = str(message.author.id) | |
| config = config_data.get(guild_id, {}) | |
| bad_words = config.get('bad_words', []) | |
| content_lower = message.content.lower() | |
| if any(word in content_lower for word in bad_words): | |
| await message.delete() | |
| today = datetime.utcnow().date().isoformat() | |
| if guild_id not in badword_counts: | |
| badword_counts[guild_id] = {} | |
| if user_id not in badword_counts[guild_id]: | |
| badword_counts[guild_id][user_id] = {} | |
| if today not in badword_counts[guild_id][user_id]: | |
| badword_counts[guild_id][user_id][today] = 0 | |
| badword_counts[guild_id][user_id][today] += 1 | |
| count = badword_counts[guild_id][user_id][today] | |
| save_data(badword_counts, BADWORD_COUNTS_FILE) | |
| lang = config.get('language', 'en') | |
| warn_msg = f"{message.author.mention} please watch your language." if lang == 'en' else f"{message.author.mention} رجاءً احترس في كلامك." | |
| await message.channel.send(warn_msg) | |
| if count == 1: | |
| duration_delta = timedelta(minutes=10) | |
| success = await apply_timeout(message.author, duration_delta, "Bad word usage (first offense)") | |
| if success: | |
| msg = f"{message.author.mention} has been timed out for 10 minutes." if lang == 'en' else f"تم وضع تايم آوت لـ {message.author.mention} لمدة 10 دقائق." | |
| await message.channel.send(msg) | |
| elif count >= 10: | |
| duration_delta = timedelta(days=30) | |
| success = await apply_timeout(message.author, duration_delta, "Excessive bad word usage") | |
| if success: | |
| msg = f"{message.author.mention} has been timed out for 1 month." if lang == 'en' else f"تم وضع تايم آوت لـ {message.author.mention} لمدة شهر." | |
| await message.channel.send(msg) | |
| admin_role_id = config.get('admin_role_id') | |
| is_admin = False | |
| if admin_role_id: | |
| admin_role = discord.utils.get(message.guild.roles, id=admin_role_id) | |
| if admin_role and admin_role in message.author.roles: | |
| is_admin = True | |
| if user_id in config.get('allowed_users', []): | |
| is_admin = True | |
| if is_admin and bot.user.mentioned_in(message): | |
| clean_content = message.content.replace(f'<@!{bot.user.id}>', '').strip() | |
| await process_ai_command(message.channel, clean_content) | |
| return | |
| if bot.user.mentioned_in(message) or message.channel.name.startswith('general'): | |
| await chat_with_ai(message) | |
| await bot.process_commands(message) | |
| async def on_close(): | |
| executor.shutdown(wait=True) | |
| logger.info("Bot is shutting down and ThreadPoolExecutor is closed.") | |
| async def is_mod(ctx): | |
| guild_id = str(ctx.guild.id) | |
| config = config_data.get(guild_id, {}) | |
| admin_role_id = config.get('admin_role_id') | |
| if admin_role_id: | |
| role = ctx.guild.get_role(admin_role_id) | |
| if role and role in ctx.author.roles: | |
| return True | |
| allowed_users = config.get('allowed_users', []) | |
| if str(ctx.author.id) in allowed_users: | |
| return True | |
| if ctx.author.guild_permissions.administrator: | |
| return True | |
| return False | |
| async def access(ctx, role: discord.Role): | |
| guild_id = str(ctx.guild.id) | |
| if guild_id not in config_data: | |
| config_data[guild_id] = {} | |
| config_data[guild_id]['admin_role_id'] = role.id | |
| save_data(config_data, CONFIG_FILE) | |
| lang = config_data[guild_id].get('language', 'en') | |
| msg = f"✅ Role **{role.name}** set as admin role." if lang == 'en' else f"✅ تم تحديد رول **{role.name}** لكي يكون لها صلاحية استخدام أوامر البوت الإدارية." | |
| await ctx.send(msg) | |
| log_action(guild_id, "set_admin_role", None, ctx.author.id, f"Set admin role to {role.name}") | |
| async def addaccess(ctx, member: discord.Member): | |
| guild_id = str(ctx.guild.id) | |
| if guild_id not in config_data: | |
| config_data[guild_id] = {} | |
| if 'allowed_users' not in config_data[guild_id]: | |
| config_data[guild_id]['allowed_users'] = [] | |
| user_id = str(member.id) | |
| if user_id not in config_data[guild_id]['allowed_users']: | |
| config_data[guild_id]['allowed_users'].append(user_id) | |
| save_data(config_data, CONFIG_FILE) | |
| lang = config_data[guild_id].get('language', 'en') | |
| msg = f"✅ Added moderation access to {member.mention}." if lang == 'en' else f"✅ تم إضافة صلاحية الإدارة لـ {member.mention}." | |
| await ctx.send(msg) | |
| log_action(guild_id, "add_access", member.id, ctx.author.id, "Added individual mod access") | |
| async def removeaccess(ctx, member: discord.Member): | |
| guild_id = str(ctx.guild.id) | |
| if guild_id in config_data and 'allowed_users' in config_data[guild_id]: | |
| user_id = str(member.id) | |
| if user_id in config_data[guild_id]['allowed_users']: | |
| config_data[guild_id]['allowed_users'].remove(user_id) | |
| save_data(config_data, CONFIG_FILE) | |
| lang = config_data[guild_id].get('language', 'en') | |
| msg = f"✅ Removed moderation access from {member.mention}." if lang == 'en' else f"✅ تم إزالة صلاحية الإدارة من {member.mention}." | |
| await ctx.send(msg) | |
| log_action(guild_id, "remove_access", member.id, ctx.author.id, "Removed individual mod access") | |
| async def setlang(ctx, lang: str): | |
| guild_id = str(ctx.guild.id) | |
| lang = lang.lower() | |
| if lang in ['en', 'ar']: | |
| if guild_id not in config_data: | |
| config_data[guild_id] = {} | |
| config_data[guild_id]['language'] = lang | |
| save_data(config_data, CONFIG_FILE) | |
| msg = "Language set to English." if lang == 'en' else "تم ضبط اللغة على العربية." | |
| await ctx.send(msg) | |
| log_action(guild_id, "set_language", None, ctx.author.id, f"Set language to {lang}") | |
| else: | |
| await ctx.send("Please specify 'en' for English or 'ar' for Arabic.") | |
| async def ban(ctx, member: discord.Member, *, reason=None): | |
| guild_id = str(ctx.guild.id) | |
| lang = config_data.get(guild_id, {}).get('language', 'en') | |
| try: | |
| await member.ban(reason=reason) | |
| msg = f"{member.mention} has been banned." if lang == 'en' else f"{member.mention} تم حظره من السيرفر." | |
| await ctx.send(msg) | |
| log_action(guild_id, "ban", member.id, ctx.author.id, reason or "No reason provided") | |
| except discord.Forbidden: | |
| msg = "❌ I don't have permission to ban members." if lang == 'en' else "❌ ماليش صلاحية أحظر أعضاء." | |
| await ctx.send(msg) | |
| async def unban(ctx, *, member): | |
| guild_id = str(ctx.guild.id) | |
| lang = config_data.get(guild_id, {}).get('language', 'en') | |
| try: | |
| banned_users = [entry async for entry in ctx.guild.bans()] | |
| member_name, member_discriminator = member.split('#') | |
| for ban_entry in banned_users: | |
| user = ban_entry.user | |
| if (user.name, user.discriminator) == (member_name, member_discriminator): | |
| await ctx.guild.unban(user) | |
| msg = f"Unbanned {user.mention}." if lang == 'en' else f"تم فك الحظر عن {user.mention}." | |
| await ctx.send(msg) | |
| log_action(guild_id, "unban", user.id, ctx.author.id, "Unbanned user") | |
| return | |
| msg = f"Could not find {member} in the ban list." if lang == 'en' else f"مقدرتش الاقي {member} في قائمة المحظورين." | |
| await ctx.send(msg) | |
| except discord.Forbidden: | |
| msg = "❌ I don't have permission to unban members." if lang == 'en' else "❌ ماليش صلاحية أفك الحظر عن أعضاء." | |
| await ctx.send(msg) | |
| async def kick(ctx, member: discord.Member, *, reason=None): | |
| guild_id = str(ctx.guild.id) | |
| lang = config_data.get(guild_id, {}).get('language', 'en') | |
| try: | |
| await member.kick(reason=reason) | |
| msg = f"{member.mention} has been kicked." if lang == 'en' else f"{member.mention} تم طرده من السيرفر." | |
| await ctx.send(msg) | |
| log_action(guild_id, "kick", member.id, ctx.author.id, reason or "No reason provided") | |
| except discord.Forbidden: | |
| msg = "❌ I don't have permission to kick members." if lang == 'en' else "❌ ماليش صلاحية أطرد أعضاء." | |
| await ctx.send(msg) | |
| async def timeout(ctx, member: discord.Member, duration_str: str, *, reason="No reason provided"): | |
| guild_id = str(ctx.guild.id) | |
| lang = config_data.get(guild_id, {}).get('language', 'en') | |
| unit = duration_str[-1].lower() | |
| try: | |
| value = int(duration_str[:-1]) | |
| except ValueError: | |
| msg = "Invalid duration format. Use s (seconds), m (minutes), h (hours)." if lang == 'en' else "صيغة المدة غلط. استخدم s (ثانية)، m (دقيقة)، h (ساعة)." | |
| await ctx.send(msg) | |
| return | |
| if unit == 's': | |
| duration_delta = timedelta(seconds=value) | |
| elif unit == 'm': | |
| duration_delta = timedelta(minutes=value) | |
| elif unit == 'h': | |
| duration_delta = timedelta(hours=value) | |
| else: | |
| msg = "Invalid duration format. Use s (seconds), m (minutes), h (hours)." if lang == 'en' else "صيغة المدة غلط. استخدم s (ثانية)، m (دقيقة)، h (ساعة)." | |
| await ctx.send(msg) | |
| return | |
| success = await apply_timeout(member, duration_delta, reason) | |
| if success: | |
| msg = f"Timed out {member.mention} for {duration_str}. Reason: {reason}" if lang == 'en' else f"تم وضع تايم آوت لـ {member.mention} لمدة {duration_str}. السبب: {reason}" | |
| await ctx.send(msg) | |
| else: | |
| msg = f"❌ I don't have permission to timeout {member.mention}." if lang == 'en' else f"❌ ماليش صلاحية أضع تايم آوت لـ {member.mention}." | |
| await ctx.send(msg) | |
| async def untimeout(ctx, member: discord.Member, *, reason="No reason provided"): | |
| guild_id = str(ctx.guild.id) | |
| lang = config_data.get(guild_id, {}).get('language', 'en') | |
| if member.timed_out_until: | |
| try: | |
| await member.edit(timed_out_until=None, reason=reason) | |
| user_id = str(member.id) | |
| if guild_id in timeout_data and user_id in timeout_data[guild_id]: | |
| del timeout_data[guild_id][user_id] | |
| save_data(timeout_data, TIMEOUT_FILE) | |
| msg = f"Removed timeout from {member.mention}." if lang == 'en' else f"تم إزالة التايم آوت من {member.mention}." | |
| await ctx.send(msg) | |
| log_action(guild_id, "untimeout", member.id, ctx.author.id, reason) | |
| except discord.Forbidden: | |
| msg = f"❌ I don't have permission to remove timeout from {member.mention}." if lang == 'en' else f"❌ ماليش صلاحية أزيل التايم آوت من {member.mention}." | |
| await ctx.send(msg) | |
| else: | |
| msg = f"{member.mention} is not timed out." if lang == 'en' else f"{member.mention} ليس في حالة تايم آوت." | |
| await ctx.send(msg) | |
| async def warn(ctx, member: discord.Member, *, reason="No reason provided"): | |
| guild_id = str(ctx.guild.id) | |
| lang = config_data.get(guild_id, {}).get('language', 'en') | |
| user_id = str(member.id) | |
| if guild_id not in warnings_data: | |
| warnings_data[guild_id] = {} | |
| if user_id not in warnings_data[guild_id]: | |
| warnings_data[guild_id][user_id] = [] | |
| warnings_data[guild_id][user_id].append({ | |
| "reason": reason, | |
| "timestamp": datetime.utcnow().isoformat(), | |
| "moderator": str(ctx.author.id) | |
| }) | |
| save_data(warnings_data, WARNS_FILE) | |
| warn_count = len(warnings_data[guild_id][user_id]) | |
| msg = f"Warned {member.mention}. Total warnings: {warn_count}. Reason: {reason}" if lang == 'en' else f"تم تحذير {member.mention}. عدد التحذيرات: {warn_count}. السبب: {reason}" | |
| await ctx.send(msg) | |
| log_action(guild_id, "warn", member.id, ctx.author.id, reason) | |
| # Auto-moderation based on warning count | |
| if warn_count >= 3: | |
| duration_delta = timedelta(hours=1) | |
| success = await apply_timeout(member, duration_delta, "Automatic timeout: 3 warnings") | |
| if success: | |
| msg = f"{member.mention} has been timed out for 1 hour due to 3 warnings." if lang == 'en' else f"تم وضع تايم آوت لـ {member.mention} لمدة ساعة بسبب 3 تحذيرات." | |
| await ctx.send(msg) | |
| if warn_count >= 5: | |
| try: | |
| await ctx.guild.kick(member, reason="Automatic kick: 5 warnings") | |
| msg = f"{member.mention} has been kicked due to 5 warnings." if lang == 'en' else f"تم طرد {member.mention} بسبب 5 تحذيرات." | |
| await ctx.send(msg) | |
| except discord.Forbidden: | |
| msg = "❌ I don't have permission to kick members." if lang == 'en' else "❌ ماليش صلاحية أطرد أعضاء." | |
| await ctx.send(msg) | |
| if warn_count >= 7: | |
| try: | |
| await ctx.guild.ban(member, reason="Automatic ban: 7 warnings") | |
| msg = f"{member.mention} has been banned due to 7 warnings." if lang == 'en' else f"تم حظر {member.mention} بسبب 7 تحذيرات." | |
| await ctx.send(msg) | |
| except discord.Forbidden: | |
| msg = "❌ I don't have permission to ban members." if lang == 'en' else "❌ ماليش صلاحية أحظر أعضاء." | |
| await ctx.send(msg) | |
| async def clear(ctx, amount: int): | |
| guild_id = str(ctx.guild.id) | |
| lang = config_data.get(guild_id, {}).get('language', 'en') | |
| if amount > 1000: | |
| msg = "I can only delete up to 1000 messages at a time." if lang == 'en' else "أقدر أمسح لحد 1000 رسالة بس في المرة الواحدة." | |
| await ctx.send(msg) | |
| return | |
| await ctx.channel.purge(limit=amount + 1) | |
| msg = f"Deleted {amount} messages." if lang == 'en' else f"{amount} رسالة اتمسحت." | |
| await ctx.send(msg, delete_after=5) | |
| log_action(guild_id, "clear", None, ctx.author.id, f"Deleted {amount} messages") | |
| async def serverinfo(ctx): | |
| guild_id = str(ctx.guild.id) | |
| lang = config_data.get(guild_id, {}).get('language', 'en') | |
| guild = ctx.guild | |
| embed = discord.Embed(title="Server Info" if lang == 'en' else "معلومات السيرفر", color=discord.Color.blue()) | |
| embed.add_field(name="Server Name" if lang == 'en' else "اسم السيرفر", value=guild.name, inline=True) | |
| embed.add_field(name="Member Count" if lang == 'en' else "عدد الأعضاء", value=guild.member_count, inline=True) | |
| embed.add_field(name="Created At" if lang == 'en' else "تاريخ الإنشاء", value=guild.created_at.strftime("%Y-%m-%d"), inline=True) | |
| embed.add_field(name="Owner" if lang == 'en' else "المالك", value=guild.owner.mention, inline=True) | |
| await ctx.send(embed=embed) | |
| async def chat(ctx, *, user_message: str): | |
| guild_id = str(ctx.guild.id) | |
| lang = config_data.get(guild_id, {}).get('language', 'en') | |
| user_id = str(ctx.author.id) | |
| if user_id not in chat_history: | |
| chat_history[user_id] = [] | |
| is_reply_to_bot = ctx.message.reference and ctx.message.reference.resolved and ctx.message.reference.resolved.author == bot.user | |
| if is_reply_to_bot: | |
| memory = chat_history[user_id] | |
| else: | |
| memory = [] | |
| chat_history[user_id] = memory | |
| memory.append({"role": "user", "content": user_message}) | |
| if len(memory) > MAX_CHAT_HISTORY: | |
| memory.pop(0) | |
| thinking_msg = await ctx.send("💭 Thinking..." if lang == 'en' else "💭 OS Bot is thinking...") | |
| for attempt in range(3): | |
| try: | |
| client = Client("amd/gpt-oss-120b-chatbot") | |
| loop = asyncio.get_running_loop() | |
| ai_output = await loop.run_in_executor( | |
| executor, | |
| lambda: client.predict( | |
| message=user_message, | |
| system_prompt=SYSTEM_PROMPT, | |
| temperature=0.7, | |
| reasoning_effort="medium", | |
| enable_browsing=False, | |
| api_name="/chat" | |
| ) | |
| ) | |
| match = re.search(r'💬 Response:\s*(.+)', ai_output, re.DOTALL) | |
| final_response = match.group(1).strip() if match else ai_output.strip() | |
| memory.append({"role": "assistant", "content": final_response}) | |
| await thinking_msg.edit(content=final_response) | |
| return | |
| except Exception as e: | |
| logger.error(f"AI attempt {attempt + 1} failed: {e}") | |
| if attempt < 2: | |
| await asyncio.sleep(2) | |
| else: | |
| msg = f"Error communicating with AI after 3 attempts: {e}" if lang == 'en' else f"حصل خطأ أثناء التواصل مع الذكاء الاصطناعي بعد 3 محاولات: {e}" | |
| await thinking_msg.edit(content=msg) | |
| if user_id in chat_history: | |
| del chat_history[user_id] | |
| async def join(ctx): | |
| guild_id = str(ctx.guild.id) | |
| lang = config_data.get(guild_id, {}).get('language', 'en') | |
| if not ctx.author.voice: | |
| msg = "You are not in a voice channel." if lang == 'en' else "أنت مش في أي قناة صوتية." | |
| return await ctx.send(msg) | |
| channel = ctx.author.voice.channel | |
| if ctx.voice_client: | |
| if ctx.voice_client.channel == channel: | |
| msg = "I'm already in this voice channel." if lang == 'en' else "أنا بالفعل في نفس القناة دي." | |
| return await ctx.send(msg) | |
| else: | |
| await ctx.voice_client.move_to(channel) | |
| msg = f"Moved to voice channel: **{channel.name}**." if lang == 'en' else f"تم الانتقال إلى قناة: **{channel.name}**." | |
| return await ctx.send(msg) | |
| await channel.connect() | |
| msg = f"Joined voice channel: **{channel.name}**." if lang == 'en' else f"تم الانضمام إلى قناة: **{channel.name}**." | |
| await ctx.send(msg) | |
| async def leave(ctx): | |
| guild_id = str(ctx.guild.id) | |
| lang = config_data.get(guild_id, {}).get('language', 'en') | |
| if ctx.voice_client: | |
| await ctx.voice_client.disconnect() | |
| msg = "Left the voice channel." if lang == 'en' else "تم الخروج من القناة الصوتية." | |
| await ctx.send(msg) | |
| else: | |
| msg = "I'm not in any voice channel." if lang == 'en' else "أنا مش في أي قناة صوتية حالياً." | |
| await ctx.send(msg) | |
| async def ask(ctx, *, text_query: str): | |
| guild_id = str(ctx.guild.id) | |
| lang = config_data.get(guild_id, {}).get('language', 'en') | |
| if not ctx.voice_client: | |
| msg = "I'm not in a voice channel. Use `$join` to connect me." if lang == 'en' else "أنا مش متصل بقناة صوتية. استخدم `$join` عشان أقدر أنضم." | |
| return await ctx.send(msg) | |
| thinking_msg = await ctx.send("💭 Thinking..." if lang == 'en' else "💭 OS Bot is thinking...") | |
| for attempt in range(3): | |
| try: | |
| client = Client("amd/gpt-oss-120b-chatbot") | |
| loop = asyncio.get_running_loop() | |
| ai_output = await loop.run_in_executor( | |
| executor, | |
| lambda: client.predict( | |
| message=text_query, | |
| system_prompt=SYSTEM_PROMPT, | |
| temperature=0.7, | |
| reasoning_effort="medium", | |
| enable_browsing=False, | |
| api_name="/chat" | |
| ) | |
| ) | |
| match = re.search(r'💬 Response:\s*(.+)', ai_output, re.DOTALL) | |
| final_response = match.group(1).strip() if match else ai_output.strip() | |
| # Save to chat history | |
| user_id = str(ctx.author.id) | |
| if user_id not in chat_history: | |
| chat_history[user_id] = [] | |
| chat_history[user_id].append({"role": "user", "content": text_query}) | |
| chat_history[user_id].append({"role": "assistant", "content": final_response}) | |
| if len(chat_history[user_id]) > MAX_CHAT_HISTORY: | |
| chat_history[user_id].pop(0) | |
| # Convert AI response to voice | |
| try: | |
| logger.info(f"Generating TTS for response: {final_response}") | |
| tts = gTTS(text=final_response, lang='ar' if lang == 'ar' else 'en', slow=False) | |
| voice_buffer = io.BytesIO() | |
| tts.write_to_fp(voice_buffer) | |
| voice_buffer.seek(0) | |
| logger.info(f"TTS audio buffer created, size: {len(voice_buffer.getvalue())} bytes") | |
| ffmpeg_options = { | |
| 'options': '-f s16le -ar 48000 -ac 2' | |
| } | |
| source = discord.FFmpegPCMAudio( | |
| source=voice_buffer, | |
| pipe=True, | |
| executable=FFMPEG_PATH, | |
| **ffmpeg_options | |
| ) | |
| def after_playback(error): | |
| if error: | |
| logger.error(f"Playback error: {error}") | |
| else: | |
| logger.info("Audio playback completed successfully") | |
| ctx.voice_client.play(source, after=after_playback) | |
| while ctx.voice_client.is_playing(): | |
| await asyncio.sleep(1) | |
| await thinking_msg.edit(content=f"Response: `{final_response}`" if lang == 'en' else f"الرد: `{final_response}`") | |
| return | |
| except Exception as e: | |
| logger.error(f"TTS error: {e}") | |
| msg = f"Error converting text to speech: {e}" if lang == 'en' else f"حصل خطأ أثناء تحويل النص إلى صوت: {e}" | |
| await thinking_msg.edit(content=msg) | |
| return | |
| except Exception as e: | |
| logger.error(f"AI attempt {attempt + 1} failed: {e}") | |
| if attempt < 2: | |
| await asyncio.sleep(2) | |
| else: | |
| msg = f"Error communicating with AI after 3 attempts: {e}" if lang == 'en' else f"حصل خطأ أثناء التواصل مع الذكاء الاصطناعي بعد 3 محاولات: {e}" | |
| await thinking_msg.edit(content=msg) | |
| return | |
| # Retry-enabled bot start | |
| async def start_bot(): | |
| for attempt in range(3): | |
| try: | |
| await bot.start(TOKEN) | |
| return | |
| except aiohttp.client_exceptions.ClientConnectorDNSError as e: | |
| logger.error(f"Connection attempt {attempt + 1} failed: {e}") | |
| if attempt < 2: | |
| await asyncio.sleep(5) | |
| else: | |
| logger.error("Failed to connect to Discord after 3 attempts. Exiting.") | |
| raise | |
| # Run the bot with retry | |
| if __name__ == "__main__": | |
| try: | |
| asyncio.run(start_bot()) | |
| except Exception as e: | |
| logger.error(f"Fatal error: {e}") | |