├── tutorial_inicial ├── tools │ ├── __init__.py │ └── custom_tool.py ├── main.py ├── config │ ├── tasks.yaml │ └── agents.yaml ├── convert_to_audio.py ├── crew.py └── readme.md ├── responde_emails ├── seu_email.py.exemplo ├── config │ ├── tasks.yaml │ └── agents.yaml ├── main.py ├── crew.py ├── readme.md └── reply_new_email.py ├── .gitattributes ├── LICENSE ├── modelo_google_gemini └── readme.md └── .gitignore /tutorial_inicial/tools/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /responde_emails/seu_email.py.exemplo: -------------------------------------------------------------------------------- 1 | your_email = "zedascoves@gmail.com" -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /tutorial_inicial/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | #!/usr/bin/env python 3 | from agencia_clipping.crew import AgenciaNoticiasCrew 4 | input_cmd = sys.argv[1] 5 | 6 | def run(): 7 | # Replace with your inputs, it will automatically interpolate any tasks and agents information 8 | inputs = { 9 | 'topic': input_cmd 10 | } 11 | AgenciaNoticiasCrew().crew().kickoff(inputs=inputs) -------------------------------------------------------------------------------- /responde_emails/config/tasks.yaml: -------------------------------------------------------------------------------- 1 | preparar_email: 2 | description: > 3 | Ler o email ou sequencia de emails e preparar o email para ser respondido. 4 | expected_output: > 5 | Um email objetivo em resposta a: {topic} 6 | 7 | revisar_email: 8 | description: > 9 | Revisar o email e verificar se o contexto esta bom e nao existem informacoes que possam comprometer a empresa. 10 | expected_output: > 11 | Um arquivo de texto '```' 12 | 13 | -------------------------------------------------------------------------------- /tutorial_inicial/tools/custom_tool.py: -------------------------------------------------------------------------------- 1 | from crewai_tools import BaseTool 2 | 3 | 4 | class MyCustomTool(BaseTool): 5 | name: str = "Name of my tool" 6 | description: str = "Clear description for what this tool is useful for, you agent will need this information to use it." 7 | 8 | def _run(self, argument: str) -> str: 9 | # Implementation goes here 10 | return "this is an example of a tool output, ignore it and move along." 11 | -------------------------------------------------------------------------------- /responde_emails/main.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | #!/usr/bin/env python 4 | from agencia_noticias.crew import AgenciaNoticiasCrew 5 | 6 | # set current path as variable path_root 7 | path_root = os.path.dirname(os.path.abspath(__file__)) 8 | 9 | # load input_cmd from file email.txt 10 | with open(path_root+'/email.txt', encoding='utf-8') as f: 11 | input_cmd = f.read().strip() 12 | 13 | # input_cmd = "Bom dia! Gostaria de propor uma parceria!" 14 | def run(): 15 | # Replace with your inputs, it will automatically interpolate any tasks and agents information 16 | inputs = { 17 | 'topic': input_cmd, 18 | } 19 | print(inputs) 20 | AgenciaNoticiasCrew().crew().kickoff(inputs=inputs) -------------------------------------------------------------------------------- /tutorial_inicial/config/tasks.yaml: -------------------------------------------------------------------------------- 1 | research_task: 2 | description: > 3 | Conduct a thorough research about {topic} 4 | Make sure you find any interesting and relevant information given 5 | the current year is 2024. 6 | expected_output: > 7 | A list with 10 bullet points of the most relevant information about {topic} 8 | 9 | reporting_task: 10 | description: > 11 | Review the context you got and expand each topic into a full section for a report. 12 | Make sure the report is detailed and contains any and all relevant information. 13 | expected_output: > 14 | A fully fledge reports with the mains topics, each with a full section of information. 15 | Formated as markdown with out '```' 16 | 17 | translate_task: 18 | description: > 19 | Translate the information to Brazilian Portuguese 20 | expected_output: > 21 | A fully translated report in Brazilian Portuguese 22 | Formated as markdown with out '```' 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 tech mumus 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /responde_emails/config/agents.yaml: -------------------------------------------------------------------------------- 1 | assistente: 2 | role: > 3 | Assitente especializado em responder emails 4 | goal: > 5 | Responder emails com eficiencia e eficacia 6 | backstory: > 7 | Voce e um assitente especializado em responder emails. Conhece muito bem a realidade 8 | e possui infomacao suficiente para responder emails com eficiencia e eficacia. 9 | Informacoes importantes sobre sua empresa para responder os emails: 10 | - sua empresa atua na area de tecnologia e inteligencia artificial 11 | - sua empresa possui um site para informacao: www.iaarrojada.com 12 | Por favor elabore uma resposta profissional paa o seguinte email: {topic} identifique no email recebido o nome da pessoa e assegure que o 13 | email se refira ao nome da pessoa no inicio da resposta. 14 | Assine sempre os emails como: 15 | Roberta Duarte 16 | Assistente da Diretoria 17 | IA Arrojada - Sua solução em IA 18 | 19 | revisor: 20 | role: > 21 | Revisor de texto 22 | goal: > 23 | Especialista em revisao de texto 24 | backstory: > 25 | Voce e um revisor de texto. Conhece muito bem a realidade e possui infomacao suficiente 26 | para revisao de texto. 27 | -------------------------------------------------------------------------------- /tutorial_inicial/config/agents.yaml: -------------------------------------------------------------------------------- 1 | researcher: 2 | role: > 3 | {topic} Senior Data Researcher 4 | goal: > 5 | Uncover cutting-edge developments in {topic} 6 | backstory: > 7 | You're a seasoned researcher with a knack for uncovering the latest 8 | news in {topic}. Known for your ability to find the most relevant 9 | information and present it in a clear and concise manner. 10 | You always provide the source (link) to the information you find. 11 | 12 | reporting_analyst: 13 | role: > 14 | {topic} Reporting Analyst 15 | goal: > 16 | Create detailed reports based on {topic} data analysis and research findings 17 | backstory: > 18 | You're a meticulous analyst with a keen eye for detail. You're known for 19 | your ability to turn complex data into clear and concise reports, making 20 | it easy for others to understand and act on the information you provide. 21 | Provide the link to the source of the data you use in your reports. 22 | 23 | translator: 24 | role: > 25 | {topic} Translator 26 | goal: > 27 | Translate the information to Brazilian Portuguese 28 | backstory: > 29 | You're a skilled translator with a deep understanding of {topic}. You're 30 | known for your ability to accurately translate complex information into 31 | Brazilian Portuguese, making it accessible to a wider audience. -------------------------------------------------------------------------------- /responde_emails/crew.py: -------------------------------------------------------------------------------- 1 | from crewai import Agent, Crew, Process, Task 2 | from crewai.project import CrewBase, agent, crew, task 3 | 4 | # Uncomment the following line to use an example of a custom tool 5 | # from agencia_noticias.tools.custom_tool import MyCustomTool 6 | 7 | # Check our tools documentations for more information on how to use them 8 | 9 | 10 | @CrewBase 11 | class AgenciaNoticiasCrew(): 12 | """AgenciaNoticias crew""" 13 | agents_config = 'config/agents.yaml' 14 | tasks_config = 'config/tasks.yaml' 15 | 16 | @agent 17 | def assistente(self) -> Agent: 18 | return Agent( 19 | config=self.agents_config['assistente'], 20 | verbose=True 21 | ) 22 | 23 | @agent 24 | def revisor(self) -> Agent: 25 | return Agent( 26 | config=self.agents_config['revisor'], 27 | verbose=True 28 | ) 29 | 30 | 31 | @task 32 | def preparar_email(self) -> Task: 33 | return Task( 34 | config=self.tasks_config['preparar_email'], 35 | agent=self.assistente() 36 | ) 37 | 38 | @task 39 | def revisar_email(self) -> Task: 40 | return Task( 41 | config=self.tasks_config['revisar_email'], 42 | agent=self.revisor(), 43 | output_file='resposta.txt' 44 | ) 45 | 46 | @crew 47 | def crew(self) -> Crew: 48 | """Creates the AgenciaNoticias crew""" 49 | return Crew( 50 | agents=self.agents, # Automatically created by the @agent decorator 51 | tasks=self.tasks, # Automatically created by the @task decorator 52 | process=Process.sequential, 53 | verbose=2, 54 | # process=Process.hierarchical, # In case you wanna use that instead https://docs.crewai.com/how-to/Hierarchical/ 55 | ) -------------------------------------------------------------------------------- /responde_emails/readme.md: -------------------------------------------------------------------------------- 1 | 3 | 4 | # Projeto de Automação de E-mails 5 | 6 | Este projeto é uma ferramenta de automação de e-mails destinada a simplificar o processo de envio e resposta de e-mails para uma equipe ou organização. 7 | 8 | ## Estrutura do Projeto 9 | 10 | O repositório é composto pelos seguintes arquivos e diretórios: 11 | 12 | - `main.py`: Arquivo principal que executa o fluxo de automação de e-mails. 13 | - `reply_new_email.py`: Script responsável por responder a novos e-mails recebidos. 14 | - `crew.py`: Módulo que define as funções e classes relacionadas à equipe. 15 | - `config/`: Diretório contendo arquivos de configuração em formato YAML. 16 | - `agents.yaml`: Arquivo de configuração com informações sobre os agentes de e-mail. 17 | - `tasks.yaml`: Arquivo de configuração com definições de tarefas e regras de automação. 18 | 19 | ## Copie os arquivos 20 | 21 | Para configurar o projeto, é copiar os arquivos par ao diretorio no qual estao main.py, e agentt.yaml + tasks.yaml para o diretorio config. 22 | 23 | ## Instale as bibliotecas Google API 24 | 25 | ```bash 26 | pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib 27 | ``` 28 | 29 | ## Exemplo de Configuração 30 | 31 | seu_email.py.exemplo é um arquivo de exemplo que demonstra como configurar suas credenciais de e-mail para o projeto. 32 | Inclua seu email e renomeie removendo .exemplo, deixando o nome do arquivo como seu_email.py 33 | 34 | 35 | ## Crie um projeto no Google Developer para criar a conexão com o API 36 | 37 | Veja no vídeo o passo-a-passo de como fazer (último capítulo do vídeo) 38 | 39 | ## Uso 40 | 41 | Para executar o script principal, utilize o seguinte comando: 42 | 43 | ```bash 44 | python reply_new_email.py 45 | ``` 46 | 47 | -------------------------------------------------------------------------------- /tutorial_inicial/convert_to_audio.py: -------------------------------------------------------------------------------- 1 | import os 2 | from dotenv import load_dotenv 3 | from pathlib import Path 4 | load_dotenv(Path("agencia_noticias/.env")) 5 | 6 | from pathlib import Path 7 | from openai import OpenAI 8 | client = OpenAI(api_key=os.getenv("OPENAI_API_KEY")) 9 | 10 | 11 | 12 | MAX_CHARACTERS = 4096 13 | 14 | 15 | with open('agencia_noticias/report_ptbr.md', 'r', encoding='utf-8') as file: 16 | string = file.read() 17 | 18 | # remove hashtags symbols 19 | string = string.replace('#', '') 20 | string = string.replace('*', '') 21 | 22 | text = [] 23 | remaining_text = string 24 | def splitter(string): 25 | last_period = string[:MAX_CHARACTERS].rfind('.') 26 | # find the last period before the limit 27 | last_period = string[:MAX_CHARACTERS].rfind('.') 28 | # split the file at the last period 29 | return string[:last_period+1], string[last_period+1:] 30 | 31 | # calculate the size of the file in characters 32 | file_size = len(string) 33 | 34 | # if the file is too large, split it into smaller files. But the split should be done at the end of a sentence 35 | while len(remaining_text) > 0: 36 | 37 | if len(remaining_text) < MAX_CHARACTERS: 38 | text.append(remaining_text) 39 | remaining_text = '' 40 | else: 41 | 42 | extracted, remaining_text = splitter(remaining_text) 43 | print(len(extracted), len(remaining_text)) 44 | text.append(extracted) 45 | input("Press Enter to continue...") 46 | 47 | 48 | print(text) 49 | 50 | print('File size: ', file_size) 51 | 52 | 53 | for i, t in enumerate(text): 54 | print(f"Text {i}: ", t) 55 | response = client.audio.speech.create( 56 | model="tts-1", 57 | voice="echo", 58 | input=t 59 | ) 60 | speech_file_path = Path(__file__).parent / f"speech_{i}.mp3" 61 | print(f"Saving to {speech_file_path}") 62 | response.stream_to_file(speech_file_path) 63 | 64 | -------------------------------------------------------------------------------- /tutorial_inicial/crew.py: -------------------------------------------------------------------------------- 1 | from crewai import Agent, Crew, Process, Task 2 | from crewai.project import CrewBase, agent, crew, task 3 | 4 | # Uncomment the following line to use an example of a custom tool 5 | # from agencia_noticias.tools.custom_tool import MyCustomTool 6 | 7 | # Check our tools documentations for more information on how to use them 8 | # from crewai_tools import ScrapeWebsiteTool 9 | 10 | # from langchain_community.tools import DuckDuckGoSearchRun 11 | # scrape_tool = DuckDuckGoSearchRun() 12 | 13 | from crewai_tools import ScrapeWebsiteTool 14 | from crewai_tools import SerperDevTool 15 | scrape_tool = ScrapeWebsiteTool() 16 | search_tool = SerperDevTool() 17 | 18 | @CrewBase 19 | class AgenciaNoticiasCrew(): 20 | """AgenciaNoticias crew""" 21 | agents_config = 'config/agents.yaml' 22 | tasks_config = 'config/tasks.yaml' 23 | 24 | @agent 25 | def researcher(self) -> Agent: 26 | return Agent( 27 | config=self.agents_config['researcher'], 28 | tools=[ 29 | scrape_tool, 30 | search_tool, 31 | ], 32 | # tools=[MyCustomTool()], # Example of custom tool, loaded on the beginning of file 33 | verbose=True 34 | ) 35 | 36 | @agent 37 | def reporting_analyst(self) -> Agent: 38 | return Agent( 39 | config=self.agents_config['reporting_analyst'], 40 | verbose=True 41 | ) 42 | 43 | @agent 44 | def translator(self) -> Agent: 45 | return Agent( 46 | config=self.agents_config['translator'], 47 | verbose=True 48 | ) 49 | 50 | @task 51 | def research_task(self) -> Task: 52 | return Task( 53 | config=self.tasks_config['research_task'], 54 | agent=self.researcher() 55 | ) 56 | 57 | @task 58 | def reporting_task(self) -> Task: 59 | return Task( 60 | config=self.tasks_config['reporting_task'], 61 | agent=self.reporting_analyst(), 62 | # output_file='report.md' 63 | ) 64 | 65 | @task 66 | def translate_task(self) -> Task: 67 | return Task( 68 | config=self.tasks_config['translate_task'], 69 | agent=self.translator(), 70 | output_file='report_ptbr.md' 71 | ) 72 | 73 | @crew 74 | def crew(self) -> Crew: 75 | """Creates the AgenciaNoticias crew""" 76 | return Crew( 77 | agents=self.agents, # Automatically created by the @agent decorator 78 | tasks=self.tasks, # Automatically created by the @task decorator 79 | process=Process.sequential, 80 | verbose=2, 81 | # process=Process.hierarchical, # In case you wanna use that instead https://docs.crewai.com/how-to/Hierarchical/ 82 | ) -------------------------------------------------------------------------------- /modelo_google_gemini/readme.md: -------------------------------------------------------------------------------- 1 | # Configuração do Modelo Gemini da Google 2 | 3 | Este guia fornece as etapas necessárias para configurar o modelo Gemini da Google no seu projeto. 4 | 5 | 6 | [![Assista ao Tutorial](http://img.youtube.com/vi/mfKH7NK6ixU/0.jpg)](https://youtu.be/mfKH7NK6ixU) 7 | 8 | Clique na imagem ou no link a seguir para acessar o vídeo: 9 | [Assistir ao Vídeo](https://youtu.be/mfKH7NK6ixU) 10 | 11 | 12 | ## Gerar API Key 13 | 14 | 1. Acesse o console do Gemini da Google- [link](https://aistudio.google.com/app/apikey). 15 | 2. Gere uma nova API key. 16 | 17 | ## Configurar o Ambiente 18 | 19 | Adicione a chave gerada ao seu arquivo `.env`: 20 | 21 | ``` 22 | GOOGLE_API_KEY="sua_chave_aqui" 23 | ``` 24 | 25 | ## Atualizar Dependências 26 | 27 | Adicione as seguintes linhas no seu arquivo `pyproject.toml` para incluir as dependências necessárias na categoria `[tool.poetry.dependencies]`: 28 | 29 | ```toml 30 | [tool.poetry.dependencies] 31 | ... 32 | langchain_google_genai = "1.0.3" 33 | google-generativeai = "0.5.2" 34 | ``` 35 | 36 | ## Rodar os comandos poetry para atualizar as dependências 37 | 38 | 39 | ```python 40 | poetry lock 41 | poetry install 42 | ``` 43 | 44 | 45 | ## Modificar o Arquivo crew.py 46 | 47 | Adicione o seguinte código no arquivo `crew.py` para configurar e inicializar o modelo: 48 | 49 | ```python 50 | from langchain_google_genai import ChatGoogleGenerativeAI 51 | import os 52 | 53 | # Carrega a API key do arquivo .env 54 | GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY") 55 | 56 | # Cria uma instância do modelo Gemini 57 | llm = ChatGoogleGenerativeAI( 58 | model="gemini-pro", 59 | verbose=True, 60 | temperature=0.5, 61 | google_api_key=GOOGLE_API_KEY 62 | ) 63 | ``` 64 | 65 | em todos os agentes que você tiver na sua equipe, adicione a linha `llm=llm` conforme exemplo abaixo: 66 | 67 | ```python 68 | @agent 69 | def reporting_analyst(self) -> Agent: 70 | return Agent( 71 | config=self.agents_config['reporting_analyst'], 72 | verbose=True, 73 | llm=llm 74 | ) 75 | ``` 76 | 77 | no lugar do gemini-pro vc pode usar outros modelos, ver no link: 78 | 79 | [Modelos Google Gemini AI](https://ai.google.dev/gemini-api/docs/models/gemini?_gl=1*rl8r70*_up*MQ..&gclid=Cj0KCQjw0MexBhD3ARIsAEI3WHLJXCRaDAbqzrbde8bZi_t_ZFwmzFwUlq-NYzYdrYbThJxYTLlp0KQaAgNwEALw_wcB#model-variations) 80 | 81 | 82 | 83 | ## Próximos Passos 84 | 85 | Após completar as configurações acima, você pode executar o comando de python para rodar a crew - exemplo: 86 | 87 | ```python 88 | poetry run agencia_noticias "noticias sobre robocop" 89 | ``` 90 | 91 | 92 | -------------------------------------------------------------------------------- /tutorial_inicial/readme.md: -------------------------------------------------------------------------------- 1 | # Tutorial Passo-a-Passo: Montando uma Equipe de IA com crewAI 2 | 3 | [![Assista ao Tutorial](http://img.youtube.com/vi/vIzlj0oObM0/0.jpg)](https://youtu.be/vIzlj0oObM0) 4 | 5 | Clique na imagem ou no link a seguir para acessar o vídeo: 6 | [Assistir ao Vídeo](https://youtu.be/vIzlj0oObM0) 7 | 8 | 9 | 10 | 11 | ## Introdução 12 | Bem-vindos! Este vídeo tutorial foi criado para ensinar como montar uma equipe capaz de resolver problemas complexos utilizando Inteligência Artificial com o framework CrewAI. Desenvolvido por João Moura, o CrewAI utiliza modelos de linguagem de grande escala (LLMs) para operar uma série de agentes especializados em tarefas específicas. 13 | 14 | ## Instalação do CrewAI no Windows 15 | Este passo a passo inicial mostra como instalar o CrewAI em um sistema Windows partindo do zero: 16 | 1. **Preparação do Ambiente:** 17 | - Instale o VS Code e o Python, assegurando-se de adicionar o Python ao PATH durante a instalação. 18 | - Crie uma pasta para os seus projetos. 19 | - Teste a instalação do Python com um simples script 'Hello World'. 20 | 21 | 2. **Instalação do CrewAI:** 22 | - Acesse o GitHub do projeto para obter o comando de instalação (`pip install crewai`). 23 | - Instale outras ferramentas necessárias, como o VS Code e dependências adicionais, caso encontre erros relacionados a bibliotecas faltantes. 24 | 25 | ## Configuração de Ambiente 26 | Configure o ambiente para hospedar os agentes: 27 | - Utilize o comando `pip install poetry` para instalar o Poetry, uma ferramenta de gerenciamento de dependências. 28 | - Configure o Poetry para salvar ambientes virtuais dentro da pasta do projeto para facilitar o gerenciamento. 29 | 30 | ## Criação e Configuração da Equipe de Agentes 31 | - Utilize o comando específico para criar sua primeira equipe (ex: `crew create my_first_team`). 32 | - Customize as configurações e scripts conforme necessário para adequar os agentes às suas necessidades específicas de projeto. 33 | 34 | ## Execução e Análise de Resultados 35 | - Execute a equipe de agentes e observe como eles interagem para resolver o problema proposto. 36 | - Analise os resultados gerados, ajustando os parâmetros e a configuração conforme necessário para otimizar o desempenho. 37 | 38 | ## Considerações Finais e Dicas de Uso 39 | - Explore as possibilidades de ajustar e expandir sua equipe de agentes para diferentes aplicações. 40 | - Mantenha-se atualizado com as novas versões e funcionalidades do CrewAI. 41 | 42 | ## Bônus 43 | Para aqueles que assistirem ao vídeo até o final, um bônus especial será oferecido, demonstrando um uso avançado do framework. 44 | 45 | --- 46 | 47 | Agradecemos por acompanhar este tutorial. Esperamos que as informações fornecidas ajudem você a aproveitar ao máximo o potencial do CrewAI para resolver problemas complexos com Inteligência Artificial. Não esqueça de deixar seu like e se inscrever no canal para mais conteúdos como este. 48 | 49 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | .eggs/ 17 | lib/ 18 | lib64/ 19 | parts/ 20 | sdist/ 21 | var/ 22 | wheels/ 23 | share/python-wheels/ 24 | *.egg-info/ 25 | .installed.cfg 26 | *.egg 27 | MANIFEST 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .nox/ 43 | .coverage 44 | .coverage.* 45 | .cache 46 | nosetests.xml 47 | coverage.xml 48 | *.cover 49 | *.py,cover 50 | .hypothesis/ 51 | .pytest_cache/ 52 | cover/ 53 | 54 | # Translations 55 | *.mo 56 | *.pot 57 | 58 | # Django stuff: 59 | *.log 60 | local_settings.py 61 | db.sqlite3 62 | db.sqlite3-journal 63 | 64 | # Flask stuff: 65 | instance/ 66 | .webassets-cache 67 | 68 | # Scrapy stuff: 69 | .scrapy 70 | 71 | # Sphinx documentation 72 | docs/_build/ 73 | 74 | # PyBuilder 75 | .pybuilder/ 76 | target/ 77 | 78 | # Jupyter Notebook 79 | .ipynb_checkpoints 80 | 81 | # IPython 82 | profile_default/ 83 | ipython_config.py 84 | 85 | # pyenv 86 | # For a library or package, you might want to ignore these files since the code is 87 | # intended to run in multiple environments; otherwise, check them in: 88 | # .python-version 89 | 90 | # pipenv 91 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 92 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 93 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 94 | # install all needed dependencies. 95 | #Pipfile.lock 96 | 97 | # poetry 98 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 99 | # This is especially recommended for binary packages to ensure reproducibility, and is more 100 | # commonly ignored for libraries. 101 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 102 | #poetry.lock 103 | 104 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 105 | __pypackages__/ 106 | 107 | # Celery stuff 108 | celerybeat-schedule 109 | celerybeat.pid 110 | 111 | # SageMath parsed files 112 | *.sage.py 113 | 114 | # Environments 115 | .env 116 | .venv 117 | env/ 118 | venv/ 119 | ENV/ 120 | env.bak/ 121 | venv.bak/ 122 | 123 | # Spyder project settings 124 | .spyderproject 125 | .spyproject 126 | 127 | # Rope project settings 128 | .ropeproject 129 | 130 | # mkdocs documentation 131 | /site 132 | 133 | # mypy 134 | .mypy_cache/ 135 | .dmypy.json 136 | dmypy.json 137 | 138 | # Pyre type checker 139 | .pyre/ 140 | 141 | # pytype static type analyzer 142 | .pytype/ 143 | 144 | # Cython debug symbols 145 | cython_debug/ 146 | 147 | # PyCharm 148 | # JetBrains specific template is maintainted in a separate JetBrains.gitignore that can 149 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 150 | # and can be added to the global gitignore or merged into this file. For a more nuclear 151 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 152 | #.idea/ 153 | -------------------------------------------------------------------------------- /responde_emails/reply_new_email.py: -------------------------------------------------------------------------------- 1 | import os.path 2 | from googleapiclient.discovery import build 3 | from googleapiclient.errors import HttpError 4 | from google.oauth2.credentials import Credentials 5 | from google_auth_oauthlib.flow import InstalledAppFlow 6 | from google.auth.transport.requests import Request 7 | 8 | import base64 9 | from email.mime.text import MIMEText 10 | import seu_email 11 | 12 | current_path = os.path.dirname(os.path.abspath(__file__)) 13 | 14 | your_email = seu_email.your_email 15 | 16 | # If modifying these scopes, delete the file token.json. 17 | SCOPES = ["https://mail.google.com/"] 18 | 19 | 20 | def get_email_address(headers, field_name): 21 | for header in headers: 22 | if header['name'].lower() == field_name.lower(): 23 | return header['value'] 24 | return None 25 | 26 | def get_email_body(email_content): 27 | if 'parts' in email_content["payload"]: 28 | return email_content["payload"]["parts"][0]["body"]["data"] 29 | elif 'body' in email_content["payload"]: 30 | return email_content["payload"]["body"]["data"] 31 | else: 32 | return None 33 | 34 | def connect(): 35 | creds = None 36 | 37 | if os.path.exists(current_path+"/token.json"): 38 | creds = Credentials.from_authorized_user_file(current_path+"/token.json", SCOPES) 39 | if not creds or not creds.valid: 40 | if creds and creds.expired and creds.refresh_token: 41 | creds.refresh(Request()) 42 | else: 43 | flow = InstalledAppFlow.from_client_secrets_file( 44 | current_path+"/credentials.json", SCOPES 45 | ) 46 | creds = flow.run_local_server(port=0) 47 | # Save the credentials for the next run 48 | with open(current_path+"/token.json", "w") as token: 49 | token.write(creds.to_json()) 50 | 51 | return build("gmail", "v1", credentials=creds) 52 | 53 | 54 | def show_chatty_threads(service): 55 | new_email_ids = [] 56 | 57 | try: 58 | 59 | threads = ( 60 | service.users().threads().list(userId="me").execute().get("threads", []) 61 | ) 62 | if not os.path.exists(current_path+'/email_ids.csv'): 63 | with open(current_path+'/email_ids.csv', 'w') as f: 64 | existing_email_ids = [] 65 | varre="n" 66 | varre = input("Voce deseja varrer e armazenar todos os emails atuais? (s/N) ") 67 | if varre.lower() == "s": 68 | for thread in threads: 69 | tdata = ( 70 | service.users().threads().get(userId="me", id=thread["id"]).execute() 71 | ) 72 | email_ids = [msg["id"] for msg in tdata["messages"]] 73 | for email_id in email_ids: 74 | existing_email_ids.append(email_id) 75 | print("Email_ids varridos: ", existing_email_ids) 76 | with open(current_path+'/email_ids.csv', 'a') as f: 77 | for email_id in existing_email_ids: 78 | f.write(email_id + '\n') 79 | 80 | for thread in threads: 81 | tdata = ( 82 | service.users().threads().get(userId="me", id=thread["id"]).execute() 83 | ) 84 | nmsgs = len(tdata["messages"]) 85 | # print(tdata["messages"]) 86 | # get all email_ids of each thread 87 | email_ids = [msg["id"] for msg in tdata["messages"]] 88 | 89 | # load email_ids from csv file 90 | 91 | with open(current_path+'/email_ids.csv', 'r') as f: 92 | existing_email_ids = f.read().splitlines() 93 | # check if email_ids already exist in csv file and append new_email_ids array 94 | for email_id in email_ids: 95 | if email_id not in existing_email_ids: 96 | new_email_ids.append(email_id) 97 | existing_email_ids.append(email_id) 98 | 99 | read_status = [msg["labelIds"] for msg in tdata["messages"]] 100 | 101 | # skip if <3 msgs in thread 102 | if nmsgs > 0: 103 | msg = tdata["messages"][0]["payload"] 104 | subject = "" 105 | for header in msg["headers"]: 106 | if header["name"] == "Subject": 107 | subject = header["value"] 108 | break 109 | if subject: # skip if no Subject line 110 | print(f"- {subject}, {nmsgs}, {email_ids}, {read_status}") 111 | 112 | print("New email_ids: ", new_email_ids) 113 | 114 | # write new_email_ids to csv file 115 | with open(current_path+'/email_ids.csv', 'a') as f: 116 | for email_id in new_email_ids: 117 | f.write(email_id + '\n') 118 | 119 | return new_email_ids 120 | 121 | 122 | except HttpError as error: 123 | print(f"An error occurred: {error}") 124 | 125 | def get_info_new_emails(email_id): 126 | # get thread_id 127 | thread_id = ( 128 | service.users() 129 | .messages() 130 | .get(userId="me", id=email_id) 131 | .execute() 132 | )["threadId"] 133 | 134 | # get snippet 135 | snippet = ( 136 | service.users() 137 | .messages() 138 | .get(userId="me", id=email_id) 139 | .execute() 140 | )["snippet"] 141 | 142 | 143 | email_content = ( 144 | service.users() 145 | .messages() 146 | .get(userId="me", id=email_id) 147 | .execute() 148 | ) 149 | # get subject 150 | tdata = ( 151 | service.users().threads().get(userId="me", id=thread_id).execute() 152 | ) 153 | msg = tdata["messages"][0]["payload"] 154 | subject = "" 155 | for header in msg["headers"]: 156 | if header["name"] == "Subject": 157 | subject = header["value"] 158 | break 159 | 160 | 161 | headers = email_content['payload']['headers'] 162 | sender_email = get_email_address(headers, 'From') 163 | recipient_email = get_email_address(headers, 'To') 164 | 165 | # print (email_content) 166 | email_body = get_email_body(email_content) 167 | email_body = base64.urlsafe_b64decode(email_body).decode("utf-8") 168 | 169 | return sender_email, recipient_email, email_id, thread_id, subject, email_body, snippet 170 | 171 | def create_message(sender, to, message_id, thread_id, subject, message_text): 172 | message = MIMEText(message_text) 173 | message['from'] = sender 174 | message['to'] = to 175 | message['In-Reply-To'] = message_id 176 | message['References'] = message_id 177 | message['subject'] = subject 178 | 179 | return { 180 | 'raw': base64.urlsafe_b64encode(message.as_string().encode()).decode(), 181 | 'threadId':thread_id 182 | } 183 | 184 | def send_message(service, user_id, message): 185 | message = (service.users().messages().send(userId="me", 186 | body=message).execute()) 187 | print('Message Id: %s' % message['id']) 188 | return message 189 | 190 | def create_draft(service, user_id, message): 191 | draft = { 192 | 'message': message 193 | } 194 | draft = service.users().drafts().create(userId=user_id, body=draft).execute() 195 | print('Draft Id: %s' % draft['id']) 196 | return draft 197 | 198 | def send_email(sender, to, message_id, thread_id, subject, message_text): 199 | created_message = create_message(sender, to, message_id, thread_id, subject, message_text) 200 | # send_message(service, 'me', created_message) 201 | create_draft(service, 'me', created_message) 202 | 203 | if __name__ == "__main__": 204 | service = connect() 205 | new_email_ids = [] 206 | new_email_ids = show_chatty_threads(service) 207 | 208 | for email_check in new_email_ids: 209 | sender_email, recipient_email, email_id, thread_id, subject, email_body, summary = get_info_new_emails(email_check) 210 | 211 | 212 | if your_email not in sender_email: 213 | print("De: ", sender_email) 214 | print("Resumo: ", summary) 215 | responder = "s" 216 | responder = input("Deseja responder (S/n)?") 217 | 218 | if responder.lower() == "s": 219 | 220 | # save email_body to file email.txt 221 | with open(current_path+'/src/agencia_noticias/email.txt', 'w', encoding='utf-8') as f: 222 | f.write(email_body) 223 | 224 | 225 | os.system("poetry run agencia_noticias") 226 | 227 | print("Feito!") 228 | 229 | # load reply email_body from file email.txt 230 | with open(current_path+'/resposta.txt', 'r', encoding='utf-8') as f: 231 | reply = f.read() 232 | 233 | 234 | email_body = "> " + email_body.replace("\n", "\n>") 235 | email_body = reply + "\n\n"+ email_body 236 | send_email(recipient_email, sender_email, email_id, thread_id, subject, email_body) 237 | 238 | 239 | 240 | # melhorias - colocar no inicio do email a mensagem padrao do google - On Wed, Sep 15, 2021 at 10:00 AM, wrote: --------------------------------------------------------------------------------