Yeoram's Project Guide
Project: Workout Weight Calculator Category: Web App (Flask) Last updated: April 21
Note: This guide reflects the latest state of your project repo. It may not match the most up-to-date version if you've worked since.
Where You Are
Good progress on your project!
weights.pyholds all the logic:EXERCISES,VALID_UNITS/GOALS/EXERCISES,ROUTINE_MAP,calculate_weight, andget_workout_data.main.pywalks the user through 4 steps (unit → exercise → goal → 1RM), validates each one withprompt_for_choice/prompt_for_number, and prints a full routine with a top set, back-off sets, and accessories.flaskis already in yourpyproject.toml, souv add flaskis done.
Project Structure
Your project splits into two kinds of code:
- Business logic — you already handwrote this. Everything in
weights.py. - View / web code — agent-assisted is fine.
app.py(reads the form, callsget_workout_data, renders a template) and the HTML files intemplates/.
Example target layout:
workout-weight-calculator/
├── main.py ← keep the CLI working (optional — nice for demo)
├── weights.py ← already done — don't touch
├── app.py ← NEW: Flask routes — read form + call weights.get_workout_data
├── templates/
│ ├── base.html ← NEW: Tailwind CDN + mobile viewport + shared layout
│ └── index.html ← NEW: the form + the result card
├── pyproject.toml
└── README.md
Phase 1: Scaffold the Flask App
Agent-assisted is fine.
Objective
Get a Flask app running locally that shows a styled "Workout Weight Calculator" heading on http://127.0.0.1:5000.
Instructions
Hints
app.py:
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def index():
return render_template("index.html")
templates/base.html:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Workout Weight Calculator</title>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body class="bg-slate-50 text-slate-900">
<main class="max-w-md mx-auto px-4 py-6">
{% block content %}{% endblock %}
</main>
</body>
</html>
templates/index.html:
{% extends "base.html" %} {% block content %}
<h1 class="text-2xl font-bold mb-4">Workout Weight Calculator</h1>
<p class="text-slate-600">Plan your next session.</p>
{% endblock %}
Optional — get help from your agent:
I just scaffolded a Flask app with a base.html using the Tailwind Play CDN. Walk me through how {% extends %} and {% block content %} connect base.html and index.html. Don't change my code — just explain.
Phase 2: Build the Form
Mixed phase. The decisions about which fields exist (unit, exercise, goal, 1RM) are yours — they mirror the 4 steps in your CLI. The Tailwind styling is agent-assisted.
Objective
Put your 4 CLI questions on one mobile-friendly page as a single <form>. Submitting it reloads / with the answers in the URL.
Instructions
Hints
Reuse the numeric string keys ("1", "2", ...) that weights.py already uses — don't change weights.py, just send the same strings from the form.
<fieldset class="mb-5">
<legend class="font-semibold mb-2">Goal</legend>
<div class="grid grid-cols-3 gap-2">
{% for value, label in [("1", "Strength"), ("2", "Hypertrophy"), ("3",
"Endurance")] %}
<label class="block">
<input
type="radio"
name="goal"
value="{{ value }}"
class="peer sr-only"
required
/>
<span
class="block text-center py-3 rounded-xl border border-slate-300
peer-checked:bg-indigo-600 peer-checked:text-white peer-checked:border-indigo-600"
>
{{ label }}
</span>
</label>
{% endfor %}
</div>
</fieldset>
1RM input + submit button:
<label class="block mb-2 font-semibold" for="one_rm">Your 1RM</label>
<input
id="one_rm"
name="one_rm"
type="number"
step="any"
min="0"
required
class="block w-full px-4 py-3 rounded-xl border border-slate-300 text-lg mb-5"
placeholder="e.g. 225"
/>
<button
type="submit"
class="w-full py-4 rounded-xl bg-indigo-600 text-white font-semibold text-lg
hover:bg-indigo-700 active:bg-indigo-800"
>
Calculate
</button>
Optional — get help from your agent:
Here is my index.html form. Keep the name attributes and values exactly as they are. Help me polish the mobile styling — better spacing, bigger tap targets, a soft card background on the form. Don't change any form field names.
Phase 3: Show the Workout Card
Handwrite the route yourself.
Objective
When the form submits, read the 4 values from the URL, call weights.get_workout_data(...), and render the same routine your CLI prints — as styled cards on the page.
Instructions
Hints
app.py:
from flask import Flask, render_template, request
import weights
app = Flask(__name__)
@app.route("/")
def index():
unit = request.args.get("unit")
exercise = request.args.get("exercise")
goal = request.args.get("goal")
one_rm_raw = request.args.get("one_rm")
data = None
error = None
if unit and exercise and goal and one_rm_raw:
try:
one_rm = float(one_rm_raw)
if one_rm <= 0:
raise ValueError
data = weights.get_workout_data(unit, goal, exercise, one_rm)
except ValueError:
error = "Please enter a positive number for your 1RM."
return render_template("index.html", data=data, error=error)
index.html:
{% if error %}
<p class="mt-5 p-3 rounded-xl bg-red-100 text-red-800">{{ error }}</p>
{% endif %} {% if data %}
<section class="mt-6 p-5 rounded-2xl bg-white shadow">
<h2 class="text-xl font-bold">{{ data.exercise }}</h2>
<p class="text-slate-500 mb-4">Goal: {{ data.goal }}</p>
<h3 class="font-semibold mb-2">Main lift</h3>
<ul class="mb-4 space-y-1">
{% for lift in data.main_lifts %}
<li class="flex justify-between">
<span>{{ lift.type }}</span>
<span class="font-mono">
{{ lift.weight }}{{ data.unit }} × {{ lift.reps }} × {{ lift.sets }}
sets
</span>
</li>
{% endfor %}
</ul>
<h3 class="font-semibold mb-2">Accessories</h3>
<ul class="space-y-1">
{% for acc in data.accessories %}
<li class="flex justify-between">
<span>{{ acc.name }}</span>
<span class="font-mono">
{{ acc.weight }}{{ data.unit }} × {{ acc.reps }} × {{ acc.sets }} sets
</span>
</li>
{% endfor %}
</ul>
</section>
{% endif %}
Optional — get help from your agent:
My /dashboard-style result card is rendering. Keep my route logic and the {% for %} loops exactly as they are. Help me polish the Tailwind styling on the result card — nicer typography hierarchy, a subtle divider between main lift and accessories, colored pill for the goal name. Don't change app.py.
Checkpoint 2 Readiness
By Thursday April 23 at 3pm, you should have:
Helpful Resources
- Checkpoint 2 Instructions
- Flask Setup Guide
- Tailwind Play CDN docs — copy-paste setup, no build step
- Tailwind utility cheatsheet — handy when you don't remember a class name