2023-01-13 16:21:56 +01:00
use_images = True
2023-01-12 07:41:01 +01:00
import openai
2023-01-12 14:33:30 +01:00
# from openai import api_key
2023-01-12 07:41:01 +01:00
import discord
from discord import Intents
from discord . commands import slash_command , option
import re
import os
import asyncio
import logging
2023-01-12 14:33:30 +01:00
import datetime
import base64
2023-01-13 16:21:56 +01:00
if use_images : import imagesGeneration
2023-01-12 07:41:01 +01:00
logging . basicConfig ( level = logging . INFO )
2023-01-13 16:21:56 +01:00
imageint = " "
if use_images : imageint = " To add an image illustration , use  at the beginning of the slide, just after " - - - " -It ' s not possible to add technical images but only illustrations. The images are generated by an ai, the name of the file should be a detailed description of the image wanted. For example \"  \" but don ' t need to show a person necessairly. "
intstructions = f ''' Here is a presentation with marp. It ' s not possible to make slides longer than 200 characters. to separate slides,
2023-01-12 07:41:01 +01:00
"
- - -
"
2023-01-13 16:21:56 +01:00
then go at the line . The presentatio should be for everybody , all technical words and concepts , explained . { imageint } The presentation is minimum 20 slides long . You can use bulletpoints . Use markdown formatting ( titles , etc . . . ) . The presentation has also a conclusion . '''
2023-01-12 07:41:01 +01:00
bot = discord . Bot ( )
styles = [ " default " , " gaia " , " uncover " , " default-dark " , " gaia-dark " , " uncover-dark " ]
2023-01-12 14:33:30 +01:00
languages = [ " english " , " french " , " spanish " , " german " , " italian " , " portuguese " , " russian " , " chinese " , " japanese " , " korean " , " arabic " ]
2023-01-12 07:41:01 +01:00
darkstyles = [ " default-dark " , " gaia-dark " , " uncover-dark " ]
async def get_style ( ctx : discord . AutocompleteContext ) :
""" Returns a list of colors that begin with the characters entered so far. """
return [ color for color in styles if color . startswith ( ctx . value . lower ( ) ) ]
2023-01-12 14:33:30 +01:00
async def get_ln ( ctx : discord . AutocompleteContext ) :
""" Returns a list of colors that begin with the characters entered so far. """
return [ color for color in languages if color . startswith ( ctx . value . lower ( ) ) ]
2023-01-12 07:41:01 +01:00
@bot.slash_command ( name = " present " , description = " Generate a presentation with marp " )
#we create a function that takes the subject of the presentation and the style of the presentation as arguments, and that
@option ( name = " subject " , description = " The subject of the presentation " , required = True )
@option ( name = " style " , description = " The style of the presentation " , required = False , autocomplete = get_style )
2023-01-12 14:33:30 +01:00
@option ( name = " language " , description = " The language of the presentation " , required = False , autocomplete = get_ln )
@option ( name = " indications " , description = " The indications for the presentation " , required = False )
async def present ( ctx : discord . ApplicationContext , subject : str , style : str = " default " , language : str = " english " , indications : str = " " ) :
2023-01-12 07:41:01 +01:00
await ctx . defer ( )
2023-01-12 14:33:30 +01:00
date = datetime . datetime . now ( )
date = date . strftime ( " % Y- % m- %d - % H- % M- % S " )
prompt = f " { intstructions } { indications } The subject of the presentation is: { subject } The Language is: { language } <|endofprompt|> \n "
2023-01-12 07:41:01 +01:00
#replace the spaces in the szbject with dashes
2023-01-12 14:33:30 +01:00
2023-01-12 07:41:01 +01:00
subject2 = subject
subject = subject . replace ( " " , " - " )
2023-01-12 14:33:30 +01:00
#we save teh subject in base64 in a variable
b64 = base64 . urlsafe_b64encode ( subject . encode ( " utf-8 " ) )
#if dosen't exist, create a directory called "userid" where the userid is the id of the user who called the command
uid = str ( ctx . author . id )
2023-01-12 23:01:10 +01:00
if not os . path . exists ( " data/ " + uid ) :
os . mkdir ( " data/ " + uid )
2023-01-12 14:33:30 +01:00
datenow = datetime . datetime . now ( )
datenow = datenow . strftime ( " % Y- % m- %d - % H- % M- % S " )
2023-01-12 21:44:14 +01:00
os . mkdir ( f " data/ { uid } / { b64 } { datenow } " )
2023-01-12 14:33:30 +01:00
response = await openai . Completion . acreate (
2023-01-12 07:41:01 +01:00
engine = " text-davinci-003 " ,
prompt = prompt ,
temperature = 0.7 ,
max_tokens = 1024 ,
top_p = 1 ,
frequency_penalty = 0 ,
presence_penalty = 0 ,
stop = [ " <|endofprompt|> " ]
)
#we save the output in a variable
output = response [ " choices " ] [ 0 ] [ " text " ]
#if the output dosent start with --- or with \n--- or with \n\n--- we add it at the beginning of the output
#we add the marp header
marp = f ''' ---
marp : true
2023-01-12 21:44:14 +01:00
theme : { styles [ styles . index ( style ) ] }
2023-01-12 07:41:01 +01:00
class :
- lead
'''
if style in darkstyles :
marp = marp + f " - invert \n "
# if not output.startswith("---") and not output.startswith("\n---") and not output.startswith("\n\n---"):
# output = "---\n" + output
present = marp + output
##we save the output in a file called "subject.md"
matches = re . finditer ( r ' ! \ [.*? \ ] \ ((.*?) \ ) ' , present )
image_filenames = [ ]
for match in matches :
image_filenames . append ( match . group ( 1 ) )
#we create a text file with the image names and a md file for the presentation with utf8 encoding
2023-01-12 21:44:14 +01:00
with open ( f " ./data/ { uid } / { b64 } { datenow } / { subject } .md " , " w " , encoding = " utf8 " ) as f :
2023-01-12 07:41:01 +01:00
f . write ( present )
2023-01-12 21:44:14 +01:00
with open ( f " ./data/ { uid } / { b64 } { datenow } / { subject } -images.txt " , " w " , encoding = " utf8 " ) as f :
2023-01-12 07:41:01 +01:00
for image in image_filenames :
f . write ( image + " \n " )
2023-01-12 21:44:14 +01:00
#now we generate the images, if there are any
2023-01-13 16:21:56 +01:00
if len ( image_filenames ) > 0 and use_images :
2023-01-12 21:44:14 +01:00
#now we first remove the extension from the image filenames by removing the last 4 characters
image_filenames = [ image [ : - 4 ] for image in image_filenames ]
print ( image_filenames )
for images in image_filenames :
#we download the image
await imagesGeneration . generate ( images , f " { os . getcwd ( ) } \\ data \\ { uid } \\ { b64 } { datenow } \\ " )
#now we rename the image to remove the _0 from the end of the filename
os . rename ( f " { os . getcwd ( ) } \\ data \\ { uid } \\ { b64 } { datenow } \\ { images } _0.png " , f " { os . getcwd ( ) } \\ data \\ { uid } \\ { b64 } { datenow } \\ { images } .png " )
#now we whait 10 seconds for discord to resume the websocket connection
2023-01-13 16:21:56 +01:00
# await asyncio.sleep(10)
2023-01-12 07:41:01 +01:00
#we execute the command to convert the markdown file to a pdf and html file and also generate the first slide image
2023-01-12 21:44:14 +01:00
cmd = f " marp --pdf --allow-local-files ./data/ { uid } / { b64 } { datenow } / { subject } .md "
2023-01-12 07:41:01 +01:00
os . system ( cmd )
print ( cmd )
2023-01-12 21:44:14 +01:00
cmd = f " marp --image png -o ./data/ { uid } / { b64 } { datenow } / { subject } .png --allow-local-files ./data/ { uid } / { b64 } { datenow } / { subject } .md "
2023-01-12 07:41:01 +01:00
os . system ( cmd )
print ( cmd )
2023-01-12 21:44:14 +01:00
cmd = f " marp --html --allow-local-files ./data/ { uid } / { b64 } { datenow } / { subject } .md "
2023-01-12 07:41:01 +01:00
os . system ( cmd )
print ( cmd )
#we create an embed with the first slide imageand send it with the pdf file and the markdown file
2023-01-12 21:44:14 +01:00
embed = discord . Embed ( title = subject2 , description = " Thanks for using presentator bot. You can download the presentation in different formats (pdf, markdown, html). The images are generated by an ai. If you want to modify your presentation you can use the markdown file. More information about how to modify the file [HERE](https://marp.app). " , color = 0xaaaaaa )
files = [ discord . File ( f " ./data/ { uid } / { b64 } { datenow } / { subject } .pdf " ) , discord . File ( f " ./data/ { uid } / { b64 } { datenow } / { subject } .md " ) , discord . File ( f " ./data/ { uid } / { b64 } { datenow } / { subject } .html " ) , discord . File ( f " ./data/ { uid } / { b64 } { datenow } / { subject } .png " ) ]
2023-01-12 07:41:01 +01:00
embed . set_image ( url = f " attachment:// { subject } .png " )
#now we send the embed and all the 4 files (pdf, markdown, html, png) at the same time
await ctx . respond ( embed = embed , files = files )
2023-01-12 14:33:30 +01:00
@bot.slash_command ( name = " list " , description = " List all the presentations you have created " )
async def list ( ctx : discord . ApplicationContext ) :
#we create an embed with the list of presentations
embed = discord . Embed ( title = " Presentations " , description = " Here is the list of all the presentations you have created. You can download the presentation in different formats (pdf, markdown, html) by doing `/get` \" *presentation id* \" . The images are generated by an ai. If you want to modify your presentation you can use the markdown file. More information about how to modify the file [HERE](https://marp.app). " , color = 0x00ff00 )
#we get the list of presentations
liste = await get_presentations ( str ( ctx . author . id ) )
#we add the list of presentations to the embed
for key in liste :
embed . add_field ( name = f " { liste [ key ] } " , value = f " </get:1063051827010084925> ` { key } ` " , inline = False )
#now we send the embed
await ctx . respond ( embed = embed , ephemeral = True )
async def get_presentations ( uid ) :
2023-01-12 23:01:10 +01:00
folders = os . listdir ( f " ./data/ { uid } " )
2023-01-12 14:33:30 +01:00
names = { }
for folder in folders :
name = base64 . urlsafe_b64decode ( folder [ 2 : - 20 ] ) . decode ( " utf-8 " )
names [ folder ] = name
return names
@bot.slash_command ( name = " get " , description = " Get a presentation " )
@option ( name = " pid " , description = " The id of the presentation " , required = True )
async def get ( ctx : discord . ApplicationContext , pid : str ) :
uid = str ( ctx . author . id )
#we get the list of presentations
liste = await get_presentations ( uid )
#we check if the presentation id is in the list
if pid in liste :
#if it is we send the pdf, markdown and html files
2023-01-12 21:44:14 +01:00
files = [ discord . File ( f " ./data/ { uid } / { pid } / { liste [ pid ] } .pdf " ) , discord . File ( f " ./data/ { uid } / { pid } / { liste [ pid ] } .md " ) , discord . File ( f " ./data/ { uid } / { pid } / { liste [ pid ] } .html " ) ]
2023-01-12 14:33:30 +01:00
await ctx . respond ( files = files , ephemeral = True )
2023-01-12 07:41:01 +01:00
#when the bot is ready we print a message
@bot.event
async def on_ready ( ) :
print ( " Bot is ready " )
2023-01-12 21:44:14 +01:00
#if the data directory doesn't exist we create it
if not os . path . exists ( " data " ) :
os . mkdir ( " data " )
2023-01-12 07:41:01 +01:00
#get the openai key drom he key.env file
with open ( " key.env " , " r " ) as f :
apikey = f . read ( )
openai . api_key = apikey
with open ( " token.env " , " r " ) as f :
token = f . read ( )
2023-01-12 14:33:30 +01:00
bot . run ( token )