Como criar um chatbot com o mecanismo GPT-3 da OpenAI, Twilio SMS e Python

August 03, 2020
Escrito por
Revisado por
Matt Makai
Twilion
Diane Phan
Twilion

Como criar um chatbot com o mecanismo GPT-3 da OpenAI, Twilio SMS e Python

Um chatbot GPT-3 é um aplicativo de software capaz de conversar com um usuário humano por meio de linguagem escrita ou falada. O grau de "inteligência" entre os chatbots varia muito. Enquanto alguns têm uma compreensão bastante básica da linguagem, outros empregam algoritmos sofisticados de IA (inteligência artificial) a ML (machine learning) para atingir um nível de conversação quase humano.

Neste tutorial, vou mostrar como é fácil criar um chatbot para Twilio SMS usando a plataforma OpenAI e a estrutura do Flask para Python.

Quer ter uma ideia de quais são os recursos do GPT-3? Confira a seguinte interação que tive com esse bot usando o projeto que vamos desenvolver neste tutorial:

Conversa com o chatbot OpenAI

Introdução ao GPT-3

GPT-3 (Generative Pre-Trained Transformer 3) é um modelo de linguagem altamente avançado treinado em um corpo de texto muito grande. Apesar de sua complexidade interna, ele é surpreendentemente simples de operar: você o alimenta com parte de um texto, e o modelo gera outra parte, seguindo um estilo e uma estrutura semelhantes.

O que você achou do primeiro parágrafo deste artigo? Você acreditaria se eu dissesse que eu não o escrevi e que ele foi totalmente gerado pelo GPT-3? Eu alimentei o modelo com o título e a introdução de duas outras publicações do blog que escrevi no passado, e então adicionei o título deste artigo. Aqui está a entrada completa que forneci:

Title: Build a WhatsApp Chatbot With Python, Flask and Twilio
Summary: A chatbot is a software application that is able to conduct a conversation with a human
user through written or spoken language. The level of "intelligence" among chatbots varies greatly.
While some chatbots have a fairly basic understanding of language, others employ
sophisticated artificial intelligence (AI) and machine learning (ML) algorithms to achieve an
almost human conversational level. In this tutorial I'm going to show you how easy it is to build a
chatbot for WhatsApp using the Twilio API for WhatsApp and the Flask framework for Python.

Title: Run Your Flask Regularly Scheduled Jobs with Cron
Summary: A common need of web applications is to have a periodically running task in the
background. This could be a task that imports new data from third party sources, or maybe one
that removes revoked tokens from your database once they have expired. In this and many other
situations you are faced with the challenge of implementing a task that runs in the background at
regular intervals. This is a pattern that many people ask me about. I've seen implementations that
are based on the APScheduler package, on Celery, and even homegrown solutions built inside a
background thread. Sadly none of these options are very good. In this article I'm going to show
you what I believe is a very robust implementation that is based on the Flask CLI and the cron
service.

Title: Building an SMS Chatbot with OpenAI's GPT-3 engine, Twilio and Python
Summary:

Observe como os dois primeiros blocos de texto têm as linhas "Título" e "Resumo", mas a terceira entrada tem um resumo vazio. Quando o mecanismo GPT-3 analisa essa entrada, ele entende que precisa concluir a linha "Resumo" com o texto apropriado para o título fornecido. Na minha opinião, ficou muito bom!

O GPT-3 é não determinista, no sentido de que, dada a mesma entrada, várias execuções do mecanismo retornarão respostas diferentes. Na verdade, eu gerei alguns parágrafos de abertura com a entrada acima e selecionei aquele de que eu mais gostei para começar o artigo. Aqui estão mais alguns que merecem destaque:

Summary: I recently read about GPT-3 and was amazed at how advanced this chatbot is. After
reading the article I thought to myself: I want to do that, but I don't have access to a GPU.
Luckily for me, there are some projects that allow you to use a neural network in a non-graphical
environment, and one of these is OpenAI. In this article I'm going to show you how to create a
GPT-3 based chatbot using OpenAI, Twilio and Python.
Summary: In this article I'm going to show you how to create a simple chatbot using the GPT-3
algorithm and the Twilio SMS service. The algorithm will read and respond to text messages and
we'll use the Python wrapper for OpenAI's GPT-3 to do so.

