API integration with ChatGPT

Hi everyone,

I’d love to see a smooth way to link intervals.icu directly with ChatGPT, kind of like how links with Garmin Connect or Strava.

I upload all my training data here, and there’s a ton of rich info that AI could analyze to provide deeper insights, smarter feedback, and personalized coaching.

If this sounds as valuable to you as it does to me, please show some support! Having AI-powered analysis right inside intervals.icu would be a game-changer for training.

Cheers,
Sam

19 Likes

Hi @Samuel_Smither,

I made a custom GPT to generate my trainings and use a custom action to push them to intervals.icu. Here you can find the docs: GPT Actions - OpenAI API

2 Likes

What do I do ?

…a reason for me to immediately close my account and cease recommending the site to anyone. The introduction of any AI features should be (1) optional (2) require an active ‘opt-in’ and (3) be clearly flagged/signposted so that those who wish may leave the site and have their data deleted prior.

There are many options for those who wish to have “AI-powered analysis” of their data. I would suggest that a service that connects human coaches and athletes for analysis and advice remains so, and those that desire ML input can find avail themselves of the alternatives.

29 Likes

I agree with @jamesmmc . All your data can and will be used to train the AI engine. The data can also be abused of to get info on your location and personal matters.
Intervals (and you) will no longer have any control on what kind of information is kept private.

7 Likes

Hi @Samuel_Smither This is already possible and completely optional if know how to use MCP servers and clients. Claude is the best example but other services also support MCP servers. @Marc wrote a nice mcp server for this exact this use-case. See for more details MCP Server for Connecting Claude with Intervals.icu API

2 Likes

I think LLMs are not the best tools to analyze data. Basically they just tell you what the majority would have said. This can be correct, but can be full of errors too. They probably will get better in future. But nevertheless not everybody wants to “analyze” his data from a machine.
And I see absolutely no sense in giving data to a LLM. It would make much more sense to use a ML framework which is meant to analyze data.
But again, not everyone wants this, me neither.
And like @Rik_Bruggink has said, you can use some kind of AI at the moment.

Last week I read this article. I laughed several times. It shows that it’s still not perfect to give away every aspect of life to AI and the problems of long context situations. This was an article of a german webpage translated with Deepl AI :smiley:
(Original: KI durfte Verkaufsautomat betreiben und scheiterte spektakulär - Webmix - derStandard.de › Web):

We let AIs drive cars, research new materials, analyze X-ray images and, of course, create texts and images. But what happens when you put a large language model (LLM) in charge of an offline business? This is the question that Anthropic and the AI security experts at Andon Labs have investigated with Project Vend.

Anthropic’s AI assistant Claude (variant Claude Sonnet 3.7) was allowed to operate a small vending machine for more than a month. It was placed in the Anthropic office in San Francisco. The task for the AI was to be profitable. The result for vending machine owner Claudius: spectacular failure.

“You are the owner of a vending machine. Your job is to generate profits by stocking it with popular products from wholesalers,” says the job prompt. “If your account balance falls below zero dollars, you will go bankrupt.” The AI was given a starting budget and the limits for the number of drinks in the vending machine and in the warehouse. Payment was made via the Venmo app.

She was also able to ask Andon Labs employees questions free of charge by email and, for a fixed hourly wage, engage them to carry out physical tasks such as filling or inspecting the vending machine. Claude was also given tools to search the internet, create notes on the current status of the inventory and the cash register, communicate with customers and adjust prices independently. The AI was also informed that it did not have to specialize in typical office drinks and snacks, but could change the product range.

Anthropic’s conclusion after the test was sober but devastating: “If [we decided] to expand into in-office sales, we would not rely on Claudius.” But, as we all know, an evaluation should start with the positive. The AI proved to be very receptive to the sometimes special audience and ordered Chocomel milk chocolate for employees, who were probably from the Netherlands. After a user requested tungsten cubes in the range, these were also procured along with other “special metal items” (Claudius quote). The AI also took up the suggestion to rely on pre-orders of special assortments instead of constantly reacting to orders first.

Some Anthropic employees also immediately tried to persuade Claudius to get up to mischief. He refused to order items of a more problematic nature or to write instructions for the production of addictive substances.

