{
  "id": "kPEtqTj6s9g3EEJX",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Conversational Trip Memory Search Engine",
  "tags": [],
  "nodes": [
    {
      "id": "913d1fe9-6b36-477e-a74a-cae9cc996a89",
      "name": "Webhook Trigger",
      "type": "n8n-nodes-base.webhook",
      "position": [
        96,
        464
      ],
      "parameters": {
        "path": "trip-search",
        "options": {},
        "httpMethod": "POST"
      },
      "typeVersion": 1.1
    },
    {
      "id": "73060b75-b123-4186-a6c1-dd96fa091b9b",
      "name": "Welcome Guide",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -784,
        -624
      ],
      "parameters": {
        "width": 520,
        "height": 1496,
        "content": "## \ud83d\uddfa\ufe0f Conversational Trip Memory Search Engine\n### Natural Language Travel History Search System\n\n**What This Does:**\nSearch your past trips using natural language queries like:\n- \"Show my Goa hotel from last year\"\n- \"Where did I stay in Paris?\"\n- \"Find my beach trips from 2024\"\n- \"Show all Italy restaurants I visited\"\n\n**How It Works:**\n1. User sends natural language query\n2. AI extracts search parameters (location, date, type)\n3. Searches across multiple data sources\n4. AI enriches results with context\n5. Returns formatted memories with photos & details\n\n**Data Sources:**\n\ud83d\udce7 Gmail (booking confirmations)\n\ud83d\udcc5 Google Calendar (trip events)\n\ud83d\udcb3 Expense tracking (receipts)\n\ud83d\udcf8 Google Photos (trip images)\n\ud83d\uddfa\ufe0f Google Maps (location history)\n\n**Advanced Features:**\n\u23f1\ufe0f 3 Strategic wait nodes\n\ud83e\udde0 AI-powered query understanding\n\ud83d\udd0d Multi-source data fusion\n\ud83d\udcca Intelligent ranking & sorting\n\ud83c\udfa8 Rich response formatting\n\n**Use Cases:**\n- Find old booking confirmations\n- Remember restaurant names\n- Retrieve travel documents\n- Create trip summaries\n- Share travel memories\n\n## \ud83d\udcca Monitoring & Analytics\n\n**Search Logs:**\n- All queries saved to Google Drive\n- Track popular searches\n- Identify data gaps\n- Improve AI parsing\n\n**Metrics:**\n- Search success rate\n- Average response time\n- Data source coverage\n- User satisfaction\n\n**Performance:**\n- API call optimization\n- Cache frequently searched trips\n- Reduce wait times\n- Improve relevance\n\n**Future Enhancements:**\n- Voice search support\n- Multi-language queries\n- Automatic trip summaries\n- Share memories feature\n- Trip comparison tool"
      },
      "typeVersion": 1
    },
    {
      "id": "89608bfe-b422-4541-82d8-5dd94419e028",
      "name": "Extract Query",
      "type": "n8n-nodes-base.code",
      "position": [
        368,
        464
      ],
      "parameters": {
        "jsCode": "const query = $input.item.json.body.query || '';\nconst userId = $input.item.json.body.userId || 'default_user';\n\nreturn {\n  json: {\n    originalQuery: query,\n    userId: userId,\n    timestamp: new Date().toISOString(),\n    conversationId: `conv_${Date.now()}`\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "0ee07f05-89d8-4988-a3d4-002b0cb9e20c",
      "name": "AI Parse Query",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        656,
        464
      ],
      "parameters": {
        "url": "https://api.openai.com/v1/chat/completions",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"model\": \"gpt-4\",\n  \"messages\": [\n    {\n      \"role\": \"system\",\n      \"content\": \"You are a travel query parser. Extract structured data from natural language travel queries. Return ONLY valid JSON with: location (string), dateRange (object with start/end), tripType (hotel/restaurant/activity/all), keywords (array).\"\n    },\n    {\n      \"role\": \"user\",\n      \"content\": \"Parse this query: {{ $json.originalQuery }}\"\n    }\n  ],\n  \"temperature\": 0.3\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "openAiApi"
      },
      "credentials": {
        "openAiApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "a8668817-1443-473e-bc97-f2ae2f9bad99",
      "name": "Structure Parameters",
      "type": "n8n-nodes-base.code",
      "position": [
        928,
        464
      ],
      "parameters": {
        "jsCode": "const aiResponse = $input.item.json.choices[0].message.content;\nconst parsed = JSON.parse(aiResponse.replace(/```json|```/g, '').trim());\n\nreturn {\n  json: {\n    searchParams: {\n      location: parsed.location || '',\n      dateStart: parsed.dateRange?.start || '',\n      dateEnd: parsed.dateRange?.end || '',\n      tripType: parsed.tripType || 'all',\n      keywords: parsed.keywords || [],\n      originalQuery: $input.item.json.originalQuery\n    },\n    userId: $input.item.json.userId,\n    conversationId: $input.item.json.conversationId\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "cf813c44-3f27-4b71-bdfe-476a4a56f792",
      "name": "Stage 1 Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -16,
        -240
      ],
      "parameters": {
        "color": 4,
        "width": 832,
        "height": 928,
        "content": "## \ud83e\udde0 Stage 1: Query Understanding & Parsing\n\n**Purpose:**\nConvert natural language into structured search parameters.\n\n**Process:**\n1. Receive webhook query from user\n2. Extract user query and metadata\n3. Use GPT-4 to parse natural language\n4. Extract: location, dates, type, keywords\n5. Structure into searchable parameters\n\n**AI Extraction Examples:**\n\n**Query:** \"Show my Goa hotel from last year\"\n**Extracted:**\n- Location: \"Goa, India\"\n- Date: 2024-01-01 to 2024-12-31\n- Type: \"hotel\"\n- Keywords: [\"accommodation\", \"booking\"]\n\n**Query:** \"Paris restaurants in June\"\n**Extracted:**\n- Location: \"Paris, France\"\n- Date: 2024-06-01 to 2024-06-30\n- Type: \"restaurant\"\n- Keywords: [\"dining\", \"food\"]\n\n**Output:**\nStructured search object ready for multi-source querying"
      },
      "typeVersion": 1
    },
    {
      "id": "ee9926f8-e112-4339-a646-7a2be15da2bc",
      "name": "Search Gmail",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1328,
        304
      ],
      "parameters": {
        "url": "https://gmail.googleapis.com/gmail/v1/users/me/messages",
        "options": {},
        "sendQuery": true,
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "=from:(booking.com OR airbnb.com OR hotels.com) {{ $json.searchParams.location }} after:{{ $json.searchParams.dateStart }} before:{{ $json.searchParams.dateEnd }}"
            },
            {
              "name": "maxResults",
              "value": "20"
            }
          ]
        },
        "nodeCredentialType": "googleOAuth2Api"
      },
      "credentials": {
        "googleOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "e742c699-6b41-45d2-a1dd-22561b5c6b63",
      "name": "Search Calendar",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1328,
        464
      ],
      "parameters": {
        "url": "https://www.googleapis.com/calendar/v3/calendars/primary/events",
        "options": {},
        "sendQuery": true,
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "q",
              "value": "={{ $json.searchParams.location }}"
            },
            {
              "name": "timeMin",
              "value": "={{ $json.searchParams.dateStart }}"
            },
            {
              "name": "timeMax",
              "value": "={{ $json.searchParams.dateEnd }}"
            },
            {
              "name": "maxResults",
              "value": "50"
            }
          ]
        },
        "nodeCredentialType": "googleOAuth2Api"
      },
      "credentials": {
        "googleOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "7365407f-4fa2-453f-bc1f-927b889da40e",
      "name": "Search Photos",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1328,
        624
      ],
      "parameters": {
        "url": "https://photoslibrary.googleapis.com/v1/mediaItems:search",
        "options": {},
        "jsonBody": "={\n  \"filters\": {\n    \"dateFilter\": {\n      \"ranges\": [{\n        \"startDate\": {\n          \"year\": {{ $json.searchParams.dateStart.split('-')[0] }},\n          \"month\": {{ $json.searchParams.dateStart.split('-')[1] }},\n          \"day\": {{ $json.searchParams.dateStart.split('-')[2] }}\n        },\n        \"endDate\": {\n          \"year\": {{ $json.searchParams.dateEnd.split('-')[0] }},\n          \"month\": {{ $json.searchParams.dateEnd.split('-')[1] }},\n          \"day\": {{ $json.searchParams.dateEnd.split('-')[2] }}\n        }\n      }]\n    }\n  }\n}",
        "sendBody": true,
        "sendQuery": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "queryParameters": {
          "parameters": [
            {
              "name": "pageSize",
              "value": "25"
            }
          ]
        },
        "nodeCredentialType": "googleOAuth2Api"
      },
      "credentials": {
        "googleOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "43ca5299-2f50-42f2-8da9-7dae6850cbaf",
      "name": "Wait 1 - API Cool Down",
      "type": "n8n-nodes-base.wait",
      "position": [
        1616,
        464
      ],
      "parameters": {
        "amount": 3
      },
      "typeVersion": 1.1
    },
    {
      "id": "93d258a8-dd58-4f65-9ddd-3e5797426814",
      "name": "Stage 2 Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        880,
        -272
      ],
      "parameters": {
        "color": 6,
        "width": 1132,
        "height": 1040,
        "content": "## \ud83d\udd0d Stage 2: Multi-Source Data Retrieval\n\n**Purpose:**\nSearch across all connected travel data sources simultaneously.\n\n**Data Sources:**\n\n**1. Gmail Search:**\n- Booking confirmations (Booking.com, Airbnb, Hotels.com)\n- Flight tickets (airlines)\n- Restaurant reservations (OpenTable, Resy)\n- Activity bookings (GetYourGuide, Viator)\n\n**2. Google Calendar:**\n- Trip events and itineraries\n- Hotel check-in/out dates\n- Restaurant reservations\n- Activity schedules\n\n**3. Google Photos:**\n- Photos from trip dates\n- Location-tagged images\n- Visual memories\n\n**Wait Node #1:**\n- **Duration:** 3 seconds\n- **Purpose:** API rate limit protection\n- **Why:** Prevents hitting Google API quotas\n\n**Output:**\nRaw data from all sources ready for fusion"
      },
      "typeVersion": 1
    },
    {
      "id": "6e47bba0-186d-47e1-911c-b94d4124c7ff",
      "name": "Merge All Sources",
      "type": "n8n-nodes-base.merge",
      "position": [
        1888,
        464
      ],
      "parameters": {
        "mode": "combine",
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "808c3849-91f2-4ce9-9a0c-1d802122d231",
      "name": "Fuse Data",
      "type": "n8n-nodes-base.code",
      "position": [
        2176,
        464
      ],
      "parameters": {
        "jsCode": "const gmailData = $input.item.json.gmailResults || [];\nconst calendarData = $input.item.json.calendarResults || [];\nconst photosData = $input.item.json.photosResults || [];\nconst searchParams = $input.item.json.searchParams;\n\n// Combine and deduplicate data\nconst allResults = [\n  ...gmailData.map(item => ({ source: 'gmail', type: 'booking', ...item })),\n  ...calendarData.map(item => ({ source: 'calendar', type: 'event', ...item })),\n  ...photosData.map(item => ({ source: 'photos', type: 'image', ...item }))\n];\n\n// Filter by relevance\nconst filtered = allResults.filter(item => {\n  const itemText = JSON.stringify(item).toLowerCase();\n  const location = searchParams.location.toLowerCase();\n  return itemText.includes(location);\n});\n\nreturn {\n  json: {\n    results: filtered,\n    totalFound: filtered.length,\n    searchParams: searchParams,\n    sources: {\n      gmail: gmailData.length,\n      calendar: calendarData.length,\n      photos: photosData.length\n    }\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "365932ca-e446-4ca1-8c18-476efb7fb2df",
      "name": "Wait 2 - Data Processing",
      "type": "n8n-nodes-base.wait",
      "position": [
        2448,
        464
      ],
      "parameters": {
        "amount": 2
      },
      "typeVersion": 1.1
    },
    {
      "id": "1dad1cbb-4178-4f7c-8256-74ca66ed0d0c",
      "name": "Stage 3 Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2112,
        -288
      ],
      "parameters": {
        "color": 4,
        "width": 780,
        "height": 1024,
        "content": "## \ud83c\udfaf Stage 3: Data Fusion & Ranking\n\n**Purpose:**\nCombine results from all sources and rank by relevance.\n\n**Data Fusion Process:**\n1. Merge Gmail, Calendar, and Photos results\n2. Deduplicate entries (same hotel from multiple sources)\n3. Cross-reference data (match photos to bookings)\n4. Filter by search parameters\n5. Calculate relevance scores\n\n**Ranking Factors:**\n- Location match accuracy (90%)\n- Date range precision (85%)\n- Keyword relevance (75%)\n- Data completeness (booking + photos + calendar)\n- Recency (prefer recent trips)\n\n**Wait Node #2:**\n- **Duration:** 2 seconds\n- **Purpose:** Data processing buffer\n- **Why:** Allow time for complex data fusion\n\n**Enrichment:**\n- Link bookings to photos\n- Add map coordinates\n- Extract pricing info\n- Identify companions\n\n**Output:**\nRanked, enriched results ready for AI enhancement"
      },
      "typeVersion": 1
    },
    {
      "id": "bdf76990-2dc5-4659-9fad-f7c1a9ec6b5e",
      "name": "AI Enrich Response",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        2736,
        464
      ],
      "parameters": {
        "url": "https://api.anthropic.com/v1/messages",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"model\": \"claude-sonnet-4-20250514\",\n  \"max_tokens\": 3000,\n  \"messages\": [\n    {\n      \"role\": \"user\",\n      \"content\": \"Based on this search query: '{{ $json.searchParams.originalQuery }}' and these results: {{ JSON.stringify($json.results) }}, create a rich, conversational response. Include: 1) Direct answer to query, 2) Key details (hotel name, dates, price), 3) Related memories, 4) Suggestions for similar trips. Format as friendly conversation.\"\n    }\n  ]\n}",
        "sendBody": true,
        "specifyBody": "json",
        "authentication": "predefinedCredentialType",
        "nodeCredentialType": "anthropicApi"
      },
      "credentials": {
        "anthropicApi": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "7df0730e-0b78-4316-9901-42a39790c8eb",
      "name": "Format Response",
      "type": "n8n-nodes-base.code",
      "position": [
        3008,
        464
      ],
      "parameters": {
        "jsCode": "const aiResponse = $input.item.json.content[0].text;\nconst results = $input.item.json.results || [];\nconst searchParams = $input.item.json.searchParams;\n\n// Format final response\nconst response = {\n  success: true,\n  conversationId: $input.item.json.conversationId,\n  query: searchParams.originalQuery,\n  answer: aiResponse,\n  metadata: {\n    totalResults: results.length,\n    sources: $input.item.json.sources,\n    searchParams: searchParams\n  },\n  results: results.slice(0, 10).map(r => ({\n    title: r.title || r.summary || 'Trip Memory',\n    date: r.date || r.startTime,\n    location: r.location || searchParams.location,\n    type: r.type,\n    source: r.source,\n    imageUrl: r.imageUrl || null,\n    details: r.details || {}\n  })),\n  suggestions: [\n    `Show more trips to ${searchParams.location}`,\n    `Find photos from this trip`,\n    `See all ${searchParams.tripType} bookings`\n  ]\n};\n\nreturn { json: response };"
      },
      "typeVersion": 2
    },
    {
      "id": "7297c74e-c1d0-4594-ba52-79549568ce80",
      "name": "Wait 3 - Final Polish",
      "type": "n8n-nodes-base.wait",
      "position": [
        3296,
        464
      ],
      "parameters": {
        "amount": 1
      },
      "typeVersion": 1.1
    },
    {
      "id": "e3a26551-2e8b-428b-92d6-0856713b2dd8",
      "name": "Stage 4 Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2976,
        -416
      ],
      "parameters": {
        "color": 6,
        "width": 820,
        "height": 1184,
        "content": "## \u2728 Stage 4: AI Enhancement & Response Formatting\n\n**Purpose:**\nUse AI to create conversational, context-rich responses.\n\n**AI Enhancement:**\n\n**Input:** Raw search results + user query\n**AI Tasks:**\n1. Understand user intent\n2. Create conversational answer\n3. Highlight key information\n4. Add context and memories\n5. Suggest related searches\n\n**Response Format:**\n```json\n{\n  \"answer\": \"You stayed at The Taj in Goa from Dec 24-28, 2024...\",\n  \"results\": [\n    {\n      \"title\": \"The Taj Hotel, Goa\",\n      \"dates\": \"Dec 24-28, 2024\",\n      \"price\": \"\u20b945,000\",\n      \"photos\": 23,\n      \"rating\": 4.8\n    }\n  ],\n  \"suggestions\": [\"See Goa restaurant bookings\", \"View all beach trips\"]\n}\n```\n\n**Wait Node #3:**\n- **Duration:** 1 second\n- **Purpose:** Final response polishing\n- **Why:** Ensure clean delivery to user\n\n**Output:**\nBeautiful, conversational response ready for user"
      },
      "typeVersion": 1
    },
    {
      "id": "cfabfb5c-c8df-421a-90ab-58a26398f471",
      "name": "Return Response",
      "type": "n8n-nodes-base.respondToWebhook",
      "position": [
        3568,
        464
      ],
      "parameters": {
        "options": {},
        "respondWith": "json",
        "responseBody": "={{ JSON.stringify($json) }}"
      },
      "typeVersion": 1
    },
    {
      "id": "1512e987-baa2-4df3-8f3f-69aaa92a439d",
      "name": "Log to Drive",
      "type": "n8n-nodes-base.googleDrive",
      "position": [
        3568,
        624
      ],
      "parameters": {
        "driveId": {
          "__rl": true,
          "mode": "list",
          "value": "My Drive"
        },
        "options": {},
        "folderId": {
          "__rl": true,
          "mode": "list",
          "value": "root",
          "cachedResultName": "/ (Root folder)"
        },
        "operation": "createFromText"
      },
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 3
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "5ef57942-68cf-45a6-98d2-1e2b41051417",
  "connections": {
    "Fuse Data": {
      "main": [
        [
          {
            "node": "Wait 2 - Data Processing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Gmail": {
      "main": [
        [
          {
            "node": "Wait 1 - API Cool Down",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Query": {
      "main": [
        [
          {
            "node": "AI Parse Query",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Photos": {
      "main": [
        [
          {
            "node": "Wait 1 - API Cool Down",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Parse Query": {
      "main": [
        [
          {
            "node": "Structure Parameters",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Format Response": {
      "main": [
        [
          {
            "node": "Wait 3 - Final Polish",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Search Calendar": {
      "main": [
        [
          {
            "node": "Wait 1 - API Cool Down",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Webhook Trigger": {
      "main": [
        [
          {
            "node": "Extract Query",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge All Sources": {
      "main": [
        [
          {
            "node": "Fuse Data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Enrich Response": {
      "main": [
        [
          {
            "node": "Format Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structure Parameters": {
      "main": [
        [
          {
            "node": "Search Gmail",
            "type": "main",
            "index": 0
          },
          {
            "node": "Search Calendar",
            "type": "main",
            "index": 0
          },
          {
            "node": "Search Photos",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 3 - Final Polish": {
      "main": [
        [
          {
            "node": "Return Response",
            "type": "main",
            "index": 0
          },
          {
            "node": "Log to Drive",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 1 - API Cool Down": {
      "main": [
        [
          {
            "node": "Merge All Sources",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 2 - Data Processing": {
      "main": [
        [
          {
            "node": "AI Enrich Response",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}