Qwen3-VL-8B-Thinking旅行规划器
高级
这是一个Personal Productivity, Multimodal AI领域的自动化工作流,包含 18 个节点。主要使用 Set, Code, Gmail, Slack, Webhook 等节点。 基于Skyscanner、Booking.com和Gmail的AI优化旅行行程生成器
前置要求
- •Google 账号和 Gmail API 凭证
- •Slack Bot Token 或 Webhook URL
- •HTTP Webhook 端点(n8n 会自动生成)
- •可能需要目标 API 的认证凭证
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"id": "Yi6ZHj09hQ6aoCt2",
"meta": {
"instanceId": "b91e510ebae4127f953fd2f5f8d40d58ca1e71c746d4500c12ae86aad04c1502",
"templateCredsSetupCompleted": true
},
"name": "Qwen3-VL-8B-Thinking旅行规划器:搜索-->比较-->邮件发送最佳行程",
"tags": [],
"nodes": [
{
"id": "f3a23f51-4039-4a08-bad5-d9e1f475e8af",
"name": "Webhook - 旅行请求",
"type": "n8n-nodes-base.webhook",
"position": [
2832,
-256
],
"webhookId": "1fa59b2c-c301-41bf-8f01-6feb10be6aa8",
"parameters": {
"path": "travel-search",
"options": {},
"httpMethod": "POST",
"responseMode": "responseNode"
},
"typeVersion": 2
},
{
"id": "65e7017e-5242-4875-bf24-661fc68eb771",
"name": "提取请求数据",
"type": "n8n-nodes-base.set",
"position": [
2992,
-256
],
"parameters": {
"options": {},
"assignments": {
"assignments": [
{
"id": "a1",
"name": "destination",
"type": "string",
"value": "={{ $json.body.destination || 'Shanghai' }}"
},
{
"id": "a2",
"name": "departureCity",
"type": "string",
"value": "={{ $json.body.departureCity }}"
},
{
"id": "a3",
"name": "checkInDate",
"type": "string",
"value": "={{ $json.body.checkInDate }}"
},
{
"id": "a4",
"name": "checkOutDate",
"type": "string",
"value": "={{ $json.body.checkOutDate }}"
},
{
"id": "a5",
"name": "travelers",
"type": "number",
"value": "={{ $json.body.travelers || 1 }}"
},
{
"id": "a6",
"name": "email",
"type": "string",
"value": "={{ $json.body.email }}"
}
]
}
},
"typeVersion": 3.4
},
{
"id": "51891077-df8a-45db-b575-0585f52aa1db",
"name": "搜索航班 - Skyscanner",
"type": "n8n-nodes-base.httpRequest",
"position": [
3216,
-640
],
"parameters": {
"url": "https://skyscanner-api.p.rapidapi.com/v3/flights/live/search/create",
"method": "POST",
"options": {},
"sendBody": true,
"sendHeaders": true,
"authentication": "predefinedCredentialType",
"bodyParameters": {
"parameters": [
{
"name": "query",
"value": "={{ {\"market\":\"US\",\"locale\":\"en-US\",\"currency\":\"USD\",\"queryLegs\":[{\"originPlace\":{\"queryPlace\":{\"iata\":$json.departureCity}},\"destinationPlace\":{\"queryPlace\":{\"iata\":$json.destination}},\"date\":{\"year\":$json.checkInDate.split('-')[0],\"month\":$json.checkInDate.split('-')[1],\"day\":$json.checkInDate.split('-')[2]}}],\"adults\":$json.travelers,\"cabinClass\":\"CABIN_CLASS_ECONOMY\"} }}"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "X-RapidAPI-Key",
"value": "={{ $credentials.rapidApiKey }}"
},
{
"name": "X-RapidAPI-Host",
"value": "skyscanner-api.p.rapidapi.com"
}
]
},
"nodeCredentialType": "httpHeaderAuth"
},
"typeVersion": 4.2
},
{
"id": "953e3d0b-528d-41ba-b7ba-4fc7363c703f",
"name": "搜索酒店 - Booking.com",
"type": "n8n-nodes-base.httpRequest",
"position": [
3216,
-448
],
"parameters": {
"url": "https://booking-com.p.rapidapi.com/v1/hotels/search",
"options": {},
"sendQuery": true,
"sendHeaders": true,
"authentication": "predefinedCredentialType",
"queryParameters": {
"parameters": [
{
"name": "dest_type",
"value": "city"
},
{
"name": "dest_id",
"value": "={{ $('Extract Request Data').item.json.destination }}"
},
{
"name": "checkin_date",
"value": "={{ $('Extract Request Data').item.json.checkInDate }}"
},
{
"name": "checkout_date",
"value": "={{ $('Extract Request Data').item.json.checkOutDate }}"
},
{
"name": "adults_number",
"value": "={{ $('Extract Request Data').item.json.travelers }}"
},
{
"name": "order_by",
"value": "price"
},
{
"name": "units",
"value": "metric"
},
{
"name": "room_number",
"value": "1"
}
]
},
"headerParameters": {
"parameters": [
{
"name": "X-RapidAPI-Key",
"value": "={{ $credentials.rapidApiKey }}"
},
{
"name": "X-RapidAPI-Host",
"value": "booking-com.p.rapidapi.com"
}
]
},
"nodeCredentialType": "httpHeaderAuth"
},
"typeVersion": 4.2
},
{
"id": "133388c8-6fe6-42cb-94b7-f76bf0cb4b2e",
"name": "通过Gmail发送邮件",
"type": "n8n-nodes-base.gmail",
"position": [
4480,
64
],
"webhookId": "10b4febd-7ca2-41c6-866c-979cc9592dbb",
"parameters": {
"sendTo": "={{ $('Webhook - Travel Request').item.json.body.email }}",
"message": "={{ $json.html }}",
"options": {},
"subject": "🤖 AI-Optimized Travel Itinerary: {{ $('Extract Request Data').item.json.destination }} Trip"
},
"typeVersion": 2.1
},
{
"id": "5fcf6271-c0fd-430b-858e-4a462e98b648",
"name": "响应Webhook",
"type": "n8n-nodes-base.respondToWebhook",
"position": [
4784,
64
],
"parameters": {
"options": {},
"respondWith": "json",
"responseBody": "={{ { \"success\": true, \"message\": \"AI-optimized travel itinerary sent successfully!\", \"itinerariesCount\": $('AI Score & Recommendations').all().length, \"email\": $('Extract Request Data').item.json.email, \"bestDeal\": { \"price\": $('AI Score & Recommendations').first().json.totalPrice, \"aiScore\": $('AI Score & Recommendations').first().json.aiScore } } }}"
},
"typeVersion": 1
},
{
"id": "2aedf5b8-536b-44bc-9b6d-3b80daa2c6c0",
"name": "AI代理 - 行程优化器",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
3808,
-496
],
"parameters": {
"options": {
"systemMessage": "You are a travel expert. Analyze the provided flight and hotel combinations and provide a detailed recommendation score (0-100) for each itinerary based on:\n1. Total price value\n2. Flight convenience (stops, duration, departure times)\n3. Hotel quality (rating, reviews, location)\n4. Overall trip experience\n\nFor each itinerary, return:\n- score (0-100)\n- reasoning (2-3 sentences)\n- highlights (bullet points)\n- warnings (if any)\n\nFormat as JSON array."
}
},
"typeVersion": 1
},
{
"id": "759f481f-598a-4bff-a3d1-3cb3310ecb88",
"name": "搜索替代航班 - Kiwi",
"type": "n8n-nodes-base.httpRequest",
"position": [
3216,
-256
],
"parameters": {
"url": "https://api.tequila.kiwi.com/v2/search",
"options": {},
"authentication": "predefinedCredentialType"
},
"typeVersion": 1
},
{
"id": "63c46681-a628-4bd8-aab0-a226ab57e703",
"name": "获取天气预报",
"type": "n8n-nodes-base.httpRequest",
"position": [
3216,
-64
],
"parameters": {
"url": "https://api.openweathermap.org/data/2.5/forecast",
"options": {}
},
"typeVersion": 1
},
{
"id": "15404c5f-d821-4455-abf6-a08db26baee3",
"name": "搜索本地活动 - Viator",
"type": "n8n-nodes-base.httpRequest",
"position": [
3216,
128
],
"parameters": {
"url": "https://viator-api.p.rapidapi.com/search",
"options": {},
"authentication": "predefinedCredentialType"
},
"typeVersion": 1
},
{
"id": "27b5a21e-02a6-43e2-b1b9-a7bd5074dd29",
"name": "合并所有数据源",
"type": "n8n-nodes-base.code",
"position": [
3440,
-256
],
"parameters": {
"jsCode": "const skyscannerFlights = $input.item(0).json;\nconst kiwiFlights = $input.item(1).json;\nconst bookingHotels = $input.item(2).json;\nconst weather = $input.item(3).json;\nconst activities = $input.item(4).json;\nconst requestData = $('Extract Request Data').first().json;\n\nconst allFlightData = {\n skyscanner: skyscannerFlights,\n kiwi: kiwiFlights,\n weather: weather,\n activities: activities\n};\n\nconst hotelData = bookingHotels;\n\nreturn [{\n json: {\n flights: allFlightData,\n hotels: hotelData,\n request: requestData\n }\n}];"
},
"typeVersion": 1
},
{
"id": "d460fa9d-9991-4f29-befc-caff18a9cf38",
"name": "增强型行程构建器",
"type": "n8n-nodes-base.code",
"position": [
3616,
-256
],
"parameters": {
"jsCode": "const mergedData = $input.first().json;\nconst requestData = mergedData.request;\n\n// Parse Skyscanner flights\nconst skyscannerFlights = [];\nif (mergedData.flights.skyscanner.itineraries?.results) {\n mergedData.flights.skyscanner.itineraries.results.slice(0, 8).forEach((flight, i) => {\n skyscannerFlights.push({\n id: `sky_${i}`,\n source: 'Skyscanner',\n airline: flight.legs[0]?.carriers?.marketing[0]?.name || 'Unknown',\n departureTime: flight.legs[0]?.departure || '',\n arrivalTime: flight.legs[0]?.arrival || '',\n duration: flight.legs[0]?.duration || 0,\n stops: flight.legs[0]?.stopCount || 0,\n price: flight.pricing?.price?.amount || 0,\n currency: flight.pricing?.price?.currency || 'USD',\n bookingLink: flight.deeplink || '#'\n });\n });\n}\n\n// Parse Kiwi flights\nconst kiwiFlights = [];\nif (mergedData.flights.kiwi.data) {\n mergedData.flights.kiwi.data.slice(0, 8).forEach((flight, i) => {\n kiwiFlights.push({\n id: `kiwi_${i}`,\n source: 'Kiwi.com',\n airline: flight.airlines?.[0] || 'Unknown',\n departureTime: new Date(flight.local_departure).toISOString(),\n arrivalTime: new Date(flight.local_arrival).toISOString(),\n duration: flight.duration?.total || 0,\n stops: (flight.route?.length || 1) - 1,\n price: flight.price || 0,\n currency: flight.currency || 'USD',\n bookingLink: flight.deep_link || '#'\n });\n });\n}\n\nconst allFlights = [...skyscannerFlights, ...kiwiFlights].sort((a,b) => a.price - b.price);\n\n// Parse hotels\nconst hotels = [];\nif (mergedData.hotels.result) {\n mergedData.hotels.result.slice(0, 10).forEach((hotel, i) => {\n hotels.push({\n id: `hotel_${i}`,\n name: hotel.hotel_name || 'Unknown',\n address: hotel.address || '',\n rating: hotel.review_score || 0,\n reviewCount: hotel.review_nr || 0,\n price: hotel.min_total_price || 0,\n pricePerNight: hotel.price_breakdown?.gross_price || 0,\n currency: hotel.currency_code || 'USD',\n amenities: hotel.unit_configuration_label || '',\n distanceToCenter: hotel.distance || '',\n bookingLink: hotel.url || '#'\n });\n });\n}\n\n// Weather summary\nlet weatherSummary = 'No weather data';\nif (mergedData.flights.weather?.list) {\n const temps = mergedData.flights.weather.list.slice(0, 8).map(w => w.main.temp);\n const avgTemp = (temps.reduce((a,b)=>a+b,0)/temps.length).toFixed(1);\n const conditions = mergedData.flights.weather.list[0]?.weather[0]?.description || 'N/A';\n weatherSummary = `${avgTemp}°C, ${conditions}`;\n}\n\n// Activities\nconst activities = [];\nif (mergedData.flights.activities?.data) {\n mergedData.flights.activities.data.slice(0, 10).forEach((act, i) => {\n activities.push({\n id: `act_${i}`,\n name: act.title || 'Activity',\n description: act.description || '',\n rating: act.rating || 0,\n reviewCount: act.reviewCount || 0,\n price: act.price?.amount || 0,\n currency: act.price?.currency || 'USD',\n duration: act.duration || '',\n bookingLink: act.productUrl || '#'\n });\n });\n}\n\n// Create enhanced itineraries (top 8)\nconst itineraries = [];\nfor (let f = 0; f < Math.min(4, allFlights.length); f++) {\n for (let h = 0; h < Math.min(2, hotels.length); h++) {\n if (itineraries.length >= 8) break;\n \n const flight = allFlights[f];\n const hotel = hotels[h];\n const selectedActivities = activities.slice(0, 3);\n \n const totalPrice = flight.price + hotel.price + selectedActivities.reduce((sum, act) => sum + act.price, 0);\n \n itineraries.push({\n id: `itinerary_${itineraries.length + 1}`,\n flight: flight,\n hotel: hotel,\n activities: selectedActivities,\n weather: weatherSummary,\n totalPrice: totalPrice,\n currency: flight.currency,\n destination: requestData.destination,\n departureCity: requestData.departureCity,\n checkInDate: requestData.checkInDate,\n checkOutDate: requestData.checkOutDate,\n travelers: requestData.travelers\n });\n }\n if (itineraries.length >= 8) break;\n}\n\nitineraries.sort((a, b) => a.totalPrice - b.totalPrice);\n\nreturn itineraries.slice(0, 8).map(it => ({ json: it }));"
},
"typeVersion": 1
},
{
"id": "33047f44-9726-4f2f-a029-c7e71c8aceb8",
"name": "AI评分与推荐",
"type": "n8n-nodes-base.code",
"position": [
4128,
64
],
"parameters": {
"jsCode": "const itineraries = $input.all().map(item => item.json);\nconst aiAnalysis = $('AI Agent - Itinerary Optimizer').first().json;\n\nlet aiScores = [];\ntry {\n aiScores = typeof aiAnalysis.output === 'string' ? JSON.parse(aiAnalysis.output) : aiAnalysis.output;\n} catch (e) {\n aiScores = itineraries.map((_, i) => ({\n score: 85 - i * 5,\n reasoning: 'AI analysis pending',\n highlights: ['Competitive pricing', 'Good availability'],\n warnings: []\n }));\n}\n\nconst enrichedItineraries = itineraries.map((itinerary, index) => {\n const aiData = aiScores[index] || { score: 75, reasoning: 'Standard option', highlights: [], warnings: [] };\n return {\n ...itinerary,\n aiScore: aiData.score || 75,\n aiReasoning: aiData.reasoning || 'Good option',\n aiHighlights: aiData.highlights || [],\n aiWarnings: aiData.warnings || []\n };\n});\n\nenrichedItineraries.sort((a, b) => b.aiScore - a.aiScore);\n\nreturn enrichedItineraries.map(it => ({ json: it }));"
},
"typeVersion": 1
},
{
"id": "015b10c8-ad0a-4f34-8855-e1366cde7658",
"name": "生成高级HTML邮件",
"type": "n8n-nodes-base.code",
"position": [
4288,
64
],
"parameters": {
"jsCode": "const itineraries = $input.all().map(item => item.json);\n\nif (itineraries.length === 0) {\n return [{ json: { html: '<html><body><h2>No Results</h2></body></html>' } }];\n}\n\nconst first = itineraries[0];\nlet html = `\n<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"UTF-8\">\n<style>\n body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; color: #1a1a1a; max-width: 1000px; margin: 0 auto; padding: 20px; background: #f8f9fa; }\n .container { background: white; border-radius: 12px; overflow: hidden; box-shadow: 0 4px 12px rgba(0,0,0,0.1); }\n .header { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 40px 30px; text-align: center; }\n .header h1 { margin: 0; font-size: 32px; font-weight: 700; }\n .summary { background: #f0f4ff; padding: 25px 30px; border-left: 5px solid #667eea; margin: 20px; }\n .summary strong { color: #667eea; }\n .itinerary { border: 2px solid #e0e0e0; margin: 20px; border-radius: 10px; overflow: hidden; transition: transform 0.2s; }\n .itinerary:hover { transform: translateY(-3px); box-shadow: 0 6px 20px rgba(0,0,0,0.15); }\n .best-deal { border-color: #ffd700; background: linear-gradient(to right, #fff9e6, #ffffff); }\n .best-deal .itinerary-header { background: linear-gradient(135deg, #ffd700, #ffed4e); }\n .itinerary-header { background: #667eea; color: white; padding: 20px; display: flex; justify-content: space-between; align-items: center; }\n .ai-score { background: white; color: #667eea; padding: 8px 20px; border-radius: 20px; font-weight: bold; font-size: 18px; }\n .section { padding: 25px; }\n .section-title { color: #667eea; font-size: 20px; font-weight: 600; margin-bottom: 15px; border-bottom: 2px solid #e0e0e0; padding-bottom: 8px; }\n .detail-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 15px; margin: 15px 0; }\n .detail-item { padding: 12px; background: #f8f9fa; border-radius: 6px; }\n .detail-label { color: #666; font-size: 13px; margin-bottom: 5px; }\n .detail-value { color: #1a1a1a; font-weight: 600; font-size: 15px; }\n .activities-list { list-style: none; padding: 0; }\n .activities-list li { padding: 12px; margin: 8px 0; background: #f0f4ff; border-left: 4px solid #667eea; border-radius: 4px; }\n .ai-insights { background: linear-gradient(135deg, #e0f7fa, #f0f4ff); padding: 20px; border-radius: 8px; margin: 15px 0; }\n .highlight { color: #2e7d32; }\n .warning { color: #d32f2f; }\n .price-box { text-align: center; background: linear-gradient(135deg, #667eea, #764ba2); color: white; padding: 25px; border-radius: 8px; margin: 20px 0; }\n .price { font-size: 42px; font-weight: 700; }\n .button { display: inline-block; padding: 14px 28px; background: linear-gradient(135deg, #667eea, #764ba2); color: white; text-decoration: none; border-radius: 25px; margin: 8px; font-weight: 600; transition: all 0.3s; }\n .button:hover { transform: scale(1.05); box-shadow: 0 4px 15px rgba(102, 126, 234, 0.4); }\n .comparison-table { width: 100%; border-collapse: collapse; margin: 20px 0; }\n .comparison-table th { background: #667eea; color: white; padding: 15px; text-align: left; font-weight: 600; }\n .comparison-table td { padding: 12px; border-bottom: 1px solid #e0e0e0; }\n .comparison-table tr:hover { background: #f8f9fa; }\n .badge { display: inline-block; padding: 5px 12px; background: #ffd700; color: #1a1a1a; border-radius: 15px; font-size: 12px; font-weight: 700; margin-left: 10px; }\n .weather-box { background: linear-gradient(135deg, #4facfe, #00f2fe); color: white; padding: 15px; border-radius: 8px; text-align: center; margin: 15px 0; }\n</style>\n</head>\n<body>\n<div class=\"container\">\n <div class=\"header\">\n <h1>✈️ Your AI-Optimized Travel Itineraries</h1>\n <p style=\"margin: 10px 0 0 0; font-size: 18px; opacity: 0.9;\">Powered by Advanced AI Analysis</p>\n </div>\n\n <div class=\"summary\">\n <strong>📍 Route:</strong> ${first.departureCity} → ${first.destination}<br>\n <strong>📅 Dates:</strong> ${first.checkInDate} to ${first.checkOutDate}<br>\n <strong>👥 Travelers:</strong> ${first.travelers}<br>\n <strong>🌤️ Weather:</strong> ${first.weather}\n </div>\n\n <div style=\"padding: 30px;\">\n <h2 style=\"color: #667eea; font-size: 28px; margin-bottom: 20px;\">🏆 Top ${itineraries.length} AI-Ranked Itineraries</h2>\n`;\n\nitineraries.forEach((it, index) => {\n const isBest = index === 0;\n html += `\n <div class=\"itinerary ${isBest ? 'best-deal' : ''}\">\n <div class=\"itinerary-header\" ${isBest ? 'style=\"background: linear-gradient(135deg, #ffd700, #ffed4e); color: #1a1a1a;\"' : ''}>\n <div>\n <h3 style=\"margin: 0; font-size: 24px;\">Option ${index + 1} ${isBest ? '<span class=\"badge\">BEST VALUE</span>' : ''}</h3>\n <p style=\"margin: 5px 0 0 0; opacity: 0.8;\">AI-Optimized Package</p>\n </div>\n <div class=\"ai-score\">🤖 ${it.aiScore}/100</div>\n </div>\n\n <div class=\"section\">\n <div class=\"ai-insights\">\n <strong style=\"color: #667eea; font-size: 16px;\">🧠 AI Analysis:</strong>\n <p style=\"margin: 10px 0;\">${it.aiReasoning}</p>\n ${it.aiHighlights.length > 0 ? `<div class=\"highlight\">✓ ${it.aiHighlights.join(' • ')}</div>` : ''}\n ${it.aiWarnings.length > 0 ? `<div class=\"warning\">⚠ ${it.aiWarnings.join(' • ')}</div>` : ''}\n </div>\n\n <div class=\"section-title\">✈️ Flight Details</div>\n <div class=\"detail-grid\">\n <div class=\"detail-item\"><div class=\"detail-label\">Source</div><div class=\"detail-value\">${it.flight.source}</div></div>\n <div class=\"detail-item\"><div class=\"detail-label\">Airline</div><div class=\"detail-value\">${it.flight.airline}</div></div>\n <div class=\"detail-item\"><div class=\"detail-label\">Departure</div><div class=\"detail-value\">${it.flight.departureTime}</div></div>\n <div class=\"detail-item\"><div class=\"detail-label\">Arrival</div><div class=\"detail-value\">${it.flight.arrivalTime}</div></div>\n <div class=\"detail-item\"><div class=\"detail-label\">Stops</div><div class=\"detail-value\">${it.flight.stops === 0 ? 'Non-stop ⭐' : it.flight.stops + ' stop(s)'}</div></div>\n <div class=\"detail-item\"><div class=\"detail-label\">Flight Price</div><div class=\"detail-value\">${it.currency} $${it.flight.price.toFixed(2)}</div></div>\n </div>\n\n <div class=\"section-title\">🏨 Hotel Details</div>\n <div class=\"detail-grid\">\n <div class=\"detail-item\"><div class=\"detail-label\">Hotel Name</div><div class=\"detail-value\">${it.hotel.name}</div></div>\n <div class=\"detail-item\"><div class=\"detail-label\">Rating</div><div class=\"detail-value\">⭐ ${it.hotel.rating}/10 (${it.hotel.reviewCount} reviews)</div></div>\n <div class=\"detail-item\"><div class=\"detail-label\">Location</div><div class=\"detail-value\">${it.hotel.distanceToCenter || 'City Center'}</div></div>\n <div class=\"detail-item\"><div class=\"detail-label\">Hotel Price</div><div class=\"detail-value\">${it.currency} $${it.hotel.price.toFixed(2)}</div></div>\n </div>\n\n ${it.activities.length > 0 ? `\n <div class=\"section-title\">🎯 Recommended Activities</div>\n <ul class=\"activities-list\">\n ${it.activities.map(act => `\n <li>\n <strong>${act.name}</strong> ${act.rating > 0 ? `(${act.rating}⭐)` : ''}<br>\n <span style=\"color: #666; font-size: 13px;\">${act.description.substring(0, 100)}...</span><br>\n <strong style=\"color: #667eea;\">${act.currency} $${act.price.toFixed(2)}</strong> • ${act.duration}\n </li>\n `).join('')}\n </ul>\n ` : ''}\n\n <div class=\"weather-box\">\n <strong>🌤️ Weather Forecast:</strong> ${it.weather}\n </div>\n\n <div class=\"price-box\">\n <div style=\"font-size: 16px; margin-bottom: 5px;\">TOTAL PACKAGE PRICE</div>\n <div class=\"price\">${it.currency} $${it.totalPrice.toFixed(2)}</div>\n <div style=\"margin-top: 20px;\">\n <a href=\"${it.flight.bookingLink}\" class=\"button\">Book Flight</a>\n <a href=\"${it.hotel.bookingLink}\" class=\"button\">Book Hotel</a>\n </div>\n </div>\n </div>\n </div>\n `;\n});\n\nhtml += `\n <div style=\"margin-top: 40px;\">\n <h2 style=\"color: #667eea; font-size: 24px;\">📊 Price Comparison Matrix</h2>\n <table class=\"comparison-table\">\n <tr>\n <th>Option</th>\n <th>AI Score</th>\n <th>Source</th>\n <th>Flight</th>\n <th>Hotel</th>\n <th>Activities</th>\n <th>Total</th>\n </tr>\n`;\n\nitineraries.forEach((it, i) => {\n const actPrice = it.activities.reduce((sum, a) => sum + a.price, 0);\n html += `\n <tr ${i === 0 ? 'style=\"background: #fff9e6; font-weight: bold;\"' : ''}>\n <td>Option ${i + 1} ${i === 0 ? '<span class=\"badge\">BEST</span>' : ''}</td>\n <td>${it.aiScore}/100</td>\n <td>${it.flight.source}</td>\n <td>$${it.flight.price.toFixed(2)}</td>\n <td>$${it.hotel.price.toFixed(2)}</td>\n <td>$${actPrice.toFixed(2)}</td>\n <td style=\"color: #667eea; font-size: 18px; font-weight: bold;\">$${it.totalPrice.toFixed(2)}</td>\n </tr>\n `;\n});\n\nhtml += `\n </table>\n </div>\n\n <div style=\"margin-top: 40px; padding: 25px; background: linear-gradient(135deg, #f0f4ff, #e0f7fa); border-radius: 10px;\">\n <h3 style=\"color: #667eea; margin-top: 0;\">💡 AI Travel Tips</h3>\n <ul style=\"line-height: 1.8;\">\n <li>Book flights and hotels separately for maximum flexibility</li>\n <li>Weather data is forecast-based; pack accordingly</li>\n <li>Activities can be booked on-site or in advance</li>\n <li>Prices are dynamic and subject to change</li>\n <li>Consider travel insurance for peace of mind</li>\n </ul>\n </div>\n </div>\n</div>\n\n<div style=\"text-align: center; margin-top: 30px; padding: 20px; color: #666; font-size: 13px;\">\n <p>🤖 This itinerary was generated by AI-powered n8n workflow automation<br>\n Prices and availability are subject to change • Book early for best rates</p>\n</div>\n</body>\n</html>\n`;\n\nreturn [{ json: { html, itineraries } }];"
},
"typeVersion": 1
},
{
"id": "0551345f-ca44-4adc-8f49-5ddf522f8a74",
"name": "发送Slack通知",
"type": "n8n-nodes-base.slack",
"position": [
4656,
256
],
"parameters": {
"text": "🎉 New travel itinerary sent!\\n✈️ Route: {{ $('Extract Request Data').item.json.departureCity }} → {{ $('Extract Request Data').item.json.destination }}\\n📧 Email: {{ $('Webhook - Travel Request').item.json.body.email }}\\n🏆 Best Deal: ${{ $('AI Score & Recommendations').first().json.totalPrice.toFixed(2) }}\\n🤖 AI Score: {{ $('AI Score & Recommendations').first().json.aiScore }}/100",
"channel": "#travel-bookings",
"attachments": [],
"otherOptions": {},
"authentication": "oAuth2"
},
"typeVersion": 1
},
{
"id": "82bb48ce-ad62-43cc-bb7e-69cf5f55e4c0",
"name": "OpenRouter 聊天模型",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenRouter",
"position": [
3792,
-320
],
"parameters": {
"model": "qwen/qwen3-vl-8b-thinking",
"options": {}
},
"credentials": {
"openRouterApi": {
"id": "fKnn6LL7cRFqNHDX",
"name": "OpenRouter account2"
}
},
"typeVersion": 1
},
{
"id": "e66d7eb9-383f-4ec3-9e76-c33dcfabffdf",
"name": "便签",
"type": "n8n-nodes-base.stickyNote",
"position": [
2288,
-608
],
"parameters": {
"width": 512,
"height": 768,
"content": "## 简介"
},
"typeVersion": 1
},
{
"id": "70771bd2-ff0c-46a1-86ae-08d5698b5c56",
"name": "便签1",
"type": "n8n-nodes-base.stickyNote",
"position": [
4144,
-544
],
"parameters": {
"color": 5,
"width": 352,
"height": 576,
"content": "## 先决条件"
},
"typeVersion": 1
}
],
"active": false,
"pinData": {},
"settings": {
"executionOrder": "v1"
},
"versionId": "973f16a5-77bb-4015-a5c5-a32efacdddd7",
"connections": {
"Generate HTML Email": {
"main": [
[
{
"node": "Send Email via Gmail",
"type": "main",
"index": 0
}
]
]
},
"Extract Request Data": {
"main": [
[
{
"node": "Search Flights - Skyscanner",
"type": "main",
"index": 0
},
{
"node": "Search Hotels - Booking.com",
"type": "main",
"index": 0
},
{
"node": "Search Alternative Flights - Kiwi",
"type": "main",
"index": 0
},
{
"node": "Get Weather Forecast",
"type": "main",
"index": 0
},
{
"node": "Search Local Activities - Viator",
"type": "main",
"index": 0
}
]
]
},
"Get Weather Forecast": {
"main": [
[
{
"node": "Merge All Data Sources",
"type": "main",
"index": 0
}
]
]
},
"Send Email via Gmail": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
},
{
"node": "Send Slack Notification",
"type": "main",
"index": 0
}
]
]
},
"OpenRouter Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Agent - Itinerary Optimizer",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Merge All Data Sources": {
"main": [
[
{
"node": "Enhanced Itinerary Builder",
"type": "main",
"index": 0
}
]
]
},
"Send Slack Notification": {
"main": [
[
{
"node": "Respond to Webhook",
"type": "main",
"index": 0
}
]
]
},
"Webhook - Travel Request": {
"main": [
[
{
"node": "Extract Request Data",
"type": "main",
"index": 0
}
]
]
},
"AI Score & Recommendations": {
"main": [
[
{
"node": "Generate Premium HTML Email",
"type": "main",
"index": 0
}
]
]
},
"Combine & Rank Itineraries": {
"main": [
[
{
"node": "Generate HTML Email",
"type": "main",
"index": 0
}
]
]
},
"Enhanced Itinerary Builder": {
"main": [
[
{
"node": "AI Agent - Itinerary Optimizer",
"type": "main",
"index": 0
},
{
"node": "AI Score & Recommendations",
"type": "main",
"index": 0
}
]
]
},
"Generate Premium HTML Email": {
"main": [
[
{
"node": "Send Email via Gmail",
"type": "main",
"index": 0
}
]
]
},
"Search Flights - Skyscanner": {
"main": [
[
{
"node": "Combine & Rank Itineraries",
"type": "main",
"index": 0
},
{
"node": "Merge All Data Sources",
"type": "main",
"index": 0
}
]
]
},
"Search Hotels - Booking.com": {
"main": [
[
{
"node": "Combine & Rank Itineraries",
"type": "main",
"index": 0
},
{
"node": "Merge All Data Sources",
"type": "main",
"index": 0
}
]
]
},
"AI Agent - Itinerary Optimizer": {
"main": [
[
{
"node": "AI Score & Recommendations",
"type": "main",
"index": 0
}
]
]
},
"Search Local Activities - Viator": {
"main": [
[
{
"node": "Merge All Data Sources",
"type": "main",
"index": 0
}
]
]
},
"Search Alternative Flights - Kiwi": {
"main": [
[
{
"node": "Merge All Data Sources",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
高级 - 个人效率, 多模态 AI
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
智能旅行套餐查找器 - 使用Skyscanner和Booking.com搜索航班和酒店
智能旅行套餐查找器:通过 Skyscanner 和 Booking.com 搜索航班与酒店
Set
Code
Gmail
+5
12 节点Cheng Siong Chin
个人效率
来自多个招聘网站的求职自动化
使用 5 个招聘平台和 AI 简历生成器自动化求职与申请
If
Set
Code
+14
34 节点Gerald Denor
个人效率
AI-Deepseek-R1t 会议差旅审批与费用授权申请
通过Deepseek AI、Gmail和Google Sheets自动化会议差旅审批
If
Set
Code
+11
24 节点Cheng Siong Chin
文档提取
基于标题和摘要的AI驱动Qwen-Max期刊论文生成器
Qwen-Max:从标题/摘要生成期刊论文
Set
Code
Merge
+5
19 节点Cheng Siong Chin
内容创作
AI驱动的同行评审作业系统,带自动评分标准生成
使用GPT-4-nano、Slack和邮件通知自动化同行评审分配
Set
Code
Slack
+9
22 节点Cheng Siong Chin
文档提取
GPT实时航班优惠分析器:自动抓取、评估并发布到WordPress
使用GPT、Google航班和WordPress的航班优惠分析器,含天气数据
Set
Html
Slack
+8
19 节点Cheng Siong Chin
内容创作
工作流信息
难度等级
高级
节点数量18
分类2
节点类型10
作者
Cheng Siong Chin
@cschinProf. Cheng Siong CHIN serves as Chair Professor in Intelligent Systems Modelling and Simulation in Newcastle University, Singapore. His academic credentials include an M.Sc. in Advanced Control and Systems Engineering from The University of Manchester and a Ph.D. in Robotics from Nanyang Technological University.
外部链接
在 n8n.io 查看 →
分享此工作流