import os from datetime import datetime from langchain import hub from langchain.agents import Tool, AgentExecutor from langchain.agents.format_scratchpad import format_log_to_str from langchain.agents.output_parsers import ReActSingleInputOutputParser from langchain.memory import ChatMessageHistory, ConversationBufferWindowMemory from langchain.tools.render import render_text_description from langchain.utilities import DuckDuckGoSearchAPIWrapper from langchain_google_genai import ( ChatGoogleGenerativeAI, HarmBlockThreshold, HarmCategory, ) import streamlit as st from planing_tools import weatherapi_forecast_periods, query_rag from calendar_tools import list_calendar_list, list_calendar_events, insert_calendar_event, create_calendar from dotenv import load_dotenv hoje = datetime.today() data_formatada = hoje.strftime("%Y/%m/%d") # Pega o dia da semana em inglês dia_da_semana_ingles = hoje.strftime("%A") # Dicionário para mapear os dias da semana de inglês para português dias_da_semana_pt = { "Monday": "segunda-feira", "Tuesday": "terça-feira", "Wednesday": "quarta-feira", "Thursday": "quinta-feira", "Friday": "sexta-feira", "Saturday": "sábado", "Sunday": "domingo" } # Traduz o dia da semana para português dia_da_semana_pt = dias_da_semana_pt.get(dia_da_semana_ingles, dia_da_semana_ingles) # Formata a data para utilizar no prompt data_atual = f"{dia_da_semana_pt}, {data_formatada}" load_dotenv() os.environ["GOOGLE_API_KEY"] = os.getenv('GOOGLE_API_KEY') os.environ["LANGCHAIN_API_KEY"] = os.getenv('LANGCHAIN_API_KEY') llm = ChatGoogleGenerativeAI( model="gemini-1.5-flash", convert_system_message_to_human=True, handle_parsing_errors=True, temperature=0.6, max_tokens= 1000, safety_settings = { HarmCategory.HARM_CATEGORY_HARASSMENT: HarmBlockThreshold.BLOCK_ONLY_HIGH, HarmCategory.HARM_CATEGORY_HATE_SPEECH: HarmBlockThreshold.BLOCK_ONLY_HIGH, HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT: HarmBlockThreshold.BLOCK_ONLY_HIGH, HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT: HarmBlockThreshold.BLOCK_ONLY_HIGH, }, ) def transfer_to_calendar_agent(input_str): return calendar_agent_executor.invoke({"input": input_str}) def transfer_to_travel_agent(input_str): return travel_agent_executor.invoke({"input": input_str}) ddg_search = DuckDuckGoSearchAPIWrapper() travel_planing_tools = [ Tool( name="DuckDuckGo Search", func=ddg_search.run, description="""Essa ferramenta DEVE ser utilizada para buscar eventos relevantes no período fornecido pelo usuário. Ela é útil para obter informações sobre eventos ou atividades especiais que estão acontecendo na cidade de destino nas datas que o usuário informou. O modelo deve usá-la para complementar as sugestões de atividades.""" ), Tool( name="Weather Forecast", func=lambda date_string: weatherapi_forecast_periods(date_string, st.session_state.selected_destino), description="""Esta ferramenta DEVE ser usada obrigatoriamente *antes* de gerar o roteiro turístico, e somente após coletar todas as informações necessárias do usuário, incluindo o intervalo exato de datas. A consulta do clima deve ser feita separadamente para cada dia do período informado, garantindo que as atividades planejadas no roteiro sejam compatíveis com as condições climáticas previstas. **Quando usar:** - O clima é um fator relevante para a definição de atividades no roteiro. - O usuário especificou o intervalo de datas para o planejamento. **Instruções:** 1. Certifique-se de coletar as datas exatas do período solicitado pelo usuário. 2. Consulte a previsão do tempo para cada dia separadamente no intervalo de datas fornecido. 3. Use o resultado da previsão para ajustar o planejamento das atividades de acordo com as condições climáticas. **Exemplo de uso:** - Entrada do usuário: "Planeje um roteiro entre os dias 1º de agosto e 4 de março." - Ações do modelo: Action input: 2025/08/01 Action input: 2025/08/02 Action input: 2025/08/03 Action input: 2025/08/04 """ ), Tool( name="Query RAG", func=lambda query_text: query_rag(query_text, st.session_state.selected_destino), description="""Esta ferramenta deve ser usada quando o modelo souber a cidade de destino e os interesses do usuário, com o objetivo de fornecer informações sobre pontos turísticos e atrações que se alinham com esses interesses. O modelo deve utilizar essa ferramenta para sugerir atividades e lugares específicos a visitar, baseados na cidade e nos interesses fornecidos.""" ), Tool( name="Calendar Agent", func=transfer_to_calendar_agent, description="Esse agente lida com tudo relacionado ao calendário. As mensagens enviadas a ele devem estar em Português." ), ] from calendar_tools import list_calendar_list, list_calendar_events, insert_calendar_event, create_calendar google_calendar_tools = [ Tool( name="Create Calendar List", func=create_calendar, description=""" Use a função create_calendar_list para criar um novo calendário. Forneça o resumo (título) do calendário que você deseja criar. - Exemplo de uso: 'Meu Calendário de Viagens' - Essa função vai criar um novo calendário com o resumo fornecido. """ ), Tool( name="List Calendar List", func=list_calendar_list, description=""" Use a função list_calendar_list para obter a lista dos seus calendários disponíveis no Google Calendar. Se você quiser limitar o número de calendários retornados, forneça o número máximo desejado. - Exemplo de uso: Forneça o número máximo de calendários a serem listados, como 50. Se não quiser um limite, apenas diga para listar 200 o máximo por padrão. """ ), Tool( name="List Calendar Events", func=list_calendar_events, description=""" Use a função list_calendar_events para obter a lista de eventos de um calendário específico. Você precisa fornecer o ID do calendário e, opcionalmente, o número máximo de eventos a serem listados. - Exemplo de uso para o calendário principal: forneça 'primary' como o ID do calendário. - Exemplo de uso com limite: forneça o ID do calendário e o número máximo de eventos, como 'primary', 20. - Para listar eventos de um calendário específico, primeiro liste seus calendários para encontrar o ID correto. """ ), Tool( name="Insert Calendar Event", func=insert_calendar_event, description=""" Use a função Insert Calendar Event para adicionar **um único evento** a um calendário Google. Esta função deve ser chamada **uma vez para cada evento** que precisa ser agendado. A entrada para esta função deve ser uma descrição clara e completa de **um único evento** em linguagem natural, contendo todas as informações necessárias para agendá-lo individualmente. Se o usuário pediu para criar um novo calendário, você DEVE utilizar o calendar_id desse novo calendário para a inserção dos eventos. **Formato de entrada esperado:** **Descrição em Linguagem Natural (obrigatório):** Forneça uma descrição textual detalhada para **um único evento**. Inclua o calendar_id (se fornecido pelo usuário), o que será feito, quando (data e hora específicas), onde (local exato) e quaisquer detalhes adicionais relevantes para esse evento em particular. **Exemplos de descrições de eventos individuais:** - "Agendar almoço com a Maria na sexta-feira ao meio-dia no restaurante X." - "Criar um compromisso para pagar as contas no dia 10 de janeiro às 9h da manhã." - "Bloquear minha agenda para foco no projeto Y na próxima segunda-feira, das 14h às 17h, na minha mesa." **Como usar esta função corretamente:** 1. **Identifique cada evento individualmente:** Se a intenção é agendar múltiplos eventos, trate cada um como uma chamada separada para esta função. 2. **Obtenha o ID do calendário (se necessário):** Se o usuário mencionar um nome de calendário específico, use a função 'list_calendar_list' **primeiro** para obter o 'calendar_id' correspondente. 3. **Chame esta função com a descrição de um único evento:** Forneça a descrição completa em linguagem natural para o evento específico que você deseja agendar. **Informações essenciais para cada descrição de evento:** - **O que:** Uma descrição concisa do evento (ex: "Reunião de equipe", "Consulta médica"). - **Quando:** A data e hora de início e fim **precisas** do evento. - **Onde:** O local **específico** do evento. - **Fuso Horário (opcional):** Se aplicável, mencione o fuso horário se for diferente de "America/Fortaleza". **Exemplo de uso** *Usuário: Agendar visita ao Aquário Natal sábado das 9h às 12h.* *Agente:* (Chama 'Insert Calendar Event' com a Action Input: "Agendar visita ao Aquário Natal sábado das 9h às 12h.") **Observação IMPORTANTE:** Esta função **NÃO** deve ser usada para criar múltiplos eventos com uma única chamada. Cada chamada deve corresponder a **um único evento**. Ao final da execução desta função, você DEVE fornecer ao usuário a confirmação do agendamento desse evento específico, incluindo o título, data, hora. No final forneça o link para o calendário google: [https://www.google.com/calendar] """ ) ] travel_planing_prompt = hub.pull("tales/agente_turismo") google_calendar_prompt = hub.pull("tales/agente_calendario") llm_with_stop = llm.bind(stop=["\nObservation"]) planing_prompt = travel_planing_prompt.partial( tools=render_text_description(travel_planing_tools), tool_names=", ".join([t.name for t in travel_planing_tools]), ) calendar_prompt = google_calendar_prompt.partial( tools=render_text_description(google_calendar_tools), tool_names=", ".join([t.name for t in google_calendar_tools]), ) history = ChatMessageHistory() memory = ConversationBufferWindowMemory( k=20, chat_memory=history, memory_key="chat_history", input_key="input", other_memory_key=["destino"]) travel_planing_agent = ( { "input": lambda x: x["input"], "destino": lambda x: x.get("destino"), "agent_scratchpad": lambda x: format_log_to_str(x["intermediate_steps"]), "chat_history": lambda x: x["chat_history"], "data_atual": lambda x: data_atual, } | planing_prompt | llm_with_stop | ReActSingleInputOutputParser() ) travel_agent_executor = AgentExecutor(agent=travel_planing_agent, tools=travel_planing_tools, verbose=True, memory=memory, handle_parsing_errors=True) google_calendar_agent = ( { "input": lambda x: x["input"], "agent_scratchpad": lambda x: format_log_to_str(x["intermediate_steps"]), "chat_history": lambda x: x["chat_history"], "data_atual": lambda x: data_atual, } | calendar_prompt | llm_with_stop | ReActSingleInputOutputParser() ) calendar_agent_executor = AgentExecutor(agent=google_calendar_agent, tools=google_calendar_tools, verbose=True, memory=memory)