diff --git a/AssistenteVirtual/AssistenteVirtual/Config/__pycache__/keys.cpython-310.pyc b/AssistenteVirtual/AssistenteVirtual/Config/__pycache__/keys.cpython-310.pyc new file mode 100644 index 0000000..ae0f1bf Binary files /dev/null and b/AssistenteVirtual/AssistenteVirtual/Config/__pycache__/keys.cpython-310.pyc differ diff --git a/AssistenteVirtual/AssistenteVirtual/Config/__pycache__/keys.cpython-313.pyc b/AssistenteVirtual/AssistenteVirtual/Config/__pycache__/keys.cpython-313.pyc new file mode 100644 index 0000000..7a33e74 Binary files /dev/null and b/AssistenteVirtual/AssistenteVirtual/Config/__pycache__/keys.cpython-313.pyc differ diff --git a/AssistenteVirtual/AssistenteVirtual/Config/keys.py b/AssistenteVirtual/AssistenteVirtual/Config/keys.py new file mode 100644 index 0000000..7b0f7aa --- /dev/null +++ b/AssistenteVirtual/AssistenteVirtual/Config/keys.py @@ -0,0 +1 @@ +GROQ_API_KEY = "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" \ No newline at end of file diff --git a/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/comandos.cpython-310.pyc b/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/comandos.cpython-310.pyc new file mode 100644 index 0000000..3f07ad1 Binary files /dev/null and b/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/comandos.cpython-310.pyc differ diff --git a/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/comandos.cpython-313.pyc b/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/comandos.cpython-313.pyc new file mode 100644 index 0000000..0835c2d Binary files /dev/null and b/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/comandos.cpython-313.pyc differ diff --git a/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/historico.cpython-310.pyc b/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/historico.cpython-310.pyc new file mode 100644 index 0000000..db9e750 Binary files /dev/null and b/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/historico.cpython-310.pyc differ diff --git a/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/historico.cpython-313.pyc b/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/historico.cpython-313.pyc new file mode 100644 index 0000000..917f130 Binary files /dev/null and b/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/historico.cpython-313.pyc differ diff --git a/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/ia.cpython-310.pyc b/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/ia.cpython-310.pyc new file mode 100644 index 0000000..e0719d6 Binary files /dev/null and b/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/ia.cpython-310.pyc differ diff --git a/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/ia.cpython-313.pyc b/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/ia.cpython-313.pyc new file mode 100644 index 0000000..e126d68 Binary files /dev/null and b/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/ia.cpython-313.pyc differ diff --git a/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/voz.cpython-310.pyc b/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/voz.cpython-310.pyc new file mode 100644 index 0000000..1f434bc Binary files /dev/null and b/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/voz.cpython-310.pyc differ diff --git a/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/voz.cpython-313.pyc b/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/voz.cpython-313.pyc new file mode 100644 index 0000000..28057b8 Binary files /dev/null and b/AssistenteVirtual/AssistenteVirtual/Core/__pycache__/voz.cpython-313.pyc differ diff --git a/AssistenteVirtual/AssistenteVirtual/Core/comandos.py b/AssistenteVirtual/AssistenteVirtual/Core/comandos.py new file mode 100644 index 0000000..80eaf4f --- /dev/null +++ b/AssistenteVirtual/AssistenteVirtual/Core/comandos.py @@ -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 diff --git a/AssistenteVirtual/AssistenteVirtual/Core/historico.py b/AssistenteVirtual/AssistenteVirtual/Core/historico.py new file mode 100644 index 0000000..e57cdcf --- /dev/null +++ b/AssistenteVirtual/AssistenteVirtual/Core/historico.py @@ -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) diff --git a/AssistenteVirtual/AssistenteVirtual/Core/ia.py b/AssistenteVirtual/AssistenteVirtual/Core/ia.py new file mode 100644 index 0000000..9d29bcb --- /dev/null +++ b/AssistenteVirtual/AssistenteVirtual/Core/ia.py @@ -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?" + } + } + ] +} +''' + \ No newline at end of file diff --git a/AssistenteVirtual/AssistenteVirtual/Core/voz.py b/AssistenteVirtual/AssistenteVirtual/Core/voz.py new file mode 100644 index 0000000..9e4fdbc --- /dev/null +++ b/AssistenteVirtual/AssistenteVirtual/Core/voz.py @@ -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 "" + diff --git a/AssistenteVirtual/AssistenteVirtual/data/Historico.json b/AssistenteVirtual/AssistenteVirtual/data/Historico.json new file mode 100644 index 0000000..fb8438c --- /dev/null +++ b/AssistenteVirtual/AssistenteVirtual/data/Historico.json @@ -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!" + } +] \ No newline at end of file diff --git a/AssistenteVirtual/AssistenteVirtual/data/__pycache__/historico.cpython-313.pyc b/AssistenteVirtual/AssistenteVirtual/data/__pycache__/historico.cpython-313.pyc new file mode 100644 index 0000000..4840fd3 Binary files /dev/null and b/AssistenteVirtual/AssistenteVirtual/data/__pycache__/historico.cpython-313.pyc differ diff --git a/AssistenteVirtual/AssistenteVirtual/main.py b/AssistenteVirtual/AssistenteVirtual/main.py new file mode 100644 index 0000000..0cc6e51 --- /dev/null +++ b/AssistenteVirtual/AssistenteVirtual/main.py @@ -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)