|
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') |
|
|
|
|
|
|
|
SLACK_CHANNEL_ID = os.getenv('SLACK_CHANNEL_ID_HF') |
|
SLACK_CHANNEL_ID_TEST = 'C07B4KNU5BQ' |
|
|
|
|
|
ASK_FOR_HELP_CHANNEL_ID = 1019883044724822016 |
|
GRADIO_CHANNEL_ID = 1025174734427656283 |
|
ARGILLA_HELP_CHANNEL_ID = 1253640751481356330 |
|
DATA_DISCUSSIONS_CHANNEL_ID = 1217179426002047076 |
|
GIVE_HF_FEEDBACK_CHANNEL_ID = 897391062975385640 |
|
|
|
TRIGGERS = { |
|
("discord bot",): ["<@U051DB2754M>"], |
|
("autotrain",): ["<@U01E3LEC2N7>"], |
|
("auto train",): ["<@U01E3LEC2N7>"], |
|
("competition",): ["<@U01E3LEC2N7>"], |
|
("competitions",): ["<@U01E3LEC2N7>"], |
|
("text to speech",): ["<@U039C2GANMV>"], |
|
("tts",): ["<@U039C2GANMV>"], |
|
("asr",): ["<@U039C2GANMV>"], |
|
("musicgen",): ["<@U039C2GANMV>"], |
|
("whisper",): ["<@U039C2GANMV>"], |
|
("speech recognition",): ["<@U039C2GANMV>"], |
|
("bark",): ["<@U039C2GANMV>"], |
|
("sentence-transformers",): ["<@U04E4DNPWG7>"], |
|
("sentence_transformers",): ["<@U04E4DNPWG7>"], |
|
("setfit",): ["<@U04E4DNPWG7>"], |
|
("sentence transformers",): ["<@U04E4DNPWG7>"], |
|
("argilla",): ["<@U076B8C7G3E>", "<@U0766H30T7F>", "<@U076MF65WEM>", "<@U0765RENPNZ>", "<@U0768QEN0LA>"], |
|
("distilabel",): ["<@U076B8C7G3E>", "<@U076MF65WEM>", "<@U0765RENPNZ>", "<@U0768QEN0LA>", "<@U076271MBUN>"], |
|
("docs",): ["<@U02DATT4C5B>"], |
|
("documentation",): ["<@U02DATT4C5B>"], |
|
("gradio",): ["<@U02NMK75F1V>", "<@U04FLGQ26PQ>"], |
|
("dataset", "feedback"): ["<@U0768RCHCRY>"], |
|
("git",): ["<@U07F1NP5U0K>"], |
|
("lfs",): ["<@U07F1NP5U0K>"], |
|
("dataset",): ["<@U07F1NP5U0K>"], |
|
("xet",): ["<@U07F1NP5U0K>"], |
|
("upload",): ["<@U07F1NP5U0K>"], |
|
("download",): ["<@U07F1NP5U0K>"], |
|
("stream",): ["<@U07F1NP5U0K>"], |
|
} |
|
|
|
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 |
|
|
|
|
|
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: |
|
if bots_role not in message.author.roles: |
|
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}") |
|
|
|
|
|
if isinstance(message.channel, discord.Thread): |
|
discord_thread_id = message.channel.id |
|
|
|
|
|
if discord_thread_id in thread_mapping: |
|
slack_thread_ts = thread_mapping[discord_thread_id] |
|
|
|
post_to_slack_forum_version(message, SLACK_CHANNEL_ID, message.content, message.author, thread_ts=slack_thread_ts) |
|
|
|
if message.channel.id == GIVE_HF_FEEDBACK_CHANNEL_ID: |
|
post_to_slack_general(message, SLACK_CHANNEL_ID) |
|
|
|
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}" |
|
|
|
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) + '...' |
|
|
|
|
|
@bot.event |
|
async def on_thread_create(thread): |
|
|
|
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}: |
|
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'] |
|
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'] |
|
except SlackApiError as e: |
|
print(f"Error posting to Slack: {e.response['error']}") |
|
return None |
|
|
|
|
|
@bot.command() |
|
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)}') |
|
|
|
|
|
|
|
SOLVED_TAG_IDS = {1026743978026094664, 1025179659215847575, 1263095032328753174, 1253641354312155208} |
|
@bot.event |
|
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}: |
|
|
|
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 = {} |
|
|
|
|
|
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) |
|
|
|
|
|
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) |
|
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) |
|
|
|
daily_pings = [] |
|
|
|
|
|
executor = ThreadPoolExecutor(max_workers=1) |
|
scheduler = BackgroundScheduler(executors={'default': executor}) |
|
scheduler.add_job(send_daily_pings, trigger='interval', days=1) |
|
scheduler.start() |
|
|
|
|
|
|
|
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() |