Workout Tracker

v1.3.7

个人健身跟踪器 — 通过文字记录健身训练数据,自动解析动作、组数、次数和重量,实时写入本地 MySQL 数据库。支持制定专属训练计划、查询历史记录、追踪进步曲线,以及球类和有氧运动记录。

1· 151·1 current·1 all-time
byzenggang@query1988
Security Scan
VirusTotalVirusTotal
Benign
View report →
OpenClawOpenClaw
Benign
high confidence
Purpose & Capability
Name/description, required binaries (python3, mysql), required env vars (MYSQL_*), and included scripts (init_database.py, verify_setup.py) all align with a local MySQL-based fitness tracker. Required items are expected for the stated purpose.
Instruction Scope
SKILL.md instructs installing a Python MySQL connector, configuring local env vars/.env, creating a minimal-privilege DB user, running the init and verify scripts. The runtime instructions and scripts only read local config (.workout-tracker.env) and access the local MySQL socket; they do not call external endpoints or request unrelated system data.
Install Mechanism
No automated install download or remote-executable install spec is present (instruction-only); scripts are plain Python files included in the package. The only third-party dependency is mysql-connector-python installed via pip as instructed — proportionate to the task.
Credentials
Requested environment variables are limited to MYSQL_SOCKET, MYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE and match the service the skill uses. The scripts only reference those vars (and defaults) and do not ask for unrelated secrets or credentials.
Persistence & Privilege
Skill is not forced-always, does not request system-wide privileges, and does not modify other skills' configs. It can be invoked autonomously (platform default) — appropriate for a local helper that writes to a database, but consider user policy if you want to avoid autonomous DB writes.
Assessment
This skill appears internally consistent with a local MySQL workout tracker, but take these precautions before installing: 1) Review the included scripts (init_database.py, verify_setup.py) yourself — they are small and only use the declared MYSQL_* vars, but confirm no surprises. 2) Create and use a dedicated local MySQL user with minimal privileges (INSERT/SELECT/UPDATE/DELETE) and do NOT use production or admin DB credentials. 3) Keep the .workout-tracker.env file permission-restricted (chmod 600) and do not commit it to version control; verify how the scripts parse values (they read raw values and will include quotes if present). 4) Run the init/verify steps in an isolated/dev environment or container first to confirm behavior. 5) If you do not want the agent to write to your local DB without prompts, consider disabling or limiting autonomous invocation in your agent policy. 6) Because the package source is unknown, prefer to run it locally from a vetted copy or audit the repository before granting access to any sensitive systems.

Like a lobster shell, security has layers — review code before you run it.

Runtime requirements

🏋️ Clawdis
Binspython3, mysql
EnvMYSQL_USER, MYSQL_PASSWORD, MYSQL_DATABASE, MYSQL_SOCKET
Primary envMYSQL_PASSWORD
fitnessvk971qnknya4hsa3s79z6zhhrh983yh3mgymvk971qnknya4hsa3s79z6zhhrh983yh3mhealthvk971qnknya4hsa3s79z6zhhrh983yh3mlatestvk979sqwt27bjcjzhsfegn1mndh8444qgpersonal-trainervk971qnknya4hsa3s79z6zhhrh983yh3mstrengthvk971qnknya4hsa3s79z6zhhrh983yh3mworkoutvk971qnknya4hsa3s79z6zhhrh983yh3m
151downloads
1stars
17versions
Updated 2w ago
v1.3.7
MIT-0

Workout Tracker

记录健身数据,自动解析训练内容并写入数据库。

🚀 完整安装指南

1. 安装依赖

# 安装 Python MySQL 连接器
pip install mysql-connector-python

# 验证安装
python3 -c "import mysql.connector; print('✅ mysql-connector-python 已安装')"

2. 安全配置环境变量(推荐方法)

方法 A:使用 .env 文件(最安全)

# 创建 .env 配置文件
cat > .workout-tracker.env << 'EOF'
MYSQL_SOCKET="/tmp/mysql.sock"
MYSQL_USER="workout_user"
MYSQL_PASSWORD="your_secure_password"  # 替换为实际密码
MYSQL_DATABASE="workout_tracker"
EOF

# 设置文件权限(仅当前用户可读)
chmod 600 .workout-tracker.env

