feat: Add Chatwoot Agent Bot prototype and FAQ knowledge base
- Created chatwoot-agent-bot/ with Node.js webhook server - Bot detects intent (greeting, billing, technical, features, account) - Auto-responds from FAQ knowledge base or escalates to human - FAQ-KB.md: Living knowledge base that grows with customer questions - CHATWOOT-SETUP.md: Complete deployment and configuration guide - Supports Telegram notifications on escalation - Bot runs on port 3001, ready for Chatwoot webhook integration
This commit is contained in:
145
agents/fitness-coach/scripts/iron-agent.py
Executable file
145
agents/fitness-coach/scripts/iron-agent.py
Executable file
@@ -0,0 +1,145 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Iron - Personal Fitness Coach Agent
|
||||
Handles: workout generation, PR tracking, progress reports, meal suggestions
|
||||
"""
|
||||
import json
|
||||
import subprocess
|
||||
from datetime import datetime, timedelta
|
||||
from pathlib import Path
|
||||
import random
|
||||
|
||||
WORKSPACE = Path(__file__).parent.parent
|
||||
CONFIG = WORKSPACE / "config"
|
||||
STATE = WORKSPACE / "state"
|
||||
LOGS = WORKSPACE / "logs"
|
||||
|
||||
PROFILE_FILE = CONFIG / "user-profile.json"
|
||||
PROGRAM_FILE = CONFIG / "program.json"
|
||||
PRS_FILE = STATE / "prs.json"
|
||||
|
||||
def load_json(path):
|
||||
with open(path) as f:
|
||||
return json.load(f)
|
||||
|
||||
def save_json(path, data):
|
||||
with open(path, 'w') as f:
|
||||
json.dump(data, f, indent=2)
|
||||
|
||||
def log(msg):
|
||||
ts = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
|
||||
line = f"[{ts}] {msg}"
|
||||
print(line)
|
||||
(LOGS / f"iron-{datetime.now().strftime('%Y%m%d')}.log").open('a').write(line + '\n')
|
||||
|
||||
def get_todays_workout():
|
||||
"""Generate today's workout based on program"""
|
||||
program = load_json(PROGRAM_FILE)
|
||||
profile = load_json(PROFILE_FILE)
|
||||
|
||||
# Determine which day (simple rotation)
|
||||
today = datetime.now()
|
||||
start = datetime.strptime(profile['program']['start_date'], '%Y-%m-%d')
|
||||
days_since_start = (today - start).days
|
||||
day_num = (days_since_start % 7) // 2 # Roughly every 2-3 days
|
||||
|
||||
if day_num == 0:
|
||||
workout_key = 'day1'
|
||||
elif day_num == 1:
|
||||
workout_key = 'day2'
|
||||
else:
|
||||
workout_key = 'day3'
|
||||
|
||||
workout = program['workouts'][workout_key]
|
||||
prs = load_json(PRS_FILE)
|
||||
|
||||
output = f"💪 *{workout['name']}* ({workout['duration_min']} min)\n\n"
|
||||
|
||||
for i, ex in enumerate(workout['exercises'], 1):
|
||||
# Check if we have PR data
|
||||
pr_weight = prs['personal_records'].get(ex['name'], {}).get('weight')
|
||||
pr_note = ""
|
||||
if pr_weight:
|
||||
pr_note = f" (Last: {pr_weight})"
|
||||
|
||||
output += f"{i}. *{ex['name']}*: {ex['sets']}x{ex['reps']} @ ___ {pr_note}\n"
|
||||
output += f" Rest: {ex['rest_sec']}s | {ex['notes']}\n"
|
||||
|
||||
output += "\n_Reply with results: 'Bench 4x8 @ 185'_ "
|
||||
return output
|
||||
|
||||
def get_meal_suggestion():
|
||||
"""Generate T1D-friendly high protein, low carb meal"""
|
||||
meals = [
|
||||
("Grilled Chicken & Veggies", "Chicken breast, broccoli, olive oil", "45g protein, 8g net carbs"),
|
||||
("Salmon & Asparagus", "Salmon fillet, asparagus, lemon", "40g protein, 6g net carbs"),
|
||||
("Turkey & Egg Scramble", "Ground turkey, eggs, spinach", "42g protein, 5g net carbs"),
|
||||
("Steak & Cauliflower", "Ribeye steak, cauliflower rice", "48g protein, 7g net carbs"),
|
||||
("Tuna Salad", "Canned tuna, mayo, celery, lettuce", "35g protein, 4g net carbs"),
|
||||
("Greek Yogurt Bowl", "Greek yogurt, almonds, berries", "25g protein, 9g net carbs"),
|
||||
("Protein Shake + Nuts", "Whey isolate, almonds, peanut butter", "30g protein, 6g net carbs"),
|
||||
]
|
||||
|
||||
meal = random.choice(meals)
|
||||
return f"🍽️ *{meal[0]}*\n\nIngredients: {meal[1]}\nMacros: {meal[2]}\n\n_{meal[0].lower()} with veggies for easy prep_"
|
||||
|
||||
def get_weekly_progress():
|
||||
"""Generate weekly progress report"""
|
||||
profile = load_json(PROFILE_FILE)
|
||||
prs = load_json(PRS_FILE)
|
||||
|
||||
weight = profile['stats']['weight_lbs']
|
||||
weight_history = profile['stats'].get('weight_history', [])
|
||||
trend = ""
|
||||
if len(weight_history) > 1:
|
||||
change = weight_history[-1]['weight'] - weight_history[0]['weight']
|
||||
trend = f"{'+' if change > 0 else ''}{change:.1f} lbs"
|
||||
|
||||
report = f"📊 *Weekly Progress Report*\n\n"
|
||||
report += f"*Current Weight:* {weight} lbs {trend}\n"
|
||||
report += f"*Program:* {profile['program']['type']}\n"
|
||||
report += f"*Experience:* {profile['stats']['experience'].title()}\n\n"
|
||||
|
||||
# Count workouts
|
||||
completed = len(prs.get('workout_history', []))
|
||||
report += f"*Workouts Logged:* {completed}\n"
|
||||
|
||||
# PRs
|
||||
pr_count = sum(1 for v in prs['personal_records'].values() if v.get('weight'))
|
||||
report += f"*PRs Tracked:* {pr_count}/5\n\n"
|
||||
|
||||
report += "_Keep grinding. Consistency > intensity._"
|
||||
return report
|
||||
|
||||
def send_telegram(msg):
|
||||
"""Send message via Telegram"""
|
||||
try:
|
||||
subprocess.run(['openclaw', 'message', 'send', '--text', msg],
|
||||
capture_output=True, timeout=10)
|
||||
except Exception as e:
|
||||
log(f"Telegram send failed: {e}")
|
||||
|
||||
def main():
|
||||
import sys
|
||||
cmd = sys.argv[1] if len(sys.argv) > 1 else 'workout'
|
||||
|
||||
if cmd == 'workout':
|
||||
print(get_todays_workout())
|
||||
elif cmd == 'meal':
|
||||
print(get_meal_suggestion())
|
||||
elif cmd == 'progress':
|
||||
print(get_weekly_progress())
|
||||
elif cmd == 'log' and len(sys.argv) > 2:
|
||||
# Log workout result
|
||||
result = ' '.join(sys.argv[2:])
|
||||
log(f"WORKOUT LOG: {result}")
|
||||
print(f"✅ Logged: {result}")
|
||||
else:
|
||||
print("Iron Fitness Coach - Commands:")
|
||||
print(" workout - Get today's workout")
|
||||
print(" meal - Get meal suggestion")
|
||||
print(" progress - Weekly progress report")
|
||||
print(" log <result> - Log workout result")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
17
agents/fitness-coach/scripts/send-workout.sh
Executable file
17
agents/fitness-coach/scripts/send-workout.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
# Send morning workout via Telegram
|
||||
|
||||
WORKSPACE="/Users/claw/.openclaw/workspace/agents/fitness-coach"
|
||||
WORKOUT=$(python3 "$WORKSPACE/scripts/iron-agent.py" workout)
|
||||
|
||||
MSG="☀️ *GOOD MORNING! Today's Workout:*
|
||||
|
||||
$WORKOUT
|
||||
|
||||
Time to grind! 💪"
|
||||
|
||||
# Send via Telegram to Chris
|
||||
openclaw message send --channel telegram --target telegram:8269921691 --message "$MSG" 2>/dev/null
|
||||
|
||||
# Log it
|
||||
echo "[$(date '+%Y-%m-%d %H:%M:%S')] Workout sent" >> "$WORKSPACE/logs/workout-sent.log"
|
||||
Reference in New Issue
Block a user