whoop-mcp-server / whoop_gradio_server.py
victoria-latynina's picture
Update whoop_gradio_server.py
32fbb4d verified
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)