1 line
39 KiB
JSON
1 line
39 KiB
JSON
{"updatedAt":"2025-11-30T14:49:06.937Z","createdAt":"2025-11-30T14:22:03.470Z","id":"jZIoYr8RW41K0j4J","name":"tg_callbacks","active":false,"isArchived":false,"nodes":[{"parameters":{"content":"# нажал ДА = ВЫБЕРИ ВЕС","height":292,"width":1178,"color":4},"id":"8cbb64b7-c351-4b48-8870-6c6ec65498c7","name":"Sticky Note5","type":"n8n-nodes-base.stickyNote","position":[0,448],"typeVersion":1},{"parameters":{"updates":["*"],"additionalFields":{}},"type":"n8n-nodes-base.telegramTrigger","typeVersion":1.2,"position":[-624,1152],"id":"de564fd6-34c6-4a15-acbb-416dcb225a40","name":"Telegram Trigger","webhookId":"e4d6b058-dc8c-4130-9abd-41243518e824","credentials":{"telegramApi":{"id":"R8VDF53JH3mzhoHd","name":"Telegram dieta"}}},{"parameters":{"rules":{"values":[{"conditions":{"options":{"caseSensitive":true,"leftValue":"","typeValidation":"strict","version":2},"conditions":[{"id":"52493568-0b68-46b8-b18a-894cf77bcac1","leftValue":"={{$json.callback_query.data}}","rightValue":"manual_","operator":{"type":"string","operation":"startsWith"}}],"combinator":"and"},"renameOutput":true,"outputKey":"manual"},{"conditions":{"options":{"caseSensitive":true,"leftValue":"","typeValidation":"strict","version":2},"conditions":[{"id":"5eeb9b3f-d4ce-45f6-bb62-32244fd9a99a","leftValue":"={{ $json.message.photo[0] }}","rightValue":"","operator":{"type":"object","operation":"exists","singleValue":true}}],"combinator":"and"},"renameOutput":true,"outputKey":"image"},{"conditions":{"options":{"caseSensitive":true,"leftValue":"","typeValidation":"strict","version":2},"conditions":[{"id":"2f1495ad-2eb2-4729-af5a-23c949adce8c","leftValue":"={{$json.callback_query.data}}","rightValue":"dish_yes_","operator":{"type":"string","operation":"startsWith"}}],"combinator":"and"},"renameOutput":true,"outputKey":"dish_yes"},{"conditions":{"options":{"caseSensitive":true,"leftValue":"","typeValidation":"strict","version":2},"conditions":[{"leftValue":"={{$json.callback_query.data}}","rightValue":"dish_no_","operator":{"type":"string","operation":"startsWith"},"id":"c9ead52e-1b81-453a-bd9b-1d18dcbd82bb"}],"combinator":"and"},"renameOutput":true,"outputKey":"dish_no"},{"conditions":{"options":{"caseSensitive":true,"leftValue":"","typeValidation":"strict","version":2},"conditions":[{"id":"646db5d3-3518-4edf-9374-cef371fa7ba9","leftValue":"={{$json.callback_query.data}}","rightValue":"alt_","operator":{"type":"string","operation":"startsWith"}}],"combinator":"and"},"renameOutput":true,"outputKey":"alt"},{"conditions":{"options":{"caseSensitive":true,"leftValue":"","typeValidation":"strict","version":2},"conditions":[{"id":"1bcf1e75-3e73-465b-8bbb-2665b845e7e9","leftValue":"={{$json.callback_query.data}}","rightValue":"weight_","operator":{"type":"string","operation":"startsWith"}}],"combinator":"and"},"renameOutput":true,"outputKey":"weight"},{"conditions":{"options":{"caseSensitive":true,"leftValue":"","typeValidation":"strict","version":2},"conditions":[{"id":"90573faf-164a-418f-a4a8-b69d3e7aaf3d","leftValue":"={{$json.callback_query.data}}","rightValue":"cancel_","operator":{"type":"string","operation":"startsWith"}}],"combinator":"and"},"renameOutput":true,"outputKey":"cancel"},{"conditions":{"options":{"caseSensitive":true,"leftValue":"","typeValidation":"strict","version":2},"conditions":[{"id":"6166763a-38e9-494a-aea0-20bdc9626314","leftValue":"={{ $json.message.text }}","rightValue":"/","operator":{"type":"string","operation":"exists","singleValue":true}}],"combinator":"and"},"renameOutput":true,"outputKey":"text_cmd"}]},"options":{}},"type":"n8n-nodes-base.switch","typeVersion":3.2,"position":[-416,1040],"id":"77416214-f1c4-4160-ae59-2c266ceec40b","name":"Switch"},{"parameters":{"jsCode":"// alt_0_7 → parts = ['alt','0','7']\nconst [, idx, id] = $json.callback_query.data.split('_');\n\nreturn [{\n json: {\n chat_id : $json.callback_query.message.chat.id, // ID чата, где лежит сообщение-клавиатура\n draft_id : Number(id), // 7\n alt_idx : Number(idx), // 0 / 1 / 2\n del_msg_id : $json.callback_query.message.message_id // ID сообщения, которое надо удалить\n }\n}];\n"},"type":"n8n-nodes-base.code","typeVersion":2,"position":[64,1168],"id":"f0f7a047-5dd6-47e0-b420-22f1d2d4b244","name":"Parse alt"},{"parameters":{"operation":"get","tableId":"meals_draft","filters":{"conditions":[{"keyName":"chat_id","keyValue":"={{$json.chat_id}}"},{"keyName":"message_id","keyValue":"={{$json.draft_id}}"},{"keyName":"status","keyValue":"await_alt"}]}},"type":"n8n-nodes-base.supabase","typeVersion":1,"position":[448,1168],"id":"dc33c3e0-b25b-415d-bef5-8fd1eb637e90","name":"GET 3","credentials":{"supabaseApi":{"id":"OoOx3pPUNd1lRJTr","name":"Supabase account"}}},{"parameters":{"operation":"update","tableId":"meals_draft","filters":{"conditions":[{"keyName":"chat_id","condition":"eq","keyValue":"={{ $json.chat_id }}"},{"keyName":"message_id","condition":"eq","keyValue":"={{$json.draft_id}}"}]},"fieldsUi":{"fieldValues":[{"fieldId":"chosen_name","fieldValue":"={{$json.dish_ru}}"},{"fieldId":"grams_pred","fieldValue":"={{$json.grams_est}}"},{"fieldId":"status","fieldValue":"await_weight"},{"fieldId":"updated_at","fieldValue":"={{ new Date().toISOString() }}"}]}},"type":"n8n-nodes-base.supabase","typeVersion":1,"position":[768,1184],"id":"f2b7c43e-769e-414d-b91b-7d9b010278bb","name":"UPDATE 3","credentials":{"supabaseApi":{"id":"OoOx3pPUNd1lRJTr","name":"Supabase account"}}},{"parameters":{"content":"# нажал НЕТ + ЕЩЕ 2 варианта","height":292,"width":1178,"color":3},"id":"4f107a54-cfa4-468d-a5d8-26f381e91e82","name":"Sticky Note","type":"n8n-nodes-base.stickyNote","position":[0,768],"typeVersion":1},{"parameters":{"content":"# нажал на 1/2 = ВЫБЕРИ ВЕС","height":292,"width":1178,"color":3},"id":"54fcc08b-bf5c-4e18-b972-8327f858ddf7","name":"Sticky Note1","type":"n8n-nodes-base.stickyNote","position":[0,1088],"typeVersion":1},{"parameters":{"content":"# РЕЗУЛЬТАТ\n\n","height":392,"width":1758,"color":4},"id":"8fb8dda2-b400-40e0-81bd-fdedfd69df23","name":"Sticky Note2","type":"n8n-nodes-base.stickyNote","position":[0,1408],"typeVersion":1},{"parameters":{"operation":"update","tableId":"meals_draft","filters":{"conditions":[{"keyName":"chat_id","condition":"eq","keyValue":"={{ $json.chat_id }}"},{"keyName":"message_id","condition":"eq","keyValue":"={{$json.draft_id}}"}]},"fieldsUi":{"fieldValues":[{"fieldId":"grams_pred","fieldValue":"={{$json.grams}}"},{"fieldId":"status","fieldValue":"done"},{"fieldId":"updated_at","fieldValue":"={{ new Date().toISOString() }}"}]}},"type":"n8n-nodes-base.supabase","typeVersion":1,"position":[1392,1632],"id":"981f62eb-7550-4756-825f-1377dffc59fd","name":"UPDATE 4","credentials":{"supabaseApi":{"id":"OoOx3pPUNd1lRJTr","name":"Supabase account"}}},{"parameters":{"chatId":"={{$json.chat_id}}","text":"=*{{ $json.dish }} – {{ $json.grams }} г*\n\n*Калорий:* {{ $json.kcal }}\n*Б:* {{ $json.prot }} *Ж:* {{ $json.fat }} *У:* {{ $json.carb }}\n\n✔️ _сохранил в память_","replyMarkup":"inlineKeyboard","inlineKeyboard":{"rows":[{"row":{"buttons":[{"text":"🚫 не сохранять","additionalFields":{"callback_data":"=cancel_{{ $json.id }}"}}]}}]},"additionalFields":{"appendAttribution":false,"parse_mode":"Markdown"}},"type":"n8n-nodes-base.telegram","typeVersion":1.2,"position":[1568,1440],"id":"d9c2dc63-f07a-4732-8c43-a8e2ea1881e6","name":"DONE","webhookId":"54ba5fcc-0866-4f93-aa38-bad03e1710e6","credentials":{"telegramApi":{"id":"R8VDF53JH3mzhoHd","name":"Telegram dieta"}}},{"parameters":{"operation":"get","tableId":"meals_draft","filters":{"conditions":[{"keyName":"chat_id","keyValue":"={{$json.chat_id}}"},{"keyName":"message_id","keyValue":"={{$json.draft_id}}"},{"keyName":"status","keyValue":"await_dish"}]}},"type":"n8n-nodes-base.supabase","typeVersion":1,"position":[448,848],"id":"e382162d-8c34-4836-b159-6c68964d94f9","name":"GET 2","credentials":{"supabaseApi":{"id":"OoOx3pPUNd1lRJTr","name":"Supabase account"}}},{"parameters":{"operation":"update","tableId":"meals_draft","filters":{"conditions":[{"keyName":"chat_id","condition":"eq","keyValue":"={{ $json.chat_id }}"},{"keyName":"message_id","condition":"eq","keyValue":"={{$json.draft_id}}"}]},"fieldsUi":{"fieldValues":[{"fieldId":"status","fieldValue":"await_alt"},{"fieldId":"updated_at","fieldValue":"={{ new Date().toISOString() }}"}]}},"type":"n8n-nodes-base.supabase","typeVersion":1,"position":[768,864],"id":"db2269cb-082a-46d0-98d2-a4dc82618059","name":"UPDATE 2","credentials":{"supabaseApi":{"id":"OoOx3pPUNd1lRJTr","name":"Supabase account"}}},{"parameters":{"operation":"update","tableId":"meals_draft","filters":{"conditions":[{"keyName":"chat_id","condition":"eq","keyValue":"={{ $json.chat_id }}"},{"keyName":"message_id","condition":"eq","keyValue":"={{$json.draft_id}}"}]},"fieldsUi":{"fieldValues":[{"fieldId":"chosen_name","fieldValue":"={{$json.dish_ru}}"},{"fieldId":"status","fieldValue":"await_weight"},{"fieldId":"updated_at","fieldValue":"={{ new Date().toISOString() }}"}]}},"type":"n8n-nodes-base.supabase","typeVersion":1,"position":[768,544],"id":"e07d29c3-4443-432b-a571-1ce443b5833e","name":"UPDATE 1","credentials":{"supabaseApi":{"id":"OoOx3pPUNd1lRJTr","name":"Supabase account"}}},{"parameters":{"operation":"get","tableId":"meals_draft","filters":{"conditions":[{"keyName":"chat_id","keyValue":"={{$json.chat_id}}"},{"keyName":"message_id","keyValue":"={{$json.draft_id}}"},{"keyName":"status","keyValue":"await_dish"}]}},"type":"n8n-nodes-base.supabase","typeVersion":1,"position":[448,528],"id":"e0a044e2-5370-4ceb-8150-23efbbd287b2","name":"GET 1","credentials":{"supabaseApi":{"id":"OoOx3pPUNd1lRJTr","name":"Supabase account"}}},{"parameters":{"chatId":"={{$json.chat_id}}","text":"Выбери массу порции:","replyMarkup":"inlineKeyboard","inlineKeyboard":{"rows":[{"row":{"buttons":[{"text":"={{$json.buttons[0].text}}","additionalFields":{"callback_data":"={{$json.buttons[0].data}}"}},{"text":"={{$json.buttons[1].text}}","additionalFields":{"callback_data":"={{$json.buttons[1].data}}"}},{"text":"={{$json.buttons[2].text}}","additionalFields":{"callback_data":"={{$json.buttons[2].data}}"}}]}}]},"additionalFields":{"appendAttribution":false}},"type":"n8n-nodes-base.telegram","typeVersion":1.2,"position":[960,1168],"id":"13871358-51f9-4b3c-8b20-70b65c18eb90","name":"await_weight 3","webhookId":"d3d32e66-ff1c-42d9-9bfe-cf7f223f745b","credentials":{"telegramApi":{"id":"R8VDF53JH3mzhoHd","name":"Telegram dieta"}}},{"parameters":{"chatId":"={{ $json.chat_id }}","text":"Выбери массу порции:","replyMarkup":"inlineKeyboard","inlineKeyboard":{"rows":[{"row":{"buttons":[{"text":"={{ $json.buttons[0].text }}","additionalFields":{"callback_data":"={{ $json.buttons[0].data }}"}},{"text":"={{ $json.buttons[1].text }}","additionalFields":{"callback_data":"={{ $json.buttons[1].data }}"}},{"text":"={{ $json.buttons[2].text }}","additionalFields":{"callback_data":"={{ $json.buttons[2].data }}"}}]}}]},"additionalFields":{"appendAttribution":false}},"type":"n8n-nodes-base.telegram","typeVersion":1.2,"position":[960,528],"id":"f0d2d066-1898-428e-9ab0-1239f76d256f","name":"await_weight 1","webhookId":"d3d32e66-ff1c-42d9-9bfe-cf7f223f745b","credentials":{"telegramApi":{"id":"R8VDF53JH3mzhoHd","name":"Telegram dieta"}}},{"parameters":{"chatId":"={{$json.chat_id}}","text":"=*Выберите альтернативу:*\n\n{{ $json.alt_lines.join('\\n') }}\n","replyMarkup":"inlineKeyboard","inlineKeyboard":{"rows":[{"row":{"buttons":[{"text":"={{$json.buttons[0].text}}","additionalFields":{"callback_data":"={{$json.buttons[0].data}}"}},{"text":"={{$json.buttons[1].text}}","additionalFields":{"callback_data":"={{$json.buttons[1].data}}"}}]}}]},"additionalFields":{"appendAttribution":false}},"type":"n8n-nodes-base.telegram","typeVersion":1.2,"position":[960,848],"id":"d2c24a86-a3fa-4432-a543-6c63fc00e436","name":"await_alt","webhookId":"d3d32e66-ff1c-42d9-9bfe-cf7f223f745b","credentials":{"telegramApi":{"id":"R8VDF53JH3mzhoHd","name":"Telegram dieta"}}},{"parameters":{"jsCode":"// weight_200_7 → parts = ['weight','200','7']\nconst [, grams, id] = $json.callback_query.data.split('_');\n\nreturn [{\n json: {\n chat_id : $json.callback_query.message.chat.id, // тот же chat_id\n draft_id : Number(id), // 7\n grams : Number(grams), // 200\n del_msg_id : $json.callback_query.message.message_id // ID клавиатуры веса\n }\n}];"},"type":"n8n-nodes-base.code","typeVersion":2,"position":[80,1504],"id":"28511818-7857-4075-a662-5a6647f128fe","name":"Split weight"},{"parameters":{"operation":"deleteMessage","chatId":"={{ $json.chat_id }}","messageId":"={{ $json.del_msg_id }}"},"type":"n8n-nodes-base.telegram","typeVersion":1.2,"position":[272,1632],"id":"b7d233d5-543a-440c-97a2-92b22ac7c717","name":"DEL await_weight","webhookId":"182771d4-324c-4a5e-9b6b-cb35d00a0a98","credentials":{"telegramApi":{"id":"R8VDF53JH3mzhoHd","name":"Telegram dieta"}}},{"parameters":{"operation":"deleteMessage","chatId":"={{ $json.chat_id }}","messageId":"={{ $json.del_msg_id }}"},"type":"n8n-nodes-base.telegram","typeVersion":1.2,"position":[240,1184],"id":"c9f1aab0-b659-49fb-b2c6-f67f83056aa4","name":"DEL await_alt","webhookId":"182771d4-324c-4a5e-9b6b-cb35d00a0a98","credentials":{"telegramApi":{"id":"R8VDF53JH3mzhoHd","name":"Telegram dieta"}}},{"parameters":{"operation":"deleteMessage","chatId":"={{ $json.chat_id }}","messageId":"={{ $json.del_msg_id }}"},"type":"n8n-nodes-base.telegram","typeVersion":1.2,"position":[240,864],"id":"7d79b792-e168-4721-ab67-d13b0af7d62f","name":"DEL dish_no","webhookId":"182771d4-324c-4a5e-9b6b-cb35d00a0a98","credentials":{"telegramApi":{"id":"R8VDF53JH3mzhoHd","name":"Telegram dieta"}}},{"parameters":{"operation":"deleteMessage","chatId":"={{ $json.chat_id }}","messageId":"={{ $json.del_msg_id }}"},"type":"n8n-nodes-base.telegram","typeVersion":1.2,"position":[240,544],"id":"2b82adaa-309e-420d-a480-5538fe31fae5","name":"DEL dish_yes","webhookId":"182771d4-324c-4a5e-9b6b-cb35d00a0a98","credentials":{"telegramApi":{"id":"R8VDF53JH3mzhoHd","name":"Telegram dieta"}}},{"parameters":{"jsCode":"/**\n * INPUT ожидает:\n * • items[0].json — строка-row из Supabase (`draft`)\n * • $json.alt_idx — 0 / 1 / 2 (пришло из «alt_0_<id>»)\n *\n * Правка: alt_idx указывает на элемент candidates[1…3],\n * поэтому делаем сдвиг +1.\n */\n\n// 0. Достаём draft: бывает либо объектом, либо массивом с одним элементом\nconst draft = Array.isArray(items[0].json)\n ? items[0].json[0]\n : items[0].json;\n\n// 1. candidates: если это строка — парсим\nconst candidates = typeof draft.candidates === 'string'\n ? JSON.parse(draft.candidates)\n : draft.candidates || [];\n\n// 2. выбираем нужную альтернативу (alt_idx + 1)\nconst offs = ($json.alt_idx ?? 0) + 1;\nconst cand = candidates[offs] || {\n dish : '(не найдено)',\n grams : draft.grams_pred || 200,\n};\n\n// 3. считаем три варианта массы\nconst g = Number(cand.grams) || 200;\nconst step = g < 120 ? 20 : 50;\nconst btns = [g - step, g, g + step].filter(x => x > 0);\n\nreturn [{\n json: {\n chat_id : draft.chat_id,\n draft_id : draft.message_id, // пригодится для UPDATE\n dish_ru : cand.dish,\n grams_est : g,\n buttons : btns.map(x => ({\n text : `${x} г`,\n data : `weight_${x}_${draft.message_id}`,\n })),\n },\n}];\n"},"type":"n8n-nodes-base.code","typeVersion":2,"position":[592,1168],"id":"3fa5e0f5-cfa6-4846-81a7-059879525667","name":"WEIGHT 3"},{"parameters":{"jsCode":"/** INPUT ожидает:\n * • items[0].json ← строка из Supabase (`draft`)\n * • $json.alt_idx ← 0 / 1 / 2 (пришло из «alt_0_id»)\n */\n\n/* 0. draft может лежать либо прямо в .json, либо в .json[0]\n (зависит от Always Output Data) */\nconst draft = Array.isArray(items[0].json)\n ? items[0].json[0]\n : items[0].json;\n\n/* 1. candidates: если строка → JSON.parse */\nconst candidates = typeof draft.candidates === 'string'\n ? JSON.parse(draft.candidates)\n : draft.candidates || [];\n\n/* 2. индекс альтернативы */\nconst idx = $json.alt_idx ?? 0;\nconst cand = candidates[idx] || { dish:'(не найдено)', grams: draft.grams_pred || 200 };\n\n/* 3. считаем кнопки веса */\nconst g = cand.grams;\nconst step = g < 120 ? 20 : 50;\nconst btns = [g-step, g, g+step].filter(x=>x>0);\n\nreturn [{\n json:{\n chat_id : draft.chat_id,\n draft_id : draft.message_id, // пригодится для UPDATE\n dish_ru : cand.dish,\n grams_est : g,\n buttons : btns.map(x=>({\n text : `${x} г`,\n data : `weight_${x}_${draft.message_id}`\n }))\n }\n}];\n"},"type":"n8n-nodes-base.code","typeVersion":2,"position":[592,528],"id":"99b613d9-8bea-47eb-95ef-09f3ca01c653","name":"WEIGHT 1","alwaysOutputData":true},{"parameters":{"jsCode":"/**\n * Упрощаем: код лишь формирует данные,\n * а финальный текст собираем прямо в Telegram-узле.\n */\n\n// 0. Достаём draft (учёт Always-Output Data)\nconst raw = items[0].json[0] ?? items[0].json;\n\n// 1. Парсим candidates, если пришла строкой\nconst candidates = typeof raw.candidates === 'string'\n ? JSON.parse(raw.candidates)\n : raw.candidates || [];\n\n// 2. Берём альтернативы (макс. 3) — без первого\nconst alts = candidates.slice(1, 4);\n\n// 3. Подготовим «красивые» строки для списка\nconst altLines = alts.map((c, i) => `${i + 1}. ${c.dish}`);\n\n// 4. Кнопки 1-2-3\nconst buttons = alts.map((_, i) => ({\n text : String(i + 1),\n data : `alt_${i}_${raw.message_id}`,\n}));\n\nreturn [{\n json: {\n chat_id : raw.chat_id,\n draft_id : raw.message_id,\n\n // для Telegram-узла\n alt_lines : altLines, // массив ['1. …', '2. …', …]\n buttons, // inline-кнопки\n },\n}];\n"},"type":"n8n-nodes-base.code","typeVersion":2,"position":[592,848],"id":"faa2cbcc-c0c4-4d9f-a899-b25b12140f9d","name":"MORE","alwaysOutputData":true},{"parameters":{"tableId":"meals","fieldsUi":{"fieldValues":[{"fieldId":"chat_id","fieldValue":"={{$json.chat_id}}"},{"fieldId":"dish","fieldValue":"={{ $json.dish }}"},{"fieldId":"grams","fieldValue":"={{ $json.grams }}"},{"fieldId":"eaten_at","fieldValue":"={{ $json.eaten_at }}"},{"fieldId":"kcal","fieldValue":"={{ $json.kcal }}"},{"fieldId":"fat","fieldValue":"={{ $json.fat }}"},{"fieldId":"carb","fieldValue":"={{ $json.carb }}"},{"fieldId":"prot","fieldValue":"={{ $json.prot }}"}]}},"type":"n8n-nodes-base.supabase","typeVersion":1,"position":[1392,1440],"id":"b2dd0185-0ef8-470b-b55d-07c25d8738cf","name":"CREATE meals","credentials":{"supabaseApi":{"id":"OoOx3pPUNd1lRJTr","name":"Supabase account"}}},{"parameters":{"jsCode":"// Пример callback_data: dish_yes_7\nconst parts = $json.callback_query.data.split('_');\nconst draftId = parts.pop(); // '7'\n\n// ID сообщения с кнопками «Да / Нет»,\n// которое нужно удалить после обработки\nconst delMsgId = $json.callback_query.message.message_id;\n\nreturn [{\n json: {\n draft_id : Number(draftId), // 7\n chat_id : $json.callback_query.from.id, // 7758…\n del_msg_id : delMsgId // для Delete-узла\n }\n}];\n"},"type":"n8n-nodes-base.code","typeVersion":2,"position":[64,528],"id":"cf73cd44-91a1-4171-8026-83c6580581a3","name":"Parse dish_YES"},{"parameters":{"jsCode":"// Пример callback_data: dish_yes_7\nconst parts = $json.callback_query.data.split('_');\nconst draftId = parts.pop(); // '7'\n\n// ID сообщения с кнопками «Да / Нет»,\n// которое нужно удалить после обработки\nconst delMsgId = $json.callback_query.message.message_id;\n\nreturn [{\n json: {\n draft_id : Number(draftId), // 7\n chat_id : $json.callback_query.from.id, // 7758…\n del_msg_id : delMsgId // для Delete-узла\n }\n}];\n"},"type":"n8n-nodes-base.code","typeVersion":2,"position":[64,848],"id":"0a101f1a-66ca-4a87-9eaa-791cb1bafb35","name":"Parse dish_NO"},{"parameters":{"jsCode":"// Parse macros (замена текущего кода)\nconst sw = $items('Split weight')[0].json; // chat_id, grams, draft_id …\n\n// assistant.content уже объект: dish, kcal, prot, …\nconst gpt = $json.message?.content ?? $json; // на случай, если jsonOutput=false\n\nconst toMsk = () => {\n const msk = new Date(new Date().toLocaleString('en-US',{timeZone:'Europe/Moscow'}));\n const p = n => String(n).padStart(2,'0');\n return `${msk.getFullYear()}-${p(msk.getMonth()+1)}-${p(msk.getDate())}` +\n `T${p(msk.getHours())}:${p(msk.getMinutes())}:00+03:00`;\n};\n\nreturn [{\n json: {\n ...sw, // chat_id, grams …\n ...gpt, // dish, kcal, prot …\n eaten_at: toMsk()\n }\n}];\n"},"type":"n8n-nodes-base.code","typeVersion":2,"position":[1168,1520],"id":"cc5abefe-1e43-4393-b223-602774224696","name":"Parse macros"},{"parameters":{},"type":"n8n-nodes-base.merge","typeVersion":3.1,"position":[672,1520],"id":"2f88a2f3-5971-414f-9684-d1d37e81387b","name":"Merge"},{"parameters":{"resource":"file","fileId":"={{ $json.photo_file_id }}","additionalFields":{}},"id":"7580a5f0-c838-4dab-9f48-38a534309e31","name":"Get Image","type":"n8n-nodes-base.telegram","position":[224,128],"typeVersion":1.2,"webhookId":"8b210039-e135-420d-a5f1-53fc3ca1e836","retryOnFail":false,"maxTries":2,"credentials":{"telegramApi":{"id":"R8VDF53JH3mzhoHd","name":"Telegram dieta"}}},{"parameters":{"operation":"toBinary","sourceProperty":"data","options":{"fileName":"={{ $json.result.file_path }}"}},"id":"e9990056-5926-4dc3-a4f5-c1a7db679dcd","name":"Convert","type":"n8n-nodes-base.convertToFile","position":[624,128],"typeVersion":1.1},{"parameters":{"jsCode":"/**\n * Берём исходный update из триггера\n */\nconst upd = $items(\"Telegram Trigger\")[0].json.message;\nconst chatId = upd.chat.id;\nconst msgId = upd.message_id;\nconst photoId = upd.photo[upd.photo.length - 1].file_id;\n\n/**\n * Русский JSON от Vision\n */\nconst vision = JSON.parse(($json.content || '').replace(/```/g, '').trim());\nconst candidates = vision.candidates || [];\nconst first = candidates[0] || { dish:'блюдо', grams:0 };\n\n/**\n * Draft‑объект\n */\nreturn [{\n json: {\n chat_id : chatId,\n message_id : msgId,\n photo_file_id : photoId,\n\n candidates, // массив на русском\n grams_pred : first.grams,\n status : 'await_dish',\n\n text : `Это *${first.dish}*?`,\n cb_yes : `dish_yes_${msgId}`,\n cb_no : `dish_no_${msgId}`\n }\n}];\n"},"type":"n8n-nodes-base.code","typeVersion":2,"position":[1024,128],"id":"890d69b4-2a3d-4d4b-ab5a-1abd06bff9d6","name":"Parse Vision"},{"parameters":{"assignments":{"assignments":[{"id":"bd8a8c20-939e-49b0-93d0-bb58b8719ebb","name":"chat_id","value":"={{ $json.message.chat.id }}","type":"string"},{"id":"f89d0646-9f73-4067-bbf7-af9913b5f688","name":"message_id","value":"={{$json.message.message_id}}","type":"string"},{"id":"07282534-971f-4430-8d45-5f3e15d3c167","name":"photo_file_id","value":"={{$json.message.photo[$json.message.photo.length - 1].file_id}}","type":"string"}]},"options":{}},"type":"n8n-nodes-base.set","typeVersion":3.4,"position":[64,128],"id":"5752a827-6495-47b2-b8ab-9b5495d264c2","name":"Get ready"},{"parameters":{"chatId":"={{ $json.chat_id }}","text":"={{ $json.text }}","replyMarkup":"inlineKeyboard","inlineKeyboard":{"rows":[{"row":{"buttons":[{"text":"Да","additionalFields":{"callback_data":"={{$json.cb_yes}}"}},{"text":"Нет","additionalFields":{"callback_data":"={{$json.cb_no}}"}}]}}]},"additionalFields":{"appendAttribution":false}},"type":"n8n-nodes-base.telegram","typeVersion":1.2,"position":[1440,224],"id":"9dc2e33f-38ee-45c1-9cc7-adb282d1331c","name":"dish YES or NO","webhookId":"dc6a9f65-91bd-46e4-8c95-17b2ebe68d7c","credentials":{"telegramApi":{"id":"R8VDF53JH3mzhoHd","name":"Telegram dieta"}}},{"parameters":{"tableId":"meals_draft","fieldsUi":{"fieldValues":[{"fieldId":"chat_id","fieldValue":"={{ $json.chat_id }}"},{"fieldId":"message_id","fieldValue":"={{ $json.message_id }}"},{"fieldId":"photo_file_id","fieldValue":"={{ $json.photo_file_id }}"},{"fieldId":"candidates","fieldValue":"={{ $json.candidates }}"},{"fieldId":"grams_pred","fieldValue":"={{ $json.grams_pred }}"},{"fieldId":"status","fieldValue":"={{ $json.status }}"},{"fieldId":"created_at","fieldValue":"={{ new Date().toISOString() }}"}]}},"type":"n8n-nodes-base.supabase","typeVersion":1,"position":[1440,48],"id":"5620bf9d-a9dc-4504-baa7-a837ce33a204","name":"CREATE candidates","credentials":{"supabaseApi":{"id":"OoOx3pPUNd1lRJTr","name":"Supabase account"}}},{"parameters":{"assignments":{"assignments":[{"id":"360c7be2-b049-4c62-bb83-5fafd0850722","name":"chat_id","value":"={{$json.chat_id}}","type":"string"},{"id":"584b9ab5-5ba9-42f9-a9d9-7bb9bb115361","name":"message_id","value":"={{$json.message_id}}","type":"string"},{"id":"8d7a3167-4cbb-4051-8c23-a0b88438c815","name":"photo_file_id","value":"={{$json.photo_file_id}}","type":"string"},{"id":"246a834e-e731-4239-aa92-60eb7c75d79f","name":"candidates","value":"={{$json.candidates}}","type":"string"},{"id":"69f21e55-55ef-4cf0-b73d-b3e39144e057","name":"grams_pred","value":"={{$json.grams_pred}}","type":"string"},{"id":"1b41e033-b7ce-47b0-8f57-0f8dc109ecab","name":"status","value":"={{$json.status}}","type":"string"}]},"includeOtherFields":true,"options":{}},"type":"n8n-nodes-base.set","typeVersion":3.4,"position":[1264,48],"id":"daf38393-7e4a-4a65-b106-772a023d6d36","name":"EDIT candidates"},{"parameters":{"content":"# ФОТО БЛЮДА = 1 ВАРИАНТ","height":392,"width":1698,"color":6},"id":"4ea9bc63-fda6-4c02-9b5e-69c2e054c18c","name":"Sticky Note3","type":"n8n-nodes-base.stickyNote","position":[0,0],"typeVersion":1},{"parameters":{"method":"POST","url":"https://api.telegram.org/botKEY/sendChatAction","sendBody":true,"bodyParameters":{"parameters":[{"name":"chat_id","value":"={{ $json.message.from.id }}"},{"name":"action","value":"typing"}]},"options":{}},"type":"n8n-nodes-base.httpRequest","typeVersion":4.2,"position":[-416,848],"id":"bf3b7eb3-2a56-448f-b354-9bf96ec4573b","name":"HTTP typing...","alwaysOutputData":true,"onError":"continueRegularOutput"},{"parameters":{"operation":"binaryToPropery","options":{}},"id":"dc25033a-af2e-459b-b776-c1dbf7e3d394","name":"Extract","type":"n8n-nodes-base.extractFromFile","position":[464,128],"typeVersion":1},{"parameters":{"workflowId":{"__rl":true,"value":"kohwX0oaY0hmL9b2","mode":"list","cachedResultUrl":"/workflow/kohwX0oaY0hmL9b2","cachedResultName":"tx_text"},"workflowInputs":{"mappingMode":"defineBelow","value":{},"matchingColumns":[],"schema":[],"attemptToConvertTypes":false,"convertFieldsToString":true},"options":{"waitForSubWorkflow":true}},"type":"n8n-nodes-base.executeWorkflow","typeVersion":1.2,"position":[112,2288],"id":"8b0bbc63-fa92-47e8-a5d7-3bdcbd32b290","name":"tg_text"},{"parameters":{"content":"# ТЕКСТ и /\n","height":312,"width":318,"color":7},"id":"d14cf488-d3a0-4208-be12-bc9393b478bf","name":"Sticky Note4","type":"n8n-nodes-base.stickyNote","position":[0,2192],"typeVersion":1},{"parameters":{"content":"# НЕ СОХРАНЯТЬ\n","height":312,"width":958,"color":7},"id":"8af20db1-b8f7-48ce-a64d-249d904bb5ea","name":"Sticky Note6","type":"n8n-nodes-base.stickyNote","position":[0,1840],"typeVersion":1},{"parameters":{"jsCode":"// cancel_62\nconst mealId = Number($json.callback_query.data.split('_').pop());\n\nreturn [{\n json:{\n meal_id : mealId,\n chat_id : $json.callback_query.from.id,\n msg_id : $json.callback_query.message.message_id\n }\n}];\n"},"type":"n8n-nodes-base.code","typeVersion":2,"position":[64,1952],"id":"d7043f72-4a21-469f-8058-ade0923d49eb","name":"Parse cancel"},{"parameters":{"operation":"update","tableId":"meals","matchType":"allFilters","filters":{"conditions":[{"keyName":"id","condition":"eq","keyValue":"={{ $json.meal_id }}"},{"keyName":"chat_id","condition":"eq","keyValue":"={{$json.chat_id}}"}]},"fieldsUi":{"fieldValues":[{"fieldId":"deleted","fieldValue":"true"}]}},"type":"n8n-nodes-base.supabase","typeVersion":1,"position":[240,1952],"id":"2d342f15-4653-4e0e-9e3e-f841eaed6772","name":"UPDATE meals","alwaysOutputData":true,"credentials":{"supabaseApi":{"id":"OoOx3pPUNd1lRJTr","name":"Supabase account"}}},{"parameters":{"operation":"get","tableId":"meals","filters":{"conditions":[{"keyName":"chat_id","keyValue":"={{ $json.chat_id }}"},{"keyName":"id","keyValue":"={{ $json.id }}"}]}},"type":"n8n-nodes-base.supabase","typeVersion":1,"position":[400,1952],"id":"6141812b-9efd-40bb-ae6e-184b42149a92","name":"GET meals","alwaysOutputData":true,"credentials":{"supabaseApi":{"id":"OoOx3pPUNd1lRJTr","name":"Supabase account"}}},{"parameters":{"jsCode":"const row = $items('GET meals')[0].json; // dish, grams, kcal …\nconst ctx = $items('Parse cancel')[0].json; // chat_id, msg_id\n\nreturn [{\n json: {\n chat_id : ctx.chat_id,\n msg_id : ctx.msg_id,\n\n // что пойдёт в текст\n dish : row.dish,\n grams : row.grams,\n kcal : row.kcal,\n prot : row.prot,\n fat : row.fat,\n carb : row.carb\n }\n}];\n"},"type":"n8n-nodes-base.code","typeVersion":2,"position":[560,1952],"id":"854e0904-640e-412d-8a48-8c569e498b17","name":"build cancel"},{"parameters":{"operation":"editMessageText","chatId":"={{ $json.chat_id }}","messageId":"={{ $json.msg_id }}","text":"=*{{ $json.dish }} – {{ $json.grams }} г*\n\n*Калорий:* {{ $json.kcal }}\n*Б:* {{ $json.prot }} *Ж:* {{ $json.fat }} *У:* {{ $json.carb }}\n\n🚫 _не сохранил_\n","additionalFields":{"parse_mode":"Markdown"}},"type":"n8n-nodes-base.telegram","typeVersion":1.2,"position":[752,1952],"id":"0d8a0b50-ff67-4170-99d4-7d4aadca132b","name":"EDITED","webhookId":"d03fb55d-8c26-4782-92a9-d0c9c351a440","credentials":{"telegramApi":{"id":"R8VDF53JH3mzhoHd","name":"Telegram dieta"}}},{"parameters":{"resource":"image","operation":"analyze","modelId":{"__rl":true,"value":"chatgpt-4o-latest","mode":"list","cachedResultName":"CHATGPT-4O-LATEST"},"text":"\nТы пищевой классификатор.\nВерни JSON ТОЛЬКО на русском, без ``` :\n\n{\n \"candidates\": [\n { \"dish\": \"строка\", \"grams\": число, \"confidence\": 0‑1 },\n … максимум 3\n ]\n}\n","inputType":"base64","options":{}},"type":"@n8n/n8n-nodes-langchain.openAi","typeVersion":1.8,"position":[864,128],"id":"4b235725-e5af-430b-8201-aa5984a0476b","name":"VISION","retryOnFail":true,"notesInFlow":false,"executeOnce":false,"credentials":{"openAiApi":{"id":"PvUURuR361IXH0ve","name":"OpenAi account"}}},{"parameters":{"modelId":{"__rl":true,"value":"chatgpt-4o-latest","mode":"list","cachedResultName":"CHATGPT-4O-LATEST"},"messages":{"values":[{"content":"=Ты нутри-калькулятор. \nНа вход получаешь JSON \n{ \"dish\":\"строка\", \"grams\":число }. \n\nОтвечай строго JSON одной строкой:\n\n{\n \"dish\":\"строка\",\n \"kcal\":число,\n \"prot\":число,\n \"fat\":число,\n \"carb\":число\n}\n\nБез пояснений, без ```.","role":"system"},{"content":"={{ $json.chosen_name }}, {{ $json.grams_pred }}"}]},"jsonOutput":true,"options":{}},"type":"@n8n/n8n-nodes-langchain.openAi","typeVersion":1.8,"position":[832,1520],"id":"0586f799-bd0a-4089-bce3-7b859600e557","name":"NUTRION","credentials":{"openAiApi":{"id":"PvUURuR361IXH0ve","name":"OpenAi account"}}},{"parameters":{"model":"openai/gpt-4o","options":{}},"type":"@n8n/n8n-nodes-langchain.lmChatOpenRouter","typeVersion":1,"position":[2288,1632],"id":"52ddcbd7-9829-4590-9eff-879a11bc72e9","name":"OpenRouter Chat Model","disabled":true},{"parameters":{"jsonSchemaExample":"{\n \"dish\": \"овощной салат с сыром\",\n \"kcal\": 122,\n \"prot\": 3.8,\n \"fat\": 8.2,\n \"carb\": 9.2\n}\n"},"type":"@n8n/n8n-nodes-langchain.outputParserStructured","typeVersion":1.2,"position":[2432,1632],"id":"ca89f1d7-5f6e-474e-9987-a89ee34da567","name":"Structured Output Parser","disabled":true},{"parameters":{"jsCode":"/**\n * Parse macros (универсально для:\n * – старого jsonOutput: true\n * – нового Structured Output Parser c массивом или без)\n */\n\n// 1. данные от Split weight (chat_id, grams, draft_id, …)\nconst sw = $items('Split weight')[0].json;\n\n// 2. что пришло от LLM / parser\n// – если это массив → берём первый элемент\n// – если внутри есть .output → берём его, иначе сам объект\nconst raw = Array.isArray($json) ? $json[0] : $json;\nconst gpt = raw.output ?? raw; // { dish, kcal, prot, fat, carb }\n\n// 3. helper → строка даты-времени в МСК ISO +03:00\nconst toMsk = () => {\n const msk = new Date(\n new Date().toLocaleString('en-US', { timeZone: 'Europe/Moscow' })\n );\n const p = n => String(n).padStart(2, '0');\n return `${msk.getFullYear()}-${p(msk.getMonth() + 1)}-${p(msk.getDate())}` +\n `T${p(msk.getHours())}:${p(msk.getMinutes())}:00+03:00`;\n};\n\n// 4. собираем итоговый объект (плоский)\nreturn [{\n json: {\n ...sw, // chat_id, grams, draft_id, …\n ...gpt, // dish, kcal, prot, fat, carb\n eaten_at: toMsk()\n }\n}];\n"},"type":"n8n-nodes-base.code","typeVersion":2,"position":[2624,1488],"id":"dad7038f-a082-4adc-b9a5-329cc2ad5e23","name":"Parse macros 2","disabled":true},{"parameters":{"promptType":"define","text":"={{ $json.chosen_name }}, {{ $json.grams_pred }}","hasOutputParser":true,"options":{"systemMessage":"Ты нутри-калькулятор. \nНа вход получаешь JSON \n{ \"dish\":\"строка\", \"grams\":число }. \n\nОтвечай строго JSON одной строкой:\n\n{\n \"dish\":\"строка\",\n \"kcal\":число,\n \"prot\":число,\n \"fat\":число,\n \"carb\":число\n}\n\nБез пояснений, без ```."}},"type":"@n8n/n8n-nodes-langchain.agent","typeVersion":1.9,"position":[2272,1488],"id":"1bf73b9a-6682-4bd7-9430-cbc841a65382","name":"NUTRION OR","disabled":true},{"parameters":{"operation":"get","tableId":"meals_draft","filters":{"conditions":[{"keyName":"chat_id","keyValue":"={{$json.chat_id}}"},{"keyName":"message_id","keyValue":"={{$json.draft_id}}"},{"keyName":"status","keyValue":"=await_dish"}]}},"type":"n8n-nodes-base.supabase","typeVersion":1,"position":[448,1600],"id":"6e3168d4-961c-4d8c-b347-faa580776f96","name":"GET await_dish","alwaysOutputData":false,"credentials":{"supabaseApi":{"id":"OoOx3pPUNd1lRJTr","name":"Supabase account"}}},{"parameters":{"operation":"get","tableId":"meals_draft","filters":{"conditions":[{"keyName":"chat_id","keyValue":"={{$json.chat_id}}"},{"keyName":"message_id","keyValue":"={{$json.draft_id}}"},{"keyName":"status","keyValue":"await_weight"}]}},"type":"n8n-nodes-base.supabase","typeVersion":1,"position":[448,1440],"id":"cb7cc959-621d-4fb0-874b-f10e96b7e39e","name":"GET await_weight","alwaysOutputData":false,"credentials":{"supabaseApi":{"id":"OoOx3pPUNd1lRJTr","name":"Supabase account"}}},{"parameters":{"content":"### другая LLM\n\n\n","height":392,"width":618,"color":5},"id":"45f631a8-6840-4219-a084-a0fb861a3ac8","name":"Sticky Note7","type":"n8n-nodes-base.stickyNote","position":[2192,1408],"typeVersion":1}],"connections":{"Telegram Trigger":{"main":[[{"node":"Switch","type":"main","index":0},{"node":"HTTP typing...","type":"main","index":0}]]},"Switch":{"main":[[],[{"node":"Get ready","type":"main","index":0}],[{"node":"Parse dish_YES","type":"main","index":0}],[{"node":"Parse dish_NO","type":"main","index":0}],[{"node":"Parse alt","type":"main","index":0}],[{"node":"Split weight","type":"main","index":0}],[{"node":"Parse cancel","type":"main","index":0}],[{"node":"tg_text","type":"main","index":0}]]},"Parse alt":{"main":[[{"node":"GET 3","type":"main","index":0},{"node":"DEL await_alt","type":"main","index":0}]]},"GET 3":{"main":[[{"node":"WEIGHT 3","type":"main","index":0}]]},"GET 2":{"main":[[{"node":"MORE","type":"main","index":0}]]},"GET 1":{"main":[[{"node":"WEIGHT 1","type":"main","index":0}]]},"Split weight":{"main":[[{"node":"DEL await_weight","type":"main","index":0},{"node":"GET await_dish","type":"main","index":0},{"node":"GET await_weight","type":"main","index":0}]]},"WEIGHT 3":{"main":[[{"node":"UPDATE 3","type":"main","index":0},{"node":"await_weight 3","type":"main","index":0}]]},"WEIGHT 1":{"main":[[{"node":"await_weight 1","type":"main","index":0},{"node":"UPDATE 1","type":"main","index":0}]]},"MORE":{"main":[[{"node":"await_alt","type":"main","index":0},{"node":"UPDATE 2","type":"main","index":0}]]},"Parse dish_YES":{"main":[[{"node":"GET 1","type":"main","index":0},{"node":"DEL dish_yes","type":"main","index":0}]]},"Parse dish_NO":{"main":[[{"node":"GET 2","type":"main","index":0},{"node":"DEL dish_no","type":"main","index":0}]]},"Parse macros":{"main":[[{"node":"UPDATE 4","type":"main","index":0},{"node":"CREATE meals","type":"main","index":0}]]},"Merge":{"main":[[{"node":"NUTRION","type":"main","index":0}]]},"Get Image":{"main":[[{"node":"Extract","type":"main","index":0}]]},"Convert":{"main":[[{"node":"VISION","type":"main","index":0}]]},"Parse Vision":{"main":[[{"node":"EDIT candidates","type":"main","index":0},{"node":"dish YES or NO","type":"main","index":0}]]},"Get ready":{"main":[[{"node":"Get Image","type":"main","index":0}]]},"EDIT candidates":{"main":[[{"node":"CREATE candidates","type":"main","index":0}]]},"Extract":{"main":[[{"node":"Convert","type":"main","index":0}]]},"Parse cancel":{"main":[[{"node":"UPDATE meals","type":"main","index":0}]]},"UPDATE meals":{"main":[[{"node":"GET meals","type":"main","index":0}]]},"GET meals":{"main":[[{"node":"build cancel","type":"main","index":0}]]},"build cancel":{"main":[[{"node":"EDITED","type":"main","index":0}]]},"CREATE meals":{"main":[[{"node":"DONE","type":"main","index":0}]]},"VISION":{"main":[[{"node":"Parse Vision","type":"main","index":0}]]},"NUTRION":{"main":[[{"node":"Parse macros","type":"main","index":0}]]},"OpenRouter Chat Model":{"ai_languageModel":[[{"node":"NUTRION OR","type":"ai_languageModel","index":0}]]},"Structured Output Parser":{"ai_outputParser":[[{"node":"NUTRION OR","type":"ai_outputParser","index":0}]]},"NUTRION OR":{"main":[[{"node":"Parse macros 2","type":"main","index":0}]]},"GET await_dish":{"main":[[{"node":"Merge","type":"main","index":1}]]},"GET await_weight":{"main":[[{"node":"Merge","type":"main","index":0}]]}},"settings":{"executionOrder":"v1"},"staticData":null,"meta":null,"pinData":{},"versionId":"df708ee1-5b21-4094-8656-93c821012ed9","activeVersionId":null,"triggerCount":1,"shared":[{"updatedAt":"2025-11-30T14:22:03.470Z","createdAt":"2025-11-30T14:22:03.470Z","role":"workflow:owner","workflowId":"jZIoYr8RW41K0j4J","projectId":"sYuiFAb87pAir6jV"}],"activeVersion":null,"tags":[]} |