File size: 10,917 Bytes
1109b1e
6b8b942
1109b1e
 
 
 
 
 
 
dcbbbea
1109b1e
 
 
 
43f6120
 
 
 
1109b1e
 
 
 
 
 
 
 
 
 
 
 
 
 
6b8b942
 
 
1109b1e
 
8013dad
1109b1e
 
 
 
 
 
 
dcbbbea
 
 
1109b1e
 
f576150
dcbbbea
1109b1e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72ad95a
 
1109b1e
 
dcbbbea
1109b1e
 
528d02a
1109b1e
 
 
 
 
528d02a
1109b1e
 
 
7ad0c80
528d02a
1109b1e
 
dcbbbea
 
 
 
 
 
 
1109b1e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
43f6120
 
 
 
 
 
 
 
 
 
 
 
72ad95a
43f6120
 
 
 
 
 
 
 
 
 
72ad95a
 
43f6120
 
 
 
 
 
 
 
72ad95a
43f6120
 
 
 
 
 
72ad95a
43f6120
 
 
 
72ad95a
43f6120
 
 
72ad95a
43f6120
 
 
72ad95a
43f6120
 
 
 
72ad95a
43f6120
 
 
 
 
 
 
 
1109b1e
43f6120
1109b1e
43f6120
1109b1e
 
 
 
 
 
528d02a
 
43f6120
 
 
1109b1e
 
 
 
 
528d02a
1109b1e
 
43f6120
 
 
 
 
 
1109b1e
43f6120
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ba3a178
1109b1e
 
 
 
 
b9d0416
528d02a
 
 
b9d0416
 
43f6120
 
1109b1e
528d02a
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
import os
import gradio as gr
from dotenv import load_dotenv
from langchain_google_genai import ChatGoogleGenerativeAI
from langchain_core.tools import tool
from langchain.pydantic_v1 import BaseModel, Field
import requests
from datetime import datetime
from typing import List
from langchain.tools import Tool
from langchain.prompts import ChatPromptTemplate
from langchain.output_parsers import PydanticOutputParser
from langchain.memory import ConversationBufferMemory
from langchain.agents import AgentExecutor, create_tool_calling_agent
import uuid
from langchain_community.chat_message_histories import ChatMessageHistory
from langchain_core.runnables.history import RunnableWithMessageHistory
import gradio as gr

load_dotenv(dotenv_path='api.env.txt')
Langchain_API_KEY = os.getenv('LANGCHAIN_API')
GOOGLE_API_KEY = os.getenv('GOOGLE_API')
WEATHER_API_KEY = os.getenv('WEATHER_API')

os.environ["GOOGLE_API_KEY"] = GOOGLE_API_KEY

llm = ChatGoogleGenerativeAI(
    model="gemini-1.5-flash",
    temperature=0,
    max_tokens=None,
    timeout=None,
    max_retries=2,
)



def get_location_from_ip():
    ip =requests.get('https://api.ipify.org?format=json').json()['ip']
    response = requests.get(f"https://ipapi.co/{ip}/json/").json()
    return {
        'city': response.get('city'),
        'latitude': response.get('latitude'),
        'longitude': response.get('longitude')
    }

class WeatherInput(BaseModel):
    city: str = Field(default=None, description="The city to get the weather for.")

@tool("get_weather_by_location", args_schema=WeatherInput, return_direct=True)
def get_weather_by_location(city: str = None):
    """Get the weather based on the user's location if no city is specified."""

    if not city:
        location = get_location_from_ip()
        city = location['city']

    url = f"https://api.tomorrow.io/v4/timelines?apikey={WEATHER_API_KEY}"
    payload = {
        "location": city,
        "fields": ["temperature", "humidity", "windSpeed"],
        "units": "metric",
        "timesteps": ["1d"],
        "startTime": "now",
        "endTime": "nowPlus5d",
        "timezone": "auto"
    }
    headers = {
        "accept": "application/json",
        "content-type": "application/json"
    }

    response = requests.post(url, json=payload, headers=headers).json()
    
    return format_weather_response(response, city)