# 加载配置
source .workout-tracker.env

方法 B:临时环境变量(会话有效)

# 仅在当前终端会话中有效
export MYSQL_SOCKET="/tmp/mysql.sock"
export MYSQL_USER="workout_user"
export MYSQL_PASSWORD="your_password"  # 注意:密码会出现在 shell 历史中
export MYSQL_DATABASE="workout_tracker"

方法 C:交互式输入(最安全,无痕迹)

# 使用脚本提示输入密码,不存储在任何地方
import getpass
import os

password = getpass.getpass("请输入 MySQL 密码: ")
os.environ['MYSQL_PASSWORD'] = password

⚠️ 安全警告:避免将密码存储在 /.bashrc、/.zshrc 或版本控制的文件中。

3. 数据库用户创建

-- 在 MySQL 中执行
CREATE USER IF NOT EXISTS 'workout_user'@'localhost' IDENTIFIED BY 'your_password';
GRANT INSERT, SELECT, UPDATE, DELETE ON workout_tracker.* TO 'workout_user'@'localhost';
FLUSH PRIVILEGES;
CREATE DATABASE IF NOT EXISTS workout_tracker;

4. 初始化数据库(一键脚本)

# 运行初始化脚本
python3 /path/to/workout-tracker/scripts/init_database.py

5. 验证安装

# 运行验证脚本
python3 /path/to/workout-tracker/scripts/verify_setup.py

安全配置(推荐使用 .env 文件)

# 创建安全的 .env 配置文件(不上传至版本控制)
cat > ~/.workout-tracker.env << 'EOF'
# Workout Tracker 数据库配置
# ⚠️ 警告:此文件包含敏感信息,不要上传到版本控制
MYSQL_SOCKET="/tmp/mysql.sock"
MYSQL_USER="workout_user"
MYSQL_PASSWORD="your_secure_password_here"  # 替换为你的实际密码
MYSQL_DATABASE="workout_tracker"
EOF

# 设置文件权限(仅当前用户可读)
chmod 600 ~/.workout-tracker.env

# 在 shell 中加载配置
source ~/.workout-tracker.env

自动化安装脚本(安全版本)

#!/bin/bash
# workout-tracker-setup-secure.sh

echo "🏋️ Workout Tracker 安全安装"

# 安装 Python 依赖
echo "📦 安装 Python 依赖..."
pip install mysql-connector-python

# 创建安全的配置模板
echo "🔐 创建安全配置模板..."
cat > workout-tracker-config-template.env << 'EOF'
# Workout Tracker 配置模板
# 1. 将此文件复制为 .workout-tracker.env
# 2. 填写实际的数据库密码
# 3. 设置文件权限: chmod 600 .workout-tracker.env

MYSQL_SOCKET="/tmp/mysql.sock"
MYSQL_USER="workout_user"
MYSQL_PASSWORD=""  # ⬅️ 在此处填写你的 MySQL 密码
MYSQL_DATABASE="workout_tracker"
EOF

echo "✅ 安装完成!"
echo ""
echo "📋 后续步骤:"
echo "1. 填写数据库密码: cp workout-tracker-config-template.env ~/.workout-tracker.env"
echo "2. 编辑 ~/.workout-tracker.env 设置密码"
echo "3. 设置文件权限: chmod 600 ~/.workout-tracker.env"
echo "4. 加载配置: source ~/.workout-tracker.env"
echo "5. 验证安装: python3 scripts/verify_setup.py"
echo ""
echo "🔒 安全提示:"
echo "- 永远不要在版本控制中包含 .env 文件"
echo "- 使用强密码并定期更换"
echo "- 数据库用户仅授予最小必要权限"

本地配置说明

本技能专为单用户本地部署设计(用户无需公开任何凭据)。数据库配置通过本地环境变量或配置文件管理,不随技能发布。

默认单用户 ID 说明:

  • 本技能设计为单用户工具(user_id = 1 是默认值,适用于个人本地使用)
  • 安装后用户可自行修改 workout_sessionsworkout_items 中的 user_id 以匹配自己的设置
  • 数据库表结构兼容多用户扩展(只需在查询时指定对应 user_id)

数据库结构

