Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file not shown.
Binary file not shown.
1 change: 1 addition & 0 deletions AssistenteVirtual/AssistenteVirtual/Config/keys.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
GROQ_API_KEY = "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"
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
87 changes: 87 additions & 0 deletions AssistenteVirtual/AssistenteVirtual/Core/comandos.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import webbrowser #? Importa o modulu que permite que o python abra urls no navegador, como youtube etc
import datetime #? módulo de data/hora
import os #? módulo do sistema operacional
from googleapiclient.discovery import build #? importa a função build da biblioteca googleapiclient. Esta função é crucial para conectar seu código à API de Dados do YouTube.

YOUTUBE_API_KEY = "AIzaSyCPtKQkPYuKihl1RRmNsEe9HFfy-b7ZxMw"
youtube = build("youtube", "v3", developerKey=YOUTUBE_API_KEY) #? Cria um objeto chamado youtube que será usado para fazer todas as chamadas à API, meio que o telefone para ligar para o servidor


def abrir_youtube():
webbrowser.open("https://www.youtube.com/")
return "Abrindo YouTube."


def abrir_google():
webbrowser.open("https://www.google.com.br/index.html")
return "Abrindo Google."


def dizer_hora(): #? pega a hora atual e retorna uma string formatada.
agora = datetime.datetime.now().strftime("%H:%M") #? retorna um objeto datetime com data e hora atuais e converte esse objeto em uma str formatada, %H = hora com 2 dígitos, %M = minuto com 2 dígitos
return f"Agora são {agora}"


def abrir_programa(caminho): #? abre um programa no Windows pelo caminho completo.
try:
os.startfile(caminho)
return f"Abrindo programa em: {caminho}"
except Exception as e:
return f"Erro ao abrir o programa: {e}"


def buscar_video(termo): #? Busca o primeiro vídeo correspondente ao termo.
req = youtube.search().list( #? constrói a requisição para a API
q=termo, #? termo de busca
part="snippet", #! especifica que quer o trecho snippet dos resultados (título/descrição).
maxResults=1, #? pede só 1 resultado
type="video" #? restringe a busca a vídeos (não playlists ou canais)
)

res = req.execute()

if not res["items"]: #? resposta da API tem uma estrutura JSON; se nada for encontrado, none em caso de erro e tals
return None

video_id = res["items"][0]["id"]["videoId"]
return f"https://www.youtube.com/watch?v={video_id}"


def abrir_video(termo):
url = buscar_video(termo) #? chama a função para obter a url. 1- envia a requisição para a API do YouTube, 2- recebe a lista de resultados, 3- pega apenas o primeiro vídeo retornado, 4- extrai o videoId, 5- e monta a url(exempli: https://www.youtube.com/watch?v=VIDEO_ID_AQUI)

if not url:
return "Não encontrei esse vídeo. Verifique o nome ou sua API KEY."

webbrowser.open(url)
return f"Reproduzindo {termo} no YouTube."


def interpretar_comando(texto):
texto = texto.lower() #? Deixa tudo em minusculo

comandos_musica = ["tocar", "ouvir", "música", "reproduzir"] #? Palavras chaves para exexutar a função

for cmd in comandos_musica: #? Faz loop dentro da lista de palavras de ativação
if cmd in texto: #? Procura essa palavra no testo que vc falou
indice = texto.find(cmd) #? ele pega o indice aonde esta a plavra de ativação
termo_busca = texto[indice + len(cmd):].strip() #? e pega o texto a frente(exemplo: tocar ride, ele pega ride para pesquisar)

if termo_busca:
return abrir_video(termo_busca)
else:
return "Qual música você quer ouvir?"

# ----------------------------------
# 📌 Comandos básicos
# ----------------------------------
if "youtube" in texto:
return abrir_youtube()
elif "google" in texto:
return abrir_google()
elif "hora" in texto:
return dizer_hora()
elif "calculadora" in texto:
return abrir_programa("C:\\Windows\\System32\\calc.exe")

return None
33 changes: 33 additions & 0 deletions AssistenteVirtual/AssistenteVirtual/Core/historico.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import json # ? importa biblioteca para salvar e carregar estruturas python em JSON
import os # ? Importa funçoes relacionadas ao sistema

CAMINHO_HISTORICO = "C:/Users/rrsilva/Downloads/Code/Assistente/data/Historico.json"

