Chatterstack é uma maneira extremamente simples e intuitiva de lidar com as variáveis de "conversação" usadas pela API ChatGPT, ao mesmo tempo que oferece funcionalidades avançadas.
Instale o pacote do pip:
pip install chatterstack
Existem duas opções para Chatterstack. A Biblioteca Base e a Biblioteca Avançada, que estende a Base.
import chatterstack
# The base library if you are only really concerned about mananging
# the conversation variable, it's order, and maybe tracking tokens.
convo = chatterstack . Chatterstack ()
# The advanced library allows you issuing commands from the chat input,
# gives the bot the ability to reach out to you with reminders, etc
convo = chatterstack . ChatterstackAdvanced ()
As APIs ChatGPT usam variáveis de "conversação" para monitorar suas interações com o bot. Esta é uma lista de dicionários, com cada dicionário representando uma mudança na conversa.
Isso deixa seu programa repleto de coisas como esta:
# append the bot's response to your conversation
conversation . append ({ 'role' : response . choices [ 0 ]. message . role , 'content' : response . choices [ 0 ]. message . content })
# to print the last message
print ( conversation [ - 1 ][ "content" ])
Ridículo.
Se você quiser fazer algo mais avançado, como "manter a variável de conversa em no máximo 8 mensagens" ou "fazer com que a mensagem do sistema seja sempre a mensagem mais recente da conversa"... bem, pouparei o trecho de código para aqueles.
Como muitos aspectos desses dicionários são altamente previsíveis, e na maioria das vezes realizamos apenas algumas tarefas básicas com eles...
...isso significa que podemos realmente abstrair grande parte dessa bagunça, de uma forma que torna seu uso muito mais intuitivo - ao mesmo tempo que mantém basicamente toda a flexibilidade inerente! Isso é uma coisa rara de se conseguir fazer.
Este é um programa de chatbot totalmente funcional usando chatterstack:
import chatterstack
import os
os . environ [ 'OPENAI_API_KEY' ] = 'your_api_key_here'
convo = chatterstack . Chatterstack ()
while True :
convo . user_input ()
convo . send_to_bot ()
convo . print_last_message ()
Isso é tudo!
Esta é a aparência da conversa no terminal:
USER: hey, can you help me with something?
ASSISTANT: Sure! What would you like help with?
USER: I need to know if France has a President or a Prime Minister
ASSISTANT: France has both a President and a Prime Minister, which [... bot goes on]
Esta biblioteca foi construída para ser intuitiva e flexível , para que você possa alterar facilmente o comportamento ou a aparência, de várias maneiras, de acordo com suas necessidades. Aqui estão alguns exemplos básicos, permanecendo no terminal por enquanto:
while True :
# Change the user's display name
convo . user_input ( prefix = "ME: " )
# change any of the API arguments
convo . send_to_bot ( model = "gpt-4" , temperature = 1 , max_tokens = 40 )
# change the line spacing of the convo
convo . print_last_message ( prefix = "GPT: " , lines_before = 0 , lines_after = 2 )
# and let's have it print the total tokens after each turn
print ( convo . tokens_total_all )
Agora sua conversa é com GPT-4, e a conversa fica assim, com contagens de tokens:
ME: hey, can you help me with something?
GPT: Of course! I'm here to help. Please let me know what you need assistance with, and I'll do my best to help you.
28
ME: I need to know if France has a President or a Prime Minister
GPT: France has both a President and a Prime Minister. The President of France is [...bot goes on]
87
Há mais informações sobre os padrões atuais e vários métodos para alterá-los abaixo na seção sobre envio de mensagens para a API
O método user_input()
é igual ao método python input()
, exceto que também anexa automaticamente a entrada do usuário como um ditado formatado corretamente à sua variável de conversa.
convo . user_input ()
Como visto acima, o padrão deste método é solicitar ao usuário "USER:", mas você pode alterá-lo para o que desejar
convo . user_input ( "Ask the bot: " )
Ask the bot:
Talvez você não esteja usando o terminal.
Ou talvez você queira alterar a entrada de alguma forma antes de anexá-la.
Existem várias maneiras de pegar qualquer variável de string e adicioná-la à conversa como um ditado formatado corretamente:
# Use the .add() method. Pass it the role, then the content
convo . add ( "user" , message_string )
# or, use the role-specific methods & just pass the content
convo . add_user ( message_string )
convo . add_assistant ( "I'm a manually added assistant response" )
convo . add_system ( "SYSTEM INSTRUCTIONS - you are a helpful assistant who responds only in JSON" )
Há também .insert() se você quiser adicionar uma mensagem em um índice específico, em vez de anexá-la ao final da conversa:
# Here's the format
convo . insert ( index , role , content )
# example
convo . insert ( 4 , "system" , "IMPORTANT: Remember to not apologize to the user so much" )
O método "send_to_bot" do chatterstack é uma chamada de API OpenAI padrão, mas é mais simples de usar e faz muitas coisas úteis para você em segundo plano. Chame assim:
convo . send_to_bot ()
É isso!
Ele se encarregará de passar todos os valores padrão para você, bem como anexar a resposta à sua conversa. Ele também mantém contagens de tokens para você (e na classe avançada, muito mais).
Por padrão, o chatterstack usa estes valores:
model = "gpt-3.5-turbo" ,
temperature = 0.8 ,
top_p = 1 ,
frequency_penalty = 0 ,
presence_penalty = 0 ,
max_tokens = 200
Existem várias maneiras de mudar isso. Escolha o que for mais conveniente para você.
A maneira mais óbvia é simplesmente passá-los como argumentos ao fazer a ligação. Por exemplo, se você quiser tokens GPT-4 e 800 no máximo:
convo . send_to_bot ( model = "gpt-4" , max_tokens = 800 )
Essa abordagem é ótima quando você deseja fazer apenas uma chamada com alguns valores diferentes.
Mas se você sabe que deseja valores diferentes para toda a conversa, você pode defini-los em letras maiúsculas no topo do seu arquivo e inicializar o chatterstack usando o ditado globals()
, assim:
MODEL = "gpt-4"
TEMPERATURE = 0.6
FREQUENCY_PENALTY = 1.25
MAX_TOKENS = 500
# initialize with 'globals()'
convo = chatterstack . Chatterstack ( user_defaults = globals ())
# and now you can just call it like this again
convo . send_to_bot ()
Finalmente, se quiser usar apenas a chamada OpenAI padronizada, você ainda pode fazer isso! Basta passar o atributo .list do seu Chatterstack, que é a lista bruta de dicionários:
response = openai . ChatCompletion . create (
model = "gpt-3.5-turbo" ,
messages = convo . list , # <--- right here
temperature = 0.9 ,
top_p = 1 ,
frequency_penalty = 0 ,
presence_penalty = 0 ,
max_tokens = 200 ,
)
Super simples:
# Print the "content" of the last message
convo . print_last_message ()
Ou, se você quiser fazer a formatação da string primeiro...
# This represents/is the content string of the last message
convo . last_message
# So you can do stuff like this:
message_in_caps = convo . last_message . upper ()
# print the message in all upper case
print ( message_in_caps )
oh sim. Estamos monitorando os tokens.
# See the tokens used on the last API call
self . last_call_prompt_tokens
self . last_call_full_context_prompt_tokens
self . last_call_completion_tokens
self . last_call_tokens_all
# At any time, check the totals for the whole conversation so far
self . prompt_tokens_total
self . assistant_tokens_total
self . tokens_total_all
Vários métodos estão disponíveis para manipular a ordem da conversa, aqui estão alguns:
# Insert message at a specified index
convo . insert ( index , role , content )
# Remove N messages from the end of the list
convo . remove_from_end ( count )
# Remove N messages from the start of the list
convo . remove_from_start ( count )
Mas muito mais importante - métodos para controle refinado sobre a mensagem do sistema.
As mensagens do sistema geralmente são usadas para instruções e muitas vezes pode ser útil fazer com que as instruções apareçam mais “recentemente” na conversa. O que significa rastrear e mover esta mensagem, sem atrapalhar as outras.
# move your system message to be the most recent message in convo
convo . move_system_to_end ()
# or second to last, etc
convo . move_system_to_end ( minus = 1 )
E meu favorito pessoal - basicamente a razão pela qual escrevi esta biblioteca inteira -
convo . set_system_lock_index ( - 1 )
Passar um valor positivo para esta função bloqueará a mensagem do sistema no índice. Sempre que mensagens são adicionadas, removidas ou reordenadas, isso garantirá que a mensagem do sistema permaneça nessa posição (ou o mais próximo possível dela).
Passar um valor negativo bloqueará a mensagem do sistema na contagem do índice a partir do final da conversa (o exemplo acima faria com que fosse sempre a penúltima mensagem da conversa).
NOTA: Atualmente, esses métodos pressupõem que você tenha apenas uma mensagem do sistema
Imprima uma versão formatada da sua conversa (ótimo para depuração)
convo . print_formatted_conversation
Por padrão, imprime assim:
System: You are a helpful assistant.
User: hi!
Assistant: Hi! How can I help you?
veja as estatísticas gerais da sua conversa.
convo . summary ()
SUMMARY:
{'total_messages': 2, 'prompt_tokens': 200, 'assistant_tokens': 78, 'total_tokens': 278}
A classe Chatterstack Advanced estende a classe base e tem muito mais funcionalidades integradas. Também é facilmente extensível.
Aviso : alterações recentes no modelo parecem ter quebrado esta funcionalidade. Pode ou não funcionar quando você tenta. Provavelmente terá que ser reescrito para usar a chamada de função para funcionar de forma consistente novamente
Agora você pode dizer ao bot "lembre-me de levar o lixo para fora às 20h" ou "lembre-me de levar o lixo para fora em uma hora"
USER: hey, can you remind me to take the garbage out in an hour
ASSISTANT: Sure! I'll send you a reminder in an hour.
USER:
{...time passes...}
ASSISTANT: Hey! Just a quick reminder to take the garbage out!
O bot pode acompanhar quantos lembretes você deseja emitir.
Emita comandos a partir da entrada do usuário:
# saves the conversation to a txt file
USER: [save]
# quit the program
USER: [quit]
Por padrão, você emite comandos usando [
e ]
como delimitadores. Mas você pode alterá-los para o que quiser:
convo.open_command = "{{"
convo.close_command = "}}"
você também pode chamar qualquer método (ou definir qualquer atributo) da própria classe chatterstack, diretamente da interface de chat:
# if you want to see what is currently in the conversation history
USER: [print_formatted_conversation]
# or how many tokens you have used so far
USER: [print_total_tokens]
# you can even pass arguments to commands
USER: [set_system_lock_index(-2)]
Portanto, embora o exemplo inicial do programa de bate-papo no início deste repositório possa ter parecido simplista no início, você pode ver que é realmente tudo o que você precisa, já que quase todas as funcionalidades desejadas podem ser chamadas de dentro do próprio bate-papo.
Se você quiser escrever seus próprios comandos, o chatterstack fornece uma classe de interface simples para fazer isso, chamada ICommand
.
class ICommand :
def execute ( self ):
pass
Basicamente, você escreve seu comando como uma classe, que herda da classe ICommand
, e possui um método "executar" (que é o que você deseja que realmente aconteça quando seu comando for chamado).
Aqui está um exemplo:
class ExampleCommand ( ICommand ):
def execute ( self ):
print ( "An example command that prints this statement right here." )
Se o seu comando precisar de argumentos, você também pode adicionar um método __init__
e passá-lo *args
exatamente assim:
class ExampleCommand ( ICommand ):
def __init__ ( self , * args ):
self . args = args
def execute ( self ):
print ( "Example command that print this statement with this extra stuff:" , self . args )
A última coisa que você precisa fazer é atribuir ao seu comando uma palavra ou frase acionadora, adicionando-a ao método init na classe ChatterstackAdvanced.
class ChatterstackAdvanced ( Chatterstack ):
def __init__ ( self , ...)
# ...Lots of other code here...
# This command is already in the class:
self . command_handler . register_command ( 'save' , SaveConversationCommand ( self ))
# Add your new command
self . command_handler . register_command ( "example" , ExampleCommand )
Atualmente existe uma versão Javascript do Chatterstack, mas ainda não a disponibilizei porque também não conheço Javascript e não estou tão confiante em sua confiabilidade. Se você conhece Javascript e gostaria de ajudar, por favor me avise!