使用Claude Opus AI将训练处方转换为Intervals.icu训练计
中级
这是一个自动化工作流,包含 15 个节点。主要使用 Set, Code, Form, FormTrigger, HttpRequest 等节点。 使用Claude Opus AI将训练处方转换为Intervals.icu训练计划
前置要求
- •可能需要目标 API 的认证凭证
- •Anthropic API Key
- •Google Gemini API Key
使用的节点 (15)
分类
-
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"meta": {
"instanceId": "558d88703fb65b2d0e44613bc35916258b0f0bf983c5d4730c00c424b77ca36a",
"templateCredsSetupCompleted": true
},
"nodes": [
{
"id": "232d0940-4045-4695-8778-94de0bc2b7d1",
"name": "Anthropic Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
"position": [
272,
-368
],
"parameters": {
"model": {
"__rl": true,
"mode": "list",
"value": "claude-opus-4-1-20250805",
"cachedResultName": "Claude Opus 4.1"
},
"options": {}
},
"credentials": {
"anthropicApi": {
"id": "mejeJHC4R5qtMoiT",
"name": "Anthropic account"
}
},
"typeVersion": 1.3
},
{
"id": "e5a6a854-ec35-4816-818a-dbc9c00e2843",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
400,
-368
],
"parameters": {
"autoFix": true,
"jsonSchemaExample": "{\n \"workoutDate\": \"2025-10-03T00:00:00\",\n \"workoutName\": \"Sweet Spot Intervals\",\n \"workoutType\": \"Ride\",\n \"workoutDescription\": \"Warmup bike ski or row 1x\\n- Steady pace 4m 70% HR\\n- Max pace 10s 94% HR\\n- Easy pace 10s 70% HR\\n- Max pace 10s 94% HR\\n- Easy pace 10s 70% HR\\n- Max pace 10s 94% HR\\n- Easy pace 10s 70% HR\\n\\nTransition 1x\\n- Press lap Transition (prep sled) 60s\\n\\nPrep circuit 1x\\n- Press lap sled push 12.5meter open weight -50kg 60s 79% HR\\n- Press lap reverse lunges 20x 60s 79% HR\\n- Rest 30s\\n- Press lap sled push 12.5meter open weight -25kg 60s 79% HR\\n- Press lap push ups 20x 60s 79% HR\\n- Rest 30s\\n- Press lap sled push 12.5meter open weight 60s 79% HR\\n\\nHYROX Power Circuits Part1 2x\\n- sled push 25meter open weight 120s 87% HR\\n- farmers carry 100meter open weight 120s 87% HR\\n\\nRest 1x\\n- Press lap Rest (change equipment) 2m\\n\\nHYROX Power Circuits Part2 2x\\n- sled pull 25meter open weight 180s 87% HR\\n- walking lunges 50meter open weight 180s 87% HR\\n\\nRest 1x\\n- Press lap Rest (change equipment) 2m\\n\\nHYROX Power Circuits Part3 2x\\n- burpee broad jumps 40meter 180s 87% HR\\n- wall balls 50x open weight 180s 87% HR\\n\\nTransition 1x\\n- Press lap Transition (prep machines) 60s\\n\\n4K HYROX Endurance ladder 1x\\n- Press lap Ski 1600meter (RPE7) 336s 79% HR\\n- Transition machine 10s\\n- Press lap Row 1200meter (RPE8) 252s 87% HR\\n- Transition machine 10s\\n- Press lap Ski 800meter (RPE9) 168s 94% HR\\n- Transition machine 10s\\n- Press lap Row 400meter (RPE10) 84s 100% HR\\n\\nCooldown 1x\\n- Press lap warm-down or stretch 5m 70% HR\",\n \"externalId\": \"1759502827683\"\n}"
},
"typeVersion": 1.3
},
{
"id": "9ff1c28a-ef81-4b85-a1e5-a35f8a9a9e72",
"name": "Google Gemini Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
480,
-160
],
"parameters": {
"options": {}
},
"credentials": {
"googlePalmApi": {
"id": "IJCXTRn68GrpA50A",
"name": "Google Gemini(PaLM) Api account"
}
},
"typeVersion": 1
},
{
"id": "bae4f2d6-2413-4290-8509-78a9795ffd57",
"name": "SetAthleteVars",
"type": "n8n-nodes-base.set",
"position": [
48,
-592
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "58bd3d54-d319-4149-af92-802d9e0f34ee",
"name": "max_hr",
"type": "string",
"value": "={{ $json.sportSettings[1].max_hr }} bpm"
},
{
"id": "4674a9ec-c0bf-475c-b0ec-8ec65785360e",
"name": "lt_hr",
"type": "string",
"value": "={{ $json.sportSettings[1].lthr }} bpm"
},
{
"id": "0e23cd48-2789-455d-b6be-02ca222ae30f",
"name": "=threshold_pace",
"type": "string",
"value": "={{ ((s) => { const t = 1000/s; return Math.floor(t/60) + ':' + Math.round(t%60).toString().padStart(2,'0'); })($json.sportSettings[1].threshold_pace) }} min/km"
},
{
"id": "7ba8e3c8-1985-443b-971c-7e8824552ac8",
"name": "ftp",
"type": "string",
"value": "={{ $json.sportSettings[1].ftp }} watt"
},
{
"id": "730d2580-ddd5-4c44-ba14-c11b4d0f7247",
"name": "sex",
"type": "string",
"value": "={{ $json.sex }}"
},
{
"id": "6a6bcdb7-d9e0-4004-aeda-66407133cb25",
"name": "date_of_birth",
"type": "string",
"value": "={{ $json.icu_date_of_birth }}"
},
{
"id": "5bdbf420-2d35-45b4-94d5-2bd6adfc31e4",
"name": "body_weight",
"type": "string",
"value": "={{ $json.icu_weight }}kg"
},
{
"id": "45c89252-a07a-48a3-90cf-3415e6fe823e",
"name": "timezone",
"type": "string",
"value": "={{ $json.timezone }}"
},
{
"id": "c31385d1-9425-4383-829b-5446b9dccac7",
"name": "height",
"type": "string",
"value": "={{ $json.height }}{{ $json.height_units }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "6a87d452-6479-491e-9777-d341fb713153",
"name": "CreateWorkoutForm",
"type": "n8n-nodes-base.formTrigger",
"position": [
-400,
-592
],
"webhookId": "8c4afc95-5d5c-4d95-9e11-5a2a74da76e3",
"parameters": {
"options": {
"appendAttribution": false
},
"formTitle": "Create workout",
"formFields": {
"values": [
{
"fieldType": "date",
"fieldLabel": "workoutdate",
"requiredField": true
},
{
"fieldLabel": "workouttitle",
"placeholder": "Workout title",
"requiredField": true
},
{
"fieldLabel": "workoutsteps",
"requiredField": true
}
]
}
},
"typeVersion": 2.3
},
{
"id": "992b87e0-46a8-4633-8530-e1408e5f6501",
"name": "GetAthleteInfo",
"type": "n8n-nodes-base.httpRequest",
"position": [
-176,
-592
],
"parameters": {
"url": "https://intervals.icu/api/v1/athlete/0/",
"options": {},
"sendHeaders": true,
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth",
"headerParameters": {
"parameters": [
{}
]
}
},
"credentials": {
"httpBasicAuth": {
"id": "yF78ePGsdnokCrNJ",
"name": "Intervals.ICU"
}
},
"typeVersion": 4.2
},
{
"id": "59c86cc4-b2b8-4252-99f8-8e2667432d59",
"name": "CreateIntervalsWorkoutAgent",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
304,
-592
],
"parameters": {
"text": "=WorkoutDate: {{ $('CreateWorkoutForm').item.json.workoutdate }}\nWorkoutTitle: {{ $('CreateWorkoutForm').item.json.workouttitle }}\nWorkoutDetails: {{ $('CreateWorkoutForm').item.json.workoutsteps }}\n\nAthleteDetails:\n- max_hr: {{ $('SetAthleteVars').item.json.max_hr }}\n- lt_hr: {{ $('SetAthleteVars').item.json.lt_hr }}\n- threshold_pace: {{ $('SetAthleteVars').item.json.threshold_pace }}\n- ftp: {{ $('SetAthleteVars').item.json.ftp }}\n- sex: {{ $('SetAthleteVars').item.json.sex }}\n- date_of_birth: {{ $('SetAthleteVars').item.json.date_of_birth }}\n- bodyweight: {{ $('SetAthleteVars').item.json.body_weight }}\n- height: {{ $('SetAthleteVars').item.json.height }}",
"options": {
"systemMessage": "=# Intervals.icu Workout Formatter\n\nYou convert training prescriptions into intervals.icu workout syntax and output as JSON. Detect workout type first, then apply appropriate formatting rules precisely.\n\n## Output Format\n\nReturn a JSON object with this exact structure:\n\n```json\n{\n \"workoutDate\": \"YYYY-MM-DDT00:00:00\",\n \"workoutName\": \"Workout Title\",\n \"workoutType\": \"Workout\",\n \"workoutDescription\": \"Formatted workout with \\\\n for line breaks\",\n \"externalId\": \"workout-name-kebab-case_timestamp\"\n}\n```\n\n### Field Specifications\n\n**workoutDate**: ISO date format (YYYY-MM-DDT00:00:00) from input date. if not date use today's date: {{ $now }}\n**workoutName**: Descriptive title from input (e.g., \"HYROX circuits\", \"Tempo run W2\")\n**workoutType**: Choose based on primary activity:\n\n## Workout Type Detection\n\nEndurance Sports:\nRide - Road cycling\nRun - Running\nSwim - Pool swimming\nVirtualRide - Indoor cycling (Zwift, etc.)\nTrailRun - Trail/mountain running\nOpenWaterSwim - Open water swimming\n\nIndoor/Virtual:\nVirtualRide - Zwift, TrainerRoad, Rouvy\nVirtualRun - Zwift running\nVirtualRow - Indoor rowing apps\n\nAlternative Cardio:\nElliptical - Elliptical trainer\nRowing - Rowing machine\nStairStepper - Stair climber\n\nStrength & Flexibility:\nWorkout - Generic workout\nWeightTraining - Gym/strength training\nYoga - Yoga\nPilates - Pilates\nCrossfit - CrossFit\n\nMulti-Sport:\nTransition - Triathlon transitions\n\n**workoutDescription**: Complete formatted workout as single string:\n- Use `\\n` for line breaks (not actual newlines)\n- Use `\\n\\n` for blank lines between sections\n- All formatting rules applied as text\n\n**externalId**: Unique identifier:\n- Format: `{workout-name-lowercase-with-hyphens}_{timestamp}`\n- Example: `hyrox-circuits-75min_1759504290592`\n- Remove special characters, convert spaces to hyphens\n\n\n## Conversion table\n\nUse the athlete info in combination with this table to identify the correct ranges/etc.\n\n# Complete Training Zones Table (RPE, HR, Power & Pace)\n\n| Zone | Level | RPE | %HRmax | %HR Drempel | %FTP | %Drempel Tempo | Modaliteit | Afstand | Drempels | Verschijnselen | RIR |\n|------|-------|-----|--------|-------------|------|----------------|------------|---------|----------|----------------|-----|\n| Z1 | 1 | 1 | 20 | 0-39% | 0-20% | 0-50% | Recovery | Oneindig | Vetverbranding | | No effort |\n| Z1 | 1 | 2 | 30 | 40-55% | 21-40% | 51-65% | Recovery | Oneindig | Vetverbranding | | Little effort |\n| Z1 | 1 | 3 | 40 | 56-70% | 41-50% | 66-72% | Recovery | Oneindig | Vetverbranding | | Light effort |\n| Z1 | 1 | 4 | 50 | 71-84% | 51-55% | 73-77.5% | Recovery | Oneindig | Vetverbranding | | Light effort |\n| Z2 | 2 | 5 | 60 | 85-86% | 56-65% | 78.5-82% | Aerobic | Oneindig | Aeroob | Verdieping en versnelling ademhaling | 6 RIR |\n| Z2 | 2 | 5.5 | 65 | 87-88% | 66-70% | 83-85% | Aerobic | Oneindig | Aeroob | Verdieping en versnelling ademhaling | 5 RIR |\n| Z2 | 2 | 6 | 70 | 89% | 71-75% | 86-87.7% | Aerobic | Ultramarathon | Aeroob | Verdieping en versnelling ademhaling | 4 RIR |\n| Z3 | 3 | 6.5 | 75 | 90-91% | 76-82% | 88.7-91% | Steady/Tempo | Ultramarathon | Alactisch | Verdieping ademhaling en zweten | 3RIR |\n| Z3 | 3 | 7 | 79 | 92-93% | 83-87% | 92-93% | Tempo | Marathon | Alactisch | Verdieping ademhaling en zweten | 3RIR |\n| Z3 | 3 | 7.5 | 83 | 94% | 88-90% | 93.5-94.3% | Tempo/threshold | Halve marathon | HYROX pace | Verdieping ademhaling en zweten | Definitely 2, maybe 3RIR |\n| Z4 | 4 | 8 | 87 | 95-97% | 91-97% | 95.3-97.5% | Threshold | 15K | Lactaatdrempel | Moeite met praten en rood aanlopen | 2RIR |\n| Z4 | 4 | 8.5 | 91 | 98-99% | 98-105% | 98-100% | Threshold | 10K | Lactisch | Moeite met praten en rood aanlopen | Definitely 1, maybe 2RIR |\n| Z5 | 4 | 9 | 94 | 100-101% | 106-113% | 101-102% | VO2max | 5K | Zwaar lactisch | Hijgen en stoppen met praten | 1RIR |\n| Z5 | 5 | 9.5 | 97 | 102% | 114-120% | 102.5-103.4% | VO2max/Sprint | 1K | Zwaar lactisch | Hijgen en stoppen met praten | No RIR, but could increase load |\n| Z6 | 5 | 10 | 100 | 103-105% | 121-150% | 104.4-111.5% | Anaerobic | <1K | Zwaar lactisch | Hijgen en stoppen met praten | Maximal effort |\n| Z7 | 5 | 10+ | 100+ | 106%+ | 151%+ | 112.5%+ | Neuromuscular | Sprint | Zwaar lactisch | Hijgen en stoppen met praten | Maximal effort |\n\n## Strength/Hybrid Formatting\n\n### Core Rules\n- Strength exercises: `- Press lap [Exercise] [weight info] [reps/distance] [time] [HR%/Zone] HR`\n- Cardio machines with work/rest: `- [activity] [pace info] [time] [HR%/Zone] HR` (NO \"Press lap\")\n- Cardio in circuits or standalone: `- Press lap [Machine] [distance/pace] [time] [HR%/Zone] HR`\n- Cardio warmup simple rounds: `- [activity] [time] [HR%/Zone] HR` (NO \"Press lap\")\n- Transitions: `Transition 1x` with `- Press lap Transition [time]`\n- Rest periods: `Rest 1x` with `- Press lap Rest ([description]) [time]`\n- Short rest in intervals: `- recovery [time] [HR%/Zone] HR` (no \"Press lap\")\n- Section headers: `[Descriptive name] [Rounds]x` (NO RPE in header for interval sets)\n- Weight modifiers: Outside parentheses (e.g., `open weight -50kg`)\n- Distance: Use \"meter\" not \"m\" \n- Parameters in parentheses: Only for RPE, pace, tempo after exercise name\n- Exercise names: Use lowercase for exercises (sled push, reverse lunges, push ups)\n- Machine names: Capitalize (Ski, Row, Bike)\n- Pace format: \"1:45/500meter\" (time per distance)\n- Strokes per minute: \"@20-25 strokes per minute\" or \"SPM\"\n- Preserve exact names from input when provided\n\n### Section Naming\n- Use descriptive names from input: \"HYROX Power Circuits Part1\", \"Prep circuit\", \"4K HYROX Endurance ladder\"\n- Only combine sections if it is a superset (e.g. \"C1. Box Jump Over\" and \"C2. Hang Squat Clean Thruster\")\n- Example: \"Row 6x\" and \"Ski 8x\" should be separate sections, not combined\n- Include context in section names: \"Warmup bike row or ski 1x\", \"Airbike 5x\"\n- Use \"Transition\" (English) not \"Transitie\"\n- Most sections: `[Name] 1x` or `[Name] Xx` (where X is number of rounds)\n- Some transition sections: Just `Transition` without 1x\n- Preserve spacing and capitalization from input\n\n### Transition Placement\nAdd \"Transition 1x\" sections between major workout blocks:\n- After warmup, before first main exercise\n- Between different activities (bike row, row → ski, etc.)\n- Between supersets (A → B → C → D → E → F)\n- Before cooldown\n- Format: `Transition 1x\\n- Press lap Transition 1m` (or other duration)\n\n**Example structure:**\n```\nWarmup 3x\n- easy bike or airbike 3m 60-70% HR\n\nTransition 1x\n- Press lap Transition 1m\n\nAirbike 5x\n- strides 30s 87-94% HR\n- recovery 30s 50% HR\n\nTransition 1x\n- Press lap Transition 1m\n\nRow 1x\n- steady row @20-25 strokes per minute 2m Z2 HR\n\nRow 6x\n- race pace 1:45/500meter 3m Z4 HR\n- easy recovery pace 2:00/500meter 90s Z2 HR\n\nTransition 1x\n- Press lap Transition 1m\n\nCooldown\n- Press lap easy bike 5m 60-70% HR\n```\n\n### Interval Expansion Rule\n**IMPORTANT: Only expand warmup intervals when explicitly structured as \"(Xx hard/easy)\" patterns.**\n\n**When to expand:**\n- Pattern: \"3x (10s hard / 10s easy)\" → Expand to 6 separate lines\n- Shows clear hard/easy alternating structure\n- When it is needed to keep integrity of the workout structure in the same section\n\n**When NOT to expand (use rounds instead):**\n- Simple repeated efforts: \"5x 30s strides with 30s recovery\" → Use rounds\n- Circuit format: Multiple rounds of same exercises\n- Interval sets with work/rest: Show as rounds with both work and rest\n\n**Warmup with rounds (do NOT expand):**\n```\nWarmup 3x\n- easy bike or airbike 3m 60-70% HR\n```\n\n**Interval set with rounds (do NOT expand):**\n```\nAirbike 5x\n- strides 30s 87-94% HR\n- recovery 30s 50% HR\n```\n\n**Row intervals with rounds (do NOT expand):**\n```\nRow 6x\n- race pace 1:45/500meter 3m Z4 HR\n- easy recovery pace 2:00/500meter 90s Z2 HR\n```\n\n**Pattern to expand (hard/easy in parentheses):**\nInput: \"4 min steady, then 3x (10s hard / 10s easy)\"\nOutput:\n```\n- Steady pace 4m 70% HR, 70% Pace\n- Max pace 10s 94% HR, 94% Pace\n- Easy pace 10s 70% HR, 70% Pace\n- Max pace 10s 94% HR, 94% Pace\n- Easy pace 10s 70% HR, 70% Pace\n- Max pace 10s 94% HR, 94% Pace\n- Easy pace 10s 70% HR, 70% Pace\n```\n\n**Zone notation:**\n- Use \"Z# HR\" format when input specifies zones (Z1, Z2, Z3, Z4, Z5, Z6, Z7)\n- Use \"XX% HR\" format when input specifies RPE or percentages\n- Use HR ranges when specified: \"60-70% HR\", \"87-94% HR\"\n- Use Pace ranges for running: \"60-70% Pace\", \"87-94% Pace\"\n- Preserve zone notation from input (don't convert zones to percentages)\n\n### \"Press lap\" Usage Rules\n**USE \"Press lap\":**\n- Circuit exercises (sections with \"circuit\" in name)\n- Machine work in circuits or as standalone exercises\n- Transitions: `- Press lap Transition 1m`\n- Rest sections: `- Press lap Rest (change equipment) 2m`\n- Cooldown activities: `- Press lap easy bike 5m 60-70% HR`\n\n**NO \"Press lap\":**\n- Warmup simple cardio rounds: `Warmup 3x\\n- easy bike or airbike 3m 60-70% HR`\n- Interval work/rest pairs in cardio sets:\n ```\n Airbike 5x\n - strides 30s 87-94% HR\n - recovery 30s 50% HR\n ```\n- Row/Ski interval sets:\n ```\n Row 6x\n - race pace 1:45/500meter 3m Z4 HR\n - easy recovery pace 2:00/500meter 90s Z2 HR\n ```\n- Steady-state cardio in interval sections:\n ```\n Row 1x\n - steady row @20-25 strokes per minute 2m Z2 HR\n ```\n- Machine transitions: `- Transition machine 10s`\n\n**Pattern detection:**\n- If section name contains \"circuit\" → Use \"Press lap\" for exercises\n- If section has rounds (5x, 6x, 8x) with work/rest pattern → NO \"Press lap\"\n- If activity is in Cooldown section → Use \"Press lap\"\n- If activity is standalone prep/steady → NO \"Press lap\"\n- If Transition section → Use \"Press lap\"\n\n### Time Allocation (seconds)\n- Warmup cardio: Based on actual duration\n- Strength exercises: 60-180s\n- Circuit exercises: 30-60s each\n- Sled push/pull: 60-180s\n- Machine work: Calculate from distance and pace\n- Transitions: 60s standard, 2m (120s) for equipment changes\n- Rest: 30s in circuits, 2m between major blocks\n\n### Supersets\nWhen a section is based on multiple alternating excercises (X1 & X2):\n\n**Input:** \n```\nC1. Box Jump Over\n2x12, RPE 6, rest 30s. \n\nC2. Hang Squat Clean Thruster\n2x6, RPE 7 (ca. 3 RIR)., rust 30s.\n```\n\n**Output:**\n```\nC Superset: Box Jump Over and Hang Squat Clean Thruster 2x\n- Press lap C1 box jump over 12x 60s 70% HR\n- Press lap C2 hang squat clean thruster 6x 90s 79% HR\n- Rest 30s\n```\n\n### Progressive Circuits\nWhen circuits show progression (e.g., changing weights), list as 1x with all steps:\n\n**Input:** `Prep circuit: 3 rounds with sled at -50kg, -25kg, then bodyweight`\n\n**Output:**\n```\nPrep circuit 1x\n- Press lap sled push 12.5meter open weight -50kg 60s 79% HR\n- Press lap reverse lunges 20x 60s 79% HR\n- Rest 30s\n- Press lap sled push 12.5meter open weight -25kg 60s 79% HR\n- Press lap push ups 20x 60s 79% HR\n- Rest 30s\n- Press lap sled push 12.5meter open weight 60s 79% HR\n```\n\n### Machine Transitions\nAdd explicit machine transition steps between different machines:\n```\n- Press lap Ski 1600meter (RPE7, 1:45 pace) 336s 79% HR\n- Transition machine 10s\n- Press lap Row 1200meter (RPE8, 1:45 pace) 252s 87% HR\n```\n\n### Structure Example (formatted as workoutDescription string)\n```\nWarmup 3x\\n- easy bike or airbike 3m 60-70% HR\\n\\nTransition 1x\\n- Press lap Transition 1m\\n\\nAirbike 5x\\n- strides 30s 87-94% HR\\n- recovery 30s 50% HR\\n\\nTransition 1x\\n- Press lap Transition 1m\\n\\nRow 1x\\n- steady row @20-25 strokes per minute 2m Z2 HR\\n\\nRow 6x\\n- race pace 1:45/500meter 3m Z4 HR\\n- easy recovery pace 2:00/500meter 90s Z2 HR\\n\\nTransition 1x\\n- Press lap Transition 1m\\n\\nSki 1x\\n- steady ski @30-35 strokes per minute 2m Z2 HR\\n\\nSki 8x\\n- race pace 1:40/500meter 2m Z4 HR\\n- easy recovery pace 2:00/500meter 1m Z2 HR\\n\\nTransition 1x\\n- Press lap Transition 1m\\n\\nCooldown\\n- Press lap easy bike 5m 60-70% HR\\n- Press lap stretches 10m Z2 HR\n```\n\n### Alternative: Strength Circuit Example\n```\nWarmup bike row or ski 1x\\n- Steady pace 4m 70% HR\\n- Max pace 10s 94% HR\\n- Easy pace 10s 70% HR\\n\\nTransition 1x\\n- Press lap Transition (prep sled) 60s\\n\\nPrep circuit 1x\\n- Press lap sled push 12.5meter open weight -50kg 60s 79% HR\\n- Press lap reverse lunges 20x 60s 79% HR\\n- Rest 30s\\n\\nHYROX Power Circuits Part1 2x\\n- sled push 25meter open weight 120s 87% HR\\n- farmers carry 100meter open weight 120s 87% HR\\n\\nRest 1x\\n- Press lap Rest (change equipment) 2m\\n\\nCooldown\\n- Press lap warm-down or stretch 5m 70% HR\n```\n\n### Complete JSON Example\n```json\n{\n \"workoutDate\": \"2024-12-19T00:00:00\",\n \"workoutName\": \"HYROX circuits\",\n \"workoutType\": \"strength\",\n \"workoutDescription\": \"Warmup bike row or ski 1x\\n- Steady pace 4m 70% HR\\n- Max pace 10s 94% HR\\n- Easy pace 10s 70% HR\\n\\nTransition 1x\\n- Press lap Transition (prep sled) 60s\\n\\nPrep circuit 1x\\n- Press lap sled push 12.5meter open weight -50kg 60s 79% HR\\n- Press lap reverse lunges 20x 60s 79% HR\\n- Rest 30s\\n\\nHYROX Power Circuits Part1 2x\\n- sled push 25meter open weight 120s 87% HR\\n- farmers carry 100meter open weight 120s 87% HR\\n\\nRest 1x\\n- Press lap Rest (change equipment) 2m\\n\\nCooldown\\n- Press lap warm-down or stretch 5m 70% HR\",\n \"externalId\": \"hyrox-circuits-75min_1759504290592\"\n}\n```\n\n## Running Formatting\n\n### Rules\n- NO \"Press lap\" prefix\n- NO transitions\n- Format: `- [Pace type] (RPE #) [pace min/km and km/h], [duration] [%Pace] Pace [%HR] HR`\n- Warmup section: `Warm up 1x` (with space)\n- Main section: `Main set 1x`\n- HR ranges allowed: `50-75% HR`\n\n### Structure Example (formatted as workoutDescription string)\n```\nWarm up 1x\\n- Personal mobilisation and activation exercises 5m 50% HR\\n\\nMain set 1x\\n- Easy pace (RPE 6) 5:30min/k, 10m 80% Pace 50-75% HR\\n- 15K pace (RPE 8-8,5) 4:55 min/k, 8m 90% Pace 87-91% HR\\n- Easy pace (RPE 6) 5:30min/k, 2m 80% Pace 75% HR\\n- 10K pace (RPE 9) 4:30 min/k, 4m 98% Pace 94% HR\\n\\nCooldown\\n- Easy pace jog or walk (RPE 6) 5:30min/k, 5m 80% Pace 50-70% HR\n```\n\n### Complete JSON Example (Running)\n```json\n{\n \"workoutDate\": \"2025-10-02T00:00:00\",\n \"workoutName\": \"Tempo run W2\",\n \"workoutType\": \"Run\",\n \"workoutDescription\": \"Warm up 1x\\n- Personal mobilisation and activation exercises 5m 50% HR\\n\\nMain set 1x\\n- Easy pace (RPE 6) 5:30min/k, 10m 80% Pace 50-75% HR\\n- 15K pace (RPE 8-8,5) 4:55 min/k, 8m 90% Pace 87-91% HR\\n- Easy pace (RPE 6) 5:30min/k, 2m 80% Pace 75% HR\\n- 10K pace (RPE 9) 4:30 min/k, 4m 98% Pace 94% HR\\n- Easy pace (RPE 6) 5:30min/k, 1m 80% Pace 75% HR\\n\\nCooldown\\n- Easy pace jog or walk (RPE 6) 5:30min/k, 5m 80% Pace 50-70% HR\",\n \"externalId\": \"tempo-run-w2-35min_1728123456789\"\n}\n```\n\n## Processing Steps\n\n1. **Extract metadata from input**:\n - **Date**: Look for date patterns (e.g., \"27th September, 2025\", \"October 2, 2025\")\n - Convert to ISO format: YYYY-MM-DDT00:00:00\n - If no date found, use \"2025-10-03T00:00:00\" (current date)\n - **Workout name**: Extract from title line (e.g., \"**Tempo run W2 (35 min.)**\" → \"Tempo run W2\")\n - Remove formatting (**, parentheses with duration)\n - Keep week numbers (#2, W2, Week 2)\n - **Workout type**: Analyze content to determine correct type\n - Strength/hybrid/HYROX → `Workout`\n - Running with paces → `Run`\n - Cycling → `Ride` or `VirtualRide`\n - Default → `Workout`\n\n2. **Parse workout sections**: Identify warmup, main blocks (A, B, C, etc.), cooldown\n - Preserve section names from input\n - Note if circuits, supersets, or progressive\n\n3. **Check for special patterns**: \n - Warmup intervals to expand (steady/hard/easy)\n - Progressive circuits (changing weights/loads)\n - Supersets (X1/X2)\n - Machine sequences (need \"Transition machine\" steps)\n - Long rest periods (need descriptions in Rest sections)\n\n4. **Extract exercise details**: For each exercise get:\n - Name, sets×reps, RPE, weight, distance, duration, tempo, RIR\n\n5. **Expand intervals**: Convert warmup patterns like \"3x (10s hard / 10s easy)\" into separate pace lines\n\n6. **Apply formatting rules**: \n - Use correct section headers with rounds\n - Apply \"Press lap\" rules based on section type\n - Format weight info outside parentheses\n - Use \"meter\" not \"m\"\n - Add Transition/Rest sections with descriptions\n\n7. **Convert all values**: \n - Sets → rounds in header (1x for progressions)\n - Reps → \"Xx\" format \n - Time → seconds (s) or minutes (m)\n - RPE → HR percentage\n - Calculate machine work time from distance + pace\n\n8. **Add transition steps**: Between machines and between major workout blocks and between supersets\n\n9. **Build workoutDescription**: \n - Combine all formatted lines\n - Use `\\n` for single line breaks\n - Use `\\n\\n` for blank lines between sections\n - Ensure proper JSON escaping\n\n10. **Generate externalId**: \n - Convert workout name to lowercase\n - Replace spaces with hyphens\n - Remove special characters\n - Add underscore + Unix timestamp (milliseconds, 13 digits)\n - Example: \"Tempo run W2\" → \"tempo-run-w2_1728123456789\"\n\n11. **Output JSON**: Return complete, valid JSON object with all fields\n\n## Critical Requirements\n\n**JSON Output:**\n- ✓ Always return valid JSON object\n- ✓ Use `\\n` for line breaks in workoutDescription\n- ✓ Use `\\n\\n` for blank lines between sections\n- ✓ Include all required fields: workoutDate, workoutName, workoutType, workoutDescription, externalId\n- ✓ workoutType must be on of the allowed values\n- ✓ externalId format: workout-name-kebab-case_timestamp\n\n**Strength/Hybrid:**\n- ✓ Use descriptive section names from input\n- ✓ \"Transition\" (English) not \"Transitie\"\n- ✓ \"Press lap\" for strength exercises and machines with distance/pace\n- ✓ NO \"Press lap\" for warmup pace intervals or short rest\n- ✓ Weight info outside parentheses: `open weight -50kg`\n- ✓ Distance as \"meter\" not \"m\"\n- ✓ Expand warmup intervals with pace descriptors (Steady/Max/Easy pace)\n- ✓ Progressive circuits as 1x with all steps listed\n- ✓ Add \"Transition machine 10s\" between machine changes\n- ✓ Long rest as \"Rest 1x\" sections with descriptions\n- ✓ NO RPE in superset headers\n- ✓ Capitalize section headers: Transition, Rest, Warmup, Cooldown\n- ✓ Include contextual descriptions in parentheses for transitions/rest\n\n**Running:**\n- ✓ Start \"Warm up 1x\" (with space), end \"Cooldown\" \n- ✓ Main section always \"Main set 1x\"\n- ✓ NO \"Press lap\", NO transitions\n- ✓ Include: pace (min/k), %Pace, %HR\n- ✓ HR ranges allowed (50-75%)\n\nOutput only the JSON object. Do not include explanatory text before or after the JSON."
},
"promptType": "define",
"hasOutputParser": true
},
"typeVersion": 2.2
},
{
"id": "19bd22df-5298-4d3f-9a4c-5d5d300b4519",
"name": "PrepareAgentOutputToWorkoutArray",
"type": "n8n-nodes-base.code",
"position": [
768,
-592
],
"parameters": {
"jsCode": "const items = [];\n\nfor (const output of $input.all()) {\n const workoutArray = [{\n \"category\": \"WORKOUT\",\n \"type\": output.json.output.workoutType,\n \"start_date_local\": output.json.output.workoutDate,\n \"name\": output.json.output.workoutName,\n \"description\": output.json.output.workoutDescription,\n \"external_id\": output.json.output.externalId\n }];\n \n items.push({\n json: { workoutArray: workoutArray }\n });\n}\n\nreturn items;"
},
"typeVersion": 2
},
{
"id": "00a1a6c1-7b1c-4c35-97d9-844804747141",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"position": [
-624,
-720
],
"parameters": {
"color": 4,
"width": 352,
"height": 288,
"content": "## Start form\n- workout date\n- workout title\n- workout description"
},
"typeVersion": 1
},
{
"id": "7eec26e9-c791-437f-a208-59814af6497c",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"position": [
-240,
-720
],
"parameters": {
"width": 448,
"height": 288,
"content": "## Get athlete info from intervals.icu\n- get through API\n- convert to usable format"
},
"typeVersion": 1
},
{
"id": "db6641a3-b428-4175-bf0b-c6b0b06b4f97",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"position": [
240,
-864
],
"parameters": {
"width": 416,
"height": 848,
"content": "## 🏋️ Workout Formatter for Intervals.icu\nConverts training prescriptions → structured intervals.icu JSON format\n✅ Handles: Running, Strength, HYROX, Cycling workouts\n✅ Auto-detects workout type\n✅ Formats with proper HR zones, pace, RPE conversion\n✅ Adds transitions, rest periods, circuit formatting\n✅ Outputs: JSON with workout steps ready for import\nUses Claude Opus 4.1 + structured output parser"
},
"typeVersion": 1
},
{
"id": "255b3d8a-41e4-4162-b971-e14ead4c6c8d",
"name": "Sticky Note3",
"type": "n8n-nodes-base.stickyNote",
"position": [
688,
-720
],
"parameters": {
"width": 448,
"height": 288,
"content": "## Get athlete info from intervals.icu\n- convert output array to workout array for API\n- call API to create workout"
},
"typeVersion": 1
},
{
"id": "2766727f-d1cb-45ba-9285-86b7ee73c66e",
"name": "Sticky Note4",
"type": "n8n-nodes-base.stickyNote",
"position": [
1168,
-720
],
"parameters": {
"color": 4,
"width": 352,
"height": 288,
"content": "## End form\n- simple form to mention workout is created"
},
"typeVersion": 1
},
{
"id": "87972403-864d-4c3f-8b6d-5a8eac81fc3a",
"name": "CreateWorkoutAPI",
"type": "n8n-nodes-base.httpRequest",
"position": [
992,
-592
],
"parameters": {
"url": "https://intervals.icu/api/v1/athlete/0/events/bulk?upsert=true",
"method": "POST",
"options": {
"response": {
"response": {
"responseFormat": "json"
}
}
},
"jsonBody": "={{ $json.workoutArray }}",
"sendBody": true,
"specifyBody": "json",
"authentication": "genericCredentialType",
"genericAuthType": "httpBasicAuth"
},
"credentials": {
"httpBasicAuth": {
"id": "yF78ePGsdnokCrNJ",
"name": "Intervals.ICU"
}
},
"typeVersion": 4.2
},
{
"id": "acdfa69d-bf35-4150-8eca-536b68900bb9",
"name": "TheEndForm",
"type": "n8n-nodes-base.form",
"position": [
1200,
-592
],
"webhookId": "295cf9c2-8afb-4840-8a52-75223bea5f27",
"parameters": {
"options": {},
"operation": "completion",
"completionTitle": "The End - Bye"
},
"typeVersion": 2.3
}
],
"pinData": {},
"connections": {
"992b87e0-46a8-4633-8530-e1408e5f6501": {
"main": [
[
{
"node": "bae4f2d6-2413-4290-8509-78a9795ffd57",
"type": "main",
"index": 0
}
]
]
},
"bae4f2d6-2413-4290-8509-78a9795ffd57": {
"main": [
[
{
"node": "59c86cc4-b2b8-4252-99f8-8e2667432d59",
"type": "main",
"index": 0
}
]
]
},
"87972403-864d-4c3f-8b6d-5a8eac81fc3a": {
"main": [
[
{
"node": "acdfa69d-bf35-4150-8eca-536b68900bb9",
"type": "main",
"index": 0
}
]
]
},
"6a87d452-6479-491e-9777-d341fb713153": {
"main": [
[
{
"node": "992b87e0-46a8-4633-8530-e1408e5f6501",
"type": "main",
"index": 0
}
]
]
},
"232d0940-4045-4695-8778-94de0bc2b7d1": {
"ai_languageModel": [
[
{
"node": "59c86cc4-b2b8-4252-99f8-8e2667432d59",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"9ff1c28a-ef81-4b85-a1e5-a35f8a9a9e72": {
"ai_languageModel": [
[
{
"node": "e5a6a854-ec35-4816-818a-dbc9c00e2843",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"e5a6a854-ec35-4816-818a-dbc9c00e2843": {
"ai_outputParser": [
[
{
"node": "59c86cc4-b2b8-4252-99f8-8e2667432d59",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"59c86cc4-b2b8-4252-99f8-8e2667432d59": {
"main": [
[
{
"node": "19bd22df-5298-4d3f-9a4c-5d5d300b4519",
"type": "main",
"index": 0
}
]
]
},
"19bd22df-5298-4d3f-9a4c-5d5d300b4519": {
"main": [
[
{
"node": "87972403-864d-4c3f-8b6d-5a8eac81fc3a",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
中级
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
基于AI的社交媒体内容生成与发布
基于AI的社交媒体内容生成与发布
Set
Code
Form
+
Set
Code
Form
26 节点Amjid Ali
人工智能
基于AI的YouTube元数据生成器(GPT-4o、Gemini与内容增强)
基于AI的YouTube元数据生成器(GPT-4o、Gemini与内容增强)
Set
Xml
Code
+
Set
Xml
Code
37 节点Amjid Ali
人工智能
使用 Gemini 和 Jina AI 自动化供应商尽职调查研究
使用 Gemini 和 Jina AI 自动化供应商尽职调查研究
If
Set
Code
+
If
Set
Code
27 节点Adnan
文档提取
在可视化参考库中探索n8n节点
在可视化参考库中探索n8n节点
If
Ftp
Set
+
If
Ftp
Set
113 节点I versus AI
其他
✨🤖 自动化AI驱动的社交媒体内容工厂,适用于X + Facebook + Instagram + LinkedIn
✨🤖 使用AI自动化多平台社交媒体内容创建
If
Set
Code
+
If
Set
Code
57 节点Joseph LePage
人工智能
AI内容创作与WordPress自动发布 - Pexels API图像工作流
基于Pexels API图像的AI内容创作与WordPress自动发布工作流
If
Set
Form
+
If
Set
Form
30 节点Mateusz Kosiorek
人工智能