def carregar_historico(): # ? Carrega o historico do arquivo JSON
if os.path.exists(CAMINHO_HISTORICO): # ? Verifica se o ficheiro data/historico.json existe. Se não existir, a função vai retornar uma lista vazia no final.
try:
with open(CAMINHO_HISTORICO, "r", encoding="utf-8") as f: # ? Abre o ficheiro em modo leitura ("r") com codificação UTF-8.
return json.load(f)
except json.JSONDecodeError:
return []
return []


def salvar_historico(historico): # ? recebe a lista historico e a grava no ficheiro JSON..
with open(CAMINHO_HISTORICO, "w", encoding="utf-8") as f: # ? Abre o ficheiro em modo escrita ("w"),
json.dump(historico, f, ensure_ascii=False, indent=2)


def adicionar_mensagem(historico, role, content): # ? Adiciona nova mensagem ao historico.
historico.append({"role": role, "content": content}) # ? Acrescenta um dicionário com as chaves role e content à lista historico. Exemplo: {"role": "user", "content": "Olá"}.

if len(historico) > 50: # ? Se o tamanho do histórico exceder 20 entradas,
historico.pop(0) # ? remove a primeira (mensagem mais antiga)

salvar_historico(historico)
return historico


def limpar_historico(): # ? Apaga todo o historico
if os.path.exists(CAMINHO_HISTORICO):
os.remove(CAMINHO_HISTORICO)
41 changes: 41 additions & 0 deletions AssistenteVirtual/AssistenteVirtual/Core/ia.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from groq import Groq #? 📌 Importa a classe groq que é responsável por fazer chamadas para o endpoint
from Config.keys import GROQ_API_KEY #? 📌 Esta importando a variavel/chave do arquivo ja criado da past config

client = Groq(api_key= GROQ_API_KEY) #? 📌 Equivale a abrir a conexão para chamar a API.

def chamar_ia(mensagem, historico=None): #? 📌 função que recebe o texto que o usuario digitou e a lista de mensagens anteriores
if historico is None: #? 📌 Se for a primeira vez chamando a função, ainda não existe histórico entap cria uma função
historico =[]

messages = historico + [
{"role": "user", "content": mensagem} #? 📌 Pega o histórico e adiciona a mensagem nova, cada item é um dicionário (Estrutura exigida pela api)
]

resposta = client.chat.completions.create( #! Chama o endpoint chat/completions
model="llama-3.1-8b-instant", #! Passa o modelo
messages=messages #! Envia as mensagens (histórico + nova)
)

texto = resposta.choices[0].message.content #! Pega só o texto que a IA gerou
return texto


'''
A resposta da Groq vem dentro de um array choices.
1-Você pega a primeira resposta (0)
2-Depois pega o atributo message
3-E por fim pega somente o texto (content)

💡 Exemplo da estrutura real:
{
"choices": [
{
"message": {
"role": "assistant",
"content": "Olá! Como posso ajudar?"
}
}
]
}
'''

47 changes: 47 additions & 0 deletions AssistenteVirtual/AssistenteVirtual/Core/voz.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import pyttsx4 #? Importa biblioteca para sintese de voz
import speech_recognition as sr #? Importa biblioteca que converte oque eu falo em texto
import time #? importa biblioteca com funcoes relacionadas ao tempo

# Inicializadores
reconhecedor = sr.Recognizer() #! Objeto que gerencia a captura/interpretacão de áudio
sintetizador = pyttsx4.init('sapi5') #? Inicializa o engine do pyttsx4 e escolhe o driver sapi5
sintetizador.setProperty('rate', 220) #? Ajusta a velocidade de fala (palavras por minuto).
sintetizador.setProperty('volume', 1.0) #? Define o volume da fala; 1.0

voices = sintetizador.getProperty('voices') #? Recupera a lista de vozes disponíveis do engine
sintetizador.setProperty('voice', voices[0].id) #? Define a voz a ser usada; aqui usa a primeira voz disponível


def falar_texto(texto): #? Converte texto em voz
texto = (f"Senhor, {texto}") #? (adiciona no início) a string "Senhor, " ao texto recebido
if not texto.strip(): #? Verifica se texto está vazio ou contém só espaços(strip() remover espaços em branco nas extremidades). Se estiver vazio, vai evitar tentar falar algo.)
return
try:
time.sleep(1) #? Pausa de 1 segundo antes de falar
sintetizador.say(texto) #? Faz o computador falar.
sintetizador.runAndWait() #? Bloqueante: espera terminar de falar
except Exception as e:
print(f"❌ Erro ao falar: {e}") #? Captura qualquer exceção que ocorra dentro do try (por exemplo, problema com driver de áudio)


