File size: 5,139 Bytes
976c655
 
 
 
 
 
 
 
 
 
 
 
 
 
d9c9ba1
149df1f
 
 
 
976c655
 
 
d9c9ba1
 
 
 
976c655
 
 
 
 
 
 
 
149df1f
 
 
976c655
 
 
 
 
 
 
32fbb4d
976c655
 
 
 
149df1f
 
 
976c655
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d0c827a
149df1f
d0c827a
 
 
 
 
 
 
 
 
976c655
d0c827a
 
149df1f
d0c827a
 
 
 
 
 
 
 
 
 
 
 
 
dee50ec
 
 
 
 
976c655
 
 
 
149df1f
 
 
 
 
 
 
 
 
 
 
 
 
 
32fbb4d
149df1f
d0c827a
 
 
 
 
 
 
 
 
 
976c655
d9c9ba1
ddebb16
d0c827a
 
976c655
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import os
from datetime import datetime, timedelta
import logging

import gradio as gr
from whoop import WhoopClient

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Global Whoop client
whoop_client = None

def initialize_whoop_client_with_input(email, password):
    """
    Authenticates a user using the provided WHOOP email and password.
    Stores credentials in the environment variables and initializes the WhoopClient.
    """
    global whoop_client

    if not email or not password:
        return "❌ Please enter both email and password."

    os.environ["WHOOP_EMAIL"] = email
    os.environ["WHOOP_PASSWORD"] = password

    try:
        whoop_client = WhoopClient(username=email, password=password)
        return "βœ… Successfully authenticated with Whoop."
    except Exception as e:
        return f"❌ Authentication failed: {e}"

def get_latest_cycle_gr():
    """
    Retrieves the most recent WHOOP cycle (recovery data) for the authenticated user.
    """
    if not whoop_client:
        return "❌ Not authenticated."

    try:
        end_date = datetime.now().strftime("%Y-%m-%d")
        start_date = (datetime.now() - timedelta(days=1)).strftime("%Y-%m-%d")
        cycles = whoop_client.get_cycle_collection(start_date, end_date)
        return cycles
    except Exception as e:
        return f"❌ Error: {e}"

def get_average_strain_gr(days):
    """
    Calculates the average strain over a given number of past days.
    """
    if not whoop_client:
        return "❌ Not authenticated."

    try:
        end_date = datetime.now().strftime("%Y-%m-%d")
        start_date = (datetime.now() - timedelta(days=int(days))).strftime("%Y-%m-%d")
        cycles = whoop_client.get_cycle_collection(start_date, end_date)

        if not cycles:
            return "⚠️ No cycle data available."

        strains = [c['score']['strain'] for c in cycles if c.get('score') and c['score'].get('strain') is not None]
        if not strains:
            return "⚠️ No strain data available."

        avg = sum(strains) / len(strains)
        return f"πŸ“Š Average Strain over {days} days: {avg:.2f} (from {len(strains)} entries)"
    except Exception as e:
        return f"❌ Error: {e}"

def get_workouts_gr():
    """
    Fetches recent workouts for the authenticated user.
    """
    if not whoop_client:
        return "❌ Not authenticated."

    try:
        end_date = datetime.now().strftime("%Y-%m-%d")
        start_date = (datetime.now() - timedelta(days=10)).strftime("%Y-%m-%d")
        workouts = whoop_client.get_workout_collection(start_date, end_date)

        if not workouts:
            return "⚠️ No workout data available."

        summary = "\n\n".join([f"πŸ‹οΈ Workout {i+1}:\nType: {w.get('sport_id')}, Avg HR: {w.get('avg_heart_rate')}, Calories: {w.get('kilojoule')} KJ"
                               for i, w in enumerate(workouts)])
        return summary
    except Exception as e:
        return f"❌ Error fetching workouts: {e}"

def get_sleeps_gr():
    """
    Fetches recent sleep records for the authenticated user.
    """
    if not whoop_client:
        return "❌ Not authenticated."

    # try:
    end_date = datetime.now().strftime("%Y-%m-%d")
    start_date = (datetime.now() - timedelta(days=10)).strftime("%Y-%m-%d")
    sleeps = whoop_client.get_sleep_collection(start_date, end_date)
    return sleeps

# UI definition
with gr.Blocks(title="Whoop API Explorer") as demo:
    gr.Markdown("# 🧠 WHOOP API Dashboard")
    gr.Markdown("Easily authenticate and explore your WHOOP recovery and strain data.")

    with gr.Group():
        gr.Markdown("## πŸ” Authentication")
        with gr.Row():
            email_input = gr.Textbox(label="WHOOP Email", placeholder="[email protected]")
            password_input = gr.Textbox(label="WHOOP Password", type="password", placeholder="β€’β€’β€’β€’β€’β€’β€’β€’")
            auth_button = gr.Button("Authenticate")
        auth_output = gr.Label(label="Auth Status")

    with gr.Group():
        gr.Markdown("## πŸ” Latest Recovery Cycle")
        cycle_button = gr.Button("Fetch Latest Cycle")
        latest_recovery = gr.Label(label="Recovery Score")
        cycle_details = gr.Textbox(label="Full Cycle Data", visible=True, lines=6)

    with gr.Group():
        gr.Markdown("## πŸ‹οΈ Workout Summary")
        workout_button = gr.Button("Fetch Recent Workouts")
        workout_output = gr.Textbox(label="Workout Summary", lines=10)

    with gr.Group():
        gr.Markdown("## 😴 Sleep Summary")
        sleep_button = gr.Button("Fetch Recent Sleeps")
        sleep_output = gr.Textbox(label="Sleep Summary", lines=10)

    # Bind actions
    auth_button.click(fn=initialize_whoop_client_with_input, inputs=[email_input, password_input], outputs=auth_output)
    cycle_button.click(fn=get_latest_cycle_gr, outputs=cycle_details)
    workout_button.click(fn=get_workouts_gr, outputs=workout_output)
    sleep_button.click(fn=get_sleeps_gr, outputs=sleep_output)

# Launch app
if __name__ == "__main__":
    demo.launch(mcp_server=True)