{
  "name": "Ollama / Open WebUI 健康監控 (含自動修復)",
  "nodes": [
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "minutes",
              "minutesInterval": 5
            }
          ]
        }
      },
      "id": "schedule-trigger",
      "name": "每 5 分鐘執行",
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [240, 300]
    },
    {
      "parameters": {
        "url": "http://192.168.0.188:11434/api/tags",
        "options": {
          "timeout": 10000
        }
      },
      "id": "check-ollama-api",
      "name": "檢查 Ollama API",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [460, 200],
      "continueOnFail": true
    },
    {
      "parameters": {
        "url": "http://192.168.0.188/",
        "options": {
          "timeout": 10000
        }
      },
      "id": "check-open-webui",
      "name": "檢查 Open WebUI",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [460, 400],
      "continueOnFail": true
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "ollama-check",
              "leftValue": "={{ $('檢查 Ollama API').first().json.models !== undefined }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            },
            {
              "id": "webui-check",
              "leftValue": "={{ $('檢查 Open WebUI').first().binary !== undefined || $('檢查 Open WebUI').first().json !== undefined }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "check-health",
      "name": "服務健康?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [680, 300]
    },
    {
      "parameters": {
        "jsCode": "// 分析失敗原因\nconst ollamaResult = $('檢查 Ollama API').first();\nconst webuiResult = $('檢查 Open WebUI').first();\n\nlet issues = [];\nlet needsDockerRestart = false;\nlet needsContainerRestart = false;\n\n// 檢查 Ollama API\nif (!ollamaResult.json.models) {\n  issues.push({\n    service: 'Ollama API',\n    status: 'down',\n    error: ollamaResult.json.error || 'API 無回應'\n  });\n}\n\n// 檢查 Open WebUI\nif (webuiResult.json && webuiResult.json.error) {\n  const errorMsg = webuiResult.json.error || '';\n  \n  if (errorMsg.includes('502') || errorMsg.includes('Bad Gateway')) {\n    issues.push({\n      service: 'Open WebUI',\n      status: '502',\n      error: '502 Bad Gateway - Docker 網路失效'\n    });\n    needsDockerRestart = true;\n  } else if (errorMsg.includes('ECONNREFUSED') || errorMsg.includes('timeout')) {\n    issues.push({\n      service: 'Open WebUI',\n      status: 'down',\n      error: '連線失敗或超時'\n    });\n    needsContainerRestart = true;\n  } else {\n    issues.push({\n      service: 'Open WebUI',\n      status: 'error',\n      error: errorMsg\n    });\n  }\n} else if (!webuiResult.binary && !webuiResult.json) {\n  issues.push({\n    service: 'Open WebUI',\n    status: 'no_response',\n    error: '無回應'\n  });\n  needsContainerRestart = true;\n}\n\nreturn {\n  timestamp: new Date().toISOString(),\n  issues: issues,\n  issueCount: issues.length,\n  needsDockerRestart: needsDockerRestart,\n  needsContainerRestart: needsContainerRestart,\n  summary: issues.map(i => `${i.service}: ${i.error}`).join('\\n')\n};"
      },
      "id": "analyze-failure",
      "name": "分析失敗原因",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [900, 400]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "docker-restart",
              "leftValue": "={{ $json.needsDockerRestart }}",
              "rightValue": true,
              "operator": {
                "type": "boolean",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "needs-docker-restart",
      "name": "需要重啟 Docker?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [1120, 400]
    },
    {
      "parameters": {
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "sshPassword",
        "resource": "command",
        "command": "sudo systemctl restart docker && sleep 60 && curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/"
      },
      "id": "restart-docker",
      "name": "重啟 Docker Daemon",
      "type": "n8n-nodes-base.ssh",
      "typeVersion": 1,
      "position": [1340, 300],
      "credentials": {
        "sshPassword": {
          "id": "ollama-ssh",
          "name": "Ollama SSH"
        }
      },
      "continueOnFail": true
    },
    {
      "parameters": {
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "sshPassword",
        "resource": "command",
        "command": "docker restart open-webui && sleep 30 && curl -s -o /dev/null -w '%{http_code}' http://127.0.0.1:3000/"
      },
      "id": "restart-container",
      "name": "重啟 Open WebUI 容器",
      "type": "n8n-nodes-base.ssh",
      "typeVersion": 1,
      "position": [1340, 500],
      "credentials": {
        "sshPassword": {
          "id": "ollama-ssh",
          "name": "Ollama SSH"
        }
      },
      "continueOnFail": true
    },
    {
      "parameters": {
        "chatId": "5619078117",
        "text": "=🔴 <b>Ollama / Open WebUI 服務異常</b>\n\n{{ $('分析失敗原因').item.json.summary }}\n\n<b>自動修復中...</b>\n時間: {{ new Date().toLocaleString('zh-TW', {timeZone: 'Asia/Taipei'}) }}",
        "additionalFields": {
          "parse_mode": "HTML"
        }
      },
      "id": "alert-failure",
      "name": "發送異常告警",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [1120, 600],
      "credentials": {
        "telegramApi": {
          "id": "telegram-bot",
          "name": "Telegram Bot"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "const dockerResult = $('重啟 Docker Daemon').first();\nconst containerResult = $('重啟 Open WebUI 容器').first();\n\nlet repairStatus = 'unknown';\nlet repairAction = '';\nlet httpCode = '000';\n\nif (dockerResult && dockerResult.json) {\n  repairAction = '重啟 Docker Daemon';\n  httpCode = dockerResult.json.stdout || '000';\n} else if (containerResult && containerResult.json) {\n  repairAction = '重啟 Open WebUI 容器';\n  httpCode = containerResult.json.stdout || '000';\n}\n\nif (httpCode === '200') {\n  repairStatus = 'success';\n} else {\n  repairStatus = 'failed';\n}\n\nreturn {\n  repairStatus: repairStatus,\n  repairAction: repairAction,\n  httpCode: httpCode\n};"
      },
      "id": "check-repair-result",
      "name": "檢查修復結果",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [1560, 400]
    },
    {
      "parameters": {
        "conditions": {
          "options": {
            "caseSensitive": true,
            "leftValue": "",
            "typeValidation": "strict"
          },
          "conditions": [
            {
              "id": "repair-success",
              "leftValue": "={{ $json.repairStatus }}",
              "rightValue": "success",
              "operator": {
                "type": "string",
                "operation": "equals"
              }
            }
          ],
          "combinator": "and"
        }
      },
      "id": "repair-success-check",
      "name": "修復成功?",
      "type": "n8n-nodes-base.if",
      "typeVersion": 2,
      "position": [1780, 400]
    },
    {
      "parameters": {
        "chatId": "5619078117",
        "text": "=🟢 <b>Ollama / Open WebUI 已恢復</b>\n\n動作: {{ $('檢查修復結果').item.json.repairAction }}\n結果: HTTP {{ $('檢查修復結果').item.json.httpCode }}\n時間: {{ new Date().toLocaleString('zh-TW', {timeZone: 'Asia/Taipei'}) }}",
        "additionalFields": {
          "parse_mode": "HTML"
        }
      },
      "id": "notify-success",
      "name": "通知修復成功",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [2000, 300],
      "credentials": {
        "telegramApi": {
          "id": "telegram-bot",
          "name": "Telegram Bot"
        }
      }
    },
    {
      "parameters": {
        "chatId": "5619078117",
        "text": "=🔴 <b>Ollama / Open WebUI 修復失敗</b>\n\n嘗試動作: {{ $('檢查修復結果').item.json.repairAction }}\n結果: HTTP {{ $('檢查修復結果').item.json.httpCode }}\n\n<b>需要人工介入處理</b>\nSSH: ssh ollama@192.168.0.188\n\n時間: {{ new Date().toLocaleString('zh-TW', {timeZone: 'Asia/Taipei'}) }}",
        "additionalFields": {
          "parse_mode": "HTML"
        }
      },
      "id": "notify-failure",
      "name": "通知修復失敗",
      "type": "n8n-nodes-base.telegram",
      "typeVersion": 1.2,
      "position": [2000, 500],
      "credentials": {
        "telegramApi": {
          "id": "telegram-bot",
          "name": "Telegram Bot"
        }
      }
    },
    {
      "parameters": {},
      "id": "no-op-healthy",
      "name": "服務正常，無需操作",
      "type": "n8n-nodes-base.noOp",
      "typeVersion": 1,
      "position": [900, 200]
    }
  ],
  "connections": {
    "每 5 分鐘執行": {
      "main": [
        [
          {
            "node": "檢查 Ollama API",
            "type": "main",
            "index": 0
          },
          {
            "node": "檢查 Open WebUI",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "檢查 Ollama API": {
      "main": [
        [
          {
            "node": "服務健康?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "檢查 Open WebUI": {
      "main": [
        [
          {
            "node": "服務健康?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "服務健康?": {
      "main": [
        [
          {
            "node": "服務正常，無需操作",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "分析失敗原因",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "分析失敗原因": {
      "main": [
        [
          {
            "node": "需要重啟 Docker?",
            "type": "main",
            "index": 0
          },
          {
            "node": "發送異常告警",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "需要重啟 Docker?": {
      "main": [
        [
          {
            "node": "重啟 Docker Daemon",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "重啟 Open WebUI 容器",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "重啟 Docker Daemon": {
      "main": [
        [
          {
            "node": "檢查修復結果",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "重啟 Open WebUI 容器": {
      "main": [
        [
          {
            "node": "檢查修復結果",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "檢查修復結果": {
      "main": [
        [
          {
            "node": "修復成功?",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "修復成功?": {
      "main": [
        [
          {
            "node": "通知修復成功",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "通知修復失敗",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1"
  },
  "tags": [
    {
      "name": "monitoring"
    },
    {
      "name": "auto-repair"
    }
  ],
  "pinData": {},
  "meta": {
    "instanceId": "momo-pro-system"
  }
}