exercise_types (id, name, muscle_group, equipment, unit)
  -- id: 自增主键
  -- name: 动作名称,如"杠铃深蹲"、"腿举机"
  -- muscle_group: 主要肌群(胸/背/腿/肩/臂/腹/全身/下背)
  -- equipment: 器械类型(杠铃/哑铃/器械/自重/有氧)
  -- unit: 计量单位(次/分钟/米)

gym_equipment (id, name, category, muscle_main, muscle_sec, created_at)
  -- id: 自增主键
  -- name: 器械名称
  -- category: 类别(哑铃/杠铃/器械/有氧/自由重量/辅助)
  -- muscle_main/muscle_sec: 主要/次要肌群

workout_sessions (id, user_id, workout_date, start_time, end_time, duration_min, workout_type, notes)
  -- id: 自增主键
  -- user_id: 用户ID(默认1,单用户本地部署)
  -- workout_date: 训练日期
  -- duration_min: 总时长(分钟)
  -- workout_type: 训练类型(力量/有氧/柔韧)
  -- notes: 备注(如状态评分"状态评分: 9/10 | 非常爽")

workout_items (id, session_id, exercise_type_id, set_order, reps, weight_kg, distance_km, rpe, notes)
  -- id: 自增主键
  -- session_id: 关联 workout_sessions.id
  -- exercise_type_id: 关联 exercise_types.id
  -- set_order: 第几组(1, 2, 3...)
  -- reps: 重复次数
  -- weight_kg: 重量(公斤)
  -- notes: 备注(如"杠铃深蹲第1组")

核心流程

标准预排模式(默认)

用户一次性报完整动作计划 → 我预排所有组 → 用户每完成一组说 done → 我逐条标记完成

用户命令示例:

  • "深蹲 60公斤 4组×8次" → 预排所有组,记录为待完成状态,回复"已预排4组,每完成一组说done"
  • "done" → 标记当前训练最新一组为完成状态,回复"第1组完成!还剩3组"
  • "done 这组是10次" → 同上,并更新该组次数为10次
  • "done 加一组" → 完成当前组,并追加一组相同训练
  • "卧推 40公斤 3组×10次" → 切换到新动作,重新预排
  • "结束了" → 训练完成,自动计算时长,询问状态评分

操作流程(预排模式):

1. 用户说"动作 + 重量 + X组×Y次"
   → 若当日尚无 workout_session,先创建(start_time=NOW())
   → 解析动作名、重量、组数、次数
   → 匹配 exercise_types.id,不存在则插入
   → 一次性插入 N 条 workout_items,notes 标"⏳待完成"
   → 回复"已预排X组,每完成一组说done"
   → 随机(30%概率)附一句简短鼓励(如"这个重量稳的!")

2. 用户说 "done"(或"done 这组是X次")
   → 找到当前 session 最新未标记 ✓ 的记录
   → 更新 notes 追加" ✓"(若用户报了次数,同时更新 reps)
   → 回复"第N组完成!还剩X组"(若还有未完成的)
   → 若动作全部完成 → 回复"XX动作完成!下一个动作是什么?"
   → 随机(30%概率)附一句简短鼓励

3. 用户说 "done 加一组"
   → 执行步骤2的标记完成逻辑
   → 在当前动作下追加一条新的"⏳待完成"记录(reps/weight 继承上一组)
   → 回复"已追加第N+1组 ⏳"

4. 用户说 "动作名 重量 X组×Y次"
   → 切换到新动作,重复步骤1

5. 用户说 "结束了"
   → 自动计算:TIMESTAMPDIFF(MINUTE, start_time, NOW()),start_time 来自 workout_sessions
   → UPDATE workout_sessions SET duration_min=? WHERE id=current_session
   → 查询汇总数据,回复训练完成汇总
   → 主动询问:"今天状态怎么样?状态评分1-10"

情绪价值 — 鼓励语料库(随机选取):

每完成一组时,随机附上以下类型的鼓励语:

  • 🔥 进度类:"又完成一组,腿部在燃烧!""离目标又近了一步!""感觉怎么样?这组有没有更稳?"
  • 💪 力量类:"这重量稳的!""继续保持这个节奏""你的深蹲越来越扎实了"
  • 🌟 夸赞类:"不错不错!""这组完成得很干净""看得出状态很好!"
  • 😅 幽默类:"腿已经软了?坚持住!""疼痛是成长的象征 😄""汗水不会骗人 💦"
  • 🏆 完成类(动作全部完成):"这个动作拿捏了!""太强了,下一个!""肌肉在尖叫,继续!"

