{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"\n",
"# Criando uma assistente virtual com Whisper, ChatGPT e ElevenLabs API\n",
"\n",
"O uso do **ChatGPT** é cada vez mais comum no nosso dia-a-dia. A IA criada pela [OpenAI](https://openai.com/) é utilizada largamente para os mais diferentes propósitos, desde a criação de textos para [roteiros de vídeos](https://filmora.wondershare.com.br/chatgpt/generate-youtube-script-with-chatgpt.html), [auxílio à estudantes](https://www.techtudo.com.br/listas/2023/03/6-truques-muito-uteis-do-chatgpt-que-vao-ajudar-voce-a-estudar-melhor-edsoftwares.ghtml) e até em [processos judiciais](https://g1.globo.com/tecnologia/noticia/2023/05/29/advogado-usa-casos-inventados-pelo-chatgpt-em-processo-judicial-e-leva-puxao-de-orelha-de-juiz.ghtml). Independente das polêmicas envolvendo o seu uso, é inegável que a tecnologia já faz parte do nosso cotidiano.\n",
"\n",
"Assim como outros *chatbots*, todas as interações realizadas com a IA (tanto os prompts quanto as respostas geradas) ocorrem via texto. Por isso, a intenção desse projeto é realizar interações com o ChatGPT através de áudio, de modo que os prompts sejam feitos com a fala do usuário e a respostas sejam transmitidas através de voz sintética; simulando, assim, uma conversa natural. Para esse feito foram utilizadas bibliotecas para gravação de fala em **Python**, o **Whisper** para transcrição de áudio e a integração com as APIs da **OpenAI** e da **ElevenLabs**, para gerar as respostas e a voz sintética natural, respectivamente.\n",
"\n",
""
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Preparando o ambiente\n",
"\n",
"Esse projeto será divido em 4 etapas: \n",
"\n",
"1. Gravação do prompt do usuário em voz;\n",
"2. Transcrição do áudio em texto;\n",
"3. Envio do texto transcrito para a API do ChatGPT e captura da resposta, também em texto;\n",
"4. Envio do texto de resposta para a API da ElevenLabs e captura do áudio sintetizado.\n",
"\n",
"Iniciaremos com a preparação do ambiente, instalando as bibliotecas e pacotes necessários. \n",
"\n",
" - Para a gravação do áudio, utilizaremos a biblioteca **sounddevice** em conjunto com o pacote **write** da biblioteca **scipy**;\n",
" - Para a transcrição do áudio utilizaremos o **Whisper**, da própria OpenAI. Precisaremos, também, da **ffmpeg-python** para a conversão do áudio gravado e envio para o Whisper;\n",
" - Para a integração com a API do ChatGPT, precisaremos da biblioteca **openai**;\n",
" - Finalmente, para a sintetização do áudio, precisaremos integrar com a API da ElevenLabs, utilizando sua própria biblioteca **elevenlabs**.\n",
"\n",
" "
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"#---Definindo o idioma padrão de gravação e reconhecimento de voz---#\n",
"language = \"pt\"\n",
"\n",
"#---Instalando as bibliotecas necessárias para a gravação do áudio---#\n",
"#%pip install sounddevice\n",
"#%pip install scipy\n",
"\n",
"#---Instalando o Whisper para reconhecimento de voz---#\n",
"#%pip install git+https://github.com/openai/whisper.git\n",
"\n",
"#---Instalando o ffmpeg para conversão de áudio---#\n",
"#%pip install ffmpeg-python\n",
"\n",
"#---Instalando a biblioteca da openai para a resposta---#\n",
"#%pip install openai\n",
"\n",
"#---Instalando a biblioteca da ElevenLABS para sintetização da voz do texto de resposta---#\n",
"#%pip install elevenlabs"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 01 - Gravando o prompt em áudio\n",
"\n",
"A biblioteca **python-sounddevice** nos permite gravar áudios através do microfone do computador e armazená-los como um array NumPy. Esse é um tipo de dados muito útil para processamento de som que pode ser convertido posteriormente como um arquivo WAV utilizando o módulo **scipy.io.wavfile** da biblioteca **scipy** (adaptado de [Real Python](https://realpython.com/playing-and-recording-sound-python/#python-sounddevice_1))."
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Ouvindo....\n"
]
}
],
"source": [
"#Importando as bibliotecas para a gravação de áudio\n",
"import sounddevice as sd\n",
"from scipy.io.wavfile import write\n",
"\n",
"#Definindo os parâmetros da gravação\n",
"fs = 44100 #Sample rate\n",
"seconds = 5 #Duração da gravação\n",
"\n",
"#Ininciando a gravação\n",
"print(\"Ouvindo....\")\n",
"minha_gravacao = sd.rec(int(fs * seconds), samplerate = fs, channels = 2)\n",
"sd.wait()\n",
"\n",
"#Salvando o arquivo de áudio\n",
"write(\"../audio/minha_gravacao.wav\", fs, minha_gravacao)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 02 - Transcrevendo com o Whisper\n",
"\n",
"Para a transcrição do áudio utilizaremos a biblioteca **whisper**, da própria OpenAI, que é um modelo de reconhecimento de fala de uso geral treinado em um grande conjunto de dados de áudio e também é um modelo multitarefa que pode realizar reconhecimento de fala multilíngue, tradução de fala e identificação de idioma.\n",
"\n",
"São cinco tamanhos de modelos, quatro com versões somente em inglês, oferecendo *tradeoffs* de velocidade e precisão. Abaixo estão os nomes dos modelos disponíveis e seus requisitos aproximados de memória e velocidade de inferência em relação ao modelo grande; a velocidade real pode variar dependendo de muitos fatores, incluindo o hardware disponível (Adaptado de [github/openai/whisper](https://github.com/openai/whisper)).\n",
"\n",
"| Tamanho | Parâmetros | Modelo apenas inglês | Modelo multilíngue | VRAM necessária | Velocidade relativa |\n",
"|--------|------------|--------------------|--------------------|---------------|----------------|\n",
"| tiny | 39 M | tiny.en | tiny | ~1 GB | ~32x |\n",
"| base | 74 M | base.en | base | ~1 GB | ~16x |\n",
"| small | 244 M | small.en | small | ~2 GB | ~6x |\n",
"| medium | 769 M | medium.en | medium | ~5 GB | ~2x |\n",
"| large | 1550 M | N/A | large | ~10 GB | 1x |\n",
"\n",
"Para esse projeto utilizamos o modelo small, que já nos dá uma excelente performance."
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Entendendo.....\n",
"\n",
"Você disse: \n",
" Cri uma história infantil de até 300 caracteres.\n"
]
}
],
"source": [
"#Importando o Whisper\n",
"import whisper\n",
"\n",
"#Iniciando o reconhecimento de voz\n",
"print(\"Entendendo.....\")\n",
"\n",
"#Selecionando o modelo de reconhecimento de voz\n",
"model = whisper.load_model(\"small\")\n",
"\n",
"#Transcrevendo o áudio gravado\n",
"resultado = model.transcribe(\"../audio/minha_gravacao.wav\", fp16 = False, language = language)\n",
"transcricao = resultado[\"text\"]\n",
"\n",
"#Imprimindo a transcrição para validação\n",
"print(\"\\nVocê disse: \")\n",
"print(transcricao)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 03 - Enviando para o ChatGPT via API da OpenAI\n",
"\n",
"Após recuperarmos a transcrição do áudio em texto feito pelo **whisper**, realizaremos uma request à API do OpenAI através do *endpoint* **Creat Chat Completions**, utilizando o modelo **GPT 3.5 Turbo** e enviando o texto recuperado.\n",
"\n",
"Como *response* teremos um *JSON* parecido com o exemplo abaixo (Disponível em [platform.openai](https://platform.openai.com/docs/api-reference/chat/create)):\n",
"\n",
"```\n",
"{\n",
" \"id\": \"chatcmpl-123\",\n",
" \"object\": \"chat.completion\",\n",
" \"created\": 1677652288,\n",
" \"model\": \"gpt-3.5-turbo-0613\",\n",
" \"system_fingerprint\": \"fp_44709d6fcb\",\n",
" \"choices\": [{\n",
" \"index\": 0,\n",
" \"message\": {\n",
" \"role\": \"assistant\",\n",
" \"content\": \"\\n\\nHello there, how may I assist you today?\",\n",
" },\n",
" \"logprobs\": null,\n",
" \"finish_reason\": \"stop\"\n",
" }],\n",
" \"usage\": {\n",
" \"prompt_tokens\": 9,\n",
" \"completion_tokens\": 12,\n",
" \"total_tokens\": 21\n",
" }\n",
"}\n",
"\n",
"```\n",
"\n",
"Do qual recuperaremos a resposta enviada pelo **ChatGPT** através do conteúdo (*content*) da mensagem (*message*) da escolha (*choice*) de *index* *0* no JSON."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Gerando resposta....\n",
"\n",
"Minha resposta em texto: \n",
"Era uma vez um coelhinho chamado Pimpão, que vivia em um lindo jardim. Um dia, ele encontrou uma mágica poção de crescimento. Curioso, Pimpão decidiu experimentar e se tornou o maior coelho que já existiu. Todos no jardim ficaram maravilhados com ele e Pimpão aprendeu a importância de ser feliz do jeito que era.\n"
]
}
],
"source": [
"#Importando a biblioteca da openai \n",
"import openai\n",
"\n",
"#importando a biblioteca os para utilização da API KEY\n",
"import os\n",
"\n",
"#Recuperando a API KEY\n",
"openai.api_key = os.environ.get(\"OPENAI_API_KEY\")\n",
"\n",
"#Iniciando a geração da resposta\n",
"print(\"Gerando resposta....\")\n",
"\n",
"#Enviando a transcrição para a API da openai\n",
"response = openai.chat.completions.create(\n",
" model = \"gpt-3.5-turbo\",\n",
" messages = [{\n",
" \"role\":\"user\",\n",
" \"content\":transcricao\n",
" }]\n",
")\n",
"\n",
"#Recuperando a resposta da API\n",
"chatgpt_response = response.choices[0].message.content\n",
"\n",
"#Imprimindo a resposta para validação\n",
"print(\"\\nMinha resposta em texto: \")\n",
"print(chatgpt_response)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 04 - Sintetizando a resposta com a ElevenLABS API\n",
"\n",
"Por último, iremos utilizar a API da **ElevenLabs** para sintetizar o texto da resposta recebida pelo ChatGPT em voz. A ElevenLabs é possui um dos modelos de voz sintéticas mais avançados atualmente e que produz resultados impressionantes e bastante naturais, por isso sua escolha.\n",
"\n",
"Para utilizar a API precisamos apenas enviar o texto que será sintetizado e o modelo de nossa preferência (multi ou monolíngue em suas versões v1 ou v2), porém escolhi uma voz específica através da `voice_id` e realizei algumas configurações extras na `stability` e na `similarity_boost`, que modificam a **tonalidade** e a **animação** (emoção) da voz gerada. A documentação da API ([aqui](https://elevenlabs.io/docs/introduction)) trás uma descrição detalhada de todas as `voice_id` disponíveis e como as configurações impactam na voz gerada.\n"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Salvando resposta....\n",
"\n",
"Respondendo....\n"
]
}
],
"source": [
"#Importando as bibliotecas necessárias\n",
"from elevenlabs import generate, play, save, Voice, VoiceSettings\n",
"\n",
"#configurações da voz\n",
"conf = Voice(\n",
" voice_id = \"21m00Tcm4TlvDq8ikWAM\", \n",
" settings = VoiceSettings(\n",
" stability = 0.2,\n",
" similarity_boost = 0.2\n",
" )\n",
")\n",
"\n",
"#Gerando o áudio da resposta\n",
"audio = generate(\n",
" text = chatgpt_response,\n",
" voice = conf, \n",
" model = \"eleven_multilingual_v1\" \n",
") \n",
"\n",
"#Salvando o áudio da resposta\n",
"print(\"Salvando resposta....\")\n",
"save(audio, \"../audio/resposta.wav\")\n",
"\n",
"#Reproduzindo o áudio da resposta\n",
"print(\"\\nRespondendo....\")\n",
"play(audio)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Finalizando\n",
"\n",
"Com esses passos conseguimos concluir com sucesso o objetivo do projeto e criar uma interação natural via áudio com o **ChatGPT**, utilizando o **python-sounddevice**, **whisper**, **openai** e **elevenlabs**. Os áudios da minha gravação e da resposta do ChatGPT sintetizada via ElevenLabs ficaram salvas na pasta `audio`, para verificação e validação."
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.10.5"
}
},
"nbformat": 4,
"nbformat_minor": 2
}