Open Weather API (and Chat GPT)

It would be really cool to feed the daily[0] response to OpenAI’s GPT API (Chat GPT API) and have it generate a summary:

Can you put together a single sentence forecast with the most relevant information from the following Open Weather API JSON response for tomorrow's weather? The units are imperial. Please keep the response concise and only include information if it is relevant. 

Before generating a response, take a moment to internally (silently) think about the steps you would take to determine what information is relevant to include in the forecast. Ignore the provided "summary" if one is included as I want you to generate your own. 
~~~
{
    "dt": 1690308000,
    "sunrise": 1690284742,
    "sunset": 1690334902,
    "moonrise": 1690310280,
    "moonset": 1690262340,
    "moon_phase": 0.25,
    "summary": "Expect a day of partly cloudy with clear spells",
    "temp": {
        "day": 93.81,
        "min": 73.45,
        "max": 102.87,
        "night": 84.83,
        "eve": 100.17,
        "morn": 77.09
    },
    "feels_like": {
        "day": 101.23,
        "night": 84.51,
        "eve": 102.6,
        "morn": 77.97
    },
    "pressure": 1019,
    "humidity": 48,
    "dew_point": 71.15,
    "wind_speed": 10.49,
    "wind_deg": 206,
    "wind_gust": 26.42,
    "weather": [
        {
            "id": 800,
            "main": "Clear",
            "description": "clear sky",
            "icon": "01d"
        }
    ],
    "clouds": 0,
    "pop": 0,
    "uvi": 10.78
}
~~~

And the output:

I also found that using GPT-4 for this kind of logical thinking and composition results in a ‘better’ result, but that’s subjective:

I’m sure with a bit of prompt engineering, you could probably get it to summarize things just the way you want.

1 Like

Here’s an example where I asked it to “try again in the style of Carrot Weather which is known for its amusing, often sassy, and sometimes profanity laden forecast summaries?”

4 Likes

This is a great idea

How did you do this?

I just did the example directly in the ChatGPT interface.

What I was suggesting, is you could use the OpenAI API to accomplish the same thing in a rule using HTTP Actions.

Here’s an approach that worked for me for getting the Open Weather response and then feeding that into OpenAI to leverage their GPT models:

:stop_sign: Note that you have to be very specific about the syntax or it won’t work. The little details really matter here.

Here’s a summary of the flow:

  1. Make the HTTP request to Open Weather’s OneCall API
  2. Use an expression to build the specially formatted payload for OpenAI’s GPT API
    1. Stub the base message template for OpenAI
    2. Double stringify the weather response data
    3. Trim off the wrapping " characters from double stringifying
    4. Build the final message using the template
  3. Make the HTTP request to OpenAI
  4. Store the response message content from Open AI in a variable

Snippets

And the relevant snippets for your reference.

First Expression
Build the specially formatted payload for OpenAI’s API.

message = "Can you put together a single sentence forecast with the most relevant information from the following Open Weather API JSON response for tomorrow's weather? The units are imperial. Please keep the response concise and only include information if it is relevant. \\n\\nBefore generating a response, take a moment to internally (silently) think about the steps you would take to determine what information is relevant to include in the forecast. Ignore the provided 'summary' if one is included as I want you to generate your own. \\n~~~\\n __WEATHER_JSON__ \\n~~~"
stringJson = stringify(stringify($context.response.data.daily[0]))
stringJson = substring(stringJson, 1, size(stringJson)-1)
replace(message, "__WEATHER_JSON__", stringJson)