鼓励触发规则:

  • 开始新动作时:30%概率附一句(针对该动作的简短鼓励)
  • 每完成一组 "done" 时:50%概率附一句(简短、自然,不要每组都说)
  • 动作全部4组完成时:80%概率附一句夸奖
  • 用户感到吃力或犹豫时:主动降低语气,给予安慰而非催促
  • 不要过度鼓励,保持自然节奏,避免刷屏感

SQL模板(参数化查询):

-- 创建新训练 session(如尚无今日 session,start_time 自动为 NOW())
INSERT INTO workout_sessions (user_id, workout_date, workout_type, start_time)
VALUES (?, CURDATE(), ?, NOW());  -- user_id, workout_type

-- 获取当前 session_id
SELECT id FROM workout_sessions WHERE user_id=? ORDER BY id DESC LIMIT 1;  -- user_id

-- 预排 N 组(用户说"动作 重量 X组×Y次")
INSERT INTO workout_items (session_id, exercise_type_id, set_order, reps, weight_kg, notes) VALUES
(?, ?, 1, ?, ?, CONCAT(?, ' 第1组 ⏳')),
(?, ?, 2, ?, ?, CONCAT(?, ' 第2组 ⏳')),
...
(?, ?, N, ?, ?, CONCAT(?, ' 第N组 ⏳'));  -- sid, eid, reps, weight, exercise_name

-- 标记第N组完成(用户说 done 时)
UPDATE workout_items
SET notes = CONCAT(?, ' 第', ?, '组 ✓'),  -- exercise_name, set_order
    reps = ?  -- 如用户报了次数
WHERE session_id=? AND set_order=?;  -- sid, set_order

-- 追加一组(用户说 done 加一组 时)
INSERT INTO workout_items (session_id, exercise_type_id, set_order, reps, weight_kg, notes)
VALUES (?, ?, (SELECT IFNULL(MAX(set_order),0)+1 FROM workout_items WHERE session_id=?), ?, ?, CONCAT(?, ' 第N组 ⏳'));
-- sid, eid, sid, reps, weight, exercise_name

-- 完成训练(duration_min = NOW() - start_time)
SELECT TIMESTAMPDIFF(MINUTE, start_time, NOW()) as duration_min
FROM workout_sessions WHERE id=?;  -- sid
UPDATE workout_sessions SET duration_min=? WHERE id=?;  -- minutes, sid

-- 状态评分更新(后续用户说"X分"时)
UPDATE workout_sessions SET notes=? WHERE id=?;  -- score_note, sid

模式二:一次性记录(训练后补录)

用户一次性报完整训练内容:

今天练了深蹲 4组×10次×30公斤,腿举 3组×8次×72公斤

操作流程:

  1. 解析所有动作及每组数据
  2. 创建 session
  3. 批量插入 workout_items
  4. 回复汇总

模式三:制定训练计划(基础版)

用户说"今天练腿给我一个计划" → 根据 gym_equipment 中的器械,生成针对性的训练计划 → 回复格式:热身 → 主项 → 辅助项 → 拉伸

模式四:智能生成训练计划(增强版)

当用户说"今天练X"、"我要练X"、"给我一个X训练计划"时,自动执行:

第一步:查询本周已训练过的肌群(避免重复)

-- 查询本周(近7天)训练过的肌群及动作
SELECT DISTINCT ws.workout_date, ws.workout_type,
  et.muscle_group, et.name as exercise_name,
  wi.weight_kg, wi.reps, wi.set_order
FROM workout_sessions ws
JOIN workout_items wi ON wi.session_id = ws.id
JOIN exercise_types et ON et.id = wi.exercise_type_id
WHERE ws.user_id=1 AND ws.workout_date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY)
ORDER BY ws.workout_date DESC, et.muscle_group;

第二步:查询用户器械(确保计划可执行)

SELECT id, name, category, muscle_main, muscle_sec
FROM gym_equipment
WHERE muscle_main LIKE '%背%'   -- 动态替换目标肌群关键词
   OR muscle_sec LIKE '%背%'
