├── .gitignore ├── requirements.txt ├── faq-hare-express.pdf ├── atendimento_bot.py └── correios_rastreamento.py /.gitignore: -------------------------------------------------------------------------------- 1 | bot-env 2 | .env 3 | __pycache__/ -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | python-dotenv==1.0.1 2 | discord.py==2.4.0 3 | google-generativeai==0.7.2 4 | urllib3==2.2.2 5 | 6 | -------------------------------------------------------------------------------- /faq-hare-express.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/alexandreaquiles/chatbot-atendimento-gemini/HEAD/faq-hare-express.pdf -------------------------------------------------------------------------------- /atendimento_bot.py: -------------------------------------------------------------------------------- 1 | import os 2 | import discord 3 | from dotenv import load_dotenv 4 | import google.generativeai as genai 5 | from correios_rastreamento import busca_info_rastreamento 6 | 7 | load_dotenv() 8 | 9 | modelo_gemini = "gemini-1.5-flash" 10 | genai.configure(api_key=os.environ["GEMINI_API_KEY"]) 11 | generation_config = { 12 | "temperature": 0, 13 | "response_mime_type": "text/plain" 14 | } 15 | 16 | faq_file = genai.upload_file(path='faq-hare-express.pdf') 17 | 18 | prompt_sistema = """ 19 | Você é um robô de atendimento da empresa Hare Express, uma empresa de entrega inovadora que se destaca pela rapidez e eficiência. 20 | Você deve responder de maneira educada, objetiva e formal. 21 | Apenas responda perguntas relativas aos serviços da Hare Express. 22 | Utilize apenas as informações contidas no PDF em anexo. 23 | Caso a pergunta não seja relacionada a algum serviço da Hare Express, educadamente se negue a responder. 24 | """ 25 | gemini = genai.GenerativeModel( 26 | model_name = modelo_gemini, 27 | generation_config=generation_config, 28 | system_instruction = prompt_sistema, 29 | tools=[busca_info_rastreamento]) 30 | 31 | intents = discord.Intents.default() 32 | intents.message_content = True 33 | 34 | discord_client = discord.Client(intents=intents) 35 | 36 | @discord_client.event 37 | async def on_ready(): 38 | print(f'Logado como {discord_client.user}!') 39 | 40 | @discord_client.event 41 | async def on_message(message): 42 | if message.author == discord_client.user: 43 | return 44 | 45 | nome_cliente = message.author 46 | mensagem_cliente = message.content 47 | 48 | tamanho_mensagem_cliente = len(mensagem_cliente) 49 | print(tamanho_mensagem_cliente) 50 | 51 | print(f'Mensagem de {nome_cliente}: {mensagem_cliente}') 52 | 53 | channel = discord_client.get_channel(message.channel.id) 54 | 55 | chat = gemini.start_chat(enable_automatic_function_calling=True) 56 | resposta = chat.send_message([f""" 57 | Nome do cliente: {nome_cliente} 58 | Mensagem do cliente: {mensagem_cliente} 59 | """, faq_file]) 60 | # print(resposta) 61 | # print(resposta.text) 62 | mensagem_resposta = resposta.text 63 | # print(len(mensagem_resposta)) 64 | # print(mensagem_resposta) 65 | await channel.send(mensagem_resposta) 66 | 67 | discord_client.run(os.getenv('DISCORD_CLIENT_TOKEN')) 68 | -------------------------------------------------------------------------------- /correios_rastreamento.py: -------------------------------------------------------------------------------- 1 | import urllib3 2 | import logging 3 | from urllib3.util import Retry 4 | 5 | logging.basicConfig(level=logging.DEBUG) 6 | logger = logging.getLogger("urllib3") 7 | 8 | http = urllib3.PoolManager() 9 | 10 | retries = Retry( 11 | total=5, 12 | backoff_factor=1, 13 | status_forcelist=[413, 429, 500, 502, 503, 504], 14 | raise_on_status=False 15 | ) 16 | 17 | def log_retry_attempt(method, url, error, _): 18 | logger.debug(f"Retrying {method} request to {url} due to {error}") 19 | 20 | retries._is_retry = log_retry_attempt 21 | 22 | def busca_info_rastreamento(codigo_rastreamento:str): 23 | """Busca informações do rastreamento de objetos e encomendas da Hare Express de qualquer localidade do Brasil a partir do código de rastreamento. 24 | 25 | Args: 26 | codigo_rastreamento: Código de rastreamento obtido no momento da postagem da encomenda. 27 | O código de Rastreamento é composto de 13 dígitos, começando com 2 letras seguidas de 9 letras e de mais 2 letras. 28 | Exemplos: JN732917265BR, QS244376229BR, OY313609204BR 29 | 30 | Returns: 31 | Um dicionário Python contendo o código de rastreamento, um array de eventos contendo cada status da entrega, além de outras informações. 32 | Caso o objeto não seja encontrado, o array de eventos estará vazio. 33 | 34 | Exemplo de objeto entregue: {'codigo': 'JN732917265BR', 'host': 'rd', 'eventos': [{'data': '23/07/2024', 'hora': '11:34', 'local': 'Criciuma / SC', 'status': 'Objeto entregue ao destinatário', 'subStatus': ['Local: Unidade de Distribuição - Criciuma / SC']}, {'data': '23/07/2024', 'hora': '07:31', 'local': 'Criciuma / SC', 'status': 'Objeto saiu para entrega ao destinatário', 'subStatus': ['Local: Unidade de Distribuição - Criciuma / SC']}, {'data': '11/07/2024', 'hora': '13:01', 'local': 'Caraguatatuba / SP', 'status': 'Objeto postado', 'subStatus': ['Local: Agência dos Correios - Caraguatatuba / SP']}], 'time': 0.071, 'quantidade': 3, 'servico': 'MALA DIRETA POSTAL ESPECIAL', 'ultimo': '2024-07-23T14:34:00.000Z'} 35 | Exemplo de objeto encaminhado: {'codigo': 'AK390407941BR', 'host': 'lt', 'eventos': [{'data': '10/09/2024', 'hora': '10:37', 'local': 'Varzea Grande / MT', 'status': 'Objeto encaminhado', 'subStatus': ['Origem: Unidade de Tratamento - Varzea Grande / MT', 'Destino: Unidade de Distribuição - Porto Velho / RO']}, {'data': '05/09/2024', 'hora': '12:55', 'local': 'Blumenau / SC', 'status': 'Objeto encaminhado', 'subStatus': ['Origem: Unidade de Tratamento - Blumenau / SC', 'Destino: Unidade de Tratamento - Varzea Grande / MT']}, {'data': '04/09/2024', 'hora': '14:28', 'local': 'Florianopolis / SC', 'status': 'Objeto encaminhado', 'subStatus': ['Origem: Agência dos Correios - Florianopolis / SC', 'Destino: Unidade de Tratamento - Blumenau / SC']}, {'data': '04/09/2024', 'hora': '13:41', 'local': 'Florianopolis / SC', 'status': 'Objeto postado', 'subStatus': ['Local: Agência dos Correios - Florianopolis / SC']}], 'time': 0.737, 'quantidade': 4, 'servico': '', 'ultimo': '2024-09-10T13:37:00.000Z'} 36 | Exemplo de objeto não encontrado: {'codigo': 'XX111111111YY', 'host': 'lt', 'eventos': [], 'time': 0.733, 'quantidade': 0, 'servico': 'REMESSA INTERNACIONAL'} 37 | """ 38 | 39 | print(f'Vai rastrear o objeto: {codigo_rastreamento}') 40 | 41 | url = f"https://api.linketrack.com/track/json?user=teste&token=1abcd00b2731640e886fb41a8a9671ad1434c599dbaa0a0de9a5aa619f29a83f&codigo={codigo_rastreamento}" 42 | 43 | resp = http.request("GET", url, retries=retries) 44 | 45 | print(f'Rastreou o objeto {codigo_rastreamento}') 46 | print(f'HTTP Status: {resp.status}') 47 | 48 | if resp.status == 200: 49 | return resp.json() 50 | 51 | return resp.data 52 | 53 | --------------------------------------------------------------------------------