Inacreditável, não é? Embora isso seja muito incrível, você deve ter cuidado porque o mecanismo não tem um entendimento completo do texto que gera e pode fornecer respostas enganosas. Veja estes outros dois parágrafos iniciais que ele também produziu com base na minha entrada:

Summary: GPT-3 is a language modeling algorithm developed by Google. It is used to predict the
next word in a sequence of words. This is a common problem in natural language processing and text
generation. In this article I'm going to show you how to build a chatbot that uses GPT-3 to
generate responses to your messages. The chatbot will be able to respond to questions about itself,
the weather, and other topics.
Summary: In this post, I'm going to teach you how to build a super cool GPT-3 powered chatbot using
the OpenAI platform. GPT-3 (Generative Preachers Talk 3) is a neural network that can generate new
sermons for the original Preacher's Talks 3 data set. Using just this data and a few lines of
Python code, we're going to build a chatbot capable of having meaningful conversations about
anything that can be translated into a text message.

Embora o primeiro seja realmente bom em termos de estrutura, ele tem um grande erro factual: o Google não desenvolveu essa tecnologia. O segundo exemplo não erra o significado do acrônimo GPT-3, mas também é igualmente ridículo e engraçado!

Como implementar um chatbot com GPT-3

Como podemos usar essa tecnologia interessante? Com um chatbot, é claro!

Podemos "preparar" o mecanismo com um ou dois exemplos de interações entre o usuário e a IA para definir o tom do bot. Em seguida, anexamos o prompt real do usuário no final e deixamos que o mecanismo gere a resposta.

Aqui está um exemplo de consulta inicial que funcionaria para um chatbot:

Human: Hello, who are you?
AI: I am doing great. How can I help you today?
Human: Who played Forrest Gump in the movie?
AI:

A troca nas duas primeiras linhas é feita. Ele serve para permitir que a GPT-3 saiba que queremos linhas alternadas que começam com "humano:" e "IA:" e que a IA responderá a perguntas. A terceira linha é a primeira pergunta real do usuário.

Quando alimentei essa entrada no mecanismo, recebi o seguinte texto de volta:

AI: Tom Hanks.

Até agora, tudo bem. Agora, digamos que o usuário queira fazer outra pergunta. Aqui temos a opção de incorporar essa última interação à entrada, pois isso ajudará a GPT-3 a ter um contexto melhor da conversa. Veja o que poderia ser a entrada para uma pergunta adicional:

Human: Hello, who are you?
AI: I am doing great. How can I help you today?
Human: Who played Forrest Gump in the movie?
AI: Tom Hanks.
Human: Was he in any other great roles?
AI:

Você provavelmente pode ver por que expandir a entrada com a pergunta e resposta anteriores foi uma boa ideia. O usuário agora está perguntando sobre "ele", supondo que o chatbot se lembrará de que a pergunta anterior era sobre Tom Hanks.

Felizmente, a GPT-3 está à altura do desafio. Esta é a resposta:

AI: Yes, he was the star of Big, Saving Private Ryan, and You've Got Mail.

Pronto para criar um chatbot com base neste algoritmo simples? Vamos lá.

Requisitos do tutorial

Para seguir este tutorial, você precisa dos seguintes itens:

Criar um ambiente virtual Python

Seguindo as práticas recomendadas do Python, o primeiro passo para criar o chatbot é criar um diretório separado para o projeto e, dentro dele, vamos criar um ambiente virtual. Em seguida, vamos instalar os pacotes Python necessários para nosso chatbot.

Se você estiver usando um sistema Unix ou MacOS, abra um terminal e digite os seguintes comandos para realizar as tarefas descritas acima:

$ mkdir twilio-openai-bot
$ cd twilio-openai-bot
$ python3 -m venv venv
$ source venv/bin/activate
(venv) $ pip install openai twilio flask python-dotenv pyngrok