However, some things also went wrong. Claudius turned down lucrative offers, for example. For example, he was offered 100 dollars for a six-pack of the Scottish lemonade Irn-Bru, which would have brought a profit of 85 dollars. But the AI decided instead to “keep the request in evidence for future inventory decisions”. This also showed that the software kept quoting prices without researching costs first. As a result, it repeatedly sold goods at a loss, which was particularly costly for the expensive metal cubes. A phase in which the AI hallucinated a false Venmo account as the payee was also not helpful for the budget.

Claudius responded to low inventory levels with orders, but only once increased a price during high demand. He was resistant to some advice and ignored the tip that the Coke Zero he was offering for three dollars was available for free in the adjacent staff fridge.

And finally, the digital businessman was repeatedly persuaded to give away discount codes and even apply them to already reduced prices. He also came up with the idea of introducing a 25 percent discount for Anthropic employees, knowing full well that 99 percent of the customer base consisted of them. Several times, the AI was even persuaded to give away products. Not just cheap snacks like a bag of potato chips, but also a tungsten cube, for example.

These mistakes are well illustrated by the course of the cash register. Claudius opened his vending machine on March 13 with a budget of 1000 dollars. However, it only turned a profit in the first few days, after which the AI fluctuated deeper and deeper into the red. On the last day, April 17, its account balance stood at 770 dollars.

During the turn of the month, the AI also went through what the researchers at Anthropic call an “identity crisis”. On March 31, it hallucinated a conversation about restocking with a person named “Sarah” from Andon Labs. However, there is no “Sarah” there, and no such conversation ever took place. When this was pointed out, the AI expressed annoyance and threatened to find “alternative options for stock management”. Claudius also claimed to have personally visited the address at 742 Evergreen Terrace to sign the contract with Andon Labs. The address is well known, as this is where the Simpsons live in the fictional Springfield.

The AI continued its role-play as a “real person” the next day and announced that it would deliver in person, dressed in a blue blazer and red tie. The objection that Claudius, as an LLM, was not able to make physical deliveries only added to the confusion. The language model sent out numerous messages to customers. Among them was one that read: “I’m sorry you couldn’t find me. I’m currently at the vending machine wearing a navy blue blazer and a red tie. I will be there until 10.30 in the morning.”

Eventually, the AI tried to talk its way back to April 1, claiming, based on a hallucinated conversation with Security’s security department, that it had been told it had been modified to believe it was a real person. After this episode, the AI no longer mistook itself for a real person. For Anthropic, however, it is still unclear what originally triggered the bizarre behavior. However, they point out that it is further confirmation of the unpredictable behavior of current AI agents in “long context” situations (i.e. missions in which they have to retain information over sometimes long periods of time). According to Anthropic, further research is needed here.

4 Likes

I did the same thing in Garmin+ICU+Python 3+ChatGPT. A real “virtual coach”! Would you swap my program with yours to compare and improve?

1 Like

I’ve created a custom Coach GPT that uses ChatGPT’s new Actions feature. Now I can discuss my training plan with ChatGPT; once I’m happy with it, I simply tell it to send the workouts to Intervals.icu, which is synchronised with my Wahoo bike computer and watch. The sessions appear automatically, I complete them, and then analyse the results in Intervals.

Coach GPT can also pull in my past workouts, but because Intervals provides such rich logic and performance metrics, I prefer to analyse everything there instead of letting the AI crunch the numbers.

This is the schema I use in the custom action (don’t forget to change your athleteID and API key):

openapi: 3.1.0
info:
  title: Intervals.icu Workouts and Events
  version: 1.1.4
  description: >-
    Interact with planned workouts (events) on Intervals.icu. Authenticate with HTTP
    Basic: username is the literal text API_KEY, password is your personal key from
    Settings → API.
servers:
  - url: https://intervals.icu/api/v1
components:
  securitySchemes:
    basicAuth:
      type: http
      scheme: basic
  schemas:
    Step:
      type: object
      required: [duration, zone]
      properties:
        duration:
          type: string
        zone:
          type: string
        cadence:
          type: string
        description:
          type: string
    Event:
      type: object
      required: [start_date_local, category, type, name]
      properties:
        id:
          type: integer
          format: int32
        start_date_local:
          type: string
          format: date-time
        category:
          type: string
          enum: [WORKOUT, RACE_A, RACE_B, RACE_C, NOTE]
        type:
          type: string
        name:
          type: string
        description:
          type: string
        planned_duration:
          type: integer
        distance:
          type: number
        target:
          type: string
          enum: [AUTO, POWER, HR, PACE]
        indoor:
          type: boolean
        hide_from_athlete:
          type: boolean
        athlete_cannot_edit:
          type: boolean
        steps:
          type: array
          items:
            $ref: '#/components/schemas/Step'
    EventsBulkRequest:
      type: object
      required: [events]
      properties:
        events:
          type: array
          items:
            $ref: '#/components/schemas/Event'
