Chatterstack es una forma muy simple e intuitiva de manejar las variables de "conversación" utilizadas por la API ChatGPT, al mismo tiempo que le brinda funcionalidad avanzada.
Instalar paquete desde pip:
pip install chatterstack
Hay dos opciones para Chatterstack. La Biblioteca Base y la Biblioteca Avanzada, que amplía la 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 ()
Las API de ChatGPT utilizan variables de "conversación" para realizar un seguimiento de sus interacciones con el bot. Esta es una lista de diccionarios, y cada diccionario representa un giro en la conversación.
Esto deja su programa lleno de cosas 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.
Si desea hacer algo más avanzado, como "mantener la variable de conversación en un máximo de 8 mensajes" o "hacer que el mensaje del sistema sea siempre el mensaje más reciente de la conversación"... bueno, le ahorraré el fragmento de código para aquellos.
Dado que muchos aspectos de estos diccionarios son muy predecibles y la mayoría de las veces solo realizamos unas pocas tareas básicas con ellos...
...esto significa que podemos abstraer gran parte de este desorden, de una manera que lo hace mucho más intuitivo de usar, ¡y al mismo tiempo mantenemos básicamente toda la flexibilidad inherente! Eso es algo raro de poder hacer.
Este es un programa de chatbot completamente funcional que utiliza 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 ()
¡Eso es todo!
Así es como se vería esa conversación en la 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 está diseñada para ser intuitiva y flexible , de modo que pueda cambiar fácilmente el comportamiento o la apariencia, de muchas maneras, según sus necesidades. A continuación se muestran algunos ejemplos básicos, quedándonos en la terminal por ahora:
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 )
Ahora su conversación es con GPT-4 y la conversación se ve así, con recuentos 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
Hay más información sobre los valores predeterminados actuales y varios métodos para cambiarlos a continuación en la sección sobre el envío de mensajes a la API.
El método user_input()
es el mismo que el método python input()
, excepto que también agrega automáticamente la entrada del usuario como un dict con el formato correcto a su variable de conversación.
convo . user_input ()
Como se vio arriba, este método por defecto solicita al usuario "USUARIO:", pero puedes cambiarlo a lo que quieras.
convo . user_input ( "Ask the bot: " )
Ask the bot:
Quizás no estés usando la terminal.
O tal vez quieras modificar la entrada de alguna manera antes de agregarla.
Hay varias formas de tomar cualquier variable de cadena y agregarla a la conversación como un dict con el formato correcto:
# 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" )
También existe .insert() si desea agregar un mensaje en un índice específico, en lugar de agregarlo al final de la conversación:
# Here's the format
convo . insert ( index , role , content )
# example
convo . insert ( 4 , "system" , "IMPORTANT: Remember to not apologize to the user so much" )
El método chatterstack "send_to_bot" es una llamada estándar a la API de OpenAI, pero es más sencillo de usar y hace un montón de cosas útiles en segundo plano. Llámalo así:
convo . send_to_bot ()
¡Eso es todo!
Se encargará de pasarle todos los valores predeterminados, así como de agregar la respuesta a su conversación. También mantiene el recuento de fichas (y en la clase avanzada, mucho más).
De forma predeterminada, chatterstack usa estos valores:
model = "gpt-3.5-turbo" ,
temperature = 0.8 ,
top_p = 1 ,
frequency_penalty = 0 ,
presence_penalty = 0 ,
max_tokens = 200
Hay varias formas de cambiarlos. Elija lo que sea más conveniente para usted.
La forma más obvia es simplemente pasarlos como argumentos cuando realiza la llamada. Por ejemplo, si quisieras GPT-4 y 800 tokens máximos:
convo . send_to_bot ( model = "gpt-4" , max_tokens = 800 )
Este enfoque es excelente cuando desea realizar una sola llamada con valores diferentes.
Pero si sabes que quieres valores diferentes para toda la conversación, puedes definirlos en mayúsculas en la parte superior de tu archivo e inicializar chatterstack usando el dictado globals()
, así:
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, si solo desea utilizar la llamada estándar de OpenAI, ¡aún puede hacerlo! Simplemente pásele el atributo .list de su Chatterstack, que es la lista sin formato de diccionarios:
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 ,
)
Súper sencillo:
# Print the "content" of the last message
convo . print_last_message ()
O, si primero desea formatear la cadena...
# 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 sí. Estamos realizando un seguimiento de las fichas.
# 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
Hay varios métodos disponibles para manipular el orden de la conversación, aquí hay algunos:
# 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 )
Pero mucho más importante: métodos para un control detallado del mensaje del sistema.
Los mensajes del sistema generalmente se usan como instrucciones y, a menudo, puede resultar útil que las instrucciones aparezcan más "recientemente" en la conversación. Lo que significa rastrear y mover este mensaje, sin interrumpir a los demás.
# 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 )
Y mi favorito personal, básicamente la razón por la que escribí toda esta biblioteca:
convo . set_system_lock_index ( - 1 )
Pasarle un valor positivo a esta función bloqueará el mensaje del sistema en el índice. Cada vez que se agregan, eliminan o reordenan mensajes, se asegurará de que el mensaje del sistema permanezca en esa posición (o lo más cerca posible de ella).
Pasarle un valor negativo bloqueará el mensaje de su sistema en el índice contando desde el final de la conversación (el ejemplo anterior haría que siempre fuera el penúltimo mensaje de la conversación).
NOTA: Actualmente, estos métodos suponen que solo tiene un mensaje del sistema
Imprima una versión formateada de su conversación (ideal para depurar)
convo . print_formatted_conversation
De forma predeterminada, se imprime así:
System: You are a helpful assistant.
User: hi!
Assistant: Hi! How can I help you?
vea las estadísticas generales de su conversación.
convo . summary ()
SUMMARY:
{'total_messages': 2, 'prompt_tokens': 200, 'assistant_tokens': 78, 'total_tokens': 278}
La clase Chatterstack Advanced amplía la clase base y tiene muchas más funciones integradas. También es fácilmente extensible.
Advertencia : los cambios recientes en el modelo parecen haber roto esta funcionalidad. Puede que funcione o no cuando lo pruebes. Probablemente será necesario reescribirlo para utilizar las llamadas a funciones para que vuelva a funcionar de manera consistente.
Ahora puedes decirle al bot "recuérdame que saque la basura a las 8 p.m." o "recuérdame que saque la basura en una 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!
El bot puede realizar un seguimiento de tantos recordatorios como desee emitir.
Emitir comandos desde la entrada del usuario:
# saves the conversation to a txt file
USER: [save]
# quit the program
USER: [quit]
De forma predeterminada, usted emite comandos utilizando [
y ]
como delimitadores. Pero puedes cambiarlos a lo que quieras:
convo.open_command = "{{"
convo.close_command = "}}"
También puedes autollamar cualquier método (o establecer cualquier atributo) de la clase chatterstack, directamente desde la interfaz 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)]
Entonces, si bien el ejemplo inicial del programa de chat al comienzo de este repositorio puede haber parecido simplista al principio, puede ver que en realidad es todo lo que necesita, ya que casi cualquier funcionalidad que desee se puede llamar desde el propio chat.
Si desea escribir sus propios comandos, chatterstack proporciona una clase de interfaz simple para hacerlo, llamada ICommand
.
class ICommand :
def execute ( self ):
pass
Básicamente, escribe su comando como una clase, que hereda de la clase ICommand
y tiene un método de "ejecución" (que es lo que realmente quiere que suceda cuando se llama a su comando).
Aquí hay un ejemplo:
class ExampleCommand ( ICommand ):
def execute ( self ):
print ( "An example command that prints this statement right here." )
Si su comando necesita argumentos, también puede agregar un método __init__
y pasarle *args
exactamente así:
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 )
Lo último que debe hacer es asignarle a su comando una palabra o frase desencadenante agregándola al método init en la clase 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 )
Actualmente existe una versión Javascript de Chatterstack, pero no la he puesto a disposición todavía porque tampoco conozco Javascript y no tengo tanta confianza en su confiabilidad. Si conoces Javascript y te gustaría ayudar, ¡házmelo saber!