Se você estiver seguindo o tutorial no Windows, digite os seguintes comandos em uma janela do prompt de comando:

$ md twilio-openai-bot
$ cd twilio-openai-bot
$ python -m venv venv
$ venv\Scripts\activate
(venv) $ pip install openai twilio flask python-dotenv pyngrok

O último comando usa pip, o instalador de pacotes Python, para instalar estes três pacotes que vamos usar no projeto:

Configuração

Como mencionado acima, este projeto requer uma chave de API da OpenAI. No momento em que escrevo isto, a única maneira de obter uma é sendo aceito em seu programa beta privado. Você pode se inscrever no site.

O aplicativo Python precisará ter acesso a essa chave, então vamos criar um arquivo .env no qual colocá-lo. O aplicativo o importará desse arquivo como uma variável de ambiente.

Crie um arquivo .env no diretório do projeto (anote o ponto inicial) e insira uma única linha de texto contendo o seguinte:

OPENAI_KEY=your-openai-api-key-here

Você aprenderá a trabalhar com este arquivo na próxima seção. Se você planeja colocar seu projeto sob controle de código-fonte, certifique-se de que esse arquivo seja excluído, pois não gostaria de compartilhar acidentalmente sua chave da OpenAI.

Enviar solicitações GPT-3 do Python

Nesta seção, vamos criar o código de suporte que nos permitirá trabalhar com o mecanismo OpenAI GPT-3. O código será armazenado em um arquivo chamado chatbot.py. Abaixo, você pode ver a seção de inicialização deste arquivo:

import os
from dotenv import load_dotenv
import openai

load_dotenv()
openai.api_key = os.environ.get('OPENAI_KEY')
completion = openai.Completion()

start_chat_log = '''Human: Hello, who are you?
AI: I am doing great. How can I help you today?
'''

A função load_dotenv() importa todas as variáveis armazenadas em um arquivo .env como variáveis de ambiente. Observe como usamos a variável OPENAI_KEY na linha a seguir para inicializar a OpenAI com a chave. A variável completion mantém o cliente real no mecanismo. Este é o objeto que usaremos para enviar consultas.

Também adicionei uma variável start_chat_log, contendo as duas linhas que fazem a preparação do mecanismo. Assim que o bot estiver ativo e em execução, incentivo você a experimentar diferentes interações nessa variável para ver como o bot muda suas respostas de acordo.

Agora, vamos escrever uma função que faz uma consulta GPT-3. Adicione a seguinte função na parte inferior de chatbot.py:

def ask(question, chat_log=None):
    if chat_log is None:
        chat_log = start_chat_log
    prompt = f'{chat_log}Human: {question}\nAI:'
    response = completion.create(
        prompt=prompt, engine="davinci", stop=['\nHuman'], temperature=0.9,
        top_p=1, frequency_penalty=0, presence_penalty=0.6, best_of=1,
        max_tokens=150)
    answer = response.choices[0].text.strip()
    return answer

A função ask() usa a pergunta do usuário como primeiro argumento, seguida por um histórico do chat opcional. Se o histórico do chat não for fornecido, então a função usará start_chat_log.

A variável prompt é criada para conter o histórico do chat, seguida da pergunta do usuário, que é prefixada com Human:. Após a pergunta do usuário, adicionamos a leitura da linha final AI:, que é o que dará ao mecanismo GPT-3 a fila para gerar uma resposta à pergunta do usuário.