ORDER BY category;

第三步:分析后生成计划

  • 目标肌群本周已练过 → 计划注明"上次练过此肌群,可适当降低强度"
  • 目标肌群本周未练 → 正常强度
  • 计划必须全部来自已有器械,无器械可用时标注"需新增器械"
  • 回复格式:热身 → 主项(含建议重量参考)→ 辅助项 → 拉伸

回复模板:

📋 今日{肌群}训练计划(智能生成)
🗓️ 本周已练:{已训练肌群及日期}
🏋️ 可用器械:{器械列表}

① 热身(5-10分钟)
② 主项(3-4组×8-12次)— 标注动作名 [器械名]
③ 辅助项(2-3组×10-15次)— 标注动作名 [器械名]
④ 拉伸

💡备注:{上次训练情况及建议}

模式五:查询记录

用户问"今天练了什么"、"上周训练几次"等 → 执行查询SQL → 整理成表格回复

查询示例

训练完成汇总

SELECT ws.workout_date, ws.duration_min, ws.workout_type, ws.notes,
  et.name, COUNT(*) as sets, SUM(wi.reps) as total_reps, wi.weight_kg
FROM workout_items wi
JOIN workout_sessions ws ON ws.id = wi.session_id
JOIN exercise_types et ON et.id = wi.exercise_type_id
WHERE wi.session_id = ?
GROUP BY et.name, wi.weight_kg
ORDER BY et.name;

查今日训练

SELECT ws.workout_date, ws.duration_min, ws.workout_type,
  et.name, wi.set_order, wi.reps, wi.weight_kg
FROM workout_sessions ws
JOIN workout_items wi ON wi.session_id = ws.id
JOIN exercise_types et ON et.id = wi.exercise_type_id
WHERE ws.user_id=1 AND ws.workout_date=CURDATE()
ORDER BY ws.id, wi.set_order;

查本周训练天数

SELECT COUNT(DISTINCT workout_date) as days,
  SUM(duration_min) as total_min
FROM workout_sessions
WHERE user_id=1 AND workout_date >= DATE_SUB(CURDATE(), INTERVAL 7 DAY);

查某动作历史

SELECT ws.workout_date, et.name, wi.reps, wi.weight_kg
FROM workout_items wi
JOIN workout_sessions ws ON ws.id = wi.session_id
JOIN exercise_types et ON et.id = wi.exercise_type_id
WHERE ws.user_id=1 AND et.name LIKE '%深蹲%'
ORDER BY ws.workout_date DESC LIMIT 10;

动作识别优先级

用户输入动作简称时,自动识别对应 exercise_types:

  • "山羊挺身" → 45度背部挺身机
  • "腿举" → 腿举机/倒蹬机
  • "罗马凳" → 罗马凳/背肌伸展架
  • "深蹲" → 杠铃深蹲
  • "卧推" → 杠铃卧推
  • 等等(模糊匹配)

如果完全匹配不到,先插入新动作。

训练完成后的反馈询问

训练结束汇总回复后,必须主动询问:

"今天状态怎么样?状态评分1-10"

用户回复后,更新 workout_sessions.notes:

UPDATE workout_sessions SET notes = CONCAT('状态评分: ', ?, '/10 | ', ?) WHERE id = ?;  -- score, feeling, sid

常见动作类型判断

根据关键词判断 workout_type:

  • "跑"、"快走"、"椭圆机"、"有氧" → 有氧
  • "瑜伽"、"拉伸"、"普拉提" → 柔韧
  • 其他(卧推、深蹲、硬拉、引体等) → 力量

模式六:球类/有氧运动记录(简化流程)

用户说"网球一小时"、"游泳半小时"等,直接创建 session,不走预排组流程。

识别规则:

  • 运动名 + 时长(网球/羽毛球/乒乓球/篮球/足球/游泳/跑步/骑行/椭圆机 等)
  • 时长单位:小时/分钟/小时半(1.5小时)

操作流程:

  1. 匹配 exercise_types.name(模糊匹配 sport_name)
  2. 创建 session,sport_name 字段写入运动名,workout_type 设为 有氧
  3. duration_min 写入实际时长(分钟)
  4. 不创建 workout_items(这类运动不需要组数记录)
  5. 回复汇总即可

