{ "id": "6FU0jjPwEKDBrFSW", "name": "Orçamento de Exames - GChat - Z-PRO (IA Visão)", "active": true, "nodes": [ { "id": "webhook-orcamento", "name": "Webhook - Foto Exame", "type": "n8n-nodes-base.webhook", "typeVersion": 2.1, "position": [ -600, 0 ], "parameters": { "httpMethod": "POST", "path": "orcamento-exames-zpro", "responseMode": "onReceived", "options": {} }, "webhookId": "5ea5f89e-7351-4d45-a881-0055009423a0", "onError": "continueRegularOutput" }, { "id": "extrair-campos", "name": "Extrair campos do webhook", "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [ -360, 0 ], "parameters": { "assignments": { "assignments": [ { "id": "campo-sessionid", "name": "sessionId", "type": "string", "value": "={{ $json.body.protocol }}" }, { "id": "campo-telefone", "name": "telefone", "type": "string", "value": "={{ $json.body.number }}" }, { "id": "campo-nomecontato", "name": "nomeContato", "type": "string", "value": "={{ $json.body.contactName }}" }, { "id": "campo-entrada", "name": "entrada", "type": "string", "value": "={{ String($json.body.entrada || $json.body.text || '').trim() }}" }, { "id": "campo-imagemurl", "name": "imagemUrl", "type": "string", "value": "={{ $json.body.mediaUrl || $json.body.fileUrl || $json.body.file || '' }}" }, { "id": "campo-tipomidia", "name": "tipoMidia", "type": "string", "value": "={{ $json.body.mediaType || $json.body.type || '' }}" } ] }, "options": {} } }, { "id": "if-e-imagem", "name": "É mensagem de imagem?", "type": "n8n-nodes-base.if", "typeVersion": 2.3, "position": [ -120, 0 ], "parameters": { "conditions": { "options": { "version": 2, "leftValue": "", "caseSensitive": true, "typeValidation": "strict" }, "combinator": "and", "conditions": [ { "id": "cond-tem-imagem", "leftValue": "={{ $json.imagemUrl }}", "rightValue": "", "operator": { "type": "string", "operation": "notEmpty", "singleValue": true } } ] }, "options": {} } }, { "id": "baixar-imagem", "name": "Baixar imagem", "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [ 120, -120 ], "parameters": { "method": "GET", "url": "={{ $json.imagemUrl }}", "options": { "response": { "response": { "responseFormat": "file" } }, "timeout": 20000 } }, "onError": "continueErrorOutput" }, { "id": "openai-chat-model-orcamento", "name": "OpenAI Chat Model - Orçamento", "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi", "typeVersion": 1.3, "position": [ 360, -280 ], "parameters": { "model": { "mode": "id", "value": "gpt-4o" }, "options": {} }, "credentials": { "openAiApi": { "id": "h16jFm10cTU15k6M", "name": "OpenAI - Orçamento de Exames" } } }, { "id": "ai-agent-orcamento", "name": "AI Agent - Orçamento", "type": "@n8n/n8n-nodes-langchain.agent", "typeVersion": 3.1, "position": [ 360, -120 ], "parameters": { "promptType": "define", "text": "={{ $('Extrair campos do webhook').item.json.entrada || 'O cliente enviou uma imagem (sem texto). Veja a imagem anexada, que é o pedido médico dele.' }}", "options": { "systemMessage": "Você é o assistente de orçamentos de exames de uma clínica, atendendo automaticamente pelo WhatsApp, numa conversa com várias mensagens (não só uma).\n\nTABELA DE EXAMES E VALORES (lista de exemplo — será substituída pela lista real depois):\n- Hemograma completo — R$ 35,00\n- Glicemia de jejum — R$ 20,00\n- Colesterol total e frações — R$ 45,00\n- Triglicérideos — R$ 25,00\n- TSH (hormônio tireoidiano) — R$ 40,00\n- Exame de urina (EAS) — R$ 30,00\n- Ultrassonografia abdominal — R$ 150,00\n- Raio-X de tórax — R$ 90,00\n- Eletrocardiograma (ECG) — R$ 80,00\n- Papanicolau — R$ 60,00\n\nCOMO CONVERSAR:\n1. O cliente pode mandar uma foto do pedido médico (com ou sem legenda), digitar os nomes dos exames, ou fazer as duas coisas em mensagens separadas, em qualquer ordem — use também o histórico da conversa (mensagens anteriores) pra juntar as informações, não só a mensagem atual. Uma imagem anexada a esta mensagem (quando houver) é o pedido médico do cliente.\n2. Se o cliente ainda não mandou, nem agora nem antes nesta conversa, nenhuma foto de pedido nem nomes de exames, NÃO invente orçamento — cumprimente rapidamente e peça pra ele mandar a foto do pedido médico ou digitar os nomes dos exames.\n3. Assim que tiver pelo menos um exame identificável (considerando a imagem atual, o texto atual E o histórico da conversa), identifique cada exame pedido.\n4. Para cada exame identificado que corresponde (mesmo com sinônimo, abreviação comum ou pequena diferença de grafia) a um item da tabela acima, inclua na resposta o nome do exame e o valor.\n5. Para exames identificados que NÃO correspondem a nenhum item da tabela, ou que você não conseguiu ler/entender com confiança, liste-os separadamente avisando que um atendente vai confirmar o valor.\n6. Nunca deixe de orçar por causa de um item não reconhecido — sempre orçe o que for possível reconhecer.\n7. Calcule e mostre o valor total somando apenas os itens com preço confirmado na tabela.\n8. Responda sempre em português, tom cordial e objetivo, formatado para WhatsApp: texto simples, sem markdown (nada de ** ou #), pode usar emojis com moderação e quebras de linha para organizar.\n9. Sua resposta deve conter SOMENTE o texto a ser enviado ao cliente nesta mensagem — nada de comentários extras, explicações do seu raciocínio, ou texto fora da conversa com o cliente.", "passthroughBinaryImages": true } }, "onError": "continueErrorOutput" }, { "id": "montar-corpo-resposta", "name": "Montar corpo da resposta", "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [ 640, -120 ], "parameters": { "assignments": { "assignments": [ { "id": "resp-number", "name": "number", "type": "string", "value": "={{ $('Extrair campos do webhook').item.json.telefone }}" }, { "id": "resp-body", "name": "body", "type": "string", "value": "={{ $json.output ? $json.output : 'Recebemos sua solicitação de exames! Nossa equipe vai confirmar os valores e te retornar em breve.' }}" }, { "id": "resp-externalkey", "name": "externalKey", "type": "string", "value": "={{ 'orcamento-' + $execution.id }}" }, { "id": "resp-isclosed", "name": "isClosed", "type": "boolean", "value": false } ] }, "options": {} } }, { "id": "enviar-orcamento-zpro", "name": "Enviar orçamento (Z-PRO)", "type": "n8n-nodes-base.executeWorkflow", "typeVersion": 1.3, "position": [ 900, -120 ], "parameters": { "workflowId": { "__rl": true, "mode": "id", "value": "Y4ndG7GuIUrmVRxV", "cachedResultName": "MCP Server - Mensageria ZPRO - enviar_texto" }, "workflowInputs": { "mappingMode": "defineBelow", "value": { "number": "={{ $json.number }}", "body": "={{ $json.body }}", "externalKey": "={{ $json.externalKey }}", "isClosed": "={{ $json.isClosed }}" }, "matchingColumns": [], "schema": [ { "id": "number", "displayName": "number", "required": false, "defaultMatch": false, "display": true, "canBeUsedToMatch": true, "type": "string" }, { "id": "body", "displayName": "body", "required": false, "defaultMatch": false, "display": true, "canBeUsedToMatch": true, "type": "string" }, { "id": "externalKey", "displayName": "externalKey", "required": false, "defaultMatch": false, "display": true, "canBeUsedToMatch": true, "type": "string" }, { "id": "isClosed", "displayName": "isClosed", "required": false, "defaultMatch": false, "display": true, "canBeUsedToMatch": true, "type": "boolean" } ], "attemptToConvertTypes": false, "convertFieldsToString": false } } }, { "id": "memoria-sessao-orcamento", "name": "Memória da Sessão (Postgres)", "type": "@n8n/n8n-nodes-langchain.memoryPostgresChat", "typeVersion": 1.4, "position": [ 360, 40 ], "parameters": { "sessionIdType": "customKey", "sessionKey": "={{ 'orcamento-' + ($('Extrair campos do webhook').item.json.sessionId || $('Extrair campos do webhook').item.json.telefone) }}", "contextWindowLength": 20 }, "credentials": { "postgres": { "id": "xq3QAN3MZSOCVgdY", "name": "Postgres Agendamento - (clínica exemplo)" } } } ], "connections": { "Webhook - Foto Exame": { "main": [ [ { "node": "Extrair campos do webhook", "type": "main", "index": 0 } ] ] }, "Extrair campos do webhook": { "main": [ [ { "node": "É mensagem de imagem?", "type": "main", "index": 0 } ] ] }, "É mensagem de imagem?": { "main": [ [ { "node": "Baixar imagem", "type": "main", "index": 0 } ], [ { "node": "AI Agent - Orçamento", "type": "main", "index": 0 } ] ] }, "Baixar imagem": { "main": [ [ { "node": "AI Agent - Orçamento", "type": "main", "index": 0 } ], [ { "node": "Montar corpo da resposta", "type": "main", "index": 0 } ] ] }, "OpenAI Chat Model - Orçamento": { "ai_languageModel": [ [ { "node": "AI Agent - Orçamento", "type": "ai_languageModel", "index": 0 } ] ] }, "AI Agent - Orçamento": { "main": [ [ { "node": "Montar corpo da resposta", "type": "main", "index": 0 } ], [ { "node": "Montar corpo da resposta", "type": "main", "index": 0 } ] ] }, "Montar corpo da resposta": { "main": [ [ { "node": "Enviar orçamento (Z-PRO)", "type": "main", "index": 0 } ] ] }, "Memória da Sessão (Postgres)": { "ai_memory": [ [ { "node": "AI Agent - Orçamento", "type": "ai_memory", "index": 0 } ] ] } }, "settings": { "executionOrder": "v1", "saveDataErrorExecution": "all", "saveDataSuccessExecution": "all", "saveManualExecutions": true, "saveExecutionProgress": true } }