File size: 11,755 Bytes
b2437ae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
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)