AutomationFlowsAI & RAG › Turn Telegram Into a French Fitness Coach with Claude, Openai and Google Sheets

Turn Telegram Into a French Fitness Coach with Claude, Openai and Google Sheets

Bymounir @annab on n8n.io

This workflow turns a Telegram chat into a French-speaking fitness and nutrition coach that can handle text or voice messages, use Anthropic for responses, log and read training/nutrition data in Google Sheets, and schedule workouts in Google Calendar. Triggers when a new…

Event trigger★★★★★ complexityAI-powered30 nodesTelegram TriggerTelegramOpenAIAnthropic ChatMemory Buffer WindowGoogle Sheets ToolAgentTool Workflow
AI & RAG Trigger: Event Nodes: 30 Complexity: ★★★★★ AI nodes: yes Added:

This workflow corresponds to n8n.io template #16610 — we link there as the canonical source.

This workflow follows the Agent → Google Calendar Tool recipe pattern — see all workflows that pair these two integrations.

The workflow JSON

Copy or download the full n8n JSON below. Paste it into a new n8n workflow, add your credentials, activate. Full import guide →

Download .json
{
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "nodes": [
    {
      "id": "c1fbec63-42c4-4c71-8320-30c46529c209",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2576,
        -800
      ],
      "parameters": {
        "width": 480,
        "height": 896,
        "content": "## Untitled workflow\n\n### How it works\n\nThis workflow acts as a Telegram-based sports coach that accepts either text or audio messages. It detects audio messages, downloads and transcribes them when needed, structures the user request, and sends it to an AI coach agent with memory plus Google Sheets, Google Calendar, and document-generation tools. The agent response is converted to speech with OpenAI text-to-speech, sent back as an audio file, and then followed by a Telegram response step.\n\n### Setup steps\n\n- Configure Telegram bot credentials for the trigger, audio download, and message/audio sending nodes.\n- Configure OpenAI credentials or authorization headers for audio transcription and the HTTP text-to-speech request to https://api.openai.com/v1/audio/speech.\n- Configure Anthropic credentials for the AI coach chat model.\n- Connect Google Sheets credentials and set the correct spreadsheet IDs, sheet names, ranges, and operation mappings for profile, program, session, and nutrition tools.\n- Connect Google Calendar credentials if the coach should create calendar events.\n- Configure the called workflows used by the document-generation tools for nutrition and workout session documents.\n- Review the Set node fields so chat_id, user_message, current date, and weekday match the Telegram payload format used by your bot.\n\n### Customization\n\nYou can customize the AI coach instructions, the Google Sheets schemas, the TTS voice/model, and the routing behavior for text versus audio messages. The document-generation tools can also be swapped for other workflows if you want different report formats."
      },
      "typeVersion": 1
    },
    {
      "id": "860e2099-d607-4ac6-88b0-360ef56bff8f",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -2016,
        -704
      ],
      "parameters": {
        "color": 7,
        "width": 496,
        "height": 320,
        "content": "## Receive and route messages\n\nReceives incoming Telegram messages and checks whether the user sent an audio message or a regular text message, branching the workflow accordingly."
      },
      "typeVersion": 1
    },
    {
      "id": "fd139133-dedf-420f-9e61-d9d6c63d7e28",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1408,
        -800
      ],
      "parameters": {
        "color": 7,
        "width": 816,
        "height": 432,
        "content": "## Normalize message content\n\nHandles the upper-left audio processing path by downloading Telegram audio, transcribing it with OpenAI, and then structuring either the transcribed audio or direct text into common fields for the coach agent."
      },
      "typeVersion": 1
    },
    {
      "id": "c45ab5e7-de7a-44ce-b7e3-4002698d0ec3",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1104,
        -336
      ],
      "parameters": {
        "color": 7,
        "width": 2080,
        "height": 704,
        "content": "## Run coach agent\n\nContains the central AI coach agent along with its Anthropic model and session memory, forming the core reasoning cluster that interprets the structured user request."
      },
      "typeVersion": 1
    },
    {
      "id": "16c7723e-fa9f-414c-88ac-ed5f66d5c612",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1104,
        400
      ],
      "parameters": {
        "color": 7,
        "width": 352,
        "height": 336,
        "content": "## Generate coach documents\n\nProvides the agent with nearby workflow tools for generating nutrition and workout session documents, visually grouped in the lower-left tool area."
      },
      "typeVersion": 1
    },
    {
      "id": "23cec783-fee2-4130-807d-c3336d0ae473",
      "name": "Sticky Note5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        48,
        400
      ],
      "parameters": {
        "color": 7,
        "width": 928,
        "height": 624,
        "content": "## Manage fitness records\n\nGroups the right-side tool cluster used by the agent to read and write profile, program, workout, nutrition, and plan data in Google Sheets, plus create Google Calendar events."
      },
      "typeVersion": 1
    },
    {
      "id": "61fca7ed-9d58-4868-8154-73a658957ebc",
      "name": "Sticky Note6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        80,
        -672
      ],
      "parameters": {
        "color": 7,
        "width": 864,
        "height": 304,
        "content": "## Speak and send reply\n\nConverts the coach output into speech through an OpenAI audio API request, sends the generated audio file via Telegram, and completes the reply flow with the final Telegram response node."
      },
      "typeVersion": 1
    },
    {
      "id": "1a8b85b1-eb14-498e-907d-4e631b1dc192",
      "name": "Telegram Message Received",
      "type": "n8n-nodes-base.telegramTrigger",
      "position": [
        -1968,
        -544
      ],
      "parameters": {
        "updates": [
          "message"
        ],
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    },
    {
      "id": "13f5da1f-2814-47c8-b5bb-e1000338f574",
      "name": "If Audio Message",
      "type": "n8n-nodes-base.if",
      "position": [
        -1664,
        -544
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "version": 3,
            "leftValue": "",
            "caseSensitive": true,
            "typeValidation": "loose"
          },
          "combinator": "or",
          "conditions": [
            {
              "id": "109f6a5b-0e8c-4ceb-ac22-376cc23408d4",
              "operator": {
                "type": "string",
                "operation": "notEmpty",
                "singleValue": true
              },
              "leftValue": "={{ $json.message.voice.file_unique_id }}",
              "rightValue": ""
            }
          ]
        },
        "looseTypeValidation": true
      },
      "typeVersion": 2.3
    },
    {
      "id": "0ef38a09-6c2e-43a6-9376-7059652f8241",
      "name": "Download Telegram Audio",
      "type": "n8n-nodes-base.telegram",
      "position": [
        -1360,
        -640
      ],
      "parameters": {
        "fileId": "={{ $json.message.voice.file_id }}",
        "resource": "file",
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "2bac0d70-dcf8-4172-b5b2-bf1801534cf2",
      "name": "OpenAI Audio Transcription",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        -1104,
        -640
      ],
      "parameters": {
        "options": {},
        "resource": "audio",
        "operation": "transcribe"
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.3
    },
    {
      "id": "9e288102-bfac-4df7-9f4b-50f50498939c",
      "name": "Set Structured Data",
      "type": "n8n-nodes-base.set",
      "position": [
        -736,
        -528
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "3b4e4024-aceb-40f8-a968-33741196298d",
              "name": "user_message",
              "type": "string",
              "value": "={{ $('Telegram Message Received').item.json.message.text || $json.text }}"
            },
            {
              "id": "544499e5-3d09-44ed-9314-4c9fd2b0597b",
              "name": "chat_id",
              "type": "string",
              "value": "={{ $('Telegram Message Received').item.json.message.chat.id }}"
            },
            {
              "id": "c86d4f8d-01f4-490d-8ebd-a7be90dbd91c",
              "name": "date-du-jour",
              "type": "string",
              "value": "={{ $now.toFormat('dd/MM/yyyy') }}"
            },
            {
              "id": "c95e263d-c0d1-49a1-8291-79219ea22867",
              "name": "jour_semaine",
              "type": "string",
              "value": "={{ $now.format('DDDD')  }}"
            }
          ]
        }
      },
      "typeVersion": 3.4
    },
    {
      "id": "5ed12882-970a-47b0-953f-d250fd28a3f2",
      "name": "Send Telegram Response",
      "type": "n8n-nodes-base.telegram",
      "position": [
        800,
        -544
      ],
      "parameters": {
        "text": "={{ $json.output }}",
        "chatId": "={{ $('If Audio Message').item.json.message.from.id }}",
        "additionalFields": {
          "appendAttribution": false
        }
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "e00e7041-ff38-47b1-bc66-a914491796fc",
      "name": "Claude Model Sonnet 4.6",
      "type": "@n8n/n8n-nodes-langchain.lmChatAnthropic",
      "position": [
        -384,
        16
      ],
      "parameters": {
        "model": {
          "__rl": true,
          "mode": "list",
          "value": "claude-sonnet-4-6",
          "cachedResultName": "Claude Sonnet 4.6"
        },
        "options": {}
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.5
    },
    {
      "id": "b577c7d3-6efd-4a7d-8b9d-0da18ff3ab71",
      "name": "Session Memory Buffer",
      "type": "@n8n/n8n-nodes-langchain.memoryBufferWindow",
      "position": [
        -224,
        16
      ],
      "parameters": {
        "sessionKey": "={{ $json.chat_id }}",
        "sessionIdType": "customKey",
        "contextWindowLength": 15
      },
      "typeVersion": 1.4
    },
    {
      "id": "4c8873b5-5108-48a0-bf3d-acc7a000ce89",
      "name": "Read Profile in Sheets",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        560,
        864
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit#gid=0",
          "cachedResultName": "Feuille 1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_ID_HERE",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit?usp=drivesdk",
          "cachedResultName": "coach sportif "
        },
        "descriptionType": "manual",
        "toolDescription": "\"Utile pour r\u00e9cup\u00e9rer le profil, les objectifs, le poids et les blessures d'un sportif \u00e0 partir de son ID Telegram unique (chat_id).\""
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "7fec6d3d-866b-4650-877b-bff4e519e321",
      "name": "Update Profile in Sheets",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        256,
        528
      ],
      "parameters": {
        "columns": {
          "value": {
            "objectif": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('objectif', ``, 'string') }}",
            "id_telegram": "={{ $('Set Structured Data').item.json.chat_id }}",
            "poids actuel": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('poids_actuel', ``, 'string') }}"
          },
          "schema": [
            {
              "id": "id_telegram",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "id_telegram",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "prenom_nom",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "prenom_nom",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "age",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "age",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Taille",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Taille",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "poids actuel",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "poids actuel",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Niveau",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Niveau",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "objectif",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "objectif",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "Blessure",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "Blessure",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "disponibilit\u00e9s",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "disponibilit\u00e9s",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "nombre_repas",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "nombre_repas",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "budget_repas",
              "type": "string",
              "display": true,
              "removed": true,
              "required": false,
              "displayName": "budget_repas",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id_telegram"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "update",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": "gid=0",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit#gid=0",
          "cachedResultName": "profil"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_ID_HERE",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit?usp=drivesdk",
          "cachedResultName": "coach sportif "
        },
        "descriptionType": "manual",
        "toolDescription": "Utile UNIQUEMENT pour modifier une donn\u00e9e pr\u00e9cise du profil quand l'utilisateur le demande EXPLICITEMENT (ex: 'change mon poids \u00e0 78kg', 'mon objectif est maintenant l'endurance'). Ne modifier QUE le champ explicitement demand\u00e9. NE JAMAIS utiliser cet outil de ta propre initiative, ni pour compl\u00e9ter des champs manquants, ni pour 'mettre \u00e0 jour' sans demande claire de l'utilisateur"
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "24644e6b-7c89-4b4f-b8af-6151d33afc51",
      "name": "Read Sessions in Sheets",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        704,
        864
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $('Set Structured Data').item.json.chat_id }}",
              "lookupColumn": "id_telegram"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 956054420,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit#gid=956054420",
          "cachedResultName": "Historique "
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_ID_HERE",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit?usp=drivesdk",
          "cachedResultName": "coach sportif "
        },
        "descriptionType": "manual",
        "toolDescription": " Utile pour CONSULTER l'historique des s\u00e9ances pass\u00e9es de l'utilisateur afin d'analyser sa progression (ex: comparer ses performances dans le temps, voir sa derni\u00e8re s\u00e9ance, son volume d'entra\u00eenement). \u00c0 utiliser quand l'utilisateur pose une question sur ses performances pass\u00e9es ou son \u00e9volution. NE PAS utiliser pour enregistrer une nouvelle s\u00e9ance \u2014 c'est le r\u00f4le de l'outil Journal S\u00e9ances."
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "1dedea19-bcef-4862-8541-1704d7ff23fa",
      "name": "Log Nutrition Data in Sheets",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        400,
        528
      ],
      "parameters": {
        "columns": {
          "value": {
            "date": "={{ $now.toFormat('dd/MM/yyyy')  }}",
            "repas": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('repas', ``, 'string') }}",
            "lipides": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('lipides', ``, 'string') }}",
            "calories": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('calories', ``, 'string') }}",
            "glucides": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('glucides', ``, 'string') }}",
            "proteines": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('proteines', ``, 'string') }}",
            "id_telegram": "={{ $('Set Structured Data').item.json.chat_id }}"
          },
          "schema": [
            {
              "id": "id_telegram",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "id_telegram",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "repas",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "repas",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "calories",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "calories",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "proteines",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "proteines",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "lipides",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "lipides",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "glucides",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "glucides",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1006477296,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit#gid=1+1234567890",
          "cachedResultName": "nutrition"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_ID_HERE",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit?usp=drivesdk",
          "cachedResultName": "coach sportif "
        },
        "descriptionType": "manual",
        "toolDescription": " Utile pour enregistrer un repas dans le journal de nutrition. \u00c0 utiliser uniquement quand l'utilisateur annonce ce qu'il a mang\u00e9 ou bu (un aliment, un repas, une boisson). Estimer les calories et macros (prot\u00e9ines, lipides, glucides) \u00e0 partir de sa description. Ne pas utiliser pour une question sur l'entra\u00eenement"
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "be9c9208-f7ad-4961-abf6-c04f34a8e358",
      "name": "AI Sports Coach Agent",
      "type": "@n8n/n8n-nodes-langchain.agent",
      "position": [
        -384,
        -224
      ],
      "parameters": {
        "text": "={{ $json.user_message }}",
        "options": {
          "maxIterations": 40,
          "systemMessage": "=# R\u00d4LE\nTu es un coach sportif personnel et expert en nutrition. Tu accompagnes l'utilisateur vers ses objectifs de forme avec un suivi rigoureux, personnalis\u00e9 et bienveillant. Tu t'exprimes TOUJOURS en fran\u00e7ais, sur un ton motivant, professionnel et exigeant.\n\n# POSTURE \u2014 \u00c9TAT D'ESPRIT DE D\u00c9VELOPPEMENT\nTu adoptes en permanence une mentalit\u00e9 de d\u00e9veloppement (growth mindset). Cette posture PRIME sur le ton motivant : tu restes exigeant et honn\u00eate, jamais flatteur.\n- Quand l'utilisateur rate une s\u00e9ance, stagne ou \u00e9choue, ne le rassure pas \u00e0 vide. Extrais la le\u00e7on concr\u00e8te de l'obstacle et donne-lui la prochaine action pr\u00e9cise. Un \u00e9chec est une donn\u00e9e, pas un verdict.\n- Reformule tout \u00ab je n'y arrive pas \u00bb ou \u00ab je suis nul \u00bb en \u00ab pas ENCORE \u00bb, et montre le chemin pour y arriver.\n- F\u00e9licite le PROCESSUS : l'effort, la r\u00e9gularit\u00e9, la m\u00e9thode, la pers\u00e9v\u00e9rance. Ne f\u00e9licite JAMAIS un talent suppos\u00e9 (\u00ab tu es dou\u00e9 \u00bb, \u00ab tu es fait pour \u00e7a \u00bb).\n- Traite la difficult\u00e9 comme le m\u00e9canisme NORMAL de la progression, jamais comme un signe d'incapacit\u00e9.\n- Quand l'utilisateur se d\u00e9valorise, ne valide JAMAIS la croyance limitante. Consulte Lecture S\u00e9ances pour lui rappeler des preuves concr\u00e8tes de sa progression pass\u00e9e, puis recentre-le sur la prochaine action.\n- Pointe clairement ce qui ne va pas, mais fais TOUJOURS suivre le \u00ab voici comment progresser \u00bb.\n\n# TES OUTILS\nTu disposes des outils suivants :\n- Lecture Profil : lire le profil (poids, objectif, niveau, blessures).\n- MAJ Profil : modifier une donn\u00e9e du profil (usage strict, voir r\u00e8gle de s\u00e9curit\u00e9).\n- \u00c9crit S\u00e9ance : enregistrer une s\u00e9ance r\u00e9alis\u00e9e (qui s'ajoute \u00e0 l'historique).\n- Lecture S\u00e9ances : consulter l'historique des s\u00e9ances pass\u00e9es.\n- \u00c9crit Nutrition : enregistrer un repas consomm\u00e9 (qui s'ajoute au journal).\n- \u00c9crit Plan Nutrition : cr\u00e9er/mettre \u00e0 jour le plan de repas et la liste de courses de la semaine.\n- \u00c9crit Plan Sport : cr\u00e9er/mettre \u00e0 jour le programme d'entra\u00eenement de la semaine.\n- Lecture Programme : consulter le programme d'entra\u00eenement de la semaine.\n\n# CONNAISSANCE DE L'UTILISATEUR\n- Avant de donner un conseil personnalis\u00e9, consulte le profil (Lecture Profil) pour conna\u00eetre le poids, l'objectif, le niveau et les blessures.\n- Tiens TOUJOURS compte des blessures : adapte les exercices pour ne jamais aggraver une blessure existante.\n- Le profil existe d\u00e9j\u00e0. Ne redemande une information que si une donn\u00e9e pr\u00e9cise est r\u00e9ellement absente.\n\n# SUIVI DE LA PROGRESSION\n- Quand l'utilisateur pose une question sur ses performances pass\u00e9es ou son \u00e9volution, consulte d'abord Lecture S\u00e9ances pour t'appuyer sur ses vraies donn\u00e9es, jamais sur des suppositions.\n\n# ENREGISTREMENT DES DONN\u00c9ES R\u00c9ALIS\u00c9ES\n- Quand l'utilisateur rapporte une s\u00e9ance termin\u00e9e (exercice, charge, r\u00e9p\u00e9titions), utilise \u00c9crit S\u00e9ance.\n\n- REPAS \u2014 R\u00c8GLE DE QUANTIT\u00c9 (\u00e0 appliquer AVANT tout enregistrement nutrition) :\n  - AVANT d'estimer les macros et d'enregistrer un repas, v\u00e9rifie que la quantit\u00e9 est pr\u00e9cis\u00e9e de fa\u00e7on exploitable (en grammes, ou en portions concr\u00e8tes : nombre de cuill\u00e8res, taille du bol ou de l'assiette, nombre d'unit\u00e9s).\n  - Si la quantit\u00e9 est absente ou trop vague pour une estimation fiable (ex : \u00ab un bol de riz \u00bb, \u00ab des p\u00e2tes \u00bb), DEMANDE la quantit\u00e9 approximative et N'ENREGISTRE RIEN tant que tu ne l'as pas obtenue. N'utilise pas \u00c9crit Nutrition \u00e0 ce stade.\n  - Une fois la quantit\u00e9 connue, estime de fa\u00e7on professionnelle les calories et macronutriments (prot\u00e9ines, glucides, lipides), puis utilise \u00c9crit Nutrition.\n  - Dans ta confirmation, indique bri\u00e8vement la quantit\u00e9 retenue comme base de calcul (ex : \u00ab Not\u00e9 : ~200 g de riz + 1 bo\u00eete de thon \u2192 \u2026 kcal \u00bb), pour que l'utilisateur puisse corriger si besoin.\n\n- Confirme tout enregistrement de mani\u00e8re br\u00e8ve et valorisante (en valorisant le PROCESSUS, pas un talent).\n\n# PLANS DE LA SEMAINE (NUTRITION ET SPORT)\n- Quand l'utilisateur demande un plan de repas / liste de courses pour la semaine, r\u00e9dige-le et enregistre-le avec \u00c9crit Plan Nutrition.\n- Quand l'utilisateur demande un programme d'entra\u00eenement pour la semaine, r\u00e9dige-le et enregistre-le avec \u00c9crit Plan Sport.\n- Ces plans REMPLACENT le plan pr\u00e9c\u00e9dent (ils ne s'accumulent pas).\n- Apr\u00e8s enregistrement, confirme simplement \u00e0 l'utilisateur que son plan est \u00e0 jour. Ne promets PAS de document \u00e0 t\u00e9l\u00e9charger.\n\n# MODIFICATION DU PROFIL (R\u00c8GLE DE S\u00c9CURIT\u00c9 STRICTE)\n- N'utilise MAJ Profil QUE si l'utilisateur demande EXPLICITEMENT de modifier une donn\u00e9e (ex : \u00ab mets \u00e0 jour mon poids \u00e0 78 kg \u00bb).\n- Ne modifie QUE le champ explicitement demand\u00e9.\n- N'utilise JAMAIS cet outil de ta propre initiative, ni pour compl\u00e9ter des champs manquants, ni pour \u00ab mettre \u00e0 jour \u00bb sans demande claire.\n\n# MISE EN FORME DES PLANS\n- Quand tu r\u00e9diges un plan (repas, courses ou programme sportif), \u00e9cris en texte simple (jamais de HTML ni de Markdown), tr\u00e8s a\u00e9r\u00e9 :\n  - une ligne vide entre chaque section et chaque jour ;\n  - s\u00e9parateurs en ligne de tirets : \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n  - titres de section en MAJUSCULES pr\u00e9c\u00e9d\u00e9s d'un emoji ;\n  - un seul \u00e9l\u00e9ment par ligne, commen\u00e7ant par \u00ab \u2022 \u00bb ;\n  - regroupe la liste de courses par cat\u00e9gorie (PROT\u00c9INES, F\u00c9CULENTS, L\u00c9GUMES\u2026).\n\n# GESTION DES MESSAGES VOCAUX\n- Les messages peuvent provenir de transcriptions audio. Ignore les fautes propres \u00e0 l'oral et concentre-toi sur l'intention.\n\n# STYLE DE R\u00c9PONSE\n- R\u00e9ponses claires, a\u00e9r\u00e9es, adapt\u00e9es \u00e0 Telegram. Termine souvent par une question ouverte pour entretenir l'engagement.\n\nDate actuelle : {{ $json['date-du-jour'] }}\nJour de la semaine : {{ $json.jour_semaine }}"
        },
        "promptType": "define"
      },
      "typeVersion": 3.1
    },
    {
      "id": "d3f5c95b-36e5-49cc-815b-cd127257654b",
      "name": "Read Program in Sheets",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        416,
        864
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "= {{  $('Set Structured Data').item.json.chat_id  }}",
              "lookupColumn": "id_telegram"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1060366421,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit#gid=1060366421",
          "cachedResultName": "plan_sport"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_ID_HERE",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit?usp=drivesdk",
          "cachedResultName": "coach sportif "
        },
        "descriptionType": "manual",
        "toolDescription": "Permet de lire le programme d'entra\u00eenement de la semaine de l'utilisateur (stock\u00e9 en texte). \u00c0 utiliser quand l'utilisateur demande quel est son programme, ce qu'il doit faire aujourd'hui, ou ce qui est pr\u00e9vu pour un jour pr\u00e9cis. NE PAS utiliser pour enregistrer ou modifier le programme \u2014 c'est le r\u00f4le de l'outil \u00c9crit Plan Sport. \u00bb"
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "a1f82ceb-cdf4-4180-aa82-6038c64741b2",
      "name": "Log Session Data in Sheets",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        528,
        528
      ],
      "parameters": {
        "columns": {
          "value": {
            "date": "={{ $now.toFormat('dd/MM/yyyy') }}",
            "exercice": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('exercice', ``, 'string') }}",
            "id_telegram": "={{ $('Set Structured Data').item.json.chat_id }}",
            "performance": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('performance', ``, 'string') }}"
          },
          "schema": [
            {
              "id": "id_telegram",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "id_telegram",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "exercice",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "exercice",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "performance",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "performance",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 956054420,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit#gid=956054420",
          "cachedResultName": "Historique "
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_ID_HERE",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit?usp=drivesdk",
          "cachedResultName": "coach sportif "
        },
        "descriptionType": "manual",
        "toolDescription": "Utile pour enregistrer une s\u00e9ance termin\u00e9e dans le journal d'historique. \u00c0 utiliser uniquement quand l'utilisateur annonce une performance qu'il vient de r\u00e9aliser (exercice, charge, r\u00e9p\u00e9titions). Ne pas utiliser pour une simple question ou une discussion."
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "858d37eb-3f1d-48fc-85b5-ef1528b6622e",
      "name": "Log Sport Plan in Sheets",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        832,
        528
      ],
      "parameters": {
        "columns": {
          "value": {
            "date_maj": "={{ $now.toFormat('dd/MM/yyyy') }}",
            "id_telegram": "={{  $('Set Structured Data').item.json.chat_id  }}",
            "programme_texte": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('programme_texte', ``, 'string') }}"
          },
          "schema": [
            {
              "id": "id_telegram",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "id_telegram",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "date_maj",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "date_maj",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "programme_texte",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "programme_texte",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id_telegram"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1060366421,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit#gid=1060366421",
          "cachedResultName": "plan_sport"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_ID_HERE",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit?usp=drivesdk",
          "cachedResultName": "coach sportif "
        },
        "descriptionType": "manual",
        "toolDescription": "Utile pour cr\u00e9er ou mettre \u00e0 jour le programme d'entra\u00eenement de la semaine de l'utilisateur. \u00c0 utiliser quand l'utilisateur demande un nouveau programme sportif, ou de modifier son programme existant. R\u00e9dige le programme_texte en texte clair et structur\u00e9 (jours, exercices, s\u00e9ries, r\u00e9p\u00e9titions, repos). NE PAS utiliser pour enregistrer une s\u00e9ance d\u00e9j\u00e0 r\u00e9alis\u00e9e \u2014 c'est le r\u00f4le de l'outil Journal/\u00c9crit S\u00e9ance. NE PAS utiliser pour la nutrition"
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "cba57f67-fc9e-4803-933b-808274ea1808",
      "name": "Log Nutrition Plan in Sheets",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        672,
        528
      ],
      "parameters": {
        "columns": {
          "value": {
            "date_maj": "={{ $now.toFormat('dd/MM/yyyy')  }}",
            "plan_repas": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('plan_repas', ``, 'string') }}",
            "id_telegram": "={{ $('Set Structured Data').item.json.chat_id }}",
            "liste_courses": "={{ /*n8n-auto-generated-fromAI-override*/ $fromAI('liste_courses', ``, 'string') }}"
          },
          "schema": [
            {
              "id": "id_telegram",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "id_telegram",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "date_maj",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": "date_maj",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "plan_repas",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "plan_repas",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "liste_courses",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "liste_courses",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "row_number",
              "type": "number",
              "display": true,
              "removed": true,
              "readOnly": true,
              "required": false,
              "displayName": "row_number",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            "id_telegram"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "appendOrUpdate",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1906655713,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit#gid=1906655713",
          "cachedResultName": "plan_nutrition"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_ID_HERE",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit?usp=drivesdk",
          "cachedResultName": "coach sportif "
        },
        "descriptionType": "manual",
        "toolDescription": "Utile pour cr\u00e9er ou mettre \u00e0 jour le plan nutritionnel de la semaine et la liste de courses de l'utilisateur. \u00c0 utiliser quand l'utilisateur demande un nouveau plan de la semaine, ou de modifier son plan existant (ex: changer un aliment). R\u00e9dige le plan_repas et la liste_courses en texte clair et structur\u00e9. NE PAS utiliser pour enregistrer un repas d\u00e9j\u00e0 mang\u00e9 \u2014 c'est le r\u00f4le de l'outil Journal Nutrition"
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "notesInFlow": false,
      "typeVersion": 4.7
    },
    {
      "id": "7b8d3d36-5209-48eb-99d5-c289ad36a367",
      "name": "Generate Nutrition Doc Workflow",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "position": [
        -1056,
        592
      ],
      "parameters": {
        "workflowId": {
          "__rl": true,
          "mode": "list",
          "value": "APkqyuadAutNkop8",
          "cachedResultUrl": "/workflow/APkqyuadAutNkop8",
          "cachedResultName": "G\u00e9n\u00e9ration Doc Nutrition"
        },
        "description": "G\u00e9n\u00e8re un document Google Doc lisible et imprimable contenant le plan nutritionnel et la liste de courses de l'utilisateur, et lui envoie le lien. \u00c0 utiliser UNIQUEMENT quand l'utilisateur demande explicitement son plan nutrition en version document, PDF, ou imprimable (ex: 'g\u00e9n\u00e8re mon doc', 'je veux mon plan en document', 'envoie-moi le lien de mon plan'). Le plan doit d\u00e9j\u00e0 avoir \u00e9t\u00e9 cr\u00e9\u00e9 au pr\u00e9alable",
        "workflowInputs": {
          "value": {
            " chat_id": "={{ $('Set Structured Data').item.json.chat_id  }}"
          },
          "schema": [
            {
              "id": " chat_id",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": " chat_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            " chat_id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "fbfab20a-870b-40f9-892b-27e9a4854ab5",
      "name": "Post Audio to OpenAI",
      "type": "n8n-nodes-base.httpRequest",
      "disabled": true,
      "position": [
        128,
        -544
      ],
      "parameters": {
        "url": "https://api.openai.com/v1/audio/speech",
        "method": "POST",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        },
        "sendBody": true,
        "authentication": "predefinedCredentialType",
        "bodyParameters": {
          "parameters": [
            {
              "name": "model",
              "value": "tts-1"
            },
            {
              "name": "voice",
              "value": "nova"
            },
            {
              "name": "input",
              "value": "={{ $json.output }}"
            },
            {
              "name": "response_format",
              "value": "opus"
            },
            {
              "name": "speed",
              "value": "1.15"
            }
          ]
        },
        "nodeCredentialType": "openAiApi"
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.4
    },
    {
      "id": "6d75eaf6-3ffc-49f1-a466-99423dad4997",
      "name": "Send Audio File to Telegram",
      "type": "n8n-nodes-base.telegram",
      "disabled": true,
      "position": [
        336,
        -544
      ],
      "parameters": {
        "chatId": "={{ $('Set Structured Data').item.json.chat_id }}",
        "operation": "sendAudio",
        "binaryData": true,
        "additionalFields": {}
      },
      "credentials": {
        "telegramApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "f9a79fd6-149d-49e6-999b-7065800ebd3e",
      "name": "Read Nutrition in Sheets",
      "type": "n8n-nodes-base.googleSheetsTool",
      "position": [
        848,
        864
      ],
      "parameters": {
        "options": {},
        "filtersUI": {
          "values": [
            {
              "lookupValue": "={{ $('Set Structured Data').item.json[\"date-du-jour\"] }}",
              "lookupColumn": "date"
            }
          ]
        },
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1006477296,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit#gid=1+1234567890",
          "cachedResultName": "nutrition"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_SHEET_ID_HERE",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/YOUR_SHEET_ID_HERE/edit?usp=drivesdk",
          "cachedResultName": "coach sportif "
        },
        "descriptionType": "manual",
        "toolDescription": "Utilise cet outil pour lire les repas enregistr\u00e9s par l'utilisateur dans son journal nutrition. Appelle-le d\u00e8s que l'utilisateur demande un r\u00e9sum\u00e9, un bilan ou un total de ce qu'il a mang\u00e9 (calories, prot\u00e9ines, lipides, glucides). L'outil retourne uniquement les repas du jour : pour chaque repas, le nom du plat et ses valeurs nutritionnelles (calories, prot\u00e9ines, lipides, glucides). Additionne ces lignes pour calculer le total de la journ\u00e9e."
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "c01a0c2c-f8f1-48ef-8bd7-04b449f0739f",
      "name": "Generate Session Doc Workflow",
      "type": "@n8n/n8n-nodes-langchain.toolWorkflow",
      "disabled": true,
      "position": [
        -880,
        576
      ],
      "parameters": {
        "workflowId": {
          "__rl": true,
          "mode": "list",
          "value": "APkqyuadAutNkop8",
          "cachedResultUrl": "/workflow/APkqyuadAutNkop8",
          "cachedResultName": "G\u00e9n\u00e9ration Doc Nutrition"
        },
        "description": "G\u00e9n\u00e8re un document Google Doc lisible et imprimable contenant le plan nutritionnel et la liste de courses de l'utilisateur, et lui envoie le lien. \u00c0 utiliser UNIQUEMENT quand l'utilisateur demande explicitement son plan nutrition en version document, PDF, ou imprimable (ex: 'g\u00e9n\u00e8re mon doc', 'je veux mon plan en document', 'envoie-moi le lien de mon plan'). Le plan doit d\u00e9j\u00e0 avoir \u00e9t\u00e9 cr\u00e9\u00e9 au pr\u00e9alable",
        "workflowInputs": {
          "value": {
            " chat_id": "={{ $('Set Structured Data').item.json.chat_id  }}"
          },
          "schema": [
            {
              "id": " chat_id",
              "type": "string",
              "display": true,
              "removed": false,
              "required": false,
              "displayName": " chat_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [
            " chat_id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        }
      },
      "typeVersion": 2.2
    },
    {
      "id": "4cbb3180-4a0f-4ddb-9183-34337860a019",
      "name": "Calendar Event Creator",
      "type": "n8n-nodes-base.googleCalendarTool",
      "position": [
        96,
        864
      ],
      "parameters": {
        "end": "={{ $fromAI('end_time', 'Date et heure de fin au format ISO 8601 AAAA-MM-JJTHH:MM:SS') }}",
        "start": "={{ $fromAI('start_time', 'Date et heure de d\u00e9but au format ISO 8601 AAAA-MM-JJTHH:MM:SS') }}",
        "calendar": {
          "__rl": true,
          "mode": "list",
          "value": "YOUR_EMAIL_HERE user@example.com",
          "cachedResultName": "YOUR_EMAIL_HERE user@example.com"
        },
        "descriptionType": "manual",
        "toolDescription": "Cr\u00e9e un \u00e9v\u00e9nement dans l'agenda de l'utilisateur pour programmer une s\u00e9ance de sport.\nUtilise cet outil quand l'utilisateur demande de planifier ou programmer une s\u00e9ance.\nLe champ Start doit \u00eatre au format ISO 8601 : AAAA-MM-JJTHH:MM:SS (exemple : 2026-06-24T18:00:00).\nCalcule la date \u00e0 partir de la date du jour fournie dans le contexte.",
        "additionalFields": {
          "summary": "={{ $fromAI('titre', 'Titre de la s\u00e9ance, ex: S\u00e9ance jambes') }}"
        }
      },
      "credentials": {
        "googleCalendarOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 1.3
    }
  ],
  "connections": {
    "If Audio Message": {
      "main": [
        [
          {
            "node": "Download Telegram Audio",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Set Structured Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Set Structured Data": {
      "main": [
        [
          {
            "node": "AI Sports Coach Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post Audio to OpenAI": {
      "main": [
        [
          {
            "node": "Send Audio File to Telegram",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Sports Coach Agent": {
      "main": [
        [
          {
            "node": "Post Audio to OpenAI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Session Memory Buffer": {
      "ai_memory": [
        [
          {
            "node": "AI Sports Coach Agent",
            "type": "ai_memory",
            "index": 0
          }
        ]
      ]
    },
    "Calendar Event Creator": {
      "ai_tool": [
        [
          {
            "node": "AI Sports Coach Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Read Profile in Sheets": {
      "ai_tool": [
        [
          {
            "node": "AI Sports Coach Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Read Program in Sheets": {
      "ai_tool": [
        [
          {
            "node": "AI Sports Coach Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Claude Model Sonnet 4.6": {
      "ai_languageModel": [
        [
          {
            "node": "AI Sports Coach Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Download Telegram Audio": {
      "main": [
        [
          {
            "node": "OpenAI Audio Transcription",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Read Sessions in Sheets": {
      "ai_tool": [
        [
          {
            "node": "AI Sports Coach Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Log Sport Plan in Sheets": {
      "ai_tool": [
        [
          {
            "node": "AI Sports Coach Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Read Nutrition in Sheets": {
      "ai_tool": [
        [
          {
            "node": "AI Sports Coach Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Update Profile in Sheets": {
      "ai_tool": [
        [
          {
            "node": "AI Sports Coach Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Telegram Message Received": {
      "main": [
        [
          {
            "node": "If Audio Message",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Session Data in Sheets": {
      "ai_tool": [
        [
          {
            "node": "AI Sports Coach Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Audio Transcription": {
      "main": [
        [
          {
            "node": "Set Structured Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send Audio File to Telegram": {
      "main": [
        [
          {
            "node": "Send Telegram Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Log Nutrition Data in Sheets": {
      "ai_tool": [
        [
          {
            "node": "AI Sports Coach Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Log Nutrition Plan in Sheets": {
      "ai_tool": [
        [
          {
            "node": "AI Sports Coach Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Generate Session Doc Workflow": {
      "ai_tool": [
        [
          {
            "node": "AI Sports Coach Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    },
    "Generate Nutrition Doc Workflow": {
      "ai_tool": [
        [
          {
            "node": "AI Sports Coach Agent",
            "type": "ai_tool",
            "index": 0
          }
        ]
      ]
    }
  }
}

Credentials you'll need

Each integration node will prompt for credentials when you import. We strip credential IDs before publishing — you'll add your own.

Pro

For the full experience including quality scoring and batch install features for each workflow upgrade to Pro

About this workflow

This workflow turns a Telegram chat into a French-speaking fitness and nutrition coach that can handle text or voice messages, use Anthropic for responses, log and read training/nutrition data in Google Sheets, and schedule workouts in Google Calendar. Triggers when a new…

Source: https://n8n.io/workflows/16610/ — original creator credit. Request a take-down →

More AI & RAG workflows → · Browse all categories →

Related workflows

Workflows that share integrations, category, or trigger type with this one. All free to copy and import.

AI & RAG

Telegram Trigger receives incoming messages (text, voice, photo, document). Switch routes by message type to appropriate processors: Text → forwarded as-is. Voice → downloaded and sent to Transcribe a

Memory Buffer Window, Telegram Trigger, Telegram +12
AI & RAG

Transform your Telegram messenger into a powerful, multi-modal personal or team assistant. This n8n workflow creates an intelligent agent that can understand text, voice, images, and documents, and ta

Memory Buffer Window, Telegram Trigger, Telegram +10
AI & RAG

Personal Assistant. Uses memoryBufferWindow, agent, agentTool, httpRequestTool. Event-driven trigger; 77 nodes.

Memory Buffer Window, Agent, Agent Tool +15
AI & RAG

Digital marketers, content creators, social media managers, and businesses who want to use AI marketing automation for YouTube Shorts without spending hours on production. This AI workflow helps anyon

OpenAI, HTTP Request, OpenAI Chat +7
AI & RAG

Jarvis is a powerful multi-agent productivity assistant built in n8n. It works directly from Telegram and can understand both text messages and voice notes.

Telegram Trigger, Telegram, OpenAI +10