{
  "id": "tzQ0PE6rXyeKv6cO",
  "name": "LINE Photo to AI Diary with Google Drive Storage",
  "tags": [],
  "nodes": [
    {
      "id": "2bf0e475-39e6-4780-914e-805f609bd9e6",
      "name": "LINE Webhook",
      "type": "n8n-nodes-base.webhook",
      "position": [
        496,
        560
      ],
      "parameters": {
        "path": "line-webhook",
        "options": {},
        "httpMethod": "POST",
        "responseMode": "lastNode"
      },
      "typeVersion": 2.1
    },
    {
      "id": "07fcd5e7-3957-462c-8b8c-6c457a5a139d",
      "name": "Extract LINE Message Data",
      "type": "n8n-nodes-base.code",
      "position": [
        720,
        560
      ],
      "parameters": {
        "jsCode": "const body = $input.first().json.body;\nconst events = body.events || [];\n\nif (events.length === 0) {\n  return [];\n}\n\nconst event = events[0];\nconst messageId = event.message?.id;\nconst replyToken = event.replyToken;\nconst messageType = event.message?.type;\n\nreturn [{\n  json: {\n    messageId,\n    replyToken,\n    messageType,\n    event\n  }\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "7cf0a1b2-9886-4872-b7da-36a139433e95",
      "name": "Get Image from LINE",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        944,
        560
      ],
      "parameters": {
        "url": "=https://api-data.line.me/v2/bot/message/{{ $json.messageId }}/content",
        "options": {
          "response": {
            "response": {
              "responseFormat": "file"
            }
          }
        },
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_TOKEN_HERE"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "ae8e9d41-31e7-414a-8be2-c3f1a431706b",
      "name": "OpenAI Vision - Generate Diary",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        1168,
        560
      ],
      "parameters": {
        "text": "\u3053\u306e\u5199\u771f\u3092\u898b\u3066\u300150\u6587\u5b57\u4ee5\u5185\u3067\u65e5\u8a18\u98a8\u306e\u4e00\u8a00\u3092\u66f8\u3044\u3066\u304f\u3060\u3055\u3044\u3002",
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o",
          "cachedResultName": "GPT-4O"
        },
        "options": {},
        "resource": "image",
        "inputType": "base64",
        "operation": "analyze"
      },
      "typeVersion": 1.8
    },
    {
      "id": "984a70ea-e52f-48ca-9f8f-9677ace45305",
      "name": "Prepare Folder Path",
      "type": "n8n-nodes-base.code",
      "position": [
        1392,
        560
      ],
      "parameters": {
        "jsCode": "const now = new Date();\nconst year = now.getFullYear();\nconst month = String(now.getMonth() + 1).padStart(2, '0');\n\n// \u30d5\u30a9\u30eb\u30c0\u306e\u30d1\u30b9\nconst folderPath = `KidsDiary/${year}/${month}`;\n\n// \u2605\u3053\u3053\u3092\u4fee\u6b63\uff1aOpenAI \u30ce\u30fc\u30c9\u306e content \u3092\u8aad\u3080\n// \u3053\u306e\u30ce\u30fc\u30c9\u306e1\u3064\u524d\u304c\u300cOpenAI Vision - Generate Diary\u300d\u306b\u306a\u3063\u3066\u3044\u308b\u524d\u63d0\nconst diaryText = $input.first().json.content || '';\n\n// \u753b\u50cf\u30d0\u30a4\u30ca\u30ea\uff08\u3053\u308c\u306f\u4eca\u307e\u3067\u901a\u308a\uff09\nconst imageBinary = $('Get Image from LINE').first().binary.data;\n\n// 1. \u5148\u306b\u753b\u50cf\u30c7\u30fc\u30bf\u3092\u53d6\u5f97\u3057\u3066\u5909\u6570\u306b\u5165\u308c\u307e\u3059\nconst binaryData = $('Get Image from LINE').first().binary;\n\n// 2. \u30c7\u30fc\u30bf\u3092\u307e\u3068\u3081\u3066\u6b21\u306e\u30ce\u30fc\u30c9\u306b\u6e21\u3057\u307e\u3059\nreturn [{\n    json: {\n        folderPath,\n        year,\n        month,\n        diaryText,\n    },\n    binary: binaryData\n}];"
      },
      "typeVersion": 2
    },
    {
      "id": "ec8032aa-d22e-4811-8bba-b3d01961b295",
      "name": "Create Folder Structure",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        1616,
        496
      ],
      "parameters": {
        "name": "=={{ 'KidsDiary_' + $json.year + '_' + $json.month }}\n",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {
          "simplifyOutput": true
        },
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "root"
        },
        "resource": "folder"
      },
      "typeVersion": 3
    },
    {
      "id": "07336be8-4edc-4cc9-8123-e27b63f59783",
      "name": "Upload Photo to Drive",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        2064,
        464
      ],
      "parameters": {
        "name": "={{ $json.diaryText }}",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "root"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "63606387-0f0b-4730-a419-6471d760a1c2",
      "name": "Reply to LINE",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2512,
        656
      ],
      "parameters": {
        "url": "https://api.line.me/v2/bot/message/reply",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"replyToken\": \"{{ $('Extract LINE Message Data').first().json.replyToken }}\",\n  \"messages\": [\n    {\n      \"type\": \"text\",\n      \"text\": \"\u5199\u771f\u3068\u65e5\u8a18\u3092\u4fdd\u5b58\u3057\u307e\u3057\u305f\uff01\"\n    }\n  ]\n}",
        "sendBody": true,
        "sendHeaders": true,
        "specifyBody": "json",
        "headerParameters": {
          "parameters": [
            {
              "name": "Authorization",
              "value": "Bearer YOUR_TOKEN_HERE"
            },
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "14e0396e-fec5-4288-b2c2-1204a5c831a5",
      "name": "Merge",
      "type": "n8n-nodes-base.merge",
      "position": [
        1840,
        560
      ],
      "parameters": {
        "mode": "combine",
        "options": {},
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "e42265f4-da00-48e3-a620-76cdff9568ab",
      "name": "Convert to File",
      "type": "n8n-nodes-base.convertToFile",
      "position": [
        2064,
        656
      ],
      "parameters": {
        "options": {},
        "operation": "toText",
        "sourceProperty": "diaryText"
      },
      "typeVersion": 1.1
    },
    {
      "id": "0d1301b6-4a36-41c2-b023-39c3e5abde15",
      "name": "Upload Photo to diary\u3000new",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        2288,
        656
      ],
      "parameters": {
        "name": "=={{ $now.format('yyyy-MM-dd_HHmmss') }}_diary.txt",
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "id",
          "value": "={{ $json.id }}"
        }
      },
      "typeVersion": 3
    },
    {
      "id": "97921c19-4783-42a0-af7a-2e339e2d11ea",
      "name": "Sticky Note - Step 1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        768,
        192
      ],
      "parameters": {
        "width": 376,
        "height": 268,
        "content": "## Step 1 \u2013 Receive photo\n\nThis group handles the incoming image from LINE:\n\n- **LINE Webhook** receives the photo message from the user.\n- **Extract LINE Message Data** pulls out the `messageId` and `replyToken` from the event payload.\n- **Get Image from LINE** calls the LINE content API and downloads the binary image file.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "e773de44-7edb-4e6c-b98d-8c050760f23c",
      "name": "Sticky Note - Step 2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1152,
        736
      ],
      "parameters": {
        "width": 440,
        "height": 332,
        "content": "## Step 2 \u2013 Create diary text & folder path\n\nThese nodes generate the AI diary sentence and prepare where it will be stored:\n\n- **OpenAI Vision \u2013 Generate Diary** analyzes the photo and returns a short, Japanese diary-style sentence (about 50 characters).\n- **Prepare Folder Path** builds a `KidsDiary/YYYY/MM` path based on the current date.\n- **Create Folder Structure** ensures the Google Drive folder exists before any files are uploaded.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "39c6583d-e08f-4993-aba2-cb7ab9e771cd",
      "name": "Sticky Note - Step 3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1696,
        112
      ],
      "parameters": {
        "width": 360,
        "height": 348,
        "content": "## Step 3 \u2013 Prepare diary file for Google Drive\n\nHere we combine data and create the text file that will sit next to the photo:\n\n- **Merge** joins together the original image metadata and the AI diary sentence.\n- **Convert to File** turns the diary text into a `.txt` file.\n- **Upload Photo to diary\u3000new** uploads the `_diary.txt` file to Google Drive so it lives next to the photo in the same folder.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "913f4033-3fbf-4dc0-80e5-0ee976ba5f04",
      "name": "Sticky Note - Step 4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2160,
        848
      ],
      "parameters": {
        "width": 440,
        "height": 284,
        "content": "## Step 4 \u2013 Save original photo & confirm to user\n\nFinally, the workflow stores the original image and lets the user know everything worked:\n\n- **Upload Photo to Drive** uploads the original photo into the `KidsDiary/YYYY/MM` folder with a timestamped filename.\n- **Reply to LINE** sends a confirmation message so the user knows their photo and diary entry were saved successfully.\n"
      },
      "typeVersion": 1
    },
    {
      "id": "7d34abbd-265f-4e3f-85bf-d684593ab04f",
      "name": "Sticky Note - Overview1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -48,
        -80
      ],
      "parameters": {
        "color": 4,
        "width": 584,
        "height": 600,
        "content": "## LINE Photo to AI Diary with Google Drive Storage\n\nThis workflow turns every photo sent to your LINE bot into a tiny AI-generated diary entry, plus neatly named image and text files in Google Drive. Each run saves the original photo and a matching `_diary.txt` file inside a `KidsDiary/YYYY/MM` folder, so you can easily look back on each day later.\n\n### Who this is for\n- Parents who want an easy kids' photo diary\n- Anyone who sends photos to LINE and wants them auto-archived\n- People who prefer a \u201ctake a photo and forget\u201d style journal\n\n### How it works\n1. **Step 1 \u2013 Receive photo** \u2013 LINE Webhook receives the image, Extract LINE Message Data pulls out `messageId` and `replyToken`, and Get Image from LINE downloads the binary photo via the LINE content API.\n2. **Step 2 \u2013 Create diary text & folder path** \u2013 OpenAI Vision \u2013 Generate Diary creates a short Japanese diary-style sentence (around 50 characters), while Prepare Folder Path and Create Folder Structure build a `KidsDiary/YYYY/MM` folder path in Google Drive.\n3. **Step 3 \u2013 Prepare files for Drive** \u2013 Merge and Convert to File combine the outputs and create a `.txt` file for the diary sentence so it can be stored alongside the image.\n4. **Step 4 \u2013 Save & confirm** \u2013 Upload Photo to Drive and Upload Photo to diary\u3000new store the photo and text file in the same folder, then Reply to LINE sends a confirmation message back to the user.\n"
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "7d79041a-fb4e-4298-99a5-fa6cd0fde74a",
  "connections": {
    "Merge": {
      "main": [
        [
          {
            "node": "Convert to File",
            "type": "main",
            "index": 0
          },
          {
            "node": "Upload Photo to Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "LINE Webhook": {
      "main": [
        [
          {
            "node": "Extract LINE Message Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Convert to File": {
      "main": [
        [
          {
            "node": "Upload Photo to diary\u3000new",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Image from LINE": {
      "main": [
        [
          {
            "node": "OpenAI Vision - Generate Diary",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Prepare Folder Path": {
      "main": [
        [
          {
            "node": "Create Folder Structure",
            "type": "main",
            "index": 0
          },
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Create Folder Structure": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract LINE Message Data": {
      "main": [
        [
          {
            "node": "Get Image from LINE",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Upload Photo to diary\u3000new": {
      "main": [
        [
          {
            "node": "Reply to LINE",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "OpenAI Vision - Generate Diary": {
      "main": [
        [
          {
            "node": "Prepare Folder Path",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}