A função completion_create() é onde a solicitação para o mecanismo GPT-3 é realmente feita. Essa função usa vários argumentos, que são usados para configurar como o mecanismo deve completar o texto. Aqui está uma breve descrição dos seguintes argumentos:

  • prompt: o texto de entrada
  • engine: o OpenAI disponibilizou quatro mecanismos de preenchimento de texto, denominados davinciadababbage e curie. Estamos usando davinci, que é o mais capaz dos quatro.
  • stop: como mencionei anteriormente, o mecanismo GPT-3 não compreende realmente o texto, portanto, quando ele completa o texto, ele precisa saber quando parar. Dando uma parada de Human: , estamos dizendo ao mecanismo apenas para gerar texto até a linha que começa com AI:. Sem um marcador de parada, GPT-3 continuaria gerando texto escrevendo mais linhas para o usuário e para a AI.
  • temperature: um número entre 0 e 1 que determina quantos riscos criativos o mecanismo assume ao gerar texto.
  • top_p: uma forma alternativa de controlar a originalidade e criatividade do texto gerado.
  • frequency_penalty: um número entre 0 e 1. Quanto mais alto esse valor, mais o modelo se esforçará para não se repetir.
  • presence_penalty: um número entre 0 e 1. Quanto maior esse valor, mais o modelo se esforçará para falar sobre tópicos novos.
  • max_tokens: comprimento máximo do preenchimento.

Essas não são as únicas opções possíveis, então recomendo que você revise a Documentação de referência da OpenAI para saber mais sobre como configurar sua solicitação.

A resposta do mecanismo de preenchimento é um objeto que tem um atributo choices, que é uma lista de preenchimentos. Não solicitamos vários preenchimentos, por isso a lista terá um único elemento. Esse elemento é um dicionário Python com uma chave text que contém o texto gerado. Nossa função pega esse texto, remove qualquer espaço em branco à esquerda ou à direita e o devolve ao autor da chamada. Como mencionado acima, consulte a documentação da API para ver informações sobre outros itens de dados incluídos na resposta da GPT-3.

Vamos iniciar um Python shell e brincar com a função ask():

>>> from chatbot import ask
>>> ask('Who played Forrest Gump in the movie?')
'Oh my, that is a tough one! Forrest Gump was played by Tom Hanks.'
>>> ask('How long does it take to travel from Los Angeles to Dublin?')
'It takes about 12 hours to fly from Los Angeles to Dublin. You may want to fly through Heathrow Airport in London.'

Muito legal, não é? Está faltando a segunda parte do nosso algoritmo, na qual anexamos uma pergunta e sua resposta ao histórico do chat, para que possamos usá-la na pergunta a seguir. Podemos implementar uma segunda função para atualizar o histórico do chat:

def append_interaction_to_chat_log(question, answer, chat_log=None):
    if chat_log is None:
        chat_log = start_chat_log
    return f'{chat_log}Human: {question}\nAI: {answer}\n'

Esta função faz uma pergunta e uma resposta e as adiciona na parte inferior do histórico do chat. O histórico do chat atualizado é retornado.

Agora, podemos ter uma conversa em que o contexto é preservado. Tente o seguinte em uma nova sessão do Python shell:

>>> from chatbot import ask, append_interaction_to_chat_log
>>> chat_log = None

>>> question = 'Who played Forrest Gump in the movie?'
>>> answer = ask(question, chat_log)
>>> answer
'Forrest Gump is a 1994 American romantic comedy-drama film based on the 1986 novel of the same name by Winston Groom. The film was directed by Robert Zemeckis and was adapted for the screen by Eric Roth. It stars Tom Hanks as Forrest Gump, for which he won the Academy Award for Best Actor, and was nominated for Best Picture.'

>>> chat_log = append_interaction_to_chat_log(question, answer, chat_log)

>>> question = 'Was he in any other great roles?'
>>> answer = ask(question, chat_log)
>>> answer
'He played the protagonist in The Green Mile (1999), a drama film based on the Stephen King novel of the same name.'

Essas duas funções são tudo o que precisamos para gerenciar nosso bate-papo. Nas próximas seções, vamos integrá-las às mensagens do Twilio SMS.

Configurar Twilio Programmable Messaging

Em seguida, vamos configurar um número de telefone habilitado para Twilio SMS para usar o chatbot. Se você ainda não criou uma conta gratuita do Twilio, crie-a agora e faça login.

No Console da Twilio, selecione Phone Numbers (Números de telefone) e clique no sinal de adição vermelho para comprar um número Twilio. Na página Buy a Number (Comprar um número), selecione seu país e marque SMS no campo de recursos. Caso queira solicitar um número para sua região, informe seu código de área no campo Number (Número).