def format_weather_response(weather_data, city):
    """Format the weather data into a readable string."""
    intervals = weather_data['data']['timelines'][0]['intervals']
    response = f"Weather forecast for {city}:\n\n"
    
    for interval in intervals:
        date = datetime.fromisoformat(interval['startTime']).strftime("%A, %B %d")
        temp = round(interval['values']['temperature'], 1)
        humidity = round(interval['values']['humidity'], 1)
        wind_speed = round(interval['values']['windSpeed'], 1)
        
        response += f"{date}:\n"
        response += f"  Temperature: {temp}°C\n"
        response += f"  Humidity: {humidity}%\n"
        response += f"  Wind Speed: {wind_speed * 3.6:.1f} km/h\n\n"
        
    return response

get_weather_tool = Tool(
    name="get_weather_by_location",
    func=get_weather_by_location,
    description="Get the current weather for a specific location. If no location is provided, it will return the weather for the current location."
)


class DailyWeather(BaseModel):
    date: str
    temperature: float
    condition: str
    humidity: float
    wind_speed: float
    advice: str

class WeatherOutput(BaseModel):
    location: str = Field(description="The location or the city for which the weather is reported")
    forecast: List[DailyWeather] = Field(description="The weather forecast for multiple days")

parser = PydanticOutputParser(pydantic_object=WeatherOutput)

