Connecting Your Strava API Data To Get Coaching Recommendations

avatar

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.

  1. Grab our Strava Token data from the DB and make sure it is valid
  2. Connect to the Strava API and gather the relevant athlete activities from the previous week
  3. Set up the athlete data in a table format ready to be posted, but also to be used to query OpenAI
  4. 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
  5. 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



0
0
0.000
9 comments
avatar

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.

0
0
0.000
avatar

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

0
0
0.000
avatar

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.

0
0
0.000
avatar

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

0
0
0.000
avatar

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.

0
0
0.000
avatar

Congratulations @strava2hive! You have completed the following achievement on the Hive blockchain And have been rewarded with New badge(s)

You received more than 8000 upvotes.
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

0
0
0.000
avatar

Tasty. Even though, I'd love see suggestions based on the weekly training and HR :)

0
0
0.000