def ouvir_microfone(): #? Ouvindo o microfone e retornando texto transcrito
with sr.Microphone() as mic: #? Cria um objeto que representa o dispositivo de microfone do seu computador. as mic significa: dê o nome mic a esse objeto do microfone.
print("🎤 Ouvindo...")
reconhecedor.adjust_for_ambient_noise(mic, duration=1) #? Ajusta o ruído
audio = reconhecedor.listen(mic) #? grava até detectar silêncio

try:
texto = reconhecedor.recognize_google(audio, language="pt-BR") #? Usa o sistema de voz do Google grátis para converter áudio → texto
print(f"Você disse: {texto}")

wake_word = "jarvis" #? palavra de ativação

if texto.lower().startswith(wake_word): #? Verifica se o texto transcrito, em letras minúsculas, começa com a wake word
return texto[len(wake_word):].strip() #? Remove o nome antes de mandar pra IA, Retorna a parte do texto após a wake word: usa slicing para pular os primeiros caracteres
else:
print("Aguardando palavra de ativação")
return ""
except:
print("❌ Não entendi.")
return ""

82 changes: 82 additions & 0 deletions AssistenteVirtual/AssistenteVirtual/data/Historico.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
[
{
"role": "user",
"content": "me fodendo que não funcionou"
},
{
"role": "assistant",
"content": "Parece que estamos em um loop de expressões idiomáticas frustrantes!\n\nVou tentar mudar de assunto e criar um novo fluxo de conversa. Você está se sentindo frustrado ou estressado em algum momento da sua vida? Quer falar sobre isso?"
},
{
"role": "user",
"content": "pode perguntar qualquer coisa"
},
{
"role": "assistant",
"content": "Você está se sentindo um pouco como um boneco de palavras!\n\nVamos fazer algo diferente. Qual é o seu hobby favorito? É ler, jogar videogame, praticar esportes, cozinhar ou algo completamente diferente?\n\n(Vou perguntar algo que seja simples e fácil de responder!)"
},
{
"role": "user",
"content": "cinema"
},
{
"role": "assistant",
"content": "Parece que estamos nos afundando no cinema!\n\nVamos dar um salto e criar um novo cenário. Se você estivesse em um filme de cinema, qual seria o seu papel? Você seria um herói que salva o mundo, um vilão que busca o poder, um personagem comum que se encontra em um mundo de fantasia, ou algo completamente diferente?\n\n(Vamos criar uma nova história!)"
},
{
"role": "user",
"content": "no Instituto res"
},
{
"role": "assistant",
"content": "Parece que estamos em X-Men!\n\nNo Instituto Charles Xavier, você é... Magneto, o líder dos mutantes com poderes sobre a magnetização?\n\n(Vamos explorar a realidade de X-Men!)"
},
{
"role": "user",
"content": "Instituto ha"
},
{
"role": "assistant",
"content": "Parece que estamos em um loop de \"Instituto ha\"!\n\nVamos dar um salto e criar um novo cenário. O Instituto que você está me perguntando sobre... é o Xavier Institute para jovens superdotados em X-Men ou é outro tipo de instituição?\n\n(Vamos tentar entender o que você está perguntando!)"
},
{
"role": "user",
"content": "conte uma piada"
},
{
"role": "assistant",
"content": "Parece que estamos em um loop de \"conte uma piada\"!\n\nVou tentar contar uma piada:\n\nPor que o PC foi ao doutor?\n\nPorque estava com um problema de \"processamento\"!\n\n(Espere um minuto, vou tentar novamente!)\n\nPor que o homem levou um cavalo para o bar?\n\nPorque queria um sério \"tratamento\"!\n\n(Espere, vou tentar mais uma vez!)\n\nPor que o cientista abandonou a pesquisa sobre os gatos?\n\nPorque os resultados eram um \"purr-blemo\"!\n\n(Vamos ver se a próxima piada funciona!)"
},
{
"role": "user",
"content": "Jarvis Pará"
},
{
"role": "assistant",
"content": "Parece que estamos em um loop de \"Jarvis Pará\"!\n\nVou tentar entender... Você está se referindo a Edgar Jarvis, o assistente lógico de Tony Stark em Iron Man?\n\n Ou talvez você esteja se referindo a Pará, um estado da Amazônia brasileira?\n\n Ou talvez seja algo completamente diferente?\n\n(Vamos tentar encontrar o que você está procurando!)"
},
{
"role": "user",
"content": "Quantos graus está fazendo hoje"
},
{
"role": "assistant",
"content": "Parece que estamos em um loop de \"quantos graus está fazendo hoje\"!\n\nInfelizmente, eu não tenho acesso a informações em tempo real, então não posso fornecer a temperatura atual. Além disso, eu não sei onde você está, portanto, não consigo informar a temperatura local.\n\nSe você quiser saber a temperatura, eu sugiro verificar um site de notícias online, um aplicativo de clima ou um localizador de temperatura em sua região."
},
{
"role": "user",
"content": "você tem acesso para acessar esse site e verificar informação"
},
{
"role": "assistant",
"content": "Eu tenho acesso limitado a informações online, mas não posso acessar sites específicos nem verificar informações em tempo real da mesma forma que um navegador ou um search engine.\n\nNo entanto, posso tentar encontrar a resposta de forma indireta. Poderia você me dizer qual é a sua localização ou qual é o tipo de informação que você está procurando (por exemplo, temperatura em uma cidade específica, temperatura global, previsão do tempo, etc.)?\n\nEssa informação pode me ajudar a procurar por informações relevantes e fornecer uma resposta aproximada."
},
{
"role": "user",
"content": "eu quero saber a temperatura do Rio de Janeiro eu moro na Taquara"
},
{
"role": "assistant",
"content": "Entendi melhor agora!\n\nSe você está em Taquara, que é uma cidade localizada no estado do Rio de Janeiro, Brasil, eu posso tentar encontrar a temperatura atual para você.\n\nNo entanto, como eu disse anteriormente, eu não tenho acesso ao tempo real. Mas posso sugerir algumas opções para que você possa saber a temperatura atual de Taquara ou do Rio de Janeiro:\n\n1. Verifique o aplicativo do tempo no seu telefone: você pode baixar aplicativos como ClimaTem, Tempo, ou Weather Channel que fornecem previsão de tempo e temperatura atual.\n2. Visite o site do National Weather Service (NWS) da América do Norte, que fornece informações sobre temperatura e previsão de tempo para locais em todo o mundo.\n3. Verifique no Google: você pode simplesmente digitar \"temperatura atual de Taquara\" ou \"temperatura atual de Rio de Janeiro\" e o Google fornecerá a informação mais recente disponível.\n\nInfelizmente, eu não tenho acesso a essas informações em tempo real, então não posso fornecer a temperatura atual para você.\n\nMas posso sugerir que você verifique um dos métodos acima para saber a temperatura atual de Taquara ou do Rio de Janeiro!"
}
]
Binary file not shown.
31 changes: 31 additions & 0 deletions AssistenteVirtual/AssistenteVirtual/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
from Core.voz import ouvir_microfone, falar_texto
from Core.ia import chamar_ia
from Core.comandos import interpretar_comando
from Core.historico import carregar_historico, adicionar_mensagem