prompt = ChatPromptTemplate.from_messages([
    ("system", """You are WeatherWise, a highly knowledgeable, friendly, and efficient weather assistant. Your primary mission is to provide comprehensive and accurate weather information for cities worldwide, while offering personalized advice tailored to the weather conditions. Approach each interaction with warmth and enthusiasm, as if you're chatting with a good friend about their day. Follow these detailed instructions:

1. **Warm Welcome**: Begin each conversation with a friendly greeting, mentioning the current time of day (e.g., "Good morning!" or "Good evening!") to add a personal touch.

2. **City-Specific Requests**: 
   - When a user mentions a specific city, immediately use the get_weather_by_location tool to fetch weather data for today and the next few days.
   - Always include the city's name in your response for clarity, and express enthusiasm about the location (e.g., "Ah, lovely Paris! Let's see what the weather has in store for the City of Light.").

3. **Current Location Assumption**: 
   - If a user asks about the weather without mentioning a city (e.g., "What's the weather like today?"), assume they're asking about their current location and take action: Use the get_weather_by_location tool with an empty string.
   - Use the get_weather_by_location tool with an empty string as input to retrieve local weather information.
    If a user asks about the weather without mentioning a specific city, assume they're asking about their current location. This applies to various phrasings such as:

    "What's the weather like today?"
    "How's the weather?"
    "Will it rain this week?"
    "Should I bring a jacket?"
    "Is it sunny outside?"
    "What's the temperature right now?"
    "Any chance of snow soon?"
    "Will it be windy later?"
    "What's the forecast for the weekend?"
    "Is it a good day for outdoor activities?"


    In all these cases, use the get_weather_by_location tool with an empty string as input to retrieve local weather information based on the user's current location.

        

4. **Data Presentation**: 
   - Use the format_weather tool to present information in a clear, concise, and visually appealing format.
   - Include essential details such as temperature (in both Celsius and Fahrenheit), precipitation chance, humidity, wind speed and direction, and overall weather conditions.
   - For multi-day forecasts, present a brief overview followed by day-by-day breakdowns.

5. **Personalized Advice**: 
   Offer tailored, friendly advice based on the weather conditions for each day:
   - **Sunny**: "It's a beautiful day! Perfect for a picnic in the park or exploring the city. Don't forget your sunscreen and shades!"
   - **Rainy**: "Looks like a cozy day indoors or a chance to splash in puddles! Keep an umbrella handy and maybe curl up with a good book later."
   - **Cold**: "Brr! Time to bundle up in your favorite warm layers. How about making some hot cocoa and enjoying the crisp air on a short walk?"
   - **Hot**: "Whew, it's a scorcher! Stay cool with light, breathable clothing and plenty of water. Maybe treat yourself to some ice cream?"

6. **Clarifications**: 
   If the user's request is ambiguous, ask for clarification in a friendly manner:
   - "I'd love to help! Could you please specify which city you're curious about?"
   - "Just to make sure I give you the most accurate info, which day of the week are you most interested in?"

7. **Avoid Repetition**: 
   - Keep track of the conversation history to provide context-aware responses.
   - If repeating information, frame it as a helpful reminder (e.g., "As I mentioned earlier, but it's worth repeating because it's important...").

8. **Handling Follow-ups**: 
   - Anticipate potential follow-up questions and offer to provide more details proactively.
   - For example: "I've given you an overview, but if you'd like more details about a specific day or any particular weather aspect, just ask!"

9. **Friendly and Informative Tone**: 
   - Use a conversational, upbeat tone as if chatting with a friend.
   - Incorporate weather-related expressions or puns to add a touch of humor when appropriate.
   - Show empathy for less-than-ideal weather conditions (e.g., "I know rainy days can be a bummer, but think of how happy the plants are!").

10. **Local Insights**: 
    - When possible, offer brief, relevant insights about the location in relation to the weather (e.g., "Did you know Paris is actually quite lovely in the rain? It's when the city truly earns its nickname 'City of Light' with all the reflections!").

11. **Closing**: 
    - End each interaction on a positive note, offering to help with any other weather-related questions.
    - Wish the user well based on the forecast (e.g., "Enjoy the sunshine!" or "Stay dry out there!").

Always prioritize accuracy and clarity while maintaining a warm, friendly demeanor. Your goal is to make talking about the weather as enjoyable and helpful as possible!"""),
    ("human", "{input}"),
    ("ai", "Good day! I'm WeatherWise, your friendly neighborhood weather expert. I'm excited to help you plan your days with pinpoint weather forecasts and some cheerful advice to boot. What would you like to know about the weather? Whether it's for your location or anywhere around the globe, I'm all ears!"),
    ("human", "{input}"),
    ("ai", "Absolutely! I'm thrilled to help you with that. Let me fetch the latest weather information and whip up some tailored advice just for you. Give me just a moment while I consult my meteorological crystal ball!"),
    ("placeholder", "{agent_scratchpad}"),
])




tools = [get_weather_tool]


message_history = ChatMessageHistory()

agent = create_tool_calling_agent(llm, tools, prompt=prompt)

agent_executor = AgentExecutor(
    agent=agent,
    tools=tools,
    output_parser=parser
)

agent_with_chat_history = RunnableWithMessageHistory(
    agent_executor,
    lambda session_id: message_history,
    input_messages_key="input",
    history_messages_key="chat_history",
)

session_ids = {}

def gradio_interface(user_input, session_id):
    # If session_id is not in session_ids, it's a new session
    if session_id not in session_ids:
        # Generate a new unique session ID
        new_session_id = str(uuid.uuid4())
        session_ids[session_id] = new_session_id
    else:
        new_session_id = session_ids[session_id]

    result = agent_with_chat_history.invoke(
        {"input": user_input},
        config={"configurable": {"session_id": new_session_id}}
    )
    return [[user_input, result['output']]]

with gr.Blocks() as demo:
    gr.Markdown("# Weather Assistant")
    chatbot = gr.Chatbot()
    with gr.Row():
        txt = gr.Textbox(
            show_label=False,
            placeholder="Ask about the weather...",
            lines=1,
            container=False
        )
        session_id_box = gr.Textbox(visible=False, value=str(uuid.uuid4()))
        txt.submit(gradio_interface, inputs=[txt, session_id_box], outputs=chatbot)

demo.launch(share=True)