|
import os |
|
from datetime import datetime, timedelta |
|
import logging |
|
|
|
import gradio as gr |
|
from whoop import WhoopClient |
|
|
|
|
|
logging.basicConfig(level=logging.INFO) |
|
logger = logging.getLogger(__name__) |
|
|
|
|
|
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." |
|
|
|
|
|
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 |
|
|
|
|
|
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) |
|
|
|
|
|
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) |
|
|
|
|
|
if __name__ == "__main__": |
|
demo.launch(mcp_server=True) |