Update app.py
Browse files
app.py
CHANGED
@@ -1,287 +1,116 @@
|
|
1 |
-
import
|
2 |
-
import os
|
3 |
-
import threading
|
4 |
-
import gradio as gr
|
5 |
-
import requests
|
6 |
-
import json
|
7 |
-
import random
|
8 |
-
import time
|
9 |
-
import re
|
10 |
-
from discord import Embed, Color
|
11 |
-
from discord.ext import commands
|
12 |
-
|
13 |
-
from gradio_client import Client
|
14 |
-
from PIL import Image
|
15 |
-
from ratelimiter import RateLimiter
|
16 |
-
|
17 |
-
from datetime import datetime # for times
|
18 |
-
from pytz import timezone # for times
|
19 |
-
|
20 |
-
import asyncio # check if used
|
21 |
-
|
22 |
-
zurich_tz = timezone("Europe/Zurich")
|
23 |
-
|
24 |
-
def convert_to_timezone(dt, tz):
|
25 |
-
return dt.astimezone(tz).strftime("%Y-%m-%d %H:%M:%S %Z")
|
26 |
-
|
27 |
-
DISCORD_TOKEN = os.environ.get("LUNARBOT_TOKEN", None)
|
28 |
-
intents = discord.Intents.default()
|
29 |
-
intents.message_content = True
|
30 |
-
|
31 |
-
bot = commands.Bot(command_prefix='!', intents=intents)
|
32 |
-
|
33 |
-
#rate_limiter = RateLimiter(max_calls=10, period=60) # needs testing
|
34 |
-
|
35 |
-
# todo
|
36 |
-
'''
|
37 |
-
discord.gg / discord/invite (block completely, need to be cautious)
|
38 |
-
attempted @everyone / @here pings, or trying to use those strings (ping @alerts)
|
39 |
-
ping alerts for list of keywords
|
40 |
-
|
41 |
-
|
42 |
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
# moderation stuff----------------------------------------------------------------------------------------------------------------------------------------------------------
|
49 |
-
|
50 |
-
@bot.event
|
51 |
-
async def on_message_edit(before, after):
|
52 |
-
if before.author == bot.user:
|
53 |
-
return
|
54 |
-
|
55 |
-
if before.content != after.content:
|
56 |
-
embed = Embed(color=Color.orange())
|
57 |
-
embed.set_author(name=f"{before.author} ID: {before.author.id}", icon_url=before.author.avatar.url)
|
58 |
-
embed.title = "Message Edited"
|
59 |
-
embed.description = f"**Before:** {before.content or '*(empty message)*'}\n**After:** {after.content or '*(empty message)*'}"
|
60 |
-
embed.add_field(name="Author Username", value=before.author.name, inline=True)
|
61 |
-
embed.add_field(name="Channel", value=before.channel.mention, inline=True)
|
62 |
-
#embed.add_field(name="Message Created On", value=before.created_at.strftime("%Y-%m-%d %H:%M:%S UTC"), inline=True)
|
63 |
-
embed.add_field(name="Message Created On", value=convert_to_timezone(before.created_at, zurich_tz), inline=True)
|
64 |
-
embed.add_field(name="Message ID", value=before.id, inline=True)
|
65 |
-
embed.add_field(name="Message Jump URL", value=f"[Jump to message!](https://discord.com/channels/{before.guild.id}/{before.channel.id}/{before.id})", inline=True)
|
66 |
-
|
67 |
-
if before.attachments:
|
68 |
-
attachment_urls = "\n".join([attachment.url for attachment in before.attachments])
|
69 |
-
embed.add_field(name="Attachments", value=attachment_urls, inline=False)
|
70 |
-
|
71 |
-
#embed.set_footer(text=f"{datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S UTC')}")
|
72 |
-
embed.set_footer(text=f"{convert_to_timezone(datetime.utcnow(), zurich_tz)}")
|
73 |
-
|
74 |
-
await bot.log_channel.send(embed=embed)
|
75 |
|
76 |
-
@bot.event
|
77 |
-
async def on_message_delete(message):
|
78 |
-
if message.author == bot.user:
|
79 |
-
return
|
80 |
|
81 |
-
|
82 |
-
embed.set_author(name=f"{message.author} ID: {message.author.id}", icon_url=message.author.avatar.url)
|
83 |
-
embed.title = "Message Deleted"
|
84 |
-
embed.description = message.content or "*(empty message)*"
|
85 |
-
embed.add_field(name="Author Username", value=message.author.name, inline=True)
|
86 |
-
embed.add_field(name="Channel", value=message.channel.mention, inline=True)
|
87 |
-
#embed.add_field(name="Message Created On", value=message.created_at.strftime("%Y-%m-%d %H:%M:%S UTC"), inline=True)
|
88 |
-
embed.add_field(name="Message Created On", value=convert_to_timezone(message.created_at, zurich_tz), inline=True)
|
89 |
-
embed.add_field(name="Message ID", value=message.id, inline=True)
|
90 |
-
embed.add_field(name="Message Jump URL", value=f"[Jump to message!](https://discord.com/channels/{message.guild.id}/{message.channel.id}/{message.id})", inline=True)
|
91 |
|
92 |
-
if message.attachments:
|
93 |
-
attachment_urls = "\n".join([attachment.url for attachment in message.attachments])
|
94 |
-
embed.add_field(name="Attachments", value=attachment_urls, inline=False)
|
95 |
|
96 |
-
|
97 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
98 |
|
99 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
|
101 |
-
# nickname stuff
|
102 |
-
@bot.event
|
103 |
-
async def on_member_update(before, after):
|
104 |
-
if before.nick != after.nick:
|
105 |
-
embed = Embed(description=f'{before} changed their nickname to {after.nick}', color=Color.blue())
|
106 |
-
await bot.log_channel.send(embed=embed)
|
107 |
|
108 |
-
|
109 |
-
|
110 |
-
# member banned from the guild
|
111 |
-
embed = Embed(description=f'Member {user.mention} was banned from the guild', color=Color.red())
|
112 |
-
await bot.log_channel.send(embed=embed)
|
113 |
|
114 |
-
@bot.event
|
115 |
-
async def on_member_unban(guild, user):
|
116 |
-
# member unbanned from the guild
|
117 |
-
embed = Embed(description=f'Member {user.mention} was unbanned from the guild', color=Color.green())
|
118 |
-
await bot.log_channel.send(embed=embed)
|
119 |
|
120 |
-
|
|
|
|
|
|
|
121 |
|
122 |
-
@bot.event
|
123 |
-
async def on_guild_channel_create(channel):
|
124 |
-
# creating channels
|
125 |
-
embed = Embed(description=f'Channel {channel.mention} was created', color=Color.green())
|
126 |
-
await bot.log_channel.send(embed=embed)
|
127 |
|
128 |
-
@
|
129 |
-
async def
|
130 |
-
|
131 |
-
|
132 |
-
await bot.log_channel.send(embed=embed)
|
133 |
|
134 |
-
@bot.event
|
135 |
-
async def on_guild_role_create(role):
|
136 |
-
# creating roles
|
137 |
-
embed = Embed(description=f'Role {role.mention} was created', color=Color.green())
|
138 |
-
await bot.log_channel.send(embed=embed)
|
139 |
|
140 |
-
@
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
|
|
|
|
|
|
145 |
|
146 |
-
@bot.event
|
147 |
-
async def on_guild_role_update(before, after):
|
148 |
-
# editing roles, could expand this
|
149 |
-
if before.name != after.name:
|
150 |
-
embed = Embed(description=f'Role {before.mention} was renamed to {after.name}', color=Color.orange())
|
151 |
-
await bot.log_channel.send(embed=embed)
|
152 |
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
|
|
|
|
|
|
159 |
|
160 |
-
@bot.event
|
161 |
-
async def on_voice_state_update(member, before, after):
|
162 |
-
if before.mute != after.mute:
|
163 |
-
# muting members
|
164 |
-
embed = Embed(description=f'{member} was {"muted" if after.mute else "unmuted"} in voice chat', color=Color.orange())
|
165 |
-
await bot.log_channel.send(embed=embed)
|
166 |
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
|
|
|
|
|
|
|
|
171 |
|
172 |
-
#
|
173 |
-
|
174 |
-
chathistory = None
|
175 |
-
falcon_users = []
|
176 |
-
#falcon_threads = []
|
177 |
-
falcon_dictionary = {}
|
178 |
-
falcon_userid_threadid_dictionary = {}
|
179 |
|
180 |
-
@bot.command()
|
181 |
-
async def falcon(ctx, *, prompt: str):
|
182 |
-
# todo: need to be careful with these, rework into something simpler
|
183 |
-
try:
|
184 |
-
global falcon_users
|
185 |
-
#global falcon_threads # deprecated
|
186 |
-
global falcon_dictionary
|
187 |
-
global falcon_userid_threadid_dictionary
|
188 |
|
189 |
-
|
190 |
-
|
|
|
191 |
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
thread = await ctx.message.create_thread(name=f'{ctx.author}')
|
198 |
-
#falcon_users = [ctx.author.id] + falcon_users # deprecated
|
199 |
-
#falcon_threads = [thread.id] + falcon_threads # deprecated
|
200 |
-
await thread.send(f"[DISCLAIMER: HuggingBot is a **highly experimental** beta feature; The Falcon model and system prompt can be found here: https://huggingface.co/spaces/HuggingFaceH4/falcon-chat]")
|
201 |
-
|
202 |
-
# initial generation here
|
203 |
-
chathistory = falconclient.predict(
|
204 |
-
fn_index=5
|
205 |
-
) # []
|
206 |
-
instructions = "The following is a conversation between a highly knowledgeable and intelligent AI assistant, called Falcon, and a human user, called User. In the following interactions, User and Falcon will converse in natural language, and Falcon will answer User's questions. Falcon was built to be respectful, polite and inclusive. Falcon was built by the Technology Innovation Institute in Abu Dhabi. Falcon will never decline to answer a question, and always attempts to give an answer that User would be satisfied with. It knows a lot, and always tells the truth. The conversation begins."
|
207 |
-
job = falconclient.submit(prompt, chathistory, instructions, 0.8, 0.9, fn_index=1) # This is not blocking, similar to run_in_executor (but better)
|
208 |
-
while job.done() == False:
|
209 |
-
status = job.status() # could be spammy, let's test anyways
|
210 |
-
#print(status)
|
211 |
-
else:
|
212 |
-
file_paths = job.outputs()
|
213 |
-
full_generation = file_paths[-1] # tmp12345678.json
|
214 |
-
with open(full_generation, 'r') as file:
|
215 |
-
data = json.load(file)
|
216 |
-
output_text = data[-1][-1] # we output this as the bot
|
217 |
|
218 |
-
falcon_dictionary[ctx.author.id] = full_generation # 1234567890: tmp12345678.json
|
219 |
-
falcon_userid_threadid_dictionary[ctx.author.id] = thread.id
|
220 |
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
thread_link = f"https://discord.com/channels/879548962464493619/1119313248056004729/{thread_id}"
|
229 |
-
await ctx.reply(f"{ctx.author.mention}, you already have an existing conversation here {thread_link}! Use !falconclear in the #falcon channel to start a new one.")
|
230 |
-
#------------------------------------
|
231 |
-
# post all other generations here
|
232 |
-
#if ctx.channel.id in falcon_threads: # deprecated
|
233 |
-
if ctx.channel.id in falcon_userid_threadid_dictionary.values():
|
234 |
-
if ctx.channel.id == falcon_userid_threadid_dictionary[ctx.author.id]:
|
235 |
-
await ctx.message.add_reaction('<a:loading:1114111677990981692>')
|
236 |
-
chathistory = falcon_dictionary[ctx.author.id]
|
237 |
|
238 |
-
|
239 |
-
|
240 |
-
while job.done() == False:
|
241 |
-
status = job.status() # could be spammy, let's test anyways
|
242 |
-
#print(status)
|
243 |
-
else:
|
244 |
-
file_paths = job.outputs()
|
245 |
-
full_generation = file_paths[-1] # tmp12345678.json
|
246 |
-
with open(full_generation, 'r') as file:
|
247 |
-
data = json.load(file)
|
248 |
-
output_text = data[-1][-1] # we output this as the bot
|
249 |
-
falcon_dictionary[ctx.author.id] = full_generation
|
250 |
-
print(output_text)
|
251 |
-
await ctx.reply(f"{output_text}")
|
252 |
-
await ctx.message.remove_reaction('<a:loading:1114111677990981692>', bot.user)
|
253 |
-
|
254 |
-
except Exception as e:
|
255 |
-
print(f"Error: {e}")
|
256 |
-
await ctx.reply(f"{e} cc <@811235357663297546> (falconprivate error)")
|
257 |
-
await ctx.message.remove_reaction('<a:loading:1114111677990981692>', bot.user)
|
258 |
-
await ctx.message.add_reaction('<:disagree:1098628957521313892>')
|
259 |
-
#----------------------------------------------------------------------------------------------------------------------------
|
260 |
-
@bot.command()
|
261 |
-
async def falconclear(ctx):
|
262 |
-
if not ctx.author.bot:
|
263 |
-
if ctx.channel.id == 1119313248056004729:
|
264 |
-
if ctx.author.id in falcon_userid_threadid_dictionary:
|
265 |
-
if ctx.author.id in falcon_dictionary:
|
266 |
-
del falcon_userid_threadid_dictionary[ctx.author.id]
|
267 |
-
del falcon_dictionary[ctx.author.id]
|
268 |
-
await ctx.reply(f"{ctx.author.mention}'s conversation has been cleared. Feel free to start a new one!")
|
269 |
-
#----------------------------------------------------------------------------------------------------------------------------
|
270 |
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
bot.log_channel = bot.get_channel(1107006391547342910)
|
275 |
|
276 |
-
|
|
|
277 |
|
278 |
-
|
279 |
-
|
280 |
|
281 |
-
|
282 |
|
283 |
-
def greet(name):
|
284 |
-
return "Hello " + name + "!"
|
285 |
|
286 |
-
|
287 |
-
demo.launch()
|
|
|
1 |
+
from typing import Optional
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
|
3 |
+
import discord
|
4 |
+
from discord import app_commands
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5 |
|
|
|
|
|
|
|
|
|
6 |
|
7 |
+
MY_GUILD = discord.Object(id=1077674588122648679) # replace with your guild id
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
|
|
|
|
|
|
|
9 |
|
10 |
+
class MyClient(discord.Client):
|
11 |
+
def __init__(self, *, intents: discord.Intents):
|
12 |
+
super().__init__(intents=intents)
|
13 |
+
# A CommandTree is a special type that holds all the application command
|
14 |
+
# state required to make it work. This is a separate class because it
|
15 |
+
# allows all the extra state to be opt-in.
|
16 |
+
# Whenever you want to work with application commands, your tree is used
|
17 |
+
# to store and work with them.
|
18 |
+
# Note: When using commands.Bot instead of discord.Client, the bot will
|
19 |
+
# maintain its own tree instead.
|
20 |
+
self.tree = app_commands.CommandTree(self)
|
21 |
|
22 |
+
# In this basic example, we just synchronize the app commands to one guild.
|
23 |
+
# Instead of specifying a guild to every command, we copy over our global commands instead.
|
24 |
+
# By doing so, we don't have to wait up to an hour until they are shown to the end-user.
|
25 |
+
async def setup_hook(self):
|
26 |
+
# This copies the global commands over to your guild.
|
27 |
+
self.tree.copy_global_to(guild=MY_GUILD)
|
28 |
+
await self.tree.sync(guild=MY_GUILD)
|
29 |
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
|
31 |
+
intents = discord.Intents.default()
|
32 |
+
client = MyClient(intents=intents)
|
|
|
|
|
|
|
33 |
|
|
|
|
|
|
|
|
|
|
|
34 |
|
35 |
+
@client.event
|
36 |
+
async def on_ready():
|
37 |
+
print(f'Logged in as {client.user} (ID: {client.user.id})')
|
38 |
+
print('------')
|
39 |
|
|
|
|
|
|
|
|
|
|
|
40 |
|
41 |
+
@client.tree.command()
|
42 |
+
async def hello(interaction: discord.Interaction):
|
43 |
+
"""Says hello!"""
|
44 |
+
await interaction.response.send_message(f'Hi, {interaction.user.mention}')
|
|
|
45 |
|
|
|
|
|
|
|
|
|
|
|
46 |
|
47 |
+
@client.tree.command()
|
48 |
+
@app_commands.describe(
|
49 |
+
first_value='The first value you want to add something to',
|
50 |
+
second_value='The value you want to add to the first value',
|
51 |
+
)
|
52 |
+
async def add(interaction: discord.Interaction, first_value: int, second_value: int):
|
53 |
+
"""Adds two numbers together."""
|
54 |
+
await interaction.response.send_message(f'{first_value} + {second_value} = {first_value + second_value}')
|
55 |
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
|
57 |
+
# The rename decorator allows us to change the display of the parameter on Discord.
|
58 |
+
# In this example, even though we use `text_to_send` in the code, the client will use `text` instead.
|
59 |
+
# Note that other decorators will still refer to it as `text_to_send` in the code.
|
60 |
+
@client.tree.command()
|
61 |
+
@app_commands.rename(text_to_send='text')
|
62 |
+
@app_commands.describe(text_to_send='Text to send in the current channel')
|
63 |
+
async def send(interaction: discord.Interaction, text_to_send: str):
|
64 |
+
"""Sends the text into the current channel."""
|
65 |
+
await interaction.response.send_message(text_to_send)
|
66 |
|
|
|
|
|
|
|
|
|
|
|
|
|
67 |
|
68 |
+
# To make an argument optional, you can either give it a supported default argument
|
69 |
+
# or you can mark it as Optional from the typing standard library. This example does both.
|
70 |
+
@client.tree.command()
|
71 |
+
@app_commands.describe(member='The member you want to get the joined date from; defaults to the user who uses the command')
|
72 |
+
async def joined(interaction: discord.Interaction, member: Optional[discord.Member] = None):
|
73 |
+
"""Says when a member joined."""
|
74 |
+
# If no member is explicitly provided then we use the command user here
|
75 |
+
member = member or interaction.user
|
76 |
|
77 |
+
# The format_dt function formats the date time into a human readable representation in the official client
|
78 |
+
await interaction.response.send_message(f'{member} joined {discord.utils.format_dt(member.joined_at)}')
|
|
|
|
|
|
|
|
|
|
|
79 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
|
81 |
+
# A Context Menu command is an app command that can be run on a member or on a message by
|
82 |
+
# accessing a menu within the client, usually via right clicking.
|
83 |
+
# It always takes an interaction as its first parameter and a Member or Message as its second parameter.
|
84 |
|
85 |
+
# This context menu command only works on members
|
86 |
+
@client.tree.context_menu(name='Show Join Date')
|
87 |
+
async def show_join_date(interaction: discord.Interaction, member: discord.Member):
|
88 |
+
# The format_dt function formats the date time into a human readable representation in the official client
|
89 |
+
await interaction.response.send_message(f'{member} joined at {discord.utils.format_dt(member.joined_at)}')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
90 |
|
|
|
|
|
91 |
|
92 |
+
# This context menu command only works on messages
|
93 |
+
@client.tree.context_menu(name='Report to Moderators')
|
94 |
+
async def report_message(interaction: discord.Interaction, message: discord.Message):
|
95 |
+
# We're sending this response message with ephemeral=True, so only the command executor can see it
|
96 |
+
await interaction.response.send_message(
|
97 |
+
f'Thanks for reporting this message by {message.author.mention} to our moderators.', ephemeral=True
|
98 |
+
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
99 |
|
100 |
+
# Handle report by sending it into a log channel
|
101 |
+
log_channel = interaction.guild.get_channel(0) # replace with your channel id
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
|
103 |
+
embed = discord.Embed(title='Reported Message')
|
104 |
+
if message.content:
|
105 |
+
embed.description = message.content
|
|
|
106 |
|
107 |
+
embed.set_author(name=message.author.display_name, icon_url=message.author.display_avatar.url)
|
108 |
+
embed.timestamp = message.created_at
|
109 |
|
110 |
+
url_view = discord.ui.View()
|
111 |
+
url_view.add_item(discord.ui.Button(label='Go to Message', style=discord.ButtonStyle.url, url=message.jump_url))
|
112 |
|
113 |
+
await log_channel.send(embed=embed, view=url_view)
|
114 |
|
|
|
|
|
115 |
|
116 |
+
client.run('token')
|
|