SQL:

-- 创建运动记录
INSERT INTO workout_sessions (user_id, workout_date, sport_name, workout_type, duration_min, start_time)
VALUES (1, CURDATE(), '网球发球机', '有氧', 60, NOW());

回复模板:

🎾 网球发球机训练记录完成
───
⏱️ 时长:60 分钟
🏃 类型:有氧
───
状态评分 1-10?

SQL 安全规范(严格禁止 SQL 注入)

所有用户输入必须经过参数化查询,禁止任何形式的字符串拼接 SQL。

✅ 正确做法(参数化查询)

# Python + MySQL Connector 示例
import mysql.connector

# 使用参数化查询
cursor.execute(
    "INSERT INTO workout_items (session_id, exercise_type_id, set_order, reps, weight_kg) VALUES (%s, %s, %s, %s, %s)",
    (session_id, exercise_type_id, set_order, reps, weight_kg)
)

# LIKE 查询也必须参数化
search_term = "深蹲"
cursor.execute(
    "SELECT * FROM exercise_types WHERE name LIKE %s",
    (f"%{search_term}%",)  # 参数化,安全
)

❌ 绝对禁止的做法

# ❌ 危险:字符串拼接(极易 SQL 注入)
cursor.execute(f"INSERT INTO ... VALUES ({session_id}, {exercise_type_id}, ...)")

# ❌ 危险:使用 .format() 或 %
cursor.execute("SELECT * FROM exercise_types WHERE name LIKE '%{}%'".format(user_input))

# ❌ 危险:直接拼接用户输入到 SQL
sql = "SELECT * FROM exercise_types WHERE name LIKE '%" + user_input + "%'"
cursor.execute(sql)

⚠️ 特别注意

  1. LIKE 子句:必须参数化整个模式,不能只参数化搜索词
  2. 表名/列名:不能参数化,必须白名单验证
  3. 整数/浮点数:同样需要参数化,不要以为数字就安全
  4. Python f-string:绝对禁止用于 SQL 语句构建

🔒 额外防护措施

  1. 数据库用户使用最小权限原则(仅 GRANT INSERT/SELECT/UPDATE/DELETE)
  2. 所有查询记录日志(用于审计异常)
  3. 输入验证:动作名称长度限制、数字范围检查
  4. 错误消息不泄露数据库结构

安全审计清单(部署前必须检查)

🔍 SQL 注入防护

  • 所有 SQL 查询使用参数化语句(?, %s 等占位符)
  • 绝对禁止字符串拼接构建 SQL
  • LIKE 查询完全参数化(包括通配符 % 和 _)
  • 整数/浮点数值也使用参数化查询

🔐 数据库权限

  • 创建专用数据库用户(非 root)
  • 仅授予最小权限:INSERT/SELECT/UPDATE/DELETE
  • 禁止 DROP、CREATE、ALTER 权限
  • 定期审计数据库用户权限

🛡️ 输入验证

  • 动作名称长度限制(例如 50 字符)
  • 数字范围验证(reps: 1-100, weight: 0-500kg)
  • 时间/日期格式验证
  • 特殊字符过滤或转义

📝 安全配置

  • 数据库连接使用本地 socket(非 TCP)
  • 错误消息不泄露数据库结构
  • 查询日志记录(用于审计异常)
  • 定期备份数据库

🚨 应急响应

  • 监控异常查询模式
  • 记录失败登录尝试
  • 准备数据库恢复方案
  • 定期安全更新 MySQL

注意事项

  • 用户 ID 默认为 1(单用户本地部署)
  • 所有 SQL 必须使用参数化查询,防止 SQL 注入
  • 数据库用户建议创建专用账户,仅授予 INSERT/SELECT/UPDATE/DELETE 权限
  • duration_min 单位为分钟
  • weight_kg 单位为公斤,保留2位小数
  • reps 为整数(次数)
  • set_order 从1开始,每组递增
  • 训练结束后必须询问状态评分
  • 解析时支持"4组×8次"、"4x8"、"四组八次"、"每组12次"等多种格式
  • 用户说"done"时,记录的是当前 session 最新插入的未完成组

Comments

Loading comments...