Spaces:
Running
on
CPU Upgrade
Running
on
CPU Upgrade
| import discord | |
| import threading | |
| import os | |
| import gradio as gr | |
| import time | |
| from discord.ext import commands | |
| from slack_sdk import WebClient | |
| from slack_sdk.errors import SlackApiError | |
| import aiojobs | |
| import asyncio | |
| import re | |
| from datetime import datetime, timedelta | |
| from apscheduler.executors.pool import ThreadPoolExecutor | |
| from apscheduler.schedulers.background import BackgroundScheduler | |
| 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 | |
| ARGILLA_HELP_CHANNEL_ID = 1253640751481356330 | |
| DATA_DISCUSSIONS_CHANNEL_ID = 1217179426002047076 | |
| COMMUNITY_FEEDBACK_CHANNEL_ID = 1353741359059570699 | |
| TRIGGERS = { | |
| ("discord bot",): ["<@U051DB2754M>"], # adam | |
| ("autotrain",): ["<@U01E3LEC2N7>"], # abhishek | |
| ("auto train",): ["<@U01E3LEC2N7>"], # abhishek | |
| ("competition",): ["<@U01E3LEC2N7>"], # abhishek | |
| ("competitions",): ["<@U01E3LEC2N7>"], # abhishek | |
| ("text to speech",): ["<@U039C2GANMV>"], # VB | |
| ("tts",): ["<@U039C2GANMV>"], # VB | |
| ("asr",): ["<@U039C2GANMV>"], # VB | |
| ("musicgen",): ["<@U039C2GANMV>"], # VB | |
| ("whisper",): ["<@U039C2GANMV>"], # VB | |
| ("speech recognition",): ["<@U039C2GANMV>"], # VB | |
| ("bark",): ["<@U039C2GANMV>"], # VB | |
| ("sentence-transformers",): ["<@U04E4DNPWG7>"], # tom aarsen | |
| ("sentence_transformers",): ["<@U04E4DNPWG7>"], # tom aarsen | |
| ("setfit",): ["<@U04E4DNPWG7>"], # tom aarsen | |
| ("sentence transformers",): ["<@U04E4DNPWG7>"], # tom aarsen | |
| ("argilla",): ["<@U076B8C7G3E>", "<@U0766H30T7F>", "<@U076MF65WEM>", "<@U0765RENPNZ>", "<@U0768QEN0LA>"], # david berenstein, natalia elvira, sara han diaz lorenzo, Gabriel Martín Blázquez | |
| ("distilabel",): ["<@U076B8C7G3E>", "<@U076MF65WEM>", "<@U0765RENPNZ>", "<@U0768QEN0LA>", "<@U076271MBUN>"], # david berenstein, sara han diaz lorenzo, Gabriel Martín Blázquez, Agustín Piqueres | |
| ("docs",): ["<@U02DATT4C5B>"], # steven liu | |
| ("documentation",): ["<@U02DATT4C5B>"], # steven liu | |
| ("gradio",): ["<@U02NMK75F1V>", "<@U04FLGQ26PQ>", "<@U03N06UP464>", "<@U04MN4U2WSW>", "<@U02P4GMLVDJ>"], # abubakar abid, yuvraj sharma, freddy boulton, hannah blair, dawood khan | |
| ("dataset", "feedback"): ["<@U0768RCHCRY>"], # ben burtenshaw | |
| ("git ",): ["<@U07F1NP5U0K>"], # ann huang | |
| ("lfs",): ["<@U07F1NP5U0K>"], # ann huang | |
| ("xet",): ["<@U07F1NP5U0K>"], # ann huang | |
| ("upload",): ["<@U07F1NP5U0K>"], # ann huang | |
| ("download",): ["<@U07F1NP5U0K>"], # ann huang | |
| ("stream",): ["<@U07F1NP5U0K>"], # ann huang | |
| } | |
| 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 = {} | |
| async def on_ready(): | |
| print(f'Logged in as {bot.user}') | |
| async def on_message(message): | |
| if message.author == bot.user: | |
| return | |
| # notification bot | |
| print("on_message") | |
| 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 | |
| print(" not bot ") | |
| content = message.content.lower() | |
| for trigger, mentions in TRIGGERS.items(): | |
| if all(word in content for word in trigger): | |
| adjacent_words = extract_adjacent_words(message.content, trigger) | |
| for slack_mention in mentions: | |
| daily_pings.append({ | |
| 'author': str(message.author), | |
| 'content': adjacent_words, | |
| 'channel': message.channel.name, | |
| 'url': message.jump_url, | |
| 'mention': slack_mention, | |
| 'trigger': trigger | |
| }) | |
| print(f"daily pings:{daily_pings}") | |
| # 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) | |
| await bot.process_commands(message) | |
| def post_to_slack_general(message, channel): | |
| text = f"New post in `#give-hf-feedback` by {message.author}: {message.content}" | |
| # Handle attachments if any | |
| if message.attachments: | |
| for attachment in message.attachments: | |
| attachment_url = attachment.url | |
| text += f"\nAttachment: {attachment_url}" | |
| try: | |
| response = slack_client.chat_postMessage( | |
| channel=channel, | |
| text=text, | |
| ) | |
| return response['ts'] | |
| except SlackApiError as e: | |
| print(f"Error posting to Slack: {e.response['error']}") | |
| return None | |
| def extract_adjacent_words(content, trigger): | |
| words = content.split() | |
| pattern = r'\s*\b'.join(map(re.escape, trigger)) | |
| regex = re.compile(pattern, re.IGNORECASE) | |
| match = regex.search(content) | |
| if match: | |
| start, end = match.span() | |
| before = content[:start].split()[-5:] | |
| after = content[end:].split()[:5] | |
| print("--------------------------------------------------------------") | |
| print('...' + ' '.join(before + [match.group()] + after) + '...') | |
| return '...' + ' '.join(before + [match.group()] + after) + '...' | |
| 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, ARGILLA_HELP_CHANNEL_ID, DATA_DISCUSSIONS_CHANNEL_ID, COMMUNITY_FEEDBACK_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, | |
| unfurl_links=False, | |
| unfurl_media=False | |
| ) | |
| 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 list_tags(ctx, forum_channel_id: int): | |
| if ctx.author.id == 811235357663297546: | |
| forum_channel = bot.get_channel(forum_channel_id) | |
| if isinstance(forum_channel, discord.ForumChannel): | |
| tags = forum_channel.available_tags | |
| tag_list = [f"{tag.name} (ID: {tag.id})" for tag in tags] | |
| await ctx.send(f'Available tags: {", ".join(tag_list)}') | |
| # react with ✅ on slack if marked with solved tag on discord | |
| SOLVED_TAG_IDS = {1026743978026094664, 1025179659215847575, 1263095032328753174, 1253641354312155208} | |
| async def on_thread_update(before, after): | |
| if isinstance(after.parent, discord.ForumChannel) and after.parent.id in {ASK_FOR_HELP_CHANNEL_ID, GRADIO_CHANNEL_ID, ARGILLA_HELP_CHANNEL_ID, DATA_DISCUSSIONS_CHANNEL_ID, COMMUNITY_FEEDBACK_CHANNEL_ID}: | |
| before_tag_ids = {tag.id for tag in before.applied_tags} | |
| after_tag_ids = {tag.id for tag in after.applied_tags} | |
| added_tags = after_tag_ids - before_tag_ids | |
| removed_tags = before_tag_ids - after_tag_ids | |
| discord_thread_id = after.id | |
| if discord_thread_id in thread_mapping: | |
| slack_thread_ts = thread_mapping[discord_thread_id] | |
| if any(tag_id in SOLVED_TAG_IDS for tag_id in added_tags): | |
| react_to_slack_message(slack_thread_ts, 'white_check_mark') | |
| if any(tag_id in SOLVED_TAG_IDS for tag_id in removed_tags): | |
| unreact_to_slack_message(slack_thread_ts, 'white_check_mark') | |
| def react_to_slack_message(thread_ts, emoji): | |
| try: | |
| response = slack_client.reactions_add( | |
| channel=SLACK_CHANNEL_ID, | |
| name=emoji, | |
| timestamp=thread_ts | |
| ) | |
| except SlackApiError as e: | |
| print(f"Error reacting to Slack message: {e.response['error']}") | |
| def unreact_to_slack_message(thread_ts, emoji): | |
| try: | |
| response = slack_client.reactions_remove( | |
| channel=SLACK_CHANNEL_ID, | |
| name=emoji, | |
| timestamp=thread_ts | |
| ) | |
| except SlackApiError as e: | |
| print(f"Error removing reaction from Slack message: {e.response['error']}") | |
| #---------------------------------------------------------------------------------------------- | |
| def send_daily_pings(): | |
| global daily_pings | |
| if daily_pings: | |
| print(f"sending daily pings...{daily_pings}") | |
| pings_by_mention = {} | |
| # group pings by who they are meant to notify | |
| for ping in daily_pings: | |
| mention = ping['mention'] | |
| if mention not in pings_by_mention: | |
| pings_by_mention[mention] = [] | |
| pings_by_mention[mention].append(ping) | |
| # send each group of pings in a separate thread | |
| for mention, pings in pings_by_mention.items(): | |
| main_message = slack_client.chat_postMessage( | |
| channel=SLACK_CHANNEL_ID, | |
| text=f"DAILY PINGS FOR {mention} ON {datetime.now().strftime('%d/%m/%Y')}", | |
| unfurl_links=False, | |
| unfurl_media=False | |
| ) | |
| time.sleep(2) # https://api.slack.com/apis/rate-limits | |
| main_ts = main_message['ts'] | |
| for ping in pings: | |
| slack_client.chat_postMessage( | |
| channel=SLACK_CHANNEL_ID, | |
| text=f"(for the keyword -> '{ping['trigger']}')\nFrom {ping['author']} in channel #{ping['channel']}: {ping['content']}\n{ping['url']}", | |
| thread_ts=main_ts, | |
| unfurl_links=False, | |
| unfurl_media=False | |
| ) | |
| time.sleep(2) # https://api.slack.com/apis/rate-limits | |
| daily_pings = [] # reset after posting | |
| # pings ------------------------------------------------------------------------------------------- | |
| executor = ThreadPoolExecutor(max_workers=1) | |
| scheduler = BackgroundScheduler(executors={'default': executor}) | |
| scheduler.add_job(send_daily_pings, trigger='interval', days=1) | |
| scheduler.start() | |
| # runs discord bot in thread = helps avoid blocking calls | |
| def run_bot(): | |
| bot.run(DISCORD_TOKEN) | |
| threading.Thread(target=run_bot).start() | |
| def greet(name): | |
| return "Hello " + name + "!" | |
| demo = gr.Interface(fn=greet, inputs="text", outputs="text") | |
| demo.launch() |