{
  "name": "n8n workflow",
  "nodes": [
    {
      "id": "bb25e4a1-cf34-4693-ae7c-0108c653ee59",
      "name": "Workout Log Form",
      "type": "n8n-nodes-base.formTrigger",
      "position": [
        -160,
        64
      ],
      "parameters": {
        "path": "9caa6885-c1c2-44b1-b749-ca28333a9cdf",
        "options": {},
        "formTitle": "Workout Logger",
        "formFields": {
          "values": [
            {
              "fieldType": "textarea",
              "fieldLabel": "What did you do today?",
              "placeholder": "e.g. Bench press 60kg x 10 x 3, Running 5km 28min, Squats bodyweight 20 reps x 4",
              "requiredField": true
            },
            {
              "fieldType": "dropdown",
              "fieldLabel": "How do you feel? (1-10)",
              "fieldOptions": {
                "values": [
                  {
                    "option": "1 - Exhausted"
                  },
                  {
                    "option": "2"
                  },
                  {
                    "option": "3"
                  },
                  {
                    "option": "4"
                  },
                  {
                    "option": "5 - Normal"
                  },
                  {
                    "option": "6"
                  },
                  {
                    "option": "7"
                  },
                  {
                    "option": "8"
                  },
                  {
                    "option": "9"
                  },
                  {
                    "option": "10 - Amazing"
                  }
                ]
              },
              "requiredField": true
            },
            {
              "fieldType": "number",
              "fieldLabel": "Duration (minutes)",
              "requiredField": true
            },
            {
              "fieldType": "textarea",
              "fieldLabel": "Notes",
              "placeholder": "Any injuries, PRs, or things to remember"
            }
          ]
        },
        "formDescription": "Log your workout and get AI-powered analysis on muscle groups, calories, and progress tips."
      },
      "typeVersion": 2
    },
    {
      "id": "984a6b52-88ac-45b3-8609-304ed0d4f1a8",
      "name": "Analyze Workout with AI",
      "type": "@n8n/n8n-nodes-langchain.chainLlm",
      "position": [
        48,
        64
      ],
      "parameters": {
        "text": "You are a certified personal trainer and sports scientist. Analyze this workout log and return ONLY valid JSON (no markdown, no extra text):\n\nWorkout description: {{ $json['What did you do today?'] }}\nDuration: {{ $json['Duration (minutes)'] }} minutes\nFeeling: {{ $json['How do you feel? (1-10)'] }}\nNotes: {{ $json['Notes'] || 'None' }}\n\nReturn this exact JSON structure:\n{\n  \"exercises\": [\n    {\n      \"name\": \"Exercise name\",\n      \"type\": \"strength/cardio/flexibility/other\",\n      \"muscle_groups\": [\"primary muscles worked\"],\n      \"sets\": 0,\n      \"reps\": 0,\n      \"weight_kg\": 0,\n      \"duration_min\": 0,\n      \"estimated_calories\": 0\n    }\n  ],\n  \"summary\": {\n    \"total_exercises\": 0,\n    \"total_calories\": 0,\n    \"primary_type\": \"strength/cardio/mixed\",\n    \"muscle_groups_hit\": [\"list of all muscles worked\"],\n    \"intensity\": \"low/moderate/high/very high\"\n  },\n  \"tips\": [\n    \"One specific, actionable tip based on this workout\",\n    \"Another tip about recovery or next session\"\n  ],\n  \"next_workout_suggestion\": \"Brief suggestion for complementary workout\"\n}",
        "promptType": "define"
      },
      "typeVersion": 1.4
    },
    {
      "id": "3650268d-d219-45fc-8827-6792434af319",
      "name": "Google Gemini",
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "position": [
        48,
        240
      ],
      "parameters": {
        "options": {
          "temperature": 0.2
        },
        "modelName": "models/gemini-1.5-flash-latest"
      },
      "typeVersion": 1
    },
    {
      "id": "025dc1e0-f596-4ba8-be6f-142d8fec46bd",
      "name": "Parse AI Results",
      "type": "n8n-nodes-base.code",
      "position": [
        336,
        64
      ],
      "parameters": {
        "jsCode": "// Parse and validate AI workout analysis\nconst aiResponse = $json.response || $json.text || '';\n\n// Extract JSON from response\nlet jsonStr = aiResponse;\nconst jsonMatch = aiResponse.match(/```(?:json)?\\s*([\\s\\S]*?)```/);\nif (jsonMatch) {\n  jsonStr = jsonMatch[1].trim();\n}\n\nlet parsed;\ntry {\n  parsed = JSON.parse(jsonStr);\n} catch (e) {\n  parsed = {\n    exercises: [],\n    summary: {\n      total_exercises: 0,\n      total_calories: 0,\n      primary_type: 'unknown',\n      muscle_groups_hit: [],\n      intensity: 'moderate'\n    },\n    tips: ['Could not parse workout details. Try being more specific next time.'],\n    next_workout_suggestion: 'Rest day or light cardio'\n  };\n}\n\n// Get original form data\nconst form = $('Workout Log Form').first().json;\nconst feelingRaw = form['How do you feel? (1-10)'] || '5';\nconst feeling = parseInt(feelingRaw.match(/\\d+/)?.[0] || '5');\n\nreturn {\n  date: new Date().toISOString().split('T')[0],\n  workout_description: form['What did you do today?'],\n  duration_min: parseInt(form['Duration (minutes)']) || 0,\n  feeling: feeling,\n  notes: form['Notes'] || '',\n  exercises: parsed.exercises || [],\n  exercise_count: (parsed.exercises || []).length,\n  total_calories: parsed.summary?.total_calories || 0,\n  primary_type: parsed.summary?.primary_type || 'unknown',\n  muscle_groups: (parsed.summary?.muscle_groups_hit || []).join(', '),\n  intensity: parsed.summary?.intensity || 'moderate',\n  tips: (parsed.tips || []).join(' | '),\n  next_suggestion: parsed.next_workout_suggestion || '',\n  logged_at: new Date().toISOString()\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "270c9b77-67cc-454f-8d0e-2e09ac26d2e5",
      "name": "Save to Workout Sheet",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        528,
        64
      ],
      "parameters": {
        "columns": {
          "value": {
            "Date": "={{ $json.date }}",
            "Tips": "={{ $json.tips }}",
            "Type": "={{ $json.primary_type }}",
            "Notes": "={{ $json.notes }}",
            "Feeling": "={{ $json.feeling }}",
            "Muscles": "={{ $json.muscle_groups }}",
            "Workout": "={{ $json.workout_description }}",
            "Calories": "={{ $json.total_calories }}",
            "Duration": "={{ $json.duration_min }}",
            "Exercises": "={{ $json.exercise_count }}",
            "Intensity": "={{ $json.intensity }}",
            "Logged At": "={{ $json.logged_at }}",
            "Next Suggestion": "={{ $json.next_suggestion }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {
          "cellFormat": "USER_ENTERED"
        },
        "operation": "appendOrUpdate",
        "sheetName": "Workouts",
        "documentId": "YOUR_GOOGLE_SHEET_ID"
      },
      "typeVersion": 4.4
    },
    {
      "id": "3f66044c-56ed-4f63-8a0f-c9e92db2ba81",
      "name": "Build Summary Message",
      "type": "n8n-nodes-base.code",
      "position": [
        736,
        64
      ],
      "parameters": {
        "jsCode": "// Build a nice summary for notifications\nconst w = $json;\n\n// Emoji for feeling\nconst feelEmoji = w.feeling >= 8 ? '🔥' : w.feeling >= 5 ? '💪' : '😤';\n\n// Emoji for type\nconst typeEmoji = {\n  'strength': '🏋️',\n  'cardio': '🏃',\n  'mixed': '🏋️🏃',\n  'flexibility': '🧘'\n};\nconst tEmoji = typeEmoji[w.primary_type] || '💪';\n\nconst intensityBar = {\n  'low': '🟢',\n  'moderate': '🟡',\n  'high': '🟠',\n  'very high': '🔴'\n};\nconst iBar = intensityBar[w.intensity] || '🟡';\n\nconst slackMsg = [\n  `${tEmoji} *Workout Logged* — ${w.date}`,\n  ``,\n  `*What:* ${w.workout_description}`,\n  `*Duration:* ${w.duration_min} min | *Feeling:* ${w.feeling}/10 ${feelEmoji}`,\n  `*Type:* ${w.primary_type} | *Intensity:* ${iBar} ${w.intensity}`,\n  `*Calories:* ~${w.total_calories} kcal`,\n  `*Muscles:* ${w.muscle_groups}`,\n  ``,\n  `💡 *Tips:* ${w.tips}`,\n  `📋 *Next time:* ${w.next_suggestion}`,\n  w.notes ? `📌 ${w.notes}` : ''\n].filter(Boolean).join('\\n');\n\nconst emailHtml = `<h2>${tEmoji} Workout Summary — ${w.date}</h2>\n<p><strong>Workout:</strong> ${w.workout_description}<br>\n<strong>Duration:</strong> ${w.duration_min} min | <strong>Feeling:</strong> ${w.feeling}/10 ${feelEmoji}<br>\n<strong>Type:</strong> ${w.primary_type} | <strong>Intensity:</strong> ${w.intensity}<br>\n<strong>Estimated Calories:</strong> ~${w.total_calories} kcal<br>\n<strong>Muscle Groups:</strong> ${w.muscle_groups}</p>\n<h3>💡 Tips</h3>\n<p>${w.tips.replace(/ \\| /g, '<br>')}</p>\n<h3>📋 Next Workout Suggestion</h3>\n<p>${w.next_suggestion}</p>\n${w.notes ? '<p><em>Notes: ' + w.notes + '</em></p>' : ''}\n<hr>\n<p><small>Logged automatically via n8n Workout Tracker</small></p>`;\n\nreturn {\n  ...w,\n  slack_message: slackMsg,\n  email_html: emailHtml\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "2c5f57f2-42cd-454b-a531-5d4128706d61",
      "name": "Notify on Slack",
      "type": "n8n-nodes-base.slack",
      "position": [
        1008,
        -16
      ],
      "parameters": {
        "text": "={{ $json.slack_message }}",
        "select": "channel",
        "channelId": "YOUR_SLACK_CHANNEL_ID",
        "otherOptions": {}
      },
      "typeVersion": 2.2
    },
    {
      "id": "39af1065-74b1-44e2-86ca-1aa0de152996",
      "name": "Email Summary",
      "type": "n8n-nodes-base.gmail",
      "position": [
        1008,
        176
      ],
      "parameters": {
        "sendTo": "YOUR_EMAIL_ADDRESS",
        "message": "={{ $json.email_html }}",
        "options": {},
        "subject": "Workout logged: {{ $json.primary_type }} {{ $json.duration_min }}min — {{ $json.total_calories }} kcal ({{ $json.date }})"
      },
      "typeVersion": 2.1
    },
    {
      "id": "5594375b-55f7-43b5-b1ec-15856306f6ab",
      "name": "Overview",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -624,
        -160
      ],
      "parameters": {
        "width": 400,
        "height": 660,
        "content": "## Workout tracker with AI analysis\nLog your workouts through a simple form and get instant AI-powered feedback on calories burned, muscles worked, and what to train next.\n\n### How it works\n1. Fill in the form with what you did — free text like \"Bench press 60kg x10 x3, 5km run\"\n2. Gemini AI parses each exercise, identifies muscle groups, and estimates calorie burn\n3. A code node validates everything and fills gaps\n4. Results are saved to Google Sheets as a structured training log\n5. You get a Slack ping and email with a visual summary and tips for your next session\n\n### Setup steps\n1. **Google Sheets** — create a spreadsheet with a \"Workouts\" tab. Headers: Date, Workout, Duration, Feeling, Type, Exercises, Calories, Muscles, Intensity, Tips, Next Suggestion, Notes, Logged At\n2. **Gemini API** — grab a free key from Google AI Studio\n3. **Slack** — pick the channel for workout notifications\n4. **Gmail** — connect for email summaries\n5. Bookmark the form URL or share it with your gym buddy\n\n**Tip:** Works great on your phone between sets — just type what you did and submit."
      },
      "typeVersion": 1
    },
    {
      "id": "38b42b53-004a-4ebb-9144-03881b6e7108",
      "name": "Input and AI Section",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -208,
        -160
      ],
      "parameters": {
        "color": 7,
        "width": 664,
        "height": 540,
        "content": "## Log & analyze\nThe form captures your workout in plain text. Gemini breaks it down into individual exercises with muscle groups, sets, reps, and calorie estimates."
      },
      "typeVersion": 1
    },
    {
      "id": "6bdc7dff-2cc5-445c-a00c-fcaf3e06cbce",
      "name": "Process and Save Section",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        480,
        -160
      ],
      "parameters": {
        "color": 7,
        "width": 428,
        "height": 540,
        "content": "## Validate & save\nThe code node cleans the AI output and builds a structured record. Everything gets appended to your Google Sheet as a training log."
      },
      "typeVersion": 1
    },
    {
      "id": "0259d68f-a980-4138-879e-7849e2a4dfe6",
      "name": "Notify Section",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        928,
        -160
      ],
      "parameters": {
        "color": 7,
        "width": 280,
        "height": 540,
        "content": "## Notifications\nSlack for quick confirmation, email with a full breakdown including tips and next workout suggestion."
      },
      "typeVersion": 1
    }
  ],
  "connections": {
    "Google Gemini": {
      "ai_languageModel": [
        [
          {
            "node": "Analyze Workout with AI",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Parse AI Results": {
      "main": [
        [
          {
            "node": "Save to Workout Sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Workout Log Form": {
      "main": [
        [
          {
            "node": "Analyze Workout with AI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Build Summary Message": {
      "main": [
        [
          {
            "node": "Notify on Slack",
            "type": "main",
            "index": 0
          },
          {
            "node": "Email Summary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Save to Workout Sheet": {
      "main": [
        [
          {
            "node": "Build Summary Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Analyze Workout with AI": {
      "main": [
        [
          {
            "node": "Parse AI Results",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "settings": {},
  "active": false
}