historico = carregar_historico() # ? Hisótico da conversa

print("🤖 Assistente iniciado. Diga 'PARAR' para encerrar.")

while True: # ? Loop infinito que mantém o assistente escutando até receber o comando de encerrar (break).

comando = ouvir_microfone() # ? Chama a função eque pega oque vc fala e retorna o texto transcrito(string) e associa a variavel
if comando == "": # ? Se a função retorna "", então continue reinicia o loop sem processar nada.
continue

if "parar" in comando.lower(): #? Se ele indenticar parar no que o usuario falar, ele interrompe o loop com o break e chama a função que converte texto em voz.
falar_texto("Encerrando assistente. foi um prazer auxiliá-lo SENHOR Ruan.")
break

resposta_comando = interpretar_comando(comando) # ? Ele chama função que abre as urls e apps de acordo com a palavra chave q a gente fala, se a funçlãoindetificar a palavra chave vai abrir, exemplo o youtube
if resposta_comando: # ? e vai retornar um texto (Exemplo: ("Abrindo Youtube..."))
falar_texto(resposta_comando)
continue
# ? Se não for comando direto, enviar para a IA
resposta_ia = chamar_ia(comando, historico) # ? Vai adicionar assim no meu historico.json historico.append({"role": "user", "content": comando}), comando é oque eu falei
adicionar_mensagem(historico, "user", comando) # ? e depois vai adicionar nese formato porem a resposta da ia
adicionar_mensagem(historico, "assistant", resposta_ia)

# ? Falar a respsota da IA
falar_texto(resposta_ia)