-
-
ChordStorm logo
-
The home page for ChordStorm where you can connect your Spotify and enter your zip code
-
Connect your Spotify account with OAuth2
-
Once connected, input your zip code (or any zip code you want!)
-
You're shown the weather, an explanation of the assistant's song recommendations, and fresh song recs based on your taste and the weather.
-
The About Us page showing our te
Disclaimer: Rename to "ChordStorm"
We found out after the hackathon that there was already a project called TuneCast and wanted to respect their claim on the original name. Although the two apps are similar, our team had no idea the other TuneCast existed until after we had already created it.
Inspiration
Imagine chilling on a chill, drizzly day, and your phone starts playing a beach party track. Doesn't quite fit, right? That's what got us going. We thought, "Hey, shouldn't our tunes match our mood and the skies?" And boom, ChordStorm was born—our cool little app that matches songs from Spotify with the kind of day you're having.
What it does
ChordStorm listens to the skies and your Spotify history to spin up playlists that feel just right. Whether it’s gloomy or sunny out there, our app makes sure your music is on the same page as the weather. It’s all about giving you the perfect backdrop for wherever your day takes you. 😎
How we built it
Building ChordStorm involved several steps and technologies:
- Backend: We used Python and Flask to handle the backend. This part of the app was responsible for processing data and communicating with various APIs.
- Frontend: Our design process started with creating mockups in Figma. We then converted these designs into functional web elements using HTML, CSS, and JavaScript.
- Integration: The key feature of ChordStorm came to life when we integrated user data with real-time weather information. We used a GPT-powered assistant to analyze this data and generate music playlists that suit the current weather conditions.
Challenges we ran into
One of the biggest hurdles was integrating our backend and frontend systems. They are fundamentally different in how they operate, and ensuring they communicated effectively proved to be quite challenging. Additionally, we encountered issues with securing our API keys, a crucial aspect of our project's security. However, we've successfully resolved these issues and have strengthened our app's overall security.
Accomplishments that we're proud of
We're really proud of how ChordStorm turned out. It's not just a working app; it's user-friendly and looks great. We've managed to create a smooth and easy experience from the moment you log in to when you start enjoying your music. And the fact that it can accurately suggest a relaxing playlist for a lazy, rainy day is something we're especially happy about.
What we learned
We learned a ton about API integration and the quirks of different browsers. We got a crash course in user experience design, ensuring that ChordStorm isn't just smart, but also a delight to use. And, of course, we picked up some best practices in code security along the way.
What's next for ChordStorm
The 5 of us had a blast making ChordStorm and want to see how far we can take it. The future of song recs will be even more nuanced. where environment and mood might be directly taken into account. Honestly, we see a future where our app not only understands the weather but also learns from your listening habits to get even smarter with its suggestions. We're thinking about social features too, where you can share your weather-inspired vibes with friends. With ChordStorm , the sky's the limit, and we're just getting started.
Highlight: Our recommendation generation code 💻
@app.route('/get_recommendations')
def get_recommendations():
# Get Zip Code from URL
zip = request.args.get('zip')
# if user goes to /display without a zip code, redirect to the index page
if zip == None:
return redirect(url_for('index'))
# if no zip code is entered, return to the index page
# type(zip) is <str>, so len(zip) can check this
if len(zip) == 0:
return redirect(url_for('index'))
# check if the zip code is a number
# 501 is the lowest zip code in the US, for an IRS office in Holtsville, NY.
# 99950 is the highest, belonging to Ketchikan, AK.
if not zip.isnumeric() or int(zip) > 99950 or int(zip) < 501:
return redirect(url_for('index'))
place_data = get_place_data(zip)
lat = place_data['latitude']
lon = place_data['longitude']
print(lat, lon)
weather_data = {}
sky = ""
icon = ""
try:
weather_data = get_weather(lat, lon)
# Icon Codes for the weather icons from fonts.google.com/icons
icon_codes = {
0: 'clear_day' if weather_data['current']['is_day'] else 'clear_night',
1: 'clear_day' if weather_data['current']['is_day'] else 'clear_night',
2: 'partly_cloudy_day' if weather_data['current']['is_day'] else 'partly_cloudy_night',
3: 'partly_cloudy_day' if weather_data['current']['is_day'] else 'partly_cloudy_night',
45: 'foggy',
48: 'foggy',
51: 'rainy',
53: 'rainy',
55: 'rainy',
56: 'rainy',
57: 'rainy',
61: 'rainy',
63: 'rainy',
65: 'rainy',
66: 'rainy',
67: 'rainy',
71: 'weather_snowy',
73: 'weather_snowy',
75: 'weather_snowy',
77: 'weather_snowy',
80: 'rainy',
81: 'rainy',
82: 'rainy',
85: 'weather_snowy',
86: 'weather_snowy',
95: 'thunderstorm',
96: 'thunderstorm',
99: 'thunderstorm',
}
# Sky Codes for the weather descriptions
sky_codes = {
0: 'Clear',
1: 'Mainly Clear',
2: 'Partly Cloudy',
3: 'Overcast',
45: 'Fog',
48: 'Freezing Fog',
51: 'Light Drizzle',
53: 'Drizzle',
55: 'Heavy Drizzle',
56: 'Light Freezing Drizzle',
57: 'Freezing Drizzle',
61: 'Light Rain',
63: 'Rain',
65: 'Heavy Rain',
66: 'Light Freezing Rain',
67: 'Freezing Rain',
71: 'Light Snow',
73: 'Snow',
75: 'Heavy Snow',
77: 'Snow Grains',
80: 'Light Showers',
81: 'Showers',
82: 'Heavy Showers',
85: 'Light Snow Showers',
86: 'Snow Showers',
95: 'Thunderstorm',
96: 'Thunderstorm with Light Hail',
99: 'Thunderstorm with Hail',
}
sky = sky_codes[weather_data['current']['weather_code']]
icon = icon_codes[weather_data['current']['weather_code']]
except TypeError:
redirect(url_for('index'))
user_top_tracks = topSongs
weather = sky
thread = client.beta.threads.create()
now = datetime.now()
current_time = now.strftime("%H:%M:%S")
message = client.beta.threads.messages.create(
thread_id=thread.id,
role="user",
content="The time is " + current_time + " and the weather is " + weather + ". The user's top 50 latest songs are, in format Songname | Artist1, Artist2,...: " + topSongs
)
run = client.beta.threads.runs.create(
thread_id=thread.id,
assistant_id="asst_pwk8lo9P7abyLiOpdWb1dpAw"
)
run = client.beta.threads.runs.retrieve(
thread_id = thread.id,
run_id = run.id
)
# The program will wait 10 seconds, as it takes time for the assistant to process the input and generate the output
time.sleep(10)
messages = client.beta.threads.messages.list(
thread_id = thread.id
)
parsed_messages = []
for message in reversed(messages.data):
print(message.role + ": " + message.content[0].text.value)
parsed_messages.append(message.content[0].text.value)
assistant_output = parsed_messages[len(parsed_messages) - 1]
paragraph, song_links = process_assistant_output(assistant_output)
return render_template('main.html', weather_data = weather_data, place_data = place_data, sky = sky, icon = icon, paragraph=paragraph, song_links=song_links)
Our slides (on Canva)
Built With
- css
- figma
- flask
- gpt4
- html
- javascript
- oauth2
- openai
- openmeteo
- pgeocode
- spotipy

Log in or sign up for Devpost to join the conversation.