2023-07-15 12:20:38 +02:00
import discord
2023-08-03 13:13:20 +02:00
import asyncio
2023-08-15 14:11:21 +02:00
import orjson
2023-07-17 18:42:45 +02:00
import aiohttp
2023-07-18 21:53:07 +02:00
import random
2023-07-18 23:18:47 +02:00
import time
2023-08-15 14:11:21 +02:00
2023-08-16 09:20:29 +02:00
from utils . misc import moderate
2023-08-15 14:11:21 +02:00
from simpleeval import simple_eval
2023-07-18 23:18:47 +02:00
from bs4 import BeautifulSoup
2023-08-03 13:31:06 +02:00
from src . config import tenor_api_key
2023-07-18 23:23:47 +02:00
2023-07-18 23:18:47 +02:00
randomseed = time . time ( )
random . seed ( randomseed )
2023-07-18 21:53:07 +02:00
tenor_api_url = f " https://tenor.googleapis.com/v2/search?key= { tenor_api_key } &q= "
2023-07-17 18:42:45 +02:00
2023-07-16 17:11:24 +02:00
functions = [
{
" name " : " add_reaction_to_last_message " ,
" description " : " React to the last message sent by the user with an emoji. " ,
" parameters " : {
" type " : " object " ,
" properties " : {
" emoji " : {
" type " : " string " ,
2023-07-18 17:51:13 +02:00
" description " : " an emoji to react with, only one emoji is supported " ,
2023-07-16 17:11:24 +02:00
} ,
2023-07-18 17:51:13 +02:00
" message " : { " type " : " string " , " description " : " Your message " } ,
2023-07-16 17:11:24 +02:00
} ,
2023-07-18 17:51:13 +02:00
" required " : [ " emoji " ] ,
} ,
2023-07-16 17:11:24 +02:00
} ,
{
" name " : " reply_to_last_message " ,
" description " : " Reply to the last message sent by the user. " ,
" parameters " : {
" type " : " object " ,
" properties " : {
2023-07-18 17:51:13 +02:00
" message " : { " type " : " string " , " description " : " Your message " }
2023-07-16 17:11:24 +02:00
} ,
2023-07-18 17:51:13 +02:00
" required " : [ " message " ] ,
} ,
2023-07-16 17:11:24 +02:00
} ,
{
" name " : " send_a_stock_image " ,
" description " : " Send a stock image in the channel. " ,
" parameters " : {
" type " : " object " ,
" properties " : {
" query " : {
" type " : " string " ,
2023-07-18 17:51:13 +02:00
" description " : " The query to search for, words separated by spaces " ,
2023-07-16 17:11:24 +02:00
} ,
" message " : {
" type " : " string " ,
2023-07-18 17:51:13 +02:00
" description " : " Your message to send with the image " ,
} ,
2023-07-16 17:11:24 +02:00
} ,
2023-07-18 17:51:13 +02:00
" required " : [ " query " ] ,
} ,
} ,
2023-07-18 21:53:07 +02:00
{
" name " : " send_a_gif " ,
" description " : " Send a gif in the channel. " ,
" parameters " : {
" type " : " object " ,
" properties " : {
" query " : {
" type " : " string " ,
" description " : " The query to search for, words separated by spaces " ,
} ,
" message " : {
" type " : " string " ,
" description " : " Your message to send with the gif " ,
} ,
" limit " : {
" type " : " integer " ,
" description " : " The number of gifs to search for, a random one will be chosen. If the gif is a really specific one, you might want to have a lower limit, to avoid sending a gif that doesn ' t match your query. " ,
} ,
} ,
" required " : [ " query " ] ,
} ,
} ,
2023-07-18 23:18:47 +02:00
{
" name " : " send_ascii_art_text " ,
" description " : " Sendsa message in huge ascii art text. " ,
" parameters " : {
" type " : " object " ,
" properties " : {
" text " : {
" type " : " string " ,
" description " : " The text to send as ascii art " ,
} ,
" font " : {
" type " : " string " ,
" description " : " The font to use, between ' standard ' (default), ' shadow ' , ' money ' (made out of $), ' bloody ' , ' dos-rebel ' (like in the matrix, a really cool one). Remember to use this with not too long text (max 5 characters), otherwise it will look weird. To send multiple max 5 length word, add line breaks between them. " ,
} ,
" message " : {
" type " : " string " ,
" description " : " Your message to send with the ascii art. It will not be converted to ascii art, just sent as a normal message. " ,
2023-07-18 23:23:47 +02:00
} ,
2023-07-18 23:18:47 +02:00
} ,
" required " : [ " text " ] ,
} ,
} ,
{
" name " : " send_ascii_art_image " ,
" description " : " Sends an image in ascii art. " ,
" parameters " : {
" type " : " object " ,
" properties " : {
" query " : {
" type " : " string " ,
" description " : " The query to search for, words separated by spaces, max 2 words " ,
} ,
" message " : {
" type " : " string " ,
" description " : " Your message to send with the image " ,
2023-07-18 23:23:47 +02:00
} ,
2023-07-18 23:18:47 +02:00
} ,
" required " : [ " query " ] ,
} ,
} ,
2023-08-15 14:11:21 +02:00
{
" name " : " evaluate_math " ,
" description " : " Get the result of a math expression. Only math expressions are supported, no variables, no functions. " ,
" parameters " : {
" type " : " object " ,
" properties " : {
" string " : {
" type " : " string " ,
" description " : " The string to evaluate " ,
}
} ,
" required " : [ " string " ] ,
} ,
} ,
2023-07-16 17:11:24 +02:00
]
server_normal_channel_functions = [
{
" name " : " create_a_thread " ,
" description " : " Create a thread in the channel. Use this if you see a long discussion coming. " ,
" parameters " : {
" type " : " object " ,
" properties " : {
2023-07-18 17:51:13 +02:00
" name " : { " type " : " string " , " description " : " The name of the thread " } ,
2023-07-16 17:11:24 +02:00
" message " : {
" type " : " string " ,
2023-07-18 17:51:13 +02:00
" description " : " Your message to send with the thread " ,
} ,
2023-07-16 17:11:24 +02:00
} ,
2023-07-18 17:51:13 +02:00
" required " : [ " name " , " message " ] ,
} ,
2023-07-16 17:11:24 +02:00
} ,
]
2023-07-16 21:18:30 +02:00
2023-07-18 23:18:47 +02:00
font_matches = {
" standard " : " ANSI Regular " ,
" shadow " : " ANSI Shadow " ,
2023-07-18 23:23:47 +02:00
" money " : random . choice (
[ " Big Money-ne " , " Big Money-nw " , " Big Money-se " , " Big Money-sw " ]
) ,
2023-07-18 23:18:47 +02:00
" bloody " : " Bloody " ,
" dos-rebel " : " DOS Rebel " ,
}
2023-07-17 18:42:45 +02:00
unsplash_random_image_url = " https://source.unsplash.com/random "
2023-08-15 12:38:47 +02:00
2023-08-15 12:38:37 +02:00
class FuntionCallError ( Exception ) :
pass
2023-07-18 17:51:13 +02:00
2023-08-15 12:38:47 +02:00
2023-07-17 18:42:45 +02:00
async def get_final_url ( url ) :
async with aiohttp . ClientSession ( ) as session :
async with session . head ( url , allow_redirects = True ) as response :
final_url = str ( response . url )
return final_url
2023-07-16 21:18:30 +02:00
2023-07-18 23:23:47 +02:00
2023-07-18 23:18:47 +02:00
async def do_async_request ( url , json = True ) :
2023-07-18 21:53:07 +02:00
async with aiohttp . ClientSession ( ) as session :
async with session . get ( url ) as response :
2023-07-18 23:18:47 +02:00
if json :
response = await response . json ( )
else :
response = await response . text ( )
2023-07-18 21:53:07 +02:00
return response
2023-07-18 17:51:13 +02:00
2023-07-18 23:23:47 +02:00
2023-07-18 17:51:13 +02:00
async def add_reaction_to_last_message (
2023-08-15 12:38:37 +02:00
message_to_react_to : discord . Message , arguments : dict
2023-08-15 12:38:47 +02:00
) :
2023-08-15 12:38:37 +02:00
emoji = arguments . get ( " emoji " , " " )
if emoji == " " :
raise FuntionCallError ( " No emoji provided " )
message = arguments . get ( " message " , " " )
2023-07-15 12:20:38 +02:00
if message == " " :
await message_to_react_to . add_reaction ( emoji )
else :
await message_to_react_to . channel . send ( message )
await message_to_react_to . add_reaction ( emoji )
2023-07-18 17:51:13 +02:00
2023-08-15 12:38:37 +02:00
async def reply_to_last_message ( message_to_reply_to : discord . Message , arguments : dict ) :
message = arguments . get ( " message " , " " )
if message == " " :
raise FuntionCallError ( " No message provided " )
2023-07-15 12:20:38 +02:00
await message_to_reply_to . reply ( message )
2023-07-18 17:51:13 +02:00
async def send_a_stock_image (
2023-08-15 12:38:37 +02:00
message_in_channel_in_wich_to_send : discord . Message , arguments : dict
2023-07-18 17:51:13 +02:00
) :
2023-08-15 12:38:37 +02:00
query = arguments . get ( " query " , " " )
if query == " " :
raise FuntionCallError ( " No query provided " )
message = arguments . get ( " message " , " " )
2023-07-15 12:20:38 +02:00
query = query . replace ( " " , " + " )
2023-07-17 18:42:45 +02:00
image_url = f " { unsplash_random_image_url } ? { query } "
final_url = await get_final_url ( image_url )
message = message + " \n " + final_url
await message_in_channel_in_wich_to_send . channel . send ( message )
2023-07-16 17:11:24 +02:00
2023-07-18 17:51:13 +02:00
2023-08-15 12:38:47 +02:00
async def create_a_thread ( called_by : discord . Message , arguments : dict ) :
2023-08-15 12:38:37 +02:00
name = arguments . get ( " name " , " " )
if name == " " :
raise FuntionCallError ( " No name provided " )
message = arguments . get ( " message " , " " )
if message == " " :
raise FuntionCallError ( " No message provided " )
channel_in_which_to_create_the_thread = called_by . channel
2023-07-16 17:11:24 +02:00
msg = await channel_in_which_to_create_the_thread . send ( message )
2023-07-18 17:51:13 +02:00
await msg . create_thread ( name = name )
2023-07-18 21:53:07 +02:00
2023-07-18 23:23:47 +02:00
async def send_a_gif (
message_in_channel_in_wich_to_send : discord . Message ,
2023-08-15 12:38:37 +02:00
arguments : dict ,
2023-07-18 23:23:47 +02:00
) :
2023-08-15 12:38:37 +02:00
query = arguments . get ( " query " , " " )
if query == " " :
raise FuntionCallError ( " No query provided " )
message = arguments . get ( " message " , " " )
limit = arguments . get ( " limit " , 15 )
2023-07-18 21:53:07 +02:00
query = query . replace ( " " , " + " )
image_url = f " { tenor_api_url } { query } &limit= { limit } "
response = await do_async_request ( image_url )
json = response
2023-07-18 23:23:47 +02:00
gif_url = random . choice ( json [ " results " ] ) [ " itemurl " ] # type: ignore
2023-07-18 21:53:07 +02:00
message = message + " \n " + gif_url
2023-07-18 23:18:47 +02:00
await message_in_channel_in_wich_to_send . channel . send ( message )
2023-07-18 23:23:47 +02:00
async def send_ascii_art_text (
message_in_channel_in_wich_to_send : discord . Message ,
2023-08-15 12:38:37 +02:00
arguments : dict ,
2023-07-18 23:23:47 +02:00
) :
2023-08-15 12:38:37 +02:00
text = arguments . get ( " text " , " " )
if text == " " :
raise FuntionCallError ( " No text provided " )
font = arguments . get ( " font " , " standard " )
message = arguments . get ( " message " , " " )
if font not in font_matches :
raise FuntionCallError ( " Invalid font " )
2023-08-15 12:38:47 +02:00
2023-07-18 23:18:47 +02:00
font = font_matches [ font ]
text = text . replace ( " " , " + " )
2023-08-03 13:58:44 +02:00
asciiiar_url = (
f " https://asciified.thelicato.io/api/v2/ascii?text= { text } &font= { font } "
)
2023-08-03 13:13:20 +02:00
ascii_art = await do_async_request ( asciiiar_url , json = False )
final_message = f " ``` \n { ascii_art } ``` \n { message } "
if len ( final_message ) < 2000 :
await message_in_channel_in_wich_to_send . channel . send ( final_message )
else :
if len ( ascii_art ) < 2000 :
await message_in_channel_in_wich_to_send . channel . send ( ascii_art )
elif len ( ascii_art ) < 8000 :
embed = discord . Embed (
title = " Ascii art " ,
2023-08-03 14:01:49 +02:00
description = ascii_art ,
)
2023-08-03 13:13:20 +02:00
await message_in_channel_in_wich_to_send . channel . send ( embed = embed )
else :
await message_in_channel_in_wich_to_send . channel . send (
" Sorry, the ascii art is too big to be sent "
)
2023-08-03 13:58:44 +02:00
if len ( message ) < 2000 :
2023-08-03 14:01:49 +02:00
await message_in_channel_in_wich_to_send . channel . send ( message )
2023-08-03 13:13:20 +02:00
else :
while len ( message ) > 0 :
await message_in_channel_in_wich_to_send . channel . send ( message [ : 2000 ] )
message = message [ 2000 : ]
2023-07-18 23:23:47 +02:00
2023-08-03 13:58:44 +02:00
2023-07-18 23:23:47 +02:00
async def send_ascii_art_image (
2023-08-15 12:38:37 +02:00
message_in_channel_in_wich_to_send : discord . Message , arguments : dict
2023-07-18 23:23:47 +02:00
) :
2023-08-15 12:38:37 +02:00
query = arguments . get ( " query " , " " )
if query == " " :
raise FuntionCallError ( " No query provided " )
message = arguments . get ( " message " , " " )
2023-07-18 23:18:47 +02:00
query = query . replace ( " " , " - " )
asciiiar_url = f " https://emojicombos.com/ { query } "
response = await do_async_request ( asciiiar_url , json = False )
soup = BeautifulSoup ( response , " html.parser " )
2023-07-18 23:23:47 +02:00
combos = soup . find_all ( " div " , class_ = lambda x : x and " combo-ctn " in x and " hidden " not in x ) [ : 5 ] # type: ignore
combos = [
combo [ " data-combo " ] for combo in combos if len ( combo [ " data-combo " ] ) < = 2000
]
2023-07-18 23:18:47 +02:00
combo = random . choice ( combos )
message = f " ``` \n { combo } ``` \n { message } "
2023-07-18 23:23:47 +02:00
await message_in_channel_in_wich_to_send . channel . send ( message )
2023-08-15 12:38:37 +02:00
2023-08-15 12:38:47 +02:00
2023-08-15 14:11:21 +02:00
async def evaluate_math (
2023-08-15 18:49:51 +02:00
message_in_channel_in_wich_to_send : discord . Message , arguments : dict , timeout = 10
2023-08-15 14:11:21 +02:00
) :
evaluable = arguments . get ( " string " , " " )
if evaluable == " " :
raise FuntionCallError ( " No string provided " )
2023-08-15 18:49:51 +02:00
loop = asyncio . get_event_loop ( )
2023-08-15 14:11:21 +02:00
try :
2023-08-15 18:50:25 +02:00
result = await asyncio . wait_for (
loop . run_in_executor ( None , simple_eval , evaluable ) , timeout = timeout
)
2023-08-15 14:11:21 +02:00
except Exception as e :
result = f " Error: { e } "
return f " Result to math eval of { evaluable } : ``` \n { str ( result ) } ``` "
2023-08-16 09:20:29 +02:00
async def call_function ( message : discord . Message , function_call , api_key ) :
2023-08-15 12:42:18 +02:00
name = function_call . get ( " name " , " " )
if name == " " :
raise FuntionCallError ( " No name provided " )
arguments = function_call . get ( " arguments " , { } )
2023-08-15 14:11:21 +02:00
# load the function call arguments json
arguments = orjson . loads ( arguments )
2023-08-15 12:42:18 +02:00
if name not in functions_matching :
raise FuntionCallError ( " Invalid function name " )
function = functions_matching [ name ]
2023-08-16 09:20:29 +02:00
if arguments . get ( " message " , " " ) != " " and moderate (
api_key = api_key , text = arguments [ " message " ]
) :
return " Message blocked by the moderation system. Please try again. "
if arguments . get ( " query " , " " ) != " " and moderate (
api_key = api_key , text = arguments [ " query " ]
) :
return " Query blocked by the moderation system. If the user asked for something edgy, please tell them in a funny way that you won ' t do it, but do not specify that it was blocked by the moderation system. "
2023-08-15 14:11:21 +02:00
returnable = await function ( message , arguments )
return returnable
2023-08-15 12:42:18 +02:00
2023-08-15 12:38:37 +02:00
functions_matching = {
" add_reaction_to_last_message " : add_reaction_to_last_message ,
" reply_to_last_message " : reply_to_last_message ,
" send_a_stock_image " : send_a_stock_image ,
" send_a_gif " : send_a_gif ,
" send_ascii_art_text " : send_ascii_art_text ,
" send_ascii_art_image " : send_ascii_art_image ,
" create_a_thread " : create_a_thread ,
2023-08-15 14:11:21 +02:00
" evaluate_math " : evaluate_math ,
2023-08-15 12:38:47 +02:00
}