2023-04-12 16:30:42 +00:00
import time
2023-04-12 16:56:14 +00:00
import traceback
2023-04-12 16:30:42 +00:00
import discord
from discord import app_commands
from discord . ext import tasks
import os
import openai
import sqlite3
import tiktoken
from dotenv import load_dotenv
2024-01-16 20:07:39 +00:00
from typing import Dict
import copeai_backend
import views . GenerationState
2023-04-12 16:30:42 +00:00
load_dotenv ( )
openai . api_key = os . environ [ ' OPENAI_API_KEY ' ]
db = sqlite3 . connect ( ' tokens.db ' )
typing = [ ]
2023-04-12 17:03:27 +00:00
intents = discord . Intents . default ( )
intents . members = True
2023-04-12 17:26:16 +00:00
intents . presences = True
2023-04-12 17:03:27 +00:00
intents . dm_messages = True
2023-04-12 16:30:42 +00:00
2024-01-16 20:07:39 +00:00
cached_conversations : Dict [ discord . User , copeai_backend . conversation . Conversation ] = { }
2023-04-12 16:30:42 +00:00
class App ( discord . Client ) :
def __init__ ( self ) :
super ( ) . __init__ ( intents = intents )
self . tree = app_commands . CommandTree ( client = self )
2023-07-29 01:07:57 +00:00
print ( ' Running ' )
2023-04-12 16:30:42 +00:00
async def setup_hook ( self ) - > None :
return
app = App ( )
@tasks.loop ( seconds = 5 )
async def typing_loop ( ) :
for channel in typing :
try :
await channel . typing ( )
except :
typing . remove ( channel )
@app.event
async def on_ready ( ) :
print ( ' We have logged in as {0.user} ' . format ( app ) )
2023-04-12 17:03:27 +00:00
await app . change_presence ( activity = discord . Activity ( type = discord . ActivityType . watching , name = " your direct messages! " ) )
2023-04-12 16:30:42 +00:00
typing_loop . start ( )
encoding = tiktoken . get_encoding ( ' cl100k_base ' )
def num_tokens_from_string ( string : str ) - > int :
""" Returns the number of tokens in a text string. """
num_tokens = len ( encoding . encode ( string ) )
return num_tokens
@app.event
async def on_message ( message : discord . Message ) :
if not isinstance ( message . channel , discord . DMChannel ) : return
if message . author . id == app . user . id : return
try :
with open ( ' base-prompt.txt ' , ' r ' , encoding = ' utf-8 ' ) as f :
bprompt = f . read ( )
2023-04-12 16:56:14 +00:00
activs = " "
for activity in message . author . mutual_guilds [ 0 ] . get_member ( message . author . id ) . activities :
if isinstance ( activity , discord . Spotify ) :
activs + = f " - Listening to { activity . title } by { activity . artist } on Spotify \n "
elif isinstance ( activity , discord . Streaming ) :
activs + = f " - Streaming { activity . name } \n "
elif isinstance ( activity , discord . Game ) :
activs + = f " - Playing { activity . name } \n "
elif isinstance ( activity , discord . CustomActivity ) :
activs + = f " - Custom Activity: { activity . name } \n "
elif isinstance ( activity , discord . Activity ) :
activs + = f " - { activity . type . name . capitalize ( ) } { activity . name } \n "
arguments = {
" username " : message . author . name ,
" status " : message . author . mutual_guilds [ 0 ] . get_member ( message . author . id ) . raw_status ,
" activities " : activs . strip ( ' \n ' )
}
for arg in arguments . keys ( ) : bprompt = bprompt . replace ( f ' | { arg } | ' , arguments [ arg ] )
2024-01-16 20:07:39 +00:00
if message . author not in cached_conversations :
cached_conversations [ message . author ] = copeai_backend . conversation . Conversation ( )
c = db . cursor ( )
c . execute ( ' SELECT * FROM message_history WHERE user_id = ? ORDER BY timestamp DESC ' , ( message . author . id , ) )
msgs = c . fetchall ( )
message_token_usage = num_tokens_from_string ( message . content )
max_token = int ( os . environ [ ' MAX_TOKEN_PER_REQUEST ' ] )
2023-04-12 16:56:14 +00:00
2024-01-16 20:07:39 +00:00
previous_tokens = 200 + len ( bprompt ) + message_token_usage
# (message_id, user_id, content, token, role, timestamp)
# order by timestamp (most recent to least recent)
usable_messages = [ ]
for msg in msgs :
d = previous_tokens + msg [ 3 ]
if d > = max_token :
break
previous_tokens + = msg [ 3 ]
usable_messages . append ( msg )
usable_messages . reverse ( )
2023-04-12 16:30:42 +00:00
2024-01-16 20:07:39 +00:00
messages = [ { " role " : " system " , " content " : bprompt } ]
for v in usable_messages : messages . append ( { " role " : v [ 4 ] , " content " : v [ 2 ] } )
else :
total_tokens = copeai_backend . conversation . text_to_tokens ( cached_conversations [ message . author ] )
while total_tokens > int ( os . environ [ ' MAX_TOKEN_PER_REQUEST ' ] ) - 400 :
cached_conversations [ message . author ] . messages . pop ( 0 )
total_tokens = copeai_backend . conversation . text_to_tokens ( cached_conversations [ message . author ] )
2023-04-12 16:30:42 +00:00
2024-01-16 20:07:39 +00:00
cached_conversations [ message . author ] . add_message (
role = copeai_backend . conversation . Role . user ,
content = message . content
)
2023-04-12 16:30:42 +00:00
await message . channel . typing ( )
typing . append ( message . channel )
2024-01-16 20:07:39 +00:00
req = copeai_backend . generate . process_text_streaming (
conversation = cached_conversations [ message . author ] ,
model = copeai_backend . models . GPT_3 ,
new_message = message . content ,
additional_args = {
" max_tokens " : int ( os . environ [ ' MAX_TOKEN_PER_REQUEST ' ] ) ,
}
2023-04-12 16:30:42 +00:00
)
2024-01-16 20:07:39 +00:00
2023-04-12 16:30:42 +00:00
typing . remove ( message . channel )
response = req [ ' choices ' ] [ 0 ] [ ' message ' ] [ ' content ' ]
prompt_used_tokens = req [ ' usage ' ] [ ' prompt_tokens ' ]
completion_used_tokens = req [ ' usage ' ] [ ' completion_tokens ' ]
r = await message . reply ( response , allowed_mentions = discord . AllowedMentions . none ( ) )
c . execute ( ' INSERT INTO message_history VALUES (?, ?, ?, ?, ?, ?) ' , ( message . id , message . author . id , message . content , prompt_used_tokens , ' user ' , int ( message . created_at . timestamp ( ) ) ) )
c . execute ( ' INSERT INTO message_history VALUES (?, ?, ?, ?, ?, ?) ' , ( r . id , message . author . id , response , completion_used_tokens , ' assistant ' , int ( time . time ( ) ) ) )
db . commit ( )
except Exception as e :
2023-04-12 16:56:14 +00:00
traceback . print_exc ( )
2023-04-12 16:30:42 +00:00
if message . channel in typing : typing . remove ( message . channel )
await message . reply ( ' I just uncountered an issue. Can you please report this problem to the administrator of the bot, or try again later? \n ```py \n ' + str ( e ) + ' ``` ' )
app . run ( os . environ [ ' TOKEN ' ] )