Spaces:
Paused
Paused
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 | |
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...") | |