2023-03-09 16:55:18 +01:00
# Copyright (c) 2023 Julian Müller (ChaoticByte)
2023-03-09 16:50:46 +01:00
from json import dumps , loads
from urllib import request as http_request
class Models :
''' This class holds available models '''
GPT_35_TURBO = " gpt-3.5-turbo "
GPT_35_TURBO_0301 = " gpt-3.5-turbo-0301 "
class Roles :
''' This class holds available roles to be used in Messages '''
ASSISTANT = " assistant "
SYSTEM = " system "
USER = " user "
class Message :
''' Message type. Supports roles. '''
def __init__ ( self , text : str , role : str = Roles . USER ) :
2023-03-11 14:10:13 +01:00
assert type ( text ) == str
assert type ( role ) == str
2023-03-09 16:50:46 +01:00
self . text = text
self . role = role
@classmethod
2023-03-11 14:10:13 +01:00
def from_api ( cls , api_msg : dict ) :
2023-03-09 16:50:46 +01:00
''' Create a Message object from API format '''
2023-03-11 14:10:13 +01:00
assert type ( api_msg ) == dict
msg = api_msg [ " choices " ] [ 0 ] [ " message " ]
msg [ " content " ] = msg [ " content " ] . strip ( " \n " )
2023-03-09 16:50:46 +01:00
return cls (
2023-03-11 14:10:13 +01:00
msg [ " content " ] ,
msg [ " role " ] )
2023-03-09 16:50:46 +01:00
def to_api ( self ) :
''' Convert to API format '''
return { " role " : self . role , " content " : self . text }
class ChatGPT :
''' ChatGPT API '''
API_ENDPOINT = " https://api.openai.com/v1/chat/completions "
def __init__ ( self , api_key : str , model : str = Models . GPT_35_TURBO ) :
2023-03-11 14:10:13 +01:00
assert type ( api_key ) == str
assert type ( model ) == str
2023-03-09 16:50:46 +01:00
# Create string used in header
self . auth = f " Bearer { api_key } "
# This list will contain all prior messages
2023-03-09 17:16:58 +01:00
self . _message_history = [ ]
2023-03-09 16:50:46 +01:00
self . model = model
def chat ( self , message : Message ) - > Message :
2023-03-09 17:16:58 +01:00
''' Add a message to the message history & send it to ChatGPT. Returns the answer as a Message instance. '''
self . add_to_chat ( message )
2023-03-11 14:10:13 +01:00
# Create api_input from message_history & encode it
2023-03-09 17:16:58 +01:00
api_input = [ m . to_api ( ) for m in self . _message_history ]
2023-03-09 16:50:46 +01:00
api_input_encoded = dumps (
{ " model " : self . model , " messages " : api_input } ,
separators = ( " , " , " : " ) ) . encode ( )
2023-03-11 14:10:13 +01:00
# Create a Request object with the right url, data, headers and http method
2023-03-09 16:50:46 +01:00
request = http_request . Request (
self . API_ENDPOINT ,
data = api_input_encoded ,
headers = {
" Authorization " : self . auth ,
" Content-Type " : " application/json "
} ,
method = " POST " )
2023-03-11 14:10:13 +01:00
# Send the request with r as the response
2023-03-09 16:50:46 +01:00
with http_request . urlopen ( request ) as r :
2023-03-11 14:10:13 +01:00
# Read response and parse json
2023-03-09 16:50:46 +01:00
api_output = loads ( r . read ( ) )
2023-03-11 14:10:13 +01:00
# Convert to Message object
response_message = Message . from_api ( api_output )
2023-03-09 17:16:58 +01:00
self . _message_history . append ( response_message )
2023-03-09 16:50:46 +01:00
return response_message
2023-03-09 17:16:58 +01:00
def add_to_chat ( self , message : Message ) - > Message :
''' Add a message to the message history without sending it to ChatGPT '''
2023-03-11 14:10:13 +01:00
# Check if the message parameter is the correct type
2023-03-09 17:16:58 +01:00
assert type ( message ) == Message , " message must be an instance of Message "
self . _message_history . append ( message )
2023-03-09 16:50:46 +01:00
def clear_message_history ( self ) :
2023-03-09 17:16:58 +01:00
self . _message_history = [ ]