#!/usr/bin/env python
# coding: utf-8
#
#
# # Criando uma assistente virtual com Whisper, ChatGPT e ElevenLabs API
#
# 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.
#
# 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.
#
#
# ## Preparando o ambiente
#
# Esse projeto será divido em 4 etapas:
#
# 1. Gravação do prompt do usuário em voz;
# 2. Transcrição do áudio em texto;
# 3. Envio do texto transcrito para a API do ChatGPT e captura da resposta, também em texto;
# 4. Envio do texto de resposta para a API da ElevenLabs e captura do áudio sintetizado.
#
# Iniciaremos com a preparação do ambiente, instalando as bibliotecas e pacotes necessários.
#
# - Para a gravação do áudio, utilizaremos a biblioteca **sounddevice** em conjunto com o pacote **write** da biblioteca **scipy**;
# - 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;
# - Para a integração com a API do ChatGPT, precisaremos da biblioteca **openai**;
# - Finalmente, para a sintetização do áudio, precisaremos integrar com a API da ElevenLabs, utilizando sua própria biblioteca **elevenlabs**.
#
#
# In[2]:
#---Definindo o idioma padrão de gravação e reconhecimento de voz---#
language = "pt"
#---Instalando as bibliotecas necessárias para a gravação do áudio---#
#%pip install sounddevice
#%pip install scipy
#---Instalando o Whisper para reconhecimento de voz---#
#%pip install git+https://github.com/openai/whisper.git
#---Instalando o ffmpeg para conversão de áudio---#
#%pip install ffmpeg-python
#---Instalando a biblioteca da openai para a resposta---#
#%pip install openai
#---Instalando a biblioteca da ElevenLABS para sintetização da voz do texto de resposta---#
#%pip install elevenlabs
# ## 01 - Gravando o prompt em áudio
#
# 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)).
# In[31]:
#Importando as bibliotecas para a gravação de áudio
import sounddevice as sd
from scipy.io.wavfile import write
#Definindo os parâmetros da gravação
fs = 44100 #Sample rate
seconds = 5 #Duração da gravação
#Ininciando a gravação
print("Ouvindo....")
minha_gravacao = sd.rec(int(fs * seconds), samplerate = fs, channels = 2)
sd.wait()
#Salvando o arquivo de áudio
write("../audio/minha_gravacao.wav", fs, minha_gravacao)
# ## 02 - Transcrevendo com o Whisper
#
# 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.
#
# 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)).
#
# | Tamanho | Parâmetros | Modelo apenas inglês | Modelo multilíngue | VRAM necessária | Velocidade relativa |
# |--------|------------|--------------------|--------------------|---------------|----------------|
# | tiny | 39 M | tiny.en | tiny | ~1 GB | ~32x |
# | base | 74 M | base.en | base | ~1 GB | ~16x |
# | small | 244 M | small.en | small | ~2 GB | ~6x |
# | medium | 769 M | medium.en | medium | ~5 GB | ~2x |
# | large | 1550 M | N/A | large | ~10 GB | 1x |
#
# Para esse projeto utilizamos o modelo small, que já nos dá uma excelente performance.
# In[3]:
#Importando o Whisper
import whisper
#Iniciando o reconhecimento de voz
print("Entendendo.....")
#Selecionando o modelo de reconhecimento de voz
model = whisper.load_model("small")
#Transcrevendo o áudio gravado
resultado = model.transcribe("../audio/minha_gravacao.wav", fp16 = False, language = language)
transcricao = resultado["text"]
#Imprimindo a transcrição para validação
print("\nVocê disse: ")
print(transcricao)
# ## 03 - Enviando para o ChatGPT via API da OpenAI
#
# 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.
#
# Como *response* teremos um *JSON* parecido com o exemplo abaixo (Disponível em [platform.openai](https://platform.openai.com/docs/api-reference/chat/create)):
#
# ```
# {
# "id": "chatcmpl-123",
# "object": "chat.completion",
# "created": 1677652288,
# "model": "gpt-3.5-turbo-0613",
# "system_fingerprint": "fp_44709d6fcb",
# "choices": [{
# "index": 0,
# "message": {
# "role": "assistant",
# "content": "\n\nHello there, how may I assist you today?",
# },
# "logprobs": null,
# "finish_reason": "stop"
# }],
# "usage": {
# "prompt_tokens": 9,
# "completion_tokens": 12,
# "total_tokens": 21
# }
# }
#
# ```
#
# 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.
# In[4]:
#Importando a biblioteca da openai
import openai
#importando a biblioteca os para utilização da API KEY
import os
#Recuperando a API KEY
openai.api_key = os.environ.get("OPENAI_API_KEY")
#Iniciando a geração da resposta
print("Gerando resposta....")
#Enviando a transcrição para a API da openai
response = openai.chat.completions.create(
model = "gpt-3.5-turbo",
messages = [{
"role":"user",
"content":transcricao
}]
)
#Recuperando a resposta da API
chatgpt_response = response.choices[0].message.content
#Imprimindo a resposta para validação
print("\nMinha resposta em texto: ")
print(chatgpt_response)
# ## 04 - Sintetizando a resposta com a ElevenLABS API
#
# 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.
#
# 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.
#
# In[5]:
#Importando as bibliotecas necessárias
from elevenlabs import generate, play, save, Voice, VoiceSettings
#configurações da voz
conf = Voice(
voice_id = "21m00Tcm4TlvDq8ikWAM",
settings = VoiceSettings(
stability = 0.2,
similarity_boost = 0.2
)
)
#Gerando o áudio da resposta
audio = generate(
text = chatgpt_response,
voice = conf,
model = "eleven_multilingual_v1"
)
#Salvando o áudio da resposta
print("Salvando resposta....")
save(audio, "../audio/resposta.wav")
#Reproduzindo o áudio da resposta
print("\nRespondendo....")
play(audio)
# ## Finalizando
#
# 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.