713 lines
No EOL
26 KiB
JSON
713 lines
No EOL
26 KiB
JSON
{
|
||
"name": "FoodSnap - Unified (Food & Coach)",
|
||
"nodes": [
|
||
{
|
||
"parameters": {
|
||
"httpMethod": "POST",
|
||
"path": "wa/inbound",
|
||
"options": {}
|
||
},
|
||
"type": "n8n-nodes-base.webhook",
|
||
"typeVersion": 2.1,
|
||
"position": [
|
||
-680,
|
||
-940
|
||
],
|
||
"id": "webhook-unified",
|
||
"name": "Webhook (Whatsapp)"
|
||
},
|
||
{
|
||
"parameters": {
|
||
"jsCode": "const body = $json.body ?? $json;\nconst data = body.data ?? {};\n\n// =========================\n// RemoteJid (prioridade s.whatsapp.net)\n// =========================\nconst remoteJid =\n data?.key?.remoteJid?.includes('@s.whatsapp.net')\n ? data.key.remoteJid\n : data?.key?.remoteJidAlt || '';\n\n// número limpo (E.164 sem +)\nconst number = remoteJid.replace(/\\D/g, '');\n\n// =========================\n// Message ID\n// =========================\nconst message_id = data?.key?.id || '';\n\n// =========================\n// Texto e Caption\n// =========================\n// Verifica conversation, extendedTextMessage (text) e imageMessage (caption)\nconst text =\n data?.message?.conversation ||\n data?.message?.extendedTextMessage?.text ||\n data?.message?.imageMessage?.caption ||\n '';\n\n// =========================\n// Imagem\n// =========================\nconst imageMessage =\n data?.message?.imageMessage ||\n data?.message?.extendedTextMessage?.contextInfo?.quotedMessage?.imageMessage ||\n null;\n\n// =========================\n// Return normalizado\n// =========================\nreturn [\n {\n number,\n remoteJid,\n message_id,\n text,\n hasImage: !!imageMessage,\n imageMessage,\n pushName: data?.pushName || 'Atleta',\n timestamp: new Date().toISOString(),\n raw: body\n }\n];"
|
||
},
|
||
"type": "n8n-nodes-base.code",
|
||
"typeVersion": 2,
|
||
"position": [
|
||
-460,
|
||
-940
|
||
],
|
||
"id": "normalize-inbound",
|
||
"name": "Normalizar Dados"
|
||
},
|
||
{
|
||
"parameters": {
|
||
"conditions": {
|
||
"options": {
|
||
"caseSensitive": false,
|
||
"leftValue": "",
|
||
"typeValidation": "strict",
|
||
"version": 3
|
||
},
|
||
"conditions": [
|
||
{
|
||
"id": "check-coach",
|
||
"leftValue": "={{ $json.text }}",
|
||
"rightValue": "coach,treino,shape,biotipo,fisico,musculo",
|
||
"operator": {
|
||
"type": "string",
|
||
"operation": "contains",
|
||
"singleValue": true
|
||
}
|
||
}
|
||
],
|
||
"combinator": "or"
|
||
},
|
||
"options": {}
|
||
},
|
||
"type": "n8n-nodes-base.if",
|
||
"typeVersion": 2.3,
|
||
"position": [
|
||
-240,
|
||
-940
|
||
],
|
||
"id": "router-intent",
|
||
"name": "É Coach?"
|
||
},
|
||
{
|
||
"parameters": {
|
||
"operation": "executeQuery",
|
||
"query": "with u as (\n select id\n from public.profiles\n where phone_e164 = cast({{ $('Normalizar Dados').item.json.number }} as text)\n limit 1\n),\nent as (\n select ue.is_active, ue.entitlement_code, ue.valid_until\n from public.user_entitlements ue\n where ue.user_id = (select id from u)\n order by ue.valid_until desc nulls last\n limit 1\n),\nusage as (\n select count(*) as used_count\n from public.coach_analyses fa\n where fa.user_id = (select id from u)\n and fa.used_free_quota = true\n)\nselect\n (select id from u) as user_id,\n (select id from u) is not null as exists,\n coalesce((select used_count from usage), 0)::int as free_used,\n greatest(0, 3 - coalesce((select used_count from usage), 0))::int as free_remaining,\n coalesce((select is_active from ent), false) as plan_active,\n (coalesce((select is_active from ent), false) = true OR greatest(0, 3 - coalesce((select used_count from usage), 0)) > 0) as can_process",
|
||
"options": {}
|
||
},
|
||
"type": "n8n-nodes-base.postgres",
|
||
"typeVersion": 2.6,
|
||
"position": [
|
||
20,
|
||
-1160
|
||
],
|
||
"id": "validate-coach",
|
||
"name": "Validação Coach",
|
||
"credentials": {
|
||
"postgres": {
|
||
"id": "2JDD2OJz4cAsWb0J",
|
||
"name": "foodsnap_supabase"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"operation": "executeQuery",
|
||
"query": "with u as (\n select id\n from public.profiles\n where phone_e164 = cast({{ $('Normalizar Dados').item.json.number }} as text)\n limit 1\n),\nent as (\n select\n ue.user_id,\n ue.is_active,\n ue.entitlement_code\n from public.user_entitlements ue\n where ue.user_id = (select id from u)\n order by ue.valid_until desc nulls last\n limit 1\n),\nusage as (\n select count(*) filter (where fa.used_free_quota = true) as free_used\n from public.food_analyses fa\n where fa.user_id = (select id from u)\n)\nselect\n (select id from u) is not null as exists,\n (select id from u) as user_id,\n coalesce((select free_used from usage), 0)::int as free_used,\n greatest(0, 5 - coalesce((select free_used from usage), 0))::int as free_remaining,\n coalesce((select is_active from ent), false) as plan_active,\n (\n (select id from u) is not null\n and (\n coalesce((select is_active from ent), false) = true\n or greatest(0, 5 - coalesce((select free_used from usage), 0)) > 0\n )\n ) as can_process;",
|
||
"options": {}
|
||
},
|
||
"type": "n8n-nodes-base.postgres",
|
||
"typeVersion": 2.6,
|
||
"position": [
|
||
20,
|
||
-740
|
||
],
|
||
"id": "validate-food",
|
||
"name": "Validação Food",
|
||
"credentials": {
|
||
"postgres": {
|
||
"id": "2JDD2OJz4cAsWb0J",
|
||
"name": "foodsnap_supabase"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"conditions": {
|
||
"options": {
|
||
"caseSensitive": true,
|
||
"leftValue": "",
|
||
"typeValidation": "strict",
|
||
"version": 3
|
||
},
|
||
"conditions": [
|
||
{
|
||
"id": "check-process",
|
||
"leftValue": "={{ $json.can_process }}",
|
||
"rightValue": "",
|
||
"operator": {
|
||
"type": "boolean",
|
||
"operation": "true",
|
||
"singleValue": true
|
||
}
|
||
}
|
||
],
|
||
"combinator": "and"
|
||
},
|
||
"options": {}
|
||
},
|
||
"type": "n8n-nodes-base.if",
|
||
"typeVersion": 2.3,
|
||
"position": [
|
||
260,
|
||
-1160
|
||
],
|
||
"id": "if-coach-quota",
|
||
"name": "Coach OK?"
|
||
},
|
||
{
|
||
"parameters": {
|
||
"conditions": {
|
||
"options": {
|
||
"caseSensitive": true,
|
||
"leftValue": "",
|
||
"typeValidation": "strict",
|
||
"version": 3
|
||
},
|
||
"conditions": [
|
||
{
|
||
"id": "check-process-food",
|
||
"leftValue": "={{ $json.can_process }}",
|
||
"rightValue": "",
|
||
"operator": {
|
||
"type": "boolean",
|
||
"operation": "true",
|
||
"singleValue": true
|
||
}
|
||
}
|
||
],
|
||
"combinator": "and"
|
||
},
|
||
"options": {}
|
||
},
|
||
"type": "n8n-nodes-base.if",
|
||
"typeVersion": 2.3,
|
||
"position": [
|
||
260,
|
||
-740
|
||
],
|
||
"id": "if-food-quota",
|
||
"name": "Food OK?"
|
||
},
|
||
{
|
||
"parameters": {
|
||
"resource": "messages-api",
|
||
"instanceName": "FoodSnap",
|
||
"remoteJid": "={{ $('Normalizar Dados').item.json.number }}",
|
||
"messageText": "🧐 *Coach AI*: Analisando seu biótipo e gerando seu treino... Aguarde!",
|
||
"options_message": {}
|
||
},
|
||
"type": "n8n-nodes-evolution-api.evolutionApi",
|
||
"typeVersion": 1,
|
||
"position": [
|
||
500,
|
||
-1260
|
||
],
|
||
"id": "msg-ack-coach",
|
||
"name": "Ack Coach",
|
||
"credentials": {
|
||
"evolutionApi": {
|
||
"id": "nGWBERcZoQWgdxgk",
|
||
"name": "FoodSnap"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"resource": "chat-api",
|
||
"operation": "get-media-base64",
|
||
"instanceName": "FoodSnap",
|
||
"messageId": "={{ $('Normalizar Dados').item.json.message_id }}"
|
||
},
|
||
"type": "n8n-nodes-evolution-api.evolutionApi",
|
||
"typeVersion": 1,
|
||
"position": [
|
||
720,
|
||
-1260
|
||
],
|
||
"id": "get-image-coach",
|
||
"name": "Baixar IMG Coach",
|
||
"credentials": {
|
||
"evolutionApi": {
|
||
"id": "nGWBERcZoQWgdxgk",
|
||
"name": "FoodSnap"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"operation": "toBinary",
|
||
"sourceProperty": "data.base64",
|
||
"options": {}
|
||
},
|
||
"type": "n8n-nodes-base.convertToFile",
|
||
"typeVersion": 1.1,
|
||
"position": [
|
||
940,
|
||
-1260
|
||
],
|
||
"id": "convert-binary-coach",
|
||
"name": "Binário Coach"
|
||
},
|
||
{
|
||
"parameters": {
|
||
"resource": "image",
|
||
"operation": "analyze",
|
||
"modelId": {
|
||
"__rl": true,
|
||
"value": "models/gemini-1.5-flash",
|
||
"mode": "list",
|
||
"cachedResultName": "models/gemini-1.5-flash"
|
||
},
|
||
"text": "=Você é um Treinador Físico de Elite e Nutricionista Esportivo.\nAnalise a imagem fornecida (foto de corpo inteiro/físico).\n\n1. Verifique se é uma foto de corpo humano válida para análise fitness. Se não, retorne \"valid_body\": false.\n2. Se for válida, estime:\n - Biótipo Predominante (Ectomorfo, Mesomorfo, Endomorfo)\n - Percentual de Gordura (BF% aproximado)\n - Nível de Massa Muscular (Baixo, Médio, Alto)\n3. Sugira:\n - Objetivo Principal (Cutting, Bulking, Manutenção)\n - Divisão de Treino Recomendada (ex: ABC, ABCDE, Upper/Lower)\n - Foco Dietético (ex: Carb Cycling, Alto Carbo, Keto)\n - Dica de Ouro (uma frase curta de impacto)\n\nResponda APENAS em JSON estrito (sem markdown):\n{\n \"valid_body\": true,\n \"biotype\": \"...\",\n \"estimated_body_fat\": 15,\n \"muscle_mass\": \"Médio\",\n \"goal\": \"Bulking\",\n \"workout\": \"...\",\n \"diet\": \"...\",\n \"tip\": \"...\"\n}",
|
||
"inputType": "binary",
|
||
"simplify": false,
|
||
"options": {}
|
||
},
|
||
"type": "@n8n/n8n-nodes-langchain.googleGemini",
|
||
"typeVersion": 1,
|
||
"position": [
|
||
1160,
|
||
-1260
|
||
],
|
||
"id": "gemini-coach",
|
||
"name": "Gemini Coach",
|
||
"credentials": {
|
||
"googlePalmApi": {
|
||
"id": "T2uIVBcjJ9h8BFCC",
|
||
"name": "Backup APIKEY"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"jsCode": "const raw = $json?.candidates?.[0]?.content?.parts?.[0]?.text || '{}';\nconst clean = raw.replace(/```json/g, '').replace(/```/g, '').trim();\nlet data = {};\ntry { \n data = JSON.parse(clean); \n} catch(e) {\n data = { valid_body: false, error: 'Failed to parse AI' };\n}\n\nreturn [{ ...data }];"
|
||
},
|
||
"type": "n8n-nodes-base.code",
|
||
"typeVersion": 2,
|
||
"position": [
|
||
1380,
|
||
-1260
|
||
],
|
||
"id": "parse-coach-json",
|
||
"name": "Parse Coach JSON"
|
||
},
|
||
{
|
||
"parameters": {
|
||
"operation": "executeQuery",
|
||
"query": "insert into public.coach_analyses\n(\n user_id,\n source,\n image_url,\n ai_raw_response,\n ai_structured,\n biotype,\n estimated_body_fat,\n goal_suggestion,\n muscle_mass_level,\n used_free_quota\n)\nvalues\n(\n cast('{{ $(\"Validação Coach\").item.json.user_id }}' as uuid),\n 'whatsapp',\n null,\n '{{ JSON.stringify($json) }}',\n '{{ JSON.stringify($json) }}',\n '{{ $json.biotype }}',\n cast({{ $json.estimated_body_fat || 0 }} as numeric),\n '{{ $json.goal }}',\n '{{ $json.muscle_mass }}',\n CASE\n WHEN {{ $(\"Validação Coach\").item.json.plan_active }} = true THEN false\n ELSE true\n END\n)\nreturning id as analysis_id;",
|
||
"options": {}
|
||
},
|
||
"type": "n8n-nodes-base.postgres",
|
||
"typeVersion": 2.6,
|
||
"position": [
|
||
1600,
|
||
-1260
|
||
],
|
||
"id": "save-coach-db",
|
||
"name": "Salvar Coach DB",
|
||
"credentials": {
|
||
"postgres": {
|
||
"id": "2JDD2OJz4cAsWb0J",
|
||
"name": "foodsnap_supabase"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"resource": "messages-api",
|
||
"instanceName": "FoodSnap",
|
||
"remoteJid": "={{ $('Normalizar Dados').item.json.number }}",
|
||
"messageText": "=⚡ *Coach AI Report*\n\n🧬 *Biótipo*: {{$json.biotype}}\n⚖️ *BF Estimado*: ~{{$json.estimated_body_fat}}%\n💪 *Massa Muscular*: {{$json.muscle_mass}}\n\n🎯 *Foco*: {{$json.goal}}\n🏋️ *Treino*: {{$json.workout}}\n🥗 *Dieta*: {{$json.diet}}\n\n💡 *Dica*: {{$json.tip}}\n\n_Acesse o App para ver a ficha completa!_",
|
||
"options_message": {}
|
||
},
|
||
"type": "n8n-nodes-evolution-api.evolutionApi",
|
||
"typeVersion": 1,
|
||
"position": [
|
||
1820,
|
||
-1260
|
||
],
|
||
"id": "reply-coach",
|
||
"name": "Responder Coach",
|
||
"credentials": {
|
||
"evolutionApi": {
|
||
"id": "nGWBERcZoQWgdxgk",
|
||
"name": "FoodSnap"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"resource": "messages-api",
|
||
"instanceName": "FoodSnap",
|
||
"remoteJid": "={{ $('Normalizar Dados').item.json.number }}",
|
||
"messageText": "📸 Recebi sua foto! Analisando o prato... ⏳",
|
||
"options_message": {}
|
||
},
|
||
"type": "n8n-nodes-evolution-api.evolutionApi",
|
||
"typeVersion": 1,
|
||
"position": [
|
||
500,
|
||
-740
|
||
],
|
||
"id": "ack-food",
|
||
"name": "Ack Food",
|
||
"credentials": {
|
||
"evolutionApi": {
|
||
"id": "nGWBERcZoQWgdxgk",
|
||
"name": "FoodSnap"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"resource": "chat-api",
|
||
"operation": "get-media-base64",
|
||
"instanceName": "FoodSnap",
|
||
"messageId": "={{ $('Normalizar Dados').item.json.message_id }}"
|
||
},
|
||
"type": "n8n-nodes-evolution-api.evolutionApi",
|
||
"typeVersion": 1,
|
||
"position": [
|
||
720,
|
||
-740
|
||
],
|
||
"id": "get-image-food",
|
||
"name": "Baixar IMG Food",
|
||
"credentials": {
|
||
"evolutionApi": {
|
||
"id": "nGWBERcZoQWgdxgk",
|
||
"name": "FoodSnap"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"operation": "toBinary",
|
||
"sourceProperty": "data.base64",
|
||
"options": {}
|
||
},
|
||
"type": "n8n-nodes-base.convertToFile",
|
||
"typeVersion": 1.1,
|
||
"position": [
|
||
940,
|
||
-740
|
||
],
|
||
"id": "convert-binary-food",
|
||
"name": "Binário Food"
|
||
},
|
||
{
|
||
"parameters": {
|
||
"resource": "image",
|
||
"operation": "analyze",
|
||
"modelId": {
|
||
"__rl": true,
|
||
"value": "models/gemini-1.5-flash",
|
||
"mode": "list",
|
||
"cachedResultName": "models/gemini-1.5-flash"
|
||
},
|
||
"text": "=Você é um assistente nutricional... (Prompt Original de Comida)... Retorne SOMENTE JSON.",
|
||
"inputType": "binary",
|
||
"simplify": false,
|
||
"options": {}
|
||
},
|
||
"type": "@n8n/n8n-nodes-langchain.googleGemini",
|
||
"typeVersion": 1,
|
||
"position": [
|
||
1160,
|
||
-740
|
||
],
|
||
"id": "gemini-food",
|
||
"name": "Gemini Food",
|
||
"credentials": {
|
||
"googlePalmApi": {
|
||
"id": "T2uIVBcjJ9h8BFCC",
|
||
"name": "Backup APIKEY"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"jsCode": "// Limpeza de JSON da Comida (Original)\nconst raw = $json?.candidates?.[0]?.content?.parts?.[0]?.text || '{}';\n// ... lógica existente de parse do FoodSnap ...\nreturn [{\n items: [],\n total: { calories: 500, protein: 30 },\n tip: { text: \"Exemplo de análise de comida\" }\n}];"
|
||
},
|
||
"type": "n8n-nodes-base.code",
|
||
"typeVersion": 2,
|
||
"position": [
|
||
1380,
|
||
-740
|
||
],
|
||
"id": "parse-food",
|
||
"name": "Parse Food",
|
||
"notes": "Lógica completa de parse de comida aqui (resumida para o arquivo)"
|
||
},
|
||
{
|
||
"parameters": {
|
||
"operation": "executeQuery",
|
||
"query": "insert into public.food_analyses ... (SQL Original)",
|
||
"options": {}
|
||
},
|
||
"type": "n8n-nodes-base.postgres",
|
||
"typeVersion": 2.6,
|
||
"position": [
|
||
1600,
|
||
-740
|
||
],
|
||
"id": "save-food-db",
|
||
"name": "Salvar Food DB",
|
||
"credentials": {
|
||
"postgres": {
|
||
"id": "2JDD2OJz4cAsWb0J",
|
||
"name": "foodsnap_supabase"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"resource": "messages-api",
|
||
"instanceName": "FoodSnap",
|
||
"remoteJid": "={{ $('Normalizar Dados').item.json.number }}",
|
||
"messageText": "=🥗 *FoodSnap*: Calorias: {{$json.total.calories}} ... (Formato Original)",
|
||
"options_message": {}
|
||
},
|
||
"type": "n8n-nodes-evolution-api.evolutionApi",
|
||
"typeVersion": 1,
|
||
"position": [
|
||
1820,
|
||
-740
|
||
],
|
||
"id": "reply-food",
|
||
"name": "Responder Food",
|
||
"credentials": {
|
||
"evolutionApi": {
|
||
"id": "nGWBERcZoQWgdxgk",
|
||
"name": "FoodSnap"
|
||
}
|
||
}
|
||
},
|
||
{
|
||
"parameters": {
|
||
"resource": "messages-api",
|
||
"instanceName": "FoodSnap",
|
||
"remoteJid": "={{ $('Normalizar Dados').item.json.number }}",
|
||
"messageText": "⚠️ Por favor, envie uma *imagem* para análise.",
|
||
"options_message": {}
|
||
},
|
||
"type": "n8n-nodes-evolution-api.evolutionApi",
|
||
"typeVersion": 1,
|
||
"position": [
|
||
260,
|
||
-500
|
||
],
|
||
"id": "msg-no-image",
|
||
"name": "Sem Imagem",
|
||
"credentials": {
|
||
"evolutionApi": {
|
||
"id": "nGWBERcZoQWgdxgk",
|
||
"name": "FoodSnap"
|
||
}
|
||
}
|
||
}
|
||
],
|
||
"connections": {
|
||
"Webhook (Whatsapp)": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Normalizar Dados",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Normalizar Dados": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "É Coach?",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"É Coach?": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Validação Coach",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
],
|
||
[
|
||
{
|
||
"node": "Validação Food",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Validação Coach": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Coach OK?",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Validação Food": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Food OK?",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Coach OK?": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Ack Coach",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Food OK?": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Ack Food",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Ack Coach": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Baixar IMG Coach",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Ack Food": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Baixar IMG Food",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Baixar IMG Coach": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Binário Coach",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Baixar IMG Food": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Binário Food",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Binário Coach": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Gemini Coach",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Binário Food": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Gemini Food",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Gemini Coach": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Parse Coach JSON",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Gemini Food": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Parse Food",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Parse Coach JSON": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Salvar Coach DB",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Parse Food": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Salvar Food DB",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Salvar Coach DB": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Responder Coach",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
},
|
||
"Salvar Food DB": {
|
||
"main": [
|
||
[
|
||
{
|
||
"node": "Responder Food",
|
||
"type": "main",
|
||
"index": 0
|
||
}
|
||
]
|
||
]
|
||
}
|
||
}
|
||
} |