import discord import threading import os import gradio as gr from discord.ext import commands from slack_sdk import WebClient from slack_sdk.errors import SlackApiError import aiojobs import asyncio from datetime import datetime, timedelta DISCORD_TOKEN = os.getenv('DISCORD_TOKEN') SLACK_BOT_TOKEN = os.getenv('BOT_USER_OAUTH_TOKEN_HF') # real = os.getenv('SLACK_CHANNEL_ID_HF') # test = 'C07B4KNU5BQ' SLACK_CHANNEL_ID = os.getenv('SLACK_CHANNEL_ID_HF') SLACK_CHANNEL_ID_TEST = 'C07B4KNU5BQ' # 1259415803879751700 = test forum # 1019883044724822016 = ask for help ASK_FOR_HELP_CHANNEL_ID = 1019883044724822016 GRADIO_CHANNEL_ID = 1025174734427656283 TRIGGERS = { ("discord bot",): "<@U051DB2754M>", # adam ("autotrain",): "<@U01E3LEC2N7>", # abhishek ("auto train",): "<@U01E3LEC2N7>", # abhishek ("competition",): "<@U01E3LEC2N7>", # abhishek ("competitions",): "<@U01E3LEC2N7>", # abhishek ("sentence-transformers",): "<@U04E4DNPWG7>", # tom aarsen ("sentence_transformers",): "<@U04E4DNPWG7>", # tom aarsen ("setfit",): "<@U04E4DNPWG7>", # tom aarsen ("sentence transformers",): "<@U04E4DNPWG7>", # tom aarsen ("argilla",): "<@U076B8C7G3E>", # david berenstein ("distilabel",): "<@U076B8C7G3E>", # david berenstein ("argilla",): "<@U0766H30T7F>", # natalia elvira ("dataset",): "<@U0766H30T7F>", # natalia elvira ("docs",): "<@U02DATT4C5B>", # steven liu ("documentation",): "<@U02DATT4C5B>", # steven liu ("gradio",): "<@U02NMK75F1V>", # abubakar abid ("argilla",): "<@U076MF65WEM>", # sara han diaz lorenzo ("distilabel",): "<@U076MF65WEM>", # sara han diaz lorenzo ("argilla",): "<@U0765RENPNZ>", # sara han diaz lorenzo ("distilabel",): "<@U0765RENPNZ>", # sara han diaz lorenzo ("dataset", "feedback"): "<@U0768RCHCRY>", # ben burtenshaw } daily_pings = [] intents = discord.Intents.all() intents.messages = True bot = commands.Bot(command_prefix='!', intents=intents) slack_client = WebClient(token=SLACK_BOT_TOKEN) thread_mapping = {} @bot.event async def on_ready(): print(f'Logged in as {bot.user}') @bot.event async def on_message(message): if message.author == bot.user: return # notification bot huggingfolks_role = discord.utils.get(message.guild.roles, id=897376942817419265) bots_role = discord.utils.get(message.guild.roles, id=1258328471609016341) #if huggingfolks_role not in message.author.roles: # no need for ping if we're already discussing if bots_role not in message.author.roles: # bots shouldn't trigger pings for this content = message.content.lower() for trigger, slack_mention in TRIGGERS.items(): if all(word in content for word in trigger): daily_pings.append({ 'author': str(message.author), 'content': message.content, 'channel': message.channel.name, 'url': message.jump_url, 'mention': slack_mention, 'trigger': trigger }) break # Check if the message is in a thread if isinstance(message.channel, discord.Thread): discord_thread_id = message.channel.id # Check if there's an existing Slack thread for this Discord thread # (the only Slack threads created should be for forum channel threads, not just any thread) if discord_thread_id in thread_mapping: slack_thread_ts = thread_mapping[discord_thread_id] # post to slack only if thread already exists post_to_slack_forum_version(message, SLACK_CHANNEL_ID, message.content, message.author, thread_ts=slack_thread_ts) @bot.event async def on_thread_create(thread): # (discord) must be the child thread of the CORRECT forum channel(s) (not just any thread, or any forum channel) if isinstance(thread.parent, discord.ForumChannel) and thread.parent.id in {ASK_FOR_HELP_CHANNEL_ID, GRADIO_CHANNEL_ID}: discord_thread_id = thread.id slack_thread_ts = post_to_slack_create_thread( SLACK_CHANNEL_ID, f"New forum thread started in {thread.parent.name} by {thread.owner}: *{thread.name}*\n" f"{thread.jump_url}" ) if slack_thread_ts: thread_mapping[discord_thread_id] = slack_thread_ts def post_to_slack_forum_version(message, channel, text, author, thread_ts=None): if message.attachments: for attachment in message.attachments: attachment_url = attachment.url text += f"\nAttachment: {attachment_url}" text = f"{author}" + ": " + text try: response = slack_client.chat_postMessage( channel=channel, text=text, thread_ts=thread_ts ) return response['ts'] # Return the Slack message timestamp (thread ID) except SlackApiError as e: print(f"Error posting to Slack: {e.response['error']}") return None def post_to_slack_create_thread(channel, text, thread_ts=None): try: response = slack_client.chat_postMessage( channel=channel, text=text, thread_ts=thread_ts ) return response['ts'] # Return the Slack message timestamp (thread ID) except SlackApiError as e: print(f"Error posting to Slack: {e.response['error']}") return None #---------------------------------------------------------------------------------------------- async def collect_pings(): await bot.wait_until_ready() while not bot.is_closed(): await aiojobs.create_scheduler().spawn(send_daily_pings()) await asyncio.sleep(60) async def send_daily_pings(): global daily_pings if daily_pings: # combine into one message combined_message = '\n'.join(f"{ping['author']} in #{ping['channel']} said: {ping['content']} (link: {ping['url']})" for ping in daily_pings) await post_to_slack(None, combined_message, SLACK_CHANNEL_ID_TEST, None, None, None) daily_pings = [] # reset after posting # pings ------------------------------------------------------------------------------------------- async def post_to_slack(author, content, channel, url, slack_mention, trigger): try: response = slack_client.chat_postMessage( channel=SLACK_CHANNEL_ID, text=f"{slack_mention} (for the keyword -> '{trigger}')\nFrom {author} in channel #{channel}: {content}\n{url}" ) except SlackApiError as e: print(f"Error posting to Slack: {e.response['error']}") # runs discord bot in thread = helps avoid blocking calls async def run_bot(): bot.loop.create_task(collect_pings()) await bot.start(DISCORD_TOKEN) def start_bot_thread(): loop = asyncio.new_event_loop() asyncio.set_event_loop(loop) loop.run_until_complete(run_bot()) threading.Thread(target=start_bot_thread).start() def greet(name): return "Hello " + name + "!" demo = gr.Interface(fn=greet, inputs="text", outputs="text") demo.launch()