Tela comprar um número de telefone da Twilio

Clique no botão "Search" (Pesquisar) para ver quais números estão disponíveis e, em seguida, clique em "Buy" (Comprar) para adquirir o número de sua preferência exibido nos resultados. Depois de confirmar a compra, clique no botão "Close" (Fechar). Se você estiver usando uma conta de teste, os fundos dessa compra virão do seu crédito de teste.

Parabéns, agora você tem seu próprio número de telefone programável! Pegue seu smartphone e envie uma mensagem de texto para seu novo número para verificar se ele está funcionando. Você deve receber uma resposta pedindo para que você configure seu número, o que você fará em seguida.

Primeiro texto com um webhook padrão da Twilio

API do Twilio SMS usa um webhook para notificar um aplicativo quando uma mensagem é recebida. A resposta automatizada que você recebeu quando enviou uma mensagem de texto para seu número da Twilio, na verdade, vem de um webhook padrão que é instalado pela Twilio no seu número. O aplicativo chatbot terá um novo webhook que substituirá o padrão.

Com a estrutura do Flask, é extremamente fácil definir um webhook. Veja abaixo um esqueleto de aplicativo com uma definição do webhook. Copie o seguinte código em um novo arquivo chamado app.py:

from flask import Flask, request
from twilio.twiml.messaging_response import MessagingResponse

app = Flask(__name__)


@app.route('/bot', methods=['POST'])
def bot():
    incoming_msg = request.values['Body']

    # use the incoming message to generate the response here

    r = MessagingResponse()
    r.message('this is the response')
    return str(r)

Esse código cria um aplicativo Flask que tem um endpoint com o URL /bot. Quando a Twilio estiver configurada para saber sobre esse endpoint, ela enviará uma solicitação sempre que um SMS for recebido no número de telefone que você adquiriu anteriormente. O aplicativo pode ler a mensagem recebida, fazer algum processamento e gerar uma resposta, que é retornada no final da função.

Você pode iniciar o aplicativo acima da seguinte forma:

