{
  "name": "09 Bedside Transcript to Draft",
  "nodes": [
    {
      "parameters": {
        "httpMethod": "POST",
        "path": "bedside-transcript-demo",
        "responseMode": "responseNode",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2.1,
      "position": [
        220,
        320
      ],
      "id": "79917335-58f7-4dcb-9bb1-b0ba6bde0091",
      "name": "Webhook",
      "webhookId": "bedside-transcript-demo"
    },
    {
      "parameters": {
        "keepOnlySet": false,
        "values": {
          "string": [
            {
              "name": "patient_id",
              "value": "={{$json.body.patient_id || ''}}"
            },
            {
              "name": "bed_no",
              "value": "={{$json.body.bed_no || ''}}"
            },
            {
              "name": "shift",
              "value": "={{$json.body.shift || ''}}"
            },
            {
              "name": "nurse_id",
              "value": "={{$json.body.nurse_id || ''}}"
            },
            {
              "name": "recorded_at",
              "value": "={{$json.body.recorded_at || $now}}"
            },
            {
              "name": "transcript",
              "value": "={{$json.body.transcript || ''}}"
            },
            {
              "name": "created_at",
              "value": "={{$now}}"
            }
          ],
          "boolean": [
            {
              "name": "has_required_fields",
              "value": "={{!!($json.body.patient_id && $json.body.bed_no && $json.body.shift && $json.body.nurse_id && $json.body.transcript)}}"
            }
          ]
        },
        "options": {}
      },
      "id": "79917335-58f7-4dcb-9bb1-b0ba6bde0092",
      "name": "Normalize Transcript Input",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        500,
        320
      ]
    },
    {
      "parameters": {
        "conditions": {
          "boolean": [
            {
              "value1": "={{$json.has_required_fields}}",
              "operation": "isTrue"
            }
          ]
        }
      },
      "id": "79917335-58f7-4dcb-9bb1-b0ba6bde0093",
      "name": "Has Required Fields",
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        760,
        320
      ]
    },
    {
      "parameters": {
        "jsCode": "const item = $input.first().json;\nconst text = (item.transcript || '').trim();\nconst lower = text.toLowerCase();\n\nfunction matchNumber(pattern) {\n  const m = text.match(pattern);\n  return m ? Number(m[1]) : null;\n}\n\nfunction matchText(pattern) {\n  const m = text.match(pattern);\n  return m ? m[1].trim() : '';\n}\n\nconst temperature = matchNumber(/體溫\\s*([0-9]+(?:\\.[0-9]+)?)/);\nconst pulse = matchNumber(/脈搏\\s*([0-9]+(?:\\.[0-9]+)?)/);\nconst respiration = matchNumber(/呼吸\\s*([0-9]+(?:\\.[0-9]+)?)/);\nconst bpMatch = text.match(/血壓\\s*([0-9]+)\\s*[\\/／]\\s*([0-9]+)/);\nconst bpSys = bpMatch ? Number(bpMatch[1]) : null;\nconst bpDia = bpMatch ? Number(bpMatch[2]) : null;\nconst spo2 = matchNumber(/(?:血氧|spo2)\\s*([0-9]+(?:\\.[0-9]+)?)/i);\nconst painScore = matchNumber(/疼痛\\s*([0-9]+(?:\\.[0-9]+)?)\\s*分/);\n\nlet consciousness = '';\nif (text.includes('清醒')) consciousness = '清醒';\nelse if (text.includes('嗜睡')) consciousness = '嗜睡';\nelse if (text.includes('意識混亂')) consciousness = '意識混亂';\n\nlet lineStatus = '';\nif (lower.includes('管路異常')) lineStatus = 'abnormal';\nelse if (lower.includes('管路正常')) lineStatus = 'normal';\n\nlet woundStatus = '';\nif (lower.includes('傷口惡化')) woundStatus = 'worsening';\nelse if (lower.includes('傷口穩定')) woundStatus = 'stable';\n\nlet interventions = matchText(/已(?:給藥|完成|執行)[，,:：\\s]*(.+?)(?:。|$)/);\nlet followUp = matchText(/(?:追蹤|之後|稍後|計畫)[，,:：\\s]*(.+?)(?:。|$)/);\nlet abnormalNotes = matchText(/(?:異常|備註|主訴)[，,:：\\s]*(.+?)(?:。|$)/);\n\nconst alertReasons = [];\nif (spo2 !== null && spo2 < 92) alertReasons.push('low_spo2');\nif (temperature !== null && temperature >= 38) alertReasons.push('high_temperature');\nif (painScore !== null && painScore >= 7) alertReasons.push('high_pain_score');\nif (lineStatus === 'abnormal') alertReasons.push('line_issue');\nif (woundStatus === 'worsening') alertReasons.push('wound_issue');\n\nconst bedsideSummary = `${item.recorded_at} 床號 ${item.bed_no}，病人 ${item.patient_id}。${consciousness ? '意識 ' + consciousness + '，' : ''}${temperature !== null ? '體溫 ' + temperature + '°C，' : ''}${pulse !== null ? '脈搏 ' + pulse + ' 次/分，' : ''}${respiration !== null ? '呼吸 ' + respiration + ' 次/分，' : ''}${bpSys !== null && bpDia !== null ? '血壓 ' + bpSys + '/' + bpDia + ' mmHg，' : ''}${spo2 !== null ? 'SpO2 ' + spo2 + '%，' : ''}${painScore !== null ? '疼痛 ' + painScore + ' 分，' : ''}${interventions ? '已做處置：' + interventions + '。' : ''}`.trim();\n\nconst nursingDraft = `${item.recorded_at} 於床邊評估，病人${consciousness ? '意識 ' + consciousness + '，' : ''}${temperature !== null ? '體溫 ' + temperature + '°C，' : ''}${pulse !== null ? '脈搏 ' + pulse + ' 次/分，' : ''}${respiration !== null ? '呼吸 ' + respiration + ' 次/分，' : ''}${bpSys !== null && bpDia !== null ? '血壓 ' + bpSys + '/' + bpDia + ' mmHg，' : ''}${spo2 !== null ? 'SpO2 ' + spo2 + '%，' : ''}${painScore !== null ? '疼痛 ' + painScore + ' 分。' : '。'}${abnormalNotes ? '主訴/異常：' + abnormalNotes + '。' : ''}${interventions ? '已執行：' + interventions + '。' : ''}${followUp ? '後續追蹤：' + followUp + '。' : ''}`;\n\nreturn [{\n  json: {\n    ...item,\n    temperature,\n    pulse,\n    respiration,\n    bp_sys: bpSys,\n    bp_dia: bpDia,\n    spo2,\n    pain_score: painScore,\n    consciousness,\n    line_status: lineStatus,\n    wound_status: woundStatus,\n    interventions,\n    abnormal_notes: abnormalNotes,\n    follow_up_needed: followUp,\n    alert_needed: alertReasons.length > 0,\n    alert_reason: alertReasons.join(','),\n    bedside_summary: bedsideSummary,\n    nursing_note_draft: nursingDraft\n  }\n}];"
      },
      "id": "79917335-58f7-4dcb-9bb1-b0ba6bde0094",
      "name": "Parse Transcript and Build Draft",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1020,
        220
      ]
    },
    {
      "parameters": {
        "operation": "append",
        "documentId": {
          "__rl": true,
          "value": "https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID/edit#gid=0",
          "mode": "url"
        },
        "sheetName": {
          "__rl": true,
          "value": "TranscriptDrafts",
          "mode": "name"
        },
        "columns": {
          "mappingMode": "defineBelow",
          "value": {
            "created_at": "={{$json.created_at}}",
            "patient_id": "={{$json.patient_id}}",
            "bed_no": "={{$json.bed_no}}",
            "shift": "={{$json.shift}}",
            "nurse_id": "={{$json.nurse_id}}",
            "recorded_at": "={{$json.recorded_at}}",
            "transcript": "={{$json.transcript}}",
            "temperature": "={{$json.temperature}}",
            "pulse": "={{$json.pulse}}",
            "respiration": "={{$json.respiration}}",
            "bp_sys": "={{$json.bp_sys}}",
            "bp_dia": "={{$json.bp_dia}}",
            "spo2": "={{$json.spo2}}",
            "pain_score": "={{$json.pain_score}}",
            "consciousness": "={{$json.consciousness}}",
            "line_status": "={{$json.line_status}}",
            "wound_status": "={{$json.wound_status}}",
            "interventions": "={{$json.interventions}}",
            "abnormal_notes": "={{$json.abnormal_notes}}",
            "follow_up_needed": "={{$json.follow_up_needed}}",
            "alert_needed": "={{$json.alert_needed}}",
            "alert_reason": "={{$json.alert_reason}}",
            "bedside_summary": "={{$json.bedside_summary}}",
            "nursing_note_draft": "={{$json.nursing_note_draft}}"
          },
          "matchingColumns": [],
          "schema": [
            { "id": "created_at", "displayName": "created_at", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "patient_id", "displayName": "patient_id", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "bed_no", "displayName": "bed_no", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "shift", "displayName": "shift", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "nurse_id", "displayName": "nurse_id", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "recorded_at", "displayName": "recorded_at", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "transcript", "displayName": "transcript", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "temperature", "displayName": "temperature", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "pulse", "displayName": "pulse", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "respiration", "displayName": "respiration", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "bp_sys", "displayName": "bp_sys", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "bp_dia", "displayName": "bp_dia", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "spo2", "displayName": "spo2", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "pain_score", "displayName": "pain_score", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "consciousness", "displayName": "consciousness", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "line_status", "displayName": "line_status", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "wound_status", "displayName": "wound_status", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "interventions", "displayName": "interventions", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "abnormal_notes", "displayName": "abnormal_notes", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "follow_up_needed", "displayName": "follow_up_needed", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "alert_needed", "displayName": "alert_needed", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "alert_reason", "displayName": "alert_reason", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "bedside_summary", "displayName": "bedside_summary", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true },
            { "id": "nursing_note_draft", "displayName": "nursing_note_draft", "type": "string", "display": true, "required": false, "defaultMatch": false, "canBeUsedToMatch": true }
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleSheets",
      "typeVersion": 4.7,
      "position": [
        1280,
        220
      ],
      "id": "79917335-58f7-4dcb-9bb1-b0ba6bde0095",
      "name": "Append row in sheet"
    },
    {
      "parameters": {
        "keepOnlySet": false,
        "values": {
          "boolean": [
            {
              "name": "ok",
              "value": true
            },
            {
              "name": "alert_needed",
              "value": "={{$node[\"Parse Transcript and Build Draft\"].json.alert_needed}}"
            }
          ],
          "string": [
            {
              "name": "message",
              "value": "Transcript processed into bedside summary and nursing draft"
            },
            {
              "name": "bedside_summary",
              "value": "={{$node[\"Parse Transcript and Build Draft\"].json.bedside_summary}}"
            },
            {
              "name": "nursing_note_draft",
              "value": "={{$node[\"Parse Transcript and Build Draft\"].json.nursing_note_draft}}"
            },
            {
              "name": "alert_reason",
              "value": "={{$node[\"Parse Transcript and Build Draft\"].json.alert_reason}}"
            }
          ]
        },
        "options": {}
      },
      "id": "79917335-58f7-4dcb-9bb1-b0ba6bde0096",
      "name": "Success Response",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        1540,
        220
      ]
    },
    {
      "parameters": {
        "keepOnlySet": true,
        "values": {
          "boolean": [
            {
              "name": "ok",
              "value": false
            }
          ],
          "string": [
            {
              "name": "message",
              "value": "Missing required fields. Required: patient_id, bed_no, shift, nurse_id, transcript"
            }
          ]
        },
        "options": {}
      },
      "id": "79917335-58f7-4dcb-9bb1-b0ba6bde0097",
      "name": "Error Response",
      "type": "n8n-nodes-base.set",
      "typeVersion": 1,
      "position": [
        1020,
        420
      ]
    },
    {
      "parameters": {
        "respondWith": "json",
        "responseBody": "={{$json}}",
        "options": {
          "responseCode": 200
        }
      },
      "type": "n8n-nodes-base.respondToWebhook",
      "typeVersion": 1.4,
      "position": [
        1800,
        320
      ],
      "id": "79917335-58f7-4dcb-9bb1-b0ba6bde0098",
      "name": "Respond to Webhook"
    }
  ],
  "connections": {
    "Webhook": {
      "main": [
        [
          {
            "node": "Normalize Transcript Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Normalize Transcript Input": {
      "main": [
        [
          {
            "node": "Has Required Fields",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Has Required Fields": {
      "main": [
        [
          {
            "node": "Parse Transcript and Build Draft",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Error Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Parse Transcript and Build Draft": {
      "main": [
        [
          {
            "node": "Append row in sheet",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Append row in sheet": {
      "main": [
        [
          {
            "node": "Success Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Success Response": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Error Response": {
      "main": [
        [
          {
            "node": "Respond to Webhook",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {},
  "settings": {},
  "meta": {}
}
