Connecting Your Strava API Data To Get Coaching Recommendations
I thought it could be cool to add recommendations to athletes based on their prior training weeks. I am definitely not trying to have AI replace writers, but it could be a good use case to use the service as tool, which setting up these types of Hive posts.
NOTE: This is a bit of a mind dump from the research I have been doing to put this information together, so hopefully it all makes sense
In this article we are going to do a little bit of work to use the OpenAI API as part of the data we are extracting from Strava to then provide a summary of the users training over the past week, and then give the athlete suggestions on their next training week to help them improve their running.
So far, we have done a lot of work using the Strava API to get athletes runs, so if you need to study up on how to do that, we will not be covering this information in this article, so you might want to head to the following link before you start:
https://stemgeeks.net/hive-163521/@strava2hive/getting-activity-data-from-the-strava-api
In this article we are going to do the following things.
- Grab our Strava Token data from the DB and make sure it is valid
- Connect to the Strava API and gather the relevant athlete activities from the previous week
- Set up the athlete data in a table format ready to be posted, but also to be used to query OpenAI
- Send requests to OpenAI to ask for a summary of the activity data, as well as asking for a new training week, based on those activities
- Collect all the information from Strava and OpenAI and create a Hive post for the athlete
1. Grab our Strava Token data from the DB
There are two important functions that need to be put together. The first is accessing the DynamoDB where our data is stored, and if the access token has expired, we then need to update the token. This was all covered in a previous article, so we won't explain the functions below, but if you want some more details, head to the original article posted at this link: https://hive.blog/hive-163521/@strava2hive/updating-your-strava-access-tokens-with-the-strava-api
# Access the DynamoDB using our access keys
def dynamo_access():
client = boto3.client('dynamodb', region_name='ap-southeast-2', aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID'), aws_secret_access_key=os.getenv('AWS_SECRET_ACCESS_KEY'),)
dynamodb = boto3.resource('dynamodb', region_name='ap-southeast-2', aws_access_key_id=os.getenv('AWS_ACCESS_KEY_ID'), aws_secret_access_key=os.getenv('AWS_SECRET_ACCESS_KEY'),)
ddb_exceptions = client.exceptions
return dynamodb
# Requesting a new token if our has expired
def refresh_access_token(athlete):
# Update the strava access token every six hours
athlete_vals = athlete[0]
code_val = athlete_vals['strava_one_time']
try:
response = requests.post("https://www.strava.com/api/v3/oauth/token", params={'client_id': os.getenv('STRAVA_CLIENT_ID'), 'client_secret': os.getenv('STRAVA_SECRET'), 'code': code_val, 'grant_type': 'refresh_token', 'refresh_token': athlete_vals['strava_refresh_token']})
access_info = dict()
activity_data = response.json()
access_info['access_token'] = activity_data['access_token']
access_info['expires_at'] = activity_data['expires_at']
access_info['refresh_token'] = activity_data['refresh_token']
return access_info['access_token'], access_info['expires_at']
except:
return False
We can then use the following code to use these functions and get the relevant information from our DynamoDB:
dynamoTable = 'ai_test_athletes' dynamodb = dynamo_access() table = dynamodb.Table(dynamoTable) athletedb_response = table.query(KeyConditionExpression=Key('athleteId').eq('1778XXX')) strava_expire_date = athletedb_response['Items'][0]['strava_token_expires']
expire_time = int(strava_expire_date)
current_time = time.time()
expired_value = expire_time - int(current_time)
if expired_value > 0:
something = 4
else:
new_access_token, new_expire_date = refresh_access_token(athletedb_response['Items'])
table = dynamodb.Table(dynamoTable)
athletedb_response = table.query(KeyConditionExpression=Key('athleteId').eq('1778XXX'))
dynamodb = dynamo_access()
athlete_table = dynamodb.Table(dynamoTable)
response = athlete_table.update_item(
Key={ 'athleteId': '1778XXX'},
UpdateExpression='SET strava_access_token = :newStravaToken',
ExpressionAttributeValues={':newStravaToken': str(new_access_token)},
ReturnValues="UPDATED_NEW")
response = athlete_table.update_item(Key={'athleteId': '1778XXX'}, UpdateExpression='SET strava_token_expires = :newStravaExpire', ExpressionAttributeValues={':newStravaExpire': new_expire_date}, ReturnValues="UPDATED_NEW")
2. Connect to the Strava API and gather the relevant athlete activities
Once again, this has been covered in a previous article, so we won't go into detail here. You can get all the details at the following link: https://hive.blog/hive-163521/@strava2hive/getting-activity-data-from-the-strava-api
# Connect to the Strava API and gather activity details
def access_strava_activities(athlete_access_token):
# Pass the athlete access token to strava to get activities
#strava_access_token = athletedb_response['Items'][0]['strava_access_token']
bearer_header = "Bearer " + str(athlete_access_token)
t = datetime.now() - timedelta(days=7)
parameters = {"after": int(t.strftime("%s"))}
headers = {'Content-Type': 'application/json', 'Authorization': bearer_header}
response = requests.get("https://www.strava.com/api/v3/athlete/activities?per_page=30", headers=headers, params=parameters)
#response = requests.get("https://www.strava.com/api/v3/athlete/activities?per_page=50", headers=headers)
activity_data = response.json()
return activity_data
# With the data provided by Strava, go through it and only provide the Run data for now
def process_activities(data_from_strava):
# Take the strava data and process is how you want
activities = []
time.sleep(3)
for i in data_from_strava:
if i["type"] != "Run":
continue
else:
activity_vals = []
activity_vals.append(i["type"])
date_val = i["start_date_local"]
date = datetime.strptime(date_val, "%Y-%m-%dT%H:%M:%SZ")
new_date_val = date.strftime("%Y-%m-%d")
activity_vals.append(new_date_val)
activity_vals.append(i["name"])
distance = str(round(i["distance"] * .001, 2))
activity_vals.append(distance)
duration = str(round(i["moving_time"] / 60))
activity_vals.append(duration)
activity_vals.append("https://www.strava.com/activities/" + str(i["id"]))
activity_vals.append(str(i["id"]))
#print(activity_vals)
activities.append(activity_vals)
return activities
3. Set up the athlete data in a table format
I have not set up a function for this data, but as you can see we are taking the returned values we processed from Strava, called "pa" and then looping through the data to create a html table:
top_table = f'''
<h2>Your Training Week</h2>
<table>
<tr>
<th>Date</th>
<th>Run Session</th>
<th>Distance(km)</th>
<th>Duration(min)</th>
</tr>'''
for i in range(len(pa)):
#print(' <tr>')
#print(' <td>{pa[i][1], pa[i][2], pa[i][3], pa[i][4], pa[i][5]}</td>')
#print(' </tr>')
#record_post(pa[i][0],pa[i][1],pa[i][2],pa[i][3],pa[i][4],pa[i][5])
#<td>{pa[i][1], pa[i][2], pa[i][3], pa[i][4], pa[i][5]}</td>
table_body = f'''
<tr>
<td>{pa[i][1]}</td>
<td>{pa[i][2]}</td>
<td>{pa[i][3]}</td>
<td>{pa[i][4]}</td>
</tr>'''
top_table = top_table + table_body
weeks_run_table = top_table + '\n</table>'
This should hopefully look like the following sample of data below.
Your Training Week
Date | Run Session | Distance(km) | Duration(min) |
---|---|---|---|
2023-10-15 | Afternoon Run | 8.04 | 40 |
2023-10-16 | Afternoon Run | 3.52 | 23 |
2023-10-17 | Morning Run | 10.46 | 53 |
4. Send requests to OpenAI
The table we have generated can also be sent to OpenAI to allow us to firstly generate a summary for our athlete, and secondly, provide the athlete with a sample training plan to help them improve their running.
We are not going to go into how we signed up to OpenAI and got a API Key, but as you can see below, we have a basic function that does a bulk of the work. We use the openai module in Python that will help us connect and communicate with the API.
NOTE: OpenAI is a paid service that I have been using to allow me to work with the API. I think there are ways to get free access on some situations but with all my research and testing, I have spent about $0.30 USD. So the costs are small
The return value, is only the response text provided by the API and not the who amount of data.
import openai
prompt_return_val = ''
api_key = str(os.getenv('OPENAI_KEY'))
# Provide prompts to OpenAI and return a response
def ask_openai(api_key, prompt, max_tokens):
openai.api_key=api_key
endpoint='https://api.openai.com/v1/chat/completions'
response = openai.Completion.create(
model="text-davinci-003",
prompt=prompt,
max_tokens=200
)
return response.choices[0].text
We have two prompts that we are going to send to OpenAI. Note that we have added the table of data at the end of the prompt as OpenAI is able to read this data:
prompt = """
Please provide a summary of my training week based on the data in the following table. Include information on the total distance and any notable patterns or achievements:
""" + weeks_run_table
prompt2 = """
Please act as a exprienced run coach and using the training data in the following table, please provide a new training week with five runs to help the run improve their running times. This training plan can be simply written as a text list:
""" + weeks_run_table
5. Collect all the information from Strava and OpenAI and create a Hive post
Once we have all our information we can now add it all together to put together a Hive post to present this data to our athlete. We use the "beem" module that works directly with Hive and allows us to communicate with the Hive API.
import random
import string
from beem.imageuploader import ImageUploader
from beem import Hive
from beem.account import Account
from beem.nodelist import NodeList
def post_to_hive(post_athlete, post_title, post_body):
nodelist = NodeList()
nodelist.update_nodes()
nodes = nodelist.get_hive_nodes()
wif = os.getenv('POSTING_KEY')
hive = Hive(nodes=nodes, keys=[wif])
author = "strava2hive"
title = post_title
community = "hive-107275"
body = post_body
parse_body = True
self_vote = False
tags = ['exhaust', 'test', 'beta', 'runningproject', 'sportstalk']
beneficiaries = [{'account': 'run.vince.run', 'weight': 1000},]
permlink = "testingopenai-" + .join(random.choices(string.digits, k=10))
hive.post(title, body, author=author, tags=tags, community=community, parse_body=parse_body, self_vote=self_vote, beneficiaries=beneficiaries, permlink=permlink)
If you would like to see what it looks like as a finished product, we have set up the following example:
https://hive.blog/hive-107275/@strava2hive/testingopenai-6071239683
The Complete Code For This Program Can Be Found Here: https://raw.githubusercontent.com/vincesesto/coach_recommendations/main/run_coach.py
Posted with STEMGeeks
I know a lot of people are sceptical about these 'AI' tools, but they can give insight. There are loads of articles out there on running, but the advice may not be consistent. How will it decide what is useful?
I have played with the new AI features in peakd. That can give you a summary of a long post or do translations.
I think the technology is still a little raw but I think it will become a tool that we will continue to use as the years go on. I don't think it will be something I will be getting too much use from just yet but feel like I still need to get my head around it. Thanks for reading @steevc
There's a lot of hype about the technology, but we need to be cautious. We're already seeing people generating posts and comments on Hive with it. It will improve and be harder to detect. Imagine it were all just bots talking to each other!
We live in interesting times.
Well, I would not blame people for adopting the usage of AI but it is really affecting us
We will become less creative...
I don't just like to use AI for my articles
It does not make sense
Yes I think you are correct, especially with writing. I do think there will be good applications for Ai in the future though, possibly with research.
Congratulations @strava2hive! You have completed the following achievement on the Hive blockchain And have been rewarded with New badge(s)
Your next target is to reach 9000 upvotes.
You can view your badges on your board and compare yourself to others in the Ranking
If you no longer want to receive notifications, reply to this comment with the word
STOP
Tasty. Even though, I'd love see suggestions based on the weekly training and HR :)
The recommendation seem to be pretty conservative
!PGM