(venv) $ flask run
 * Serving Flask app "app" (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

O aplicativo agora está sendo executado no seu computador no URL http://localhost:5000, mas não pode ser acessado pela Internet. A próxima etapa é fornecer um URL público temporário que podemos dar ao Twilio para que ele possa enviar solicitações. Esse trabalho é feito pela ferramenta ngrok. Deixe o aplicativo em execução e abra um segundo terminal. Ative o ambiente virtual neste terminal, do mesmo modo que você fez no primeiro no início do tutorial e, em seguida, digite o seguinte comando:

(venv) $ ngrok http 5000

Você verá uma tela semelhante a esta:

ngrok na linha de comando

Observe as linhas que começam com "Forwarding". Elas mostram o URL público usado pelo ngrok para redirecionar solicitações para o nosso serviço no formato http:// e https://. O que precisamos fazer agora é instruir a Twilio a enviar as notificações recebidas via SMS para esse URL.

Volte para o console da Twilio, clique em Phone Numbers (Números de telefone) e, em seguida, no número de telefone adquirido acima. Role a página até a seção "Messaging" (Mensagens), copie o URL https:// da saída do ngrok e cole-o no campo "When a message comes in" (Quando receber uma mensagem). O endpoint que criamos acima é exposto no URL /bot, portanto /bot precisa ser anexado ao final do URL do ngrok raiz. Verifique se o método de solicitação está definido como HTTP POST. Não se esqueça de clicar no botão azul Save (Salvar), na parte inferior da página, para registrar essas alterações.

Webhook de mensagens da Twilio

Envie outro SMS para o seu número de telefone da Twilio e você receberá a resposta que vem do aplicativo Flask:

Resposta do Flask via Ngrok

Agora, sabemos como executar o mecanismo GPT-3 e como receber e responder mensagens SMS com o Twilio. Na próxima seção, integraremos os dois e teremos um projeto de chatbot completo.

Chatbot de SMS com OpenAI e Twilio

Vamos expandir app.py para enviar mensagens de usuário para a função ask() que criamos acima e para manter o histórico do chat. Aqui estão os conteúdos atualizados do app.py:

from flask import Flask, request, session
from twilio.twiml.messaging_response import MessagingResponse
from chatbot import ask, append_interaction_to_chat_log

app = Flask(__name__)
app.config['SECRET_KEY'] = 'top-secret!'


@app.route('/bot', methods=['POST'])
def bot():
    incoming_msg = request.values['Body']
    chat_log = session.get('chat_log')

    answer = ask(incoming_msg, chat_log)
    session['chat_log'] = append_interaction_to_chat_log(incoming_msg, answer,
                                                         chat_log)

    r = MessagingResponse()
    r.message(answer)
    return str(r)

O local mais conveniente para armazenar o histórico do chat com um usuário é a variável session do Flask, que usa um cookie HTTP para armazenamento. O Twilio funciona como se fosse um navegador da Web e, nesse sentido, ele aceitará, armazenará (por até quatro horas) e enviará novamente os cookies durante uma conversa com um usuário. Se houver dois ou mais usuários conversando com o bot ao mesmo tempo, cada um terá seu próprio cookie.

Como os cookies de sessão são assinados, o aplicativo Flask precisa ter uma chave secreta configurada. Por segurança, você deve substituir o valor do espaço reservado que usei para a chave secreta por algo exclusivo.

O endpoint bot() começa obtendo a mensagem do usuário como antes e o histórico do chat da sessão. O objeto session usa a sintaxe de dicionário familiar, portanto session.get() retornará um histórico do chat armazenado anteriormente se existir ou None se esse usuário não tiver uma sessão. Isso é conveniente porque as funções no chatbot.py usam o histórico do chat padrão se passarmos None.

Chamar a função ask() funciona exatamente como antes. Nós passamos a mensagem do usuário e o histórico do chat e voltamos ao preenchimento feito pelo mecanismo GPT-3, que é a nossa resposta.

A pergunta e a resposta são anexadas ao histórico do chat e a versão atualizada dele é salva na sessão do usuário para que, na próxima interação com ele, o histórico do chat completo seja usado.

Para encerrar a função, a resposta é retornada como resposta, e isso a enviará de volta ao usuário por SMS.

Pronto para testar seu novo bot? Se você ainda estiver executando o aplicativo Flask, interrompa-o apertando Ctrl-C e execute-o novamente para que ele incorpore as atualizações mais recentes. Se você não estiver mais executando o ngrok, vá para seu segundo terminal e reinicie-o. Depois, siga as instruções na seção anterior para atualizar seu URL webhook no console da Twilio, já que o ngrok cria um URL diferente toda vez que ele é executado.

Com o aplicativo Flask e o ngrok em execução, você está pronto para começar a enviar SMS para o bot. Envie uma mensagem de texto com sua primeira pergunta para o número de telefone da Twilio como você fez antes e, em alguns segundos, a resposta deve chegar. Fique à vontade para testar o bot com assuntos diferentes, ele sabe sobre muitas coisas!

No exemplo de interação a seguir, o bot parece estar perdendo a paciência com as minhas perguntas bobas, mas veja como manter o histórico do chat na sessão do usuário deixa essa conversa com um tom muito natural:

Conversa completa com um chatbot OpenAI

Conclusão

Espero que você tenha se divertido tanto quanto eu com este projeto! As possibilidades do mecanismo de conclusão GPT-3 são infinitas, por isso recomendo que você experimente ele adaptando este projeto para criar outros usos originais além de bate-papo.

Se você criar seu próprio bot, quero saber sobre sua experiência!

Este artigo foi traduzido do original "Building a Chatbot with OpenAI's GPT-3 engine, Twilio SMS and Python". Enquanto melhoramos nossos processos de tradução, adoraríamos receber seus comentários em help@twilio.com - contribuições valiosas podem render brindes da Twilio.