Notes:

  • The base message template must properly escape any new-lines, double quotes, etc.
  • We double stringify the JSON that we get back from open weather since we need it properly escaped
    "{\"humidity\": 48, \"temp\": {\"min\": 73.45... }"
    
  • But the double stringify ends up wrapping the whole things in quotes, so we strip those off
    {\"humidity\": 48, \"temp\": {\"min\": 73.45... }
    

OpenAI HTTP Action
This is a standard HTTP action and the formatting is following the documentation from OpenAI. If you want to adjust the parameters, you might want to do so in the OpenAI Playground and use the View Code button and change the type to JSON to make sure you get the right format. It’s critical that your content within your messages gets injected properly as shown in the example.

{
  "model": "gpt-3.5-turbo",
  "messages": [{"role": "user", "content": "{{$AString}}"}],
  "temperature": 1,
  "max_tokens": 256,
  "top_p": 1,
  "frequency_penalty": 0,
  "presence_penalty": 0
}

Notes:

  • Make sure to POST the JSON data to the right endpoint
  • Ensure you’ve setup the headers properly:
    Key Value
    Authorization Bearer YOUR-KEY
  • Ensure the Payload is formatted exactly as show above and the content is pointing to the proper variable (the output from the earlier expression)

Use OpenAI Response
We’re grabbing the result from the response based on the format noted in the OpenAI documentation:

$context.response.data.choices[0].message.content
2 Likes

This is a great guide, worked first time, Thanks

Edit - It’s also really handy having Chat GPT on my dashboard and again using SharpTools Rule’s and TTS, the dashboard will kindly read the response

3 Likes

That’s really awesome, Paul! I didn’t get the notice of your post edit and just saw your screenshot! :star_struck:

Edit: You’re featured in our latest Twitter post and Facebook post! :sunglasses:

2 Likes

So for anyone who hasn’t tried @josh Chat GPT openweather summary

(Open Weather API)

Expect a day of partly cloudy with rain

(Chat GPT)

Tomorrow, 30th July 2023, the weather is expected to bring moderate rain throughout the day. The maximum temperature will reach 16°C, while the minimum temperature will be around 14°C. The sunset is set for 21:15. The atmospheric pressure will be 1006Mb. The wind will be quite strong, with a constant speed of 29Mph and gusts reaching up to 34Mph. The wind direction will be from the north. Cloud cover is estimated at 75%, meaning the sky will be mostly cloudy. The chance of rain is at a high 100%, so it is advisable to carry an umbrella or raincoat if you plan to be outside. The UV index is low at 2. The pollen count is expected to be low at 0, which may bring some relief to allergy sufferers.

1 Like

This is super cool, thanks for sharing @josh I’m having an issue where the response isn’t getting stored in my variable. I’m trying to troubleshoot it in the logs and when I click show raw response, nothing displays. Am I not doing something really obvious? I have it working in Postman, but it just won’t work in SharpTools.

Edit: I added the error status and I’m getting a 404 from OpenAI. I copied it from Postman.

I would triple check the URL. A 404 means the OpenAI servers are responding saying that the URL you’re trying to access is not found. I would check for any extra spaces before and after and little details like that too.

You can share a screenshot if you’d like the community to take a closer look. Just make sure to redact any personal information like API keys.

I had PUT instead of POST. Fixed it, thanks for taking a look.

1 Like

Are you all using the free tier for Open AI API? I decided to give this a try but I could not get the variable to populate from open ai. I tried it Postman and got an error that I exceeded my current quota. I only tried about a dozen times over the course of a few hours.

Edit - looks like my free tier credit expired :frowning:

If you’re only doing a couple per day, it’s super cheap. For the month of August having a busy test day where I hit $0.004, yes not even a penny, and then 2 hits a day after that, I am up to $0.02. You can always set an upper $$ limit, if you’re worried.

1 Like

Thanks Zach. At first I didn’t realize there was a cost to use the api until I tried it with postman and in their api playground.

Do you use the v4 or v3.5?

Since Josh was using v3.5 and this is pretty simple work for ChatGPT, I went with v3.5.

2 Likes

Unfortunately I still can’t seem to get this to work. For some reason the response from chatgpt is not being populated in my variable. The rule logs does not show anything in particular that could be causing this. But I tested the payload content in the API playground and the result was expected i.e. I got a weather report back so the message is being parsed over correctly. I also see the api key usage is being hit so the http call is making it there but for whatever reason the result is not making it back.

I’m going to try on postman to see if I get any errors back.

The HTTP Action Troubleshooting article has some helpful tips that you might be interested in:

Thanks Josh. I use http calls for other things but I’ll look into the article you sent. I’ll share a snippet of my rule as well just in case I’m doing something wrong.

Edit - So this is working with Postman but with Sharptools rule, I am unable to get the response into my variable.

Edit 2 - I got this working…silly mistake…I had no space between bearer and my token.

@josh - thanks for pointing me to that http troubleshooting guide. I created a new variable to catch the response.status which generated a 401 and led me to reviewing the auth headers…

So I discovered that ChatGPT is not looking at tomorrows weather data in the JSON response and instead is looking at todays data. Any idea how I can explain to ChatGPT that it needs to look at the data with tomorrows timestamp? Or maybe how I can exclude the current day in the open weather api call? I’m already excluding current, hourly and minutely in my call.

Here is the weather json, it is the second section under daily that is tomorrow:

  "daily": [
        {
            "dt": 1703005200,
            "sunrise": 1702992290,
            "sunset": 1703024180,
            "moonrise": 1703009220,
            "moonset": 0,
            "moon_phase": 0.25,
            "summary": "There will be clear sky until morning, then partly cloudy",
            "temp": {
                "day": 21.88,
                "min": 21.76,
                "max": 31.93,
                "night": 31.84,
                "eve": 31.23,
                "morn": 22.3
            },
            "feels_like": {
                "day": 9.28,
                "night": 23.29,
                "eve": 21,
                "morn": 14.32
            },
            "pressure": 1022,
            "humidity": 73,
            "dew_point": 15.39,
            "wind_speed": 14.52,
            "wind_deg": 221,
            "wind_gust": 31.36,
            "weather": [
                {
                    "id": 803,
                    "main": "Clouds",
                    "description": "broken clouds",
                    "icon": "04d"
                }
            ],
            "clouds": 75,
            "pop": 0,
            "uvi": 0.71
        },
        {
            "dt": 1703091600,
            "sunrise": 1703078724,
            "sunset": 1703110604,
            "moonrise": 1703096820,
            "moonset": 1703053080,
            "moon_phase": 0.28,
            "summary": "Expect a day of partly cloudy with clear spells",
            "temp": {
                "day": 35.31,
                "min": 30,
                "max": 37.31,
                "night": 31.53,
                "eve": 32.07,
                "morn": 30.22
            },
            "feels_like": {
                "day": 35.31,
                "night": 25.66,
                "eve": 25.39,
                "morn": 24.57
            },
            "pressure": 1025,
            "humidity": 51,
            "dew_point": 19.18,
            "wind_speed": 9.6,
            "wind_deg": 215,
            "wind_gust": 23.11,
            "weather": [
                {
                    "id": 802,
                    "main": "Clouds",
                    "description": "scattered clouds",
                    "icon": "03d"
                }
            ],
            "clouds": 34,
            "pop": 0,
            "uvi": 1
        },

Here is my chatgpt text:

message = "Can you put together a two sentence forecast with the most relevant information from the following Open Weather API JSON response for tomorrow's weather? The units are imperial. Please keep the response concise and only include information if it is relevant. Any numerical values should be rounded to the nearest whole number.\\n\\nBefore generating a response, take a moment to internally (silently) think about the steps you would take to determine what information is relevant to include in the forecast. Ignore the provided 'summary' if one is included as I want you to generate your own.\\n\\nMake sure you find the correct value for dt where the UTC is tomorrow.\\n~~~\\n __WEATHER_JSON__ \\n~~~"
stringJson = stringify(stringify($context.response.data.daily[0]))
stringJson = substring(stringJson, 1, size(stringJson)-1)
replace(message, "__WEATHER_JSON__", stringJson)

Thanks for your insights