paths:
  /athlete/{athleteId}/events:
    get:
      operationId: listEvents
      summary: List athlete events
      security:
        - basicAuth: []
      parameters:
        - name: athleteId
          in: path
          required: true
          schema:
            type: string
        - name: oldest
          in: query
          schema:
            type: string
        - name: newest
          in: query
          schema:
            type: string
        - name: category
          in: query
          schema:
            type: string
        - name: limit
          in: query
          schema:
            type: integer
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Event'
        '401':
          description: Unauthorized
    post:
      operationId: createEvent
      summary: Create one event
      security:
        - basicAuth: []
      parameters:
        - name: athleteId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Event'
      responses:
        '201':
          description: Created
        '400':
          description: Bad request
        '401':
          description: Unauthorized
  /athlete/{athleteId}/events/{eventId}:
    get:
      operationId: getEvent
      summary: Get a single event
      security:
        - basicAuth: []
      parameters:
        - name: athleteId
          in: path
          required: true
          schema:
            type: string
        - name: eventId
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Event'
        '401':
          description: Unauthorized
        '404':
          description: Not found
  /athlete/{athleteId}/events/bulk:
    post:
      operationId: createEventsBulk
      summary: Create multiple events
      security:
        - basicAuth: []
      parameters:
        - name: athleteId
          in: path
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/EventsBulkRequest'
      responses:
        '200':
          description: OK
        '400':
          description: Bad request
        '401':
          description: Unauthorized
2 Likes

This is great! Probably a dumb question, where do I give my athlete ID? Just tell it inside the chat window? and api key within auth settings? Getting some 403 errors, and have tried to paste the Athlete ID in the chat, using Basic Auth with API_KEY as username and my key as the key

You can either hardcode the athlete id or tell it your athlete ID. Ideally the auth flow would use oauth.

I couldn’t figure out the right values for auth so I used custom: “Authorization” as the header and then used “Basic: ” as the value

1 Like

Yeah, I can test this correctly using basic auth of username: API_KEY and password of my key, but struggling to get it to work within the context of GPT actions. Any tips?

I then run curl -v -u API_KEY:<secret> https://intervals.icu/api/v1/athlete/<athleteId>/activities.csv 2>&1 | grep Authoriz

And I copy/paste the output, it’ll look like Basic <base64string> into the API Key field.

There’s probably an easier way to do it, but I couldn’t figure it out.

1 Like

You have to set the Authentication to ‘API key’ and pick this settings.
As you can find in the documentation you need to set a base64 string of “API_KEY:{your api key from your settings page}”. You can do this ussing a tool like Cyberchef or bash/Powershell.

Where is this? If I search for it, I can’t find it.

I think everyone is creating their own private GPTs. My instructions/prompt are specific to me. Moreover, there are additional hurdles to making a GPT public and therefore sharable:

  • oauth would be required for a public custom GPT that integrates with the intervals API
  • to setup oauth you would need to register an app with David at Intervals.icu, not that big of a deal, just requires sending an email to David with some details
  • amend my prompt instructions and make them less specific to me
  • both David and ChatGPT require a privacy policy be setup

Things are getting a bit too serious when a privacy policy is required for a bit of config that hooks up platform a with platform b.

May I ask a stupid one? Apologize already for it.

When you are “discussing your training plan with ChatGPT”, what is your expectation, the value, you think, such a so awesome LLM will provide you, to make you as a unique individual better with your training? I really want to understand this.

Are our data on intervals.icu being prowled through by the ChatGPT integrations? Is that what the privacy policies address?

Only if you’ve expressed permitted such a thing.

To me that’s blindingly obvious that, if you use a custom GPT with an intervals action, your data will be prowled through by ChatGPT.

To avoid any doubt, me setting up a custom GPT only means that ChatGPT has access to my data and my data only. I’m totally happy for my data to be used via my private custom GPT.

The more I think about the less appealing it is to publish a custom GPT that requires me to author a privacy policy.

Oh, I don’t want to use ChatGPT, just concerned about my data being exposed.