import os import io import sys import asyncio import discord import aiohttp import pandas as pd import gradio as gr import logging from discord.ext import commands # Set up logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) # Environment variable for Discord token DISCORD_TOKEN = os.environ.get("DISCORD_TOKEN", None) if not DISCORD_TOKEN: logger.error("DISCORD_TOKEN not set. Exiting.") sys.exit(1) # Create Discord bot with all intents intents = discord.Intents.all() bot = commands.Bot(command_prefix="!", intents=intents) async def process_row(row, guild, role): """ Process a single CSV row: if the Discord member associated with the row hasn't received the role, add it. """ hf_user_name = row["hf_user_name"] if pd.notna(hf_user_name) and hf_user_name.lower() != "n/a": discord_id = row["discord_user_id"].strip("L") try: member = guild.get_member(int(discord_id)) except Exception as e: logger.error(f"Error converting Discord ID {discord_id}: {e}") return if not member: return if role not in member.roles: try: await member.add_roles(role) logger.info(f"Role added to member: {member}") lunar = bot.get_user(811235357663297546) if lunar: await lunar.send(f"Verified role given to {member}!") await member.send( f"Verification successful! [{member} <---> {row['discord_user_name']}]" ) except Exception as e: logger.error(f"Error processing member {member}: {e}") async def give_verified_roles(): """ Periodically fetch CSV data from Google Sheets and verify roles for members. """ while True: try: async with aiohttp.ClientSession() as session: try: async with session.get( "https://docs.google.com/spreadsheets/d/1C8aLqgCqLYcMiIFf-P_Aosaa03C_WLIB_UyqvjSdWg8/export?format=csv&gid=0", timeout=10, ) as response: if response.status != 200: logger.error(f"Failed to fetch CSV: HTTP {response.status}") await asyncio.sleep(30) continue csv_data = await response.text() # Offload CSV parsing to avoid blocking the event loop. global_df = await asyncio.to_thread(pd.read_csv, io.StringIO(csv_data)) except asyncio.TimeoutError: logger.error("CSV fetch timed out.") await asyncio.sleep(30) continue except Exception as e: logger.error(f"Error fetching CSV: {e}") await asyncio.sleep(30) continue guild = bot.get_guild(879548962464493619) if not guild: logger.error("Guild not found.") await asyncio.sleep(30) continue role = guild.get_role(900063512829755413) if not role: logger.error("Role not found.") await asyncio.sleep(30) continue # Ensure all guild members are cached. await guild.chunk() tasks = [process_row(row, guild, role) for _, row in global_df.iterrows()] await asyncio.gather(*tasks) except Exception as e: logger.error(f"Error in give_verified_roles loop: {e}") await asyncio.sleep(30) # Adjust the sleep interval as needed @bot.event async def on_ready(): logger.info(f"We have logged in as {bot.user}") # Start the background role verification loop bot.loop.create_task(give_verified_roles()) # Optionally, you can add a heartbeat task to log regular status messages. bot.loop.create_task(heartbeat()) async def heartbeat(): """Simple heartbeat task to indicate the bot is still responsive.""" while True: logger.info("Heartbeat: Bot is active.") await asyncio.sleep(60) def greet(name): return "Hello " + name + "!" # Create the Gradio interface demo = gr.Interface(fn=greet, inputs="text", outputs="text") async def main(): # Launch Gradio in a separate thread to avoid blocking gradio_thread = asyncio.to_thread(demo.launch, share=False) await asyncio.gather( bot.start(DISCORD_TOKEN), gradio_thread ) if __name__ == "__main__": try: asyncio.run(main()) except KeyboardInterrupt: logger.info("Shutting down...")