使用Gemini AI从Google Maps评论生成市场研究报告
中级
这是一个Market Research, AI Summarization领域的自动化工作流,包含 15 个节点。主要使用 Set, Code, Gmail, Aggregate, HttpRequest 等节点。 使用Gemini AI从Google Maps评论生成市场研究报告
前置要求
- •Google 账号和 Gmail API 凭证
- •可能需要目标 API 的认证凭证
- •Google Gemini API Key
使用的节点 (15)
工作流预览
可视化展示节点连接关系,支持缩放和平移
导出工作流
复制以下 JSON 配置到 n8n 导入,即可使用此工作流
{
"meta": {
"instanceId": "fec3a82e5888606db7f18bce6d6a86acc72be4b93a270dd22cfc357c585bfc28"
},
"nodes": [
{
"id": "7a561138-c149-4f92-97b7-087771017521",
"name": "启动工作流",
"type": "n8n-nodes-base.manualTrigger",
"position": [
-608,
288
],
"parameters": {},
"typeVersion": 1
},
{
"id": "acc1a472-587e-4dc2-b215-e986ca907163",
"name": "用户输入配置",
"type": "n8n-nodes-base.set",
"position": [
-416,
288
],
"parameters": {
"fields": {
"values": [
{
"name": "search_query",
"stringValue": "nhà hàng quận 1 TP.HCM"
},
{
"name": "search_location",
"stringValue": "@10.8231,106.6297,12z"
},
{
"name": "language_code",
"stringValue": "vi"
},
{
"name": "analysis_focus",
"stringValue": "restaurant"
},
{
"name": "city_name",
"stringValue": "TP. Hồ Chí Minh"
}
]
},
"options": {}
},
"typeVersion": 3.2
},
{
"id": "9c3ced66-5ec2-4e70-8150-e11711bc3f90",
"name": "动态搜索地点",
"type": "n8n-nodes-base.httpRequest",
"position": [
-208,
288
],
"parameters": {
"url": "https://serpapi.com/search.json",
"options": {},
"jsonQuery": "={\n \"engine\": \"google_maps\",\n \"q\": \"{{ $('User Input Configuration').item.json.search_query }}\",\n \"ll\": \"{{ $('User Input Configuration').item.json.search_location }}\",\n \"hl\": \"{{ $('User Input Configuration').item.json.language_code }}\",\n \"api_key\": \"ffbea3b40ea41b0e10dbceb1302b81209669f83c5b9b75ed8309dbc3f2ae624d\"\n}",
"sendQuery": true,
"specifyQuery": "json"
},
"typeVersion": 4.2
},
{
"id": "0062335c-2c19-4132-938c-37a7013668ed",
"name": "增强数据提取",
"type": "n8n-nodes-base.code",
"position": [
-16,
288
],
"parameters": {
"jsCode": "// Enhanced extraction with better filtering and validation\nconst localResults = $input.first().json.local_results || [];\nconst userConfig = $('User Input Configuration').item.json;\n\nconsole.log(`Processing ${localResults.length} search results for: ${userConfig.search_query}`);\n\n// Extract and filter places with more comprehensive data\nconst places = localResults.map(place => {\n // Extract additional data that might be useful for analysis\n const placeData = {\n place_name: place.title || 'Unknown',\n address: place.address || 'No address',\n rating: place.rating || 'No rating',\n reviews_count: place.reviews || 0,\n reviews_link: place.reviews_link || null,\n data_id: place.data_id || null,\n type: place.type || 'Unknown',\n place_id: place.place_id || null,\n lsig: place.lsig || null,\n phone: place.phone || null,\n website: place.website || null,\n thumbnail: place.thumbnail || null,\n operating_hours: place.operating_hours || null,\n price_level: place.price_level || null,\n plus_code: place.plus_code || null,\n coordinates: {\n lat: place.gps_coordinates?.latitude || null,\n lng: place.gps_coordinates?.longitude || null\n },\n // Add context about what we're analyzing\n search_context: {\n original_query: userConfig.search_query,\n analysis_focus: userConfig.analysis_focus,\n city: userConfig.city_name,\n search_timestamp: new Date().toISOString()\n }\n };\n \n return placeData;\n}).filter(place => {\n // Enhanced filtering - keep places that have either reviews_link OR sufficient basic data\n return place.reviews_link || (place.rating && place.rating !== 'No rating') || place.reviews_count > 0;\n});\n\nconsole.log(`Filtered to ${places.length} places with review data or sufficient information`);\nconsole.log(`Analysis focus: ${userConfig.analysis_focus} in ${userConfig.city_name}`);\n\n// Return array of places with enhanced metadata\nreturn places.map(place => ({ json: place }));"
},
"typeVersion": 2
},
{
"id": "136b7156-e38c-43a2-95d5-38a76c8e067a",
"name": "循环处理地点",
"type": "n8n-nodes-base.splitInBatches",
"position": [
192,
80
],
"parameters": {
"options": {}
},
"typeVersion": 3
},
{
"id": "31112897-af1c-4476-85b9-81a7f287a7ca",
"name": "获取评论内容",
"type": "n8n-nodes-base.httpRequest",
"position": [
400,
240
],
"parameters": {
"url": "={{ $json.reviews_link }}",
"options": {
"timeout": 30000,
"allowUnauthorizedCerts": true
},
"jsonQuery": "{\n \"api_key\": \"ffbea3b40ea41b0e10dbceb1302b81209669f83c5b9b75ed8309dbc3f2ae624d\"\n}",
"sendQuery": true,
"specifyQuery": "json"
},
"typeVersion": 4.2
},
{
"id": "c9f7f981-8476-4ba1-8448-5f29ae13d989",
"name": "增强数据合并",
"type": "n8n-nodes-base.code",
"position": [
592,
384
],
"parameters": {
"jsCode": "// Enhanced data combination with error handling\nconst currentItem = $('Loop Over Places').item;\nconst reviewsResponse = $input.first().json;\nconst userConfig = $('User Input Configuration').item.json;\n\n// Enhanced combined data with more comprehensive information\nconst combinedData = {\n // Basic place information\n place_name: currentItem.json.place_name,\n address: currentItem.json.address,\n rating: currentItem.json.rating,\n reviews_count: currentItem.json.reviews_count,\n data_id: currentItem.json.data_id,\n type: currentItem.json.type,\n phone: currentItem.json.phone,\n website: currentItem.json.website,\n coordinates: currentItem.json.coordinates,\n operating_hours: currentItem.json.operating_hours,\n price_level: currentItem.json.price_level,\n \n // Reviews content with error handling\n reviews_content: reviewsResponse || { error: 'No reviews data available' },\n \n // Enhanced metadata for analysis\n analysis_metadata: {\n search_query: userConfig.search_query,\n analysis_focus: userConfig.analysis_focus,\n target_city: userConfig.city_name,\n data_collection_time: new Date().toISOString(),\n has_reviews: !!(reviewsResponse && reviewsResponse.reviews),\n review_source: currentItem.json.reviews_link || 'No review link',\n place_completeness_score: calculateCompletenessScore(currentItem.json)\n }\n};\n\n// Function to calculate how complete the place data is\nfunction calculateCompletenessScore(placeData) {\n const fields = ['place_name', 'address', 'rating', 'phone', 'website', 'operating_hours'];\n const filledFields = fields.filter(field => \n placeData[field] && placeData[field] !== 'Unknown' && placeData[field] !== 'No address'\n );\n return Math.round((filledFields.length / fields.length) * 100);\n}\n\nconsole.log(`Processing ${combinedData.analysis_metadata.analysis_focus}: ${combinedData.place_name}`);\nconsole.log(`Data completeness: ${combinedData.analysis_metadata.place_completeness_score}%`);\n\nreturn { json: combinedData };"
},
"typeVersion": 2
},
{
"id": "68e789cd-2df5-4783-8891-5cd4d6eb0553",
"name": "收集所有数据",
"type": "n8n-nodes-base.aggregate",
"position": [
800,
288
],
"parameters": {
"options": {},
"aggregate": "aggregateAllItemData"
},
"typeVersion": 1
},
{
"id": "d1084cb2-0d34-4f6a-8a51-f87b1c01c6c3",
"name": "准备分析数据",
"type": "n8n-nodes-base.code",
"position": [
992,
288
],
"parameters": {
"jsCode": "// Enhanced data preparation with flexible analysis structure\nconst allPlaces = $input.all();\nconst userConfig = $('User Input Configuration').item.json;\n\nconsole.log(`Preparing analysis for ${allPlaces.length} ${userConfig.analysis_focus} locations in ${userConfig.city_name}`);\n\n// Create comprehensive analysis dataset\nlet analysisPrompt = `MARKET RESEARCH DATA ANALYSIS\\n`;\nanalysisPrompt += `Research Focus: ${userConfig.analysis_focus}\\n`;\nanalysisPrompt += `Location: ${userConfig.city_name}\\n`;\nanalysisPrompt += `Search Query: \"${userConfig.search_query}\"\\n`;\nanalysisPrompt += `Total Locations Found: ${allPlaces.length}\\n`;\nanalysisPrompt += `Analysis Date: ${new Date().toLocaleDateString('vi-VN')}\\n\\n`;\n\n// Enhanced data summary\nanalysisPrompt += `=== DATASET OVERVIEW ===\\n`;\nlet totalReviews = 0;\nlet avgRating = 0;\nlet placesWithReviews = 0;\nlet completenessScores = [];\n\nallPlaces.forEach((place, index) => {\n const data = place.json;\n \n // Calculate statistics\n if (data.reviews_count && typeof data.reviews_count === 'number') {\n totalReviews += data.reviews_count;\n }\n \n if (data.rating && data.rating !== 'No rating') {\n avgRating += parseFloat(data.rating) || 0;\n }\n \n if (data.reviews_content && data.reviews_content.reviews) {\n placesWithReviews++;\n }\n \n if (data.analysis_metadata && data.analysis_metadata.place_completeness_score) {\n completenessScores.push(data.analysis_metadata.place_completeness_score);\n }\n \n // Add detailed place information\n analysisPrompt += `\\n${index + 1}. ${data.place_name}\\n`;\n analysisPrompt += ` Address: ${data.address}\\n`;\n analysisPrompt += ` Rating: ${data.rating}/5 (${data.reviews_count || 0} reviews)\\n`;\n \n // Add contact and operational info if available\n if (data.phone) analysisPrompt += ` Phone: ${data.phone}\\n`;\n if (data.website) analysisPrompt += ` Website: ${data.website}\\n`;\n if (data.operating_hours) analysisPrompt += ` Hours: ${JSON.stringify(data.operating_hours)}\\n`;\n if (data.price_level) analysisPrompt += ` Price Level: ${data.price_level}\\n`;\n \n // Add review samples if available\n if (data.reviews_content && data.reviews_content.reviews) {\n analysisPrompt += ` Recent Reviews:\\n`;\n data.reviews_content.reviews.slice(0, 5).forEach(review => {\n const reviewText = review.snippet || review.text || review.comment || 'No text available';\n const reviewRating = review.rating || 'No rating';\n analysisPrompt += ` - \"${reviewText.substring(0, 200)}...\" (${reviewRating}/5)\\n`;\n });\n }\n \n analysisPrompt += ` Data Completeness: ${data.analysis_metadata?.place_completeness_score || 'N/A'}%\\n`;\n analysisPrompt += `\\n${'-'.repeat(60)}\\n`;\n});\n\n// Add summary statistics\nconst avgRatingCalculated = allPlaces.length > 0 ? (avgRating / allPlaces.length).toFixed(2) : 0;\nconst avgCompleteness = completenessScores.length > 0 ? \n (completenessScores.reduce((a, b) => a + b, 0) / completenessScores.length).toFixed(1) : 'N/A';\n\nanalysisPrompt += `\\n=== SUMMARY STATISTICS ===\\n`;\nanalysisPrompt += `Total Places Analyzed: ${allPlaces.length}\\n`;\nanalysisPrompt += `Places with Review Data: ${placesWithReviews}\\n`;\nanalysisPrompt += `Total Reviews Collected: ${totalReviews}\\n`;\nanalysisPrompt += `Average Rating: ${avgRatingCalculated}/5\\n`;\nanalysisPrompt += `Average Data Completeness: ${avgCompleteness}%\\n`;\n\nreturn {\n json: {\n analysis_prompt: analysisPrompt,\n raw_data: allPlaces.map(place => place.json),\n summary_stats: {\n total_places: allPlaces.length,\n places_with_reviews: placesWithReviews,\n total_reviews: totalReviews,\n average_rating: avgRatingCalculated,\n average_completeness: avgCompleteness,\n search_context: userConfig\n }\n }\n};"
},
"typeVersion": 2
},
{
"id": "0cdd33f4-447d-4246-98bf-410e562686c1",
"name": "AI市场分析",
"type": "@n8n/n8n-nodes-langchain.agent",
"position": [
1168,
288
],
"parameters": {
"text": "=Bạn là chuyên gia phân tích và nghiên cứu thị trường chuyên sâu với khả năng tạo ra các báo cáo insights chi tiết và actionable.\n\nBạn đã nhận được dữ liệu thị trường thực tế về \"{{ $('User Input Configuration').item.json.analysis_focus }}\" tại {{ $('User Input Configuration').item.json.city_name }} với đầy đủ thông tin từ khách hàng thực tế.\n\n=== DỮ LIỆU PHÂN TÍCH ===\n{{ JSON.stringify($json.raw_data, null, 2) }}\n\n=== NHIỆM VỤ PHÂN TÍCH ===\n\nHãy tạo một báo cáo phân tích thị trường toàn diện với cấu trúc sau:\n\n**I. TÓM TẮT ĐIỀU HÀNH (EXECUTIVE SUMMARY)**\n- Insights chính trong 3-4 câu\n- Cơ hội kinh doanh lớn nhất\n- Khuyến nghị hành động ngay lập tức\n\n**II. PHÂN TÍCH TỔNG QUAN THỊ TRƯỜNG**\n- Quy mô và mật độ thị trường {{ $('User Input Configuration').item.json.analysis_focus }} tại {{ $('User Input Configuration').item.json.city_name }}\n- Phân khúc giá và chất lượng dịch vụ\n- Phân bố địa lý và khu vực hot\n- Mức độ cạnh tranh và gap thị trường\n\n**III. PHÂN TÍCH TRẢI NGHIỆM KHÁCH HÀNG**\n- Top 5 yếu tố được đánh giá cao nhất (với % khách hàng mention)\n- Top 5 vấn đề phổ biến nhất (với tần suất xuất hiện)\n- Sentiment analysis tổng thể\n- Customer journey và pain points chính\n\n**IV. COMPETITIVE LANDSCAPE**\n- Phân tích 3-5 player mạnh nhất\n- Điểm mạnh/yếu của từng competitor\n- Pricing strategy và value proposition\n- Market positioning gaps\n\n**V. INSIGHTS VÀ XU HƯỚNG**\n- Behavioral patterns của target customers\n- Emerging trends và changing preferences\n- Seasonal/temporal patterns nếu có\n- Technology adoption và digital readiness\n\n**VI. KHUYẾN NGHỊ CHIẾN LƯỢC**\n- Business model tối ưu cho thị trường này\n- Pricing strategy và revenue streams\n- Marketing approach và customer acquisition\n- Operational excellence priorities\n- Investment areas và resource allocation\n\n**VII. ACTION PLAN**\n- 3 hành động ngay lập tức (next 30 days)\n- 3 initiatives trung hạn (3-6 months)\n- Long-term strategy (6-12 months)\n\nYêu cầu:\n- Sử dụng số liệu cụ thể từ dữ liệu thực tế\n- Đưa ra insights độc đáo, không chỉ mô tả\n- Tập trung vào actionable recommendations\n- Viết bằng tiếng Việt chuyên nghiệp nhưng dễ hiểu\n- Highlight key metrics và success factors\n- Đề xuất KPIs để theo dõi success",
"options": {},
"promptType": "define"
},
"typeVersion": 2.1
},
{
"id": "82c701cb-a88a-410c-bda4-aaaf4c5227ef",
"name": "Google Gemini聊天模型",
"type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
"position": [
1152,
480
],
"parameters": {
"options": {}
},
"credentials": {
"googlePalmApi": {
"id": "MT1SUsx0Hy6XtV22",
"name": "Google Gemini(PaLM) Api account"
}
},
"typeVersion": 1
},
{
"id": "2ec72fea-962e-45d4-aa48-abf02c0d80de",
"name": "准备邮件内容",
"type": "n8n-nodes-base.code",
"position": [
1536,
176
],
"parameters": {
"jsCode": "// Simplified email preparation - Analysis content only\nconst reportContent = $input.first().json.output;\nconst userConfig = $('User Input Configuration').item.json;\nconst summaryStats = $('Prepare Analysis Data').item.json.summary_stats;\n\n// Generate dynamic subject based on analysis focus\nconst analysisType = userConfig.analysis_focus;\nconst cityName = userConfig.city_name;\nconst currentDate = new Date().toLocaleDateString('vi-VN');\n\nconst emailSubject = `📊 Báo Cáo Phân Tích Thị Trường ${analysisType} ${cityName} - ${currentDate}`;\n\n// Enhanced HTML formatting function\nfunction formatToHTML(content) {\n let html = content\n // Convert markdown-style formatting\n .replace(/\\*\\*([^*]+)\\*\\*/g, '<strong>$1</strong>')\n .replace(/\\*([^*]+)\\*/g, '<em>$1</em>')\n \n // Convert main sections (I., II., III., etc.)\n .replace(/\\*\\*([IVX]+\\. [^*]+)\\*\\*/g, '<h2 style=\"color: #2c3e50; border-bottom: 2px solid #3498db; padding-bottom: 8px; margin-top: 30px;\">$1</h2>')\n \n // Convert subsections\n .replace(/\\*\\*([^*]+:)\\*\\*/g, '<h3 style=\"color: #34495e; margin-top: 20px; margin-bottom: 10px;\">$1</h3>')\n \n // Convert numbered lists with enhanced styling\n .replace(/^(\\d+\\. )/gm, '<div style=\"margin: 8px 0;\"><strong style=\"color: #3498db;\">$1</strong>')\n \n // Convert bullet points with different levels\n .replace(/^- /gm, '<div style=\"margin-left: 20px; margin: 5px 0;\">• ')\n .replace(/^ - /gm, '<div style=\"margin-left: 40px; margin: 5px 0;\">◦ ')\n .replace(/^ - /gm, '<div style=\"margin-left: 60px; margin: 5px 0;\">▪ ')\n \n // Close div tags and handle line breaks\n .replace(/(• [^<\\n]+)(?=\\n|$)/g, '$1</div>')\n .replace(/(◦ [^<\\n]+)(?=\\n|$)/g, '$1</div>')\n .replace(/(▪ [^<\\n]+)(?=\\n|$)/g, '$1</div>')\n .replace(/\\n\\n/g, '</p><p>')\n .replace(/\\n/g, '<br>');\n\n return '<p>' + html + '</p>'.replace(/<p><\\/p>/g, '');\n}\n\n// Create comprehensive HTML email template - Analysis focused\nconst htmlContent = `\n<!DOCTYPE html>\n<html lang=\"vi\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${emailSubject}</title>\n <style>\n body {\n font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;\n line-height: 1.6;\n color: #333;\n max-width: 900px;\n margin: 0 auto;\n padding: 20px;\n background-color: #f8f9fa;\n }\n .container {\n background-color: white;\n padding: 40px;\n border-radius: 12px;\n box-shadow: 0 4px 20px rgba(0,0,0,0.1);\n }\n .header {\n text-align: center;\n margin-bottom: 40px;\n padding: 30px;\n background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);\n color: white;\n border-radius: 10px;\n }\n .header h1 {\n margin: 0;\n font-size: 26px;\n font-weight: bold;\n }\n .header .subtitle {\n font-size: 16px;\n margin-top: 10px;\n opacity: 0.95;\n }\n .stats-overview {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n gap: 20px;\n margin: 30px 0;\n padding: 25px;\n background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);\n border-radius: 10px;\n }\n .stat-item {\n text-align: center;\n padding: 15px;\n background: white;\n border-radius: 8px;\n box-shadow: 0 2px 10px rgba(0,0,0,0.1);\n }\n .stat-number {\n font-size: 24px;\n font-weight: bold;\n color: #3498db;\n }\n .stat-label {\n font-size: 12px;\n color: #7f8c8d;\n margin-top: 5px;\n }\n h2 {\n color: #2c3e50;\n border-bottom: 2px solid #3498db;\n padding-bottom: 8px;\n margin-top: 30px;\n }\n h3 {\n color: #34495e;\n margin-top: 20px;\n margin-bottom: 10px;\n }\n .highlight {\n background: #fff3cd;\n border: 1px solid #ffeaa7;\n padding: 15px;\n border-radius: 5px;\n margin: 15px 0;\n }\n .footer {\n margin-top: 40px;\n padding: 25px;\n background: #34495e;\n color: white;\n text-align: center;\n border-radius: 10px;\n font-size: 14px;\n }\n @media (max-width: 600px) {\n body { padding: 10px; }\n .container { padding: 20px; }\n .stats-overview { grid-template-columns: 1fr; }\n }\n </style>\n</head>\n<body>\n <div class=\"container\">\n <div class=\"header\">\n <h1>📊 BÁO CÁO PHÂN TÍCH THỊ TRƯỜNG</h1>\n <div class=\"subtitle\">${analysisType} tại ${cityName}</div>\n <div style=\"font-size: 14px; margin-top: 15px; opacity: 0.9;\">\n Ngày phân tích: ${new Date().toLocaleDateString('vi-VN', { \n year: 'numeric', \n month: 'long', \n day: 'numeric',\n hour: '2-digit',\n minute: '2-digit'\n })}\n </div>\n </div>\n \n ${formatToHTML(reportContent)}\n \n <div class=\"footer\">\n <p><strong>🚀 Market Research Analytics System</strong></p>\n <p>📧 Báo cáo được tạo tự động từ dữ liệu thực tế \n <p>🎯 Phân tích: ${analysisType} | 📍 Địa điểm: ${cityName}</p>\n <p style=\"margin-top: 15px; font-size: 12px; opacity: 0.8;\">\n Query gốc: \"${userConfig.search_query}\"\n </p>\n </div>\n </div>\n</body>\n</html>\n`;\n\n// Create simplified plain text version - Analysis only\nconst plainTextContent = `\nBÁO CÁO PHÂN TÍCH THỊ TRƯỜNG - ${analysisType.toUpperCase()} ${cityName.toUpperCase()}\n${'='.repeat(60)}\n\nSỐ LIỆU TỔNG QUAN:\n- Địa điểm phân tích: ${summaryStats.total_places}\n- Tổng đánh giá: ${summaryStats.total_reviews}\n- Rating TB: ${summaryStats.average_rating}/5\n- Có data chi tiết: ${summaryStats.places_with_reviews}\n\n${reportContent.replace(/\\*\\*([^*]+)\\*\\*/g, '$1').replace(/\\*/g, '')}\n\n${'='.repeat(60)}\nBáo cáo tự động - ${currentDate}\n`;\n\nreturn {\n json: {\n htmlContent: htmlContent,\n plainTextContent: plainTextContent,\n subject: emailSubject,\n analysis_metadata: {\n analysis_type: analysisType,\n city: cityName,\n total_locations: summaryStats.total_places,\n total_reviews: summaryStats.total_reviews,\n average_rating: summaryStats.average_rating,\n search_query: userConfig.search_query,\n generation_time: new Date().toISOString()\n }\n }};"
},
"typeVersion": 2
},
{
"id": "7dd14586-d25d-4b12-baef-2be0c6987456",
"name": "发送邮件报告",
"type": "n8n-nodes-base.gmail",
"position": [
1728,
384
],
"webhookId": "4632d0f8-2acf-4508-acf5-f2d1e9a77bbf",
"parameters": {
"sendTo": "truong11062002@gmail.com",
"message": "={{ $json.htmlContent }}",
"options": {
"ccList": "",
"bccList": "",
"replyTo": ""
},
"subject": "={{ $json.subject }}"
},
"credentials": {
"gmailOAuth2": {
"id": "9hqpp5Ew9HbGDqNu",
"name": "Gmail account"
}
},
"typeVersion": 2
},
{
"id": "1ecc0e85-5ec2-4f9f-a6e8-23a3f7f826a8",
"name": "最终状态与日志记录",
"type": "n8n-nodes-base.code",
"position": [
1936,
384
],
"parameters": {
"jsCode": "// Final workflow status and comprehensive logging\nconst emailResult = $input.first().json;\nconst userConfig = $('User Input Configuration').item.json;\nconst summaryStats = $('Prepare Analysis Data').item.json.summary_stats;\nconst analysisMetadata = $('Prepare Email Content').item.json.analysis_metadata;\n\nconst completionTime = new Date().toISOString();\n\nconsole.log('🎉 ========= FLEXIBLE MARKET ANALYSIS COMPLETED =========');\nconsole.log(`📊 Analysis Type: ${userConfig.analysis_focus}`);\nconsole.log(`🏙️ Target City: ${userConfig.city_name}`);\nconsole.log(`🔍 Search Query: \"${userConfig.search_query}\"`);\nconsole.log(`📍 Total Locations Analyzed: ${summaryStats.total_places}`);\nconsole.log(`💬 Total Reviews Processed: ${summaryStats.total_reviews}`);\nconsole.log(`⭐ Average Rating: ${summaryStats.average_rating}/5`);\nconsole.log(`📧 Email Report Sent Successfully`);\nconsole.log(`⏰ Completion Time: ${completionTime}`);\nconsole.log('=========================================================');\n\n// Generate comprehensive final report\nconst workflowSummary = {\n workflow_status: 'COMPLETED_SUCCESSFULLY',\n workflow_type: 'FLEXIBLE_MARKET_RESEARCH_ANALYSIS',\n execution_metadata: {\n analysis_focus: userConfig.analysis_focus,\n target_location: userConfig.city_name,\n search_query: userConfig.search_query,\n language_code: userConfig.language_code,\n completion_time: completionTime\n },\n data_collection_results: {\n total_places_found: summaryStats.total_places,\n places_with_review_data: summaryStats.places_with_reviews,\n total_reviews_collected: summaryStats.total_reviews,\n average_rating_calculated: summaryStats.average_rating,\n data_completeness_average: summaryStats.average_completeness\n },\n analysis_outputs: {\n ai_model_used: 'Google_Gemini',\n report_format: 'Comprehensive_Market_Analysis',\n email_delivery_status: emailResult.messageId ? 'SUCCESS' : 'UNKNOWN',\n email_subject: analysisMetadata.subject,\n email_recipient: 'truong11062002@gmail.com'\n },\n workflow_capabilities: {\n flexible_search_query: true,\n dynamic_location_targeting: true,\n multi_language_support: true,\n comprehensive_data_extraction: true,\n ai_powered_analysis: true,\n automated_report_generation: true,\n email_delivery: true\n },\n next_steps_recommendations: [\n 'Review the detailed market analysis report in your email',\n 'Customize search parameters for different market segments',\n 'Set up recurring analysis for market monitoring',\n 'Expand analysis to additional cities or business categories',\n 'Integrate insights into business strategy planning'\n ]\n};\n\nreturn { json: workflowSummary };"
},
"typeVersion": 2
},
{
"id": "599485d6-b773-4462-83d4-e0124c6450d6",
"name": "便签",
"type": "n8n-nodes-base.stickyNote",
"position": [
-832,
-1248
],
"parameters": {
"width": 944,
"height": 1392,
"content": "# 🚀 市场研究分析系统"
},
"typeVersion": 1
}
],
"pinData": {
"Start Workflow": [
{}
]
},
"connections": {
"Start Workflow": {
"main": [
[
{
"node": "User Input Configuration",
"type": "main",
"index": 0
}
]
]
},
"Collect All Data": {
"main": [
[
{
"node": "Prepare Analysis Data",
"type": "main",
"index": 0
}
]
]
},
"Loop Over Places": {
"main": [
[
{
"node": "Collect All Data",
"type": "main",
"index": 0
}
],
[
{
"node": "Get Reviews Content",
"type": "main",
"index": 0
}
]
]
},
"Send Email Report": {
"main": [
[
{
"node": "Final Status & Logging",
"type": "main",
"index": 0
}
]
]
},
"AI Market Analysis": {
"main": [
[
{
"node": "Prepare Email Content",
"type": "main",
"index": 0
}
]
]
},
"Get Reviews Content": {
"main": [
[
{
"node": "Enhanced Combine Data",
"type": "main",
"index": 0
}
]
]
},
"Dynamic Search Places": {
"main": [
[
{
"node": "Enhanced Extract Data",
"type": "main",
"index": 0
}
]
]
},
"Enhanced Combine Data": {
"main": [
[
{
"node": "Loop Over Places",
"type": "main",
"index": 0
}
]
]
},
"Enhanced Extract Data": {
"main": [
[
{
"node": "Loop Over Places",
"type": "main",
"index": 0
}
]
]
},
"Prepare Analysis Data": {
"main": [
[
{
"node": "AI Market Analysis",
"type": "main",
"index": 0
}
]
]
},
"Prepare Email Content": {
"main": [
[
{
"node": "Send Email Report",
"type": "main",
"index": 0
}
]
]
},
"Google Gemini Chat Model": {
"ai_languageModel": [
[
{
"node": "AI Market Analysis",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"User Input Configuration": {
"main": [
[
{
"node": "Dynamic Search Places",
"type": "main",
"index": 0
}
]
]
}
}
}常见问题
如何使用这个工作流?
复制上方的 JSON 配置代码,在您的 n8n 实例中创建新工作流并选择「从 JSON 导入」,粘贴配置后根据需要修改凭证设置即可。
这个工作流适合什么场景?
中级 - 市场调研, AI 摘要总结
需要付费吗?
本工作流完全免费,您可以直接导入使用。但请注意,工作流中使用的第三方服务(如 OpenAI API)可能需要您自行付费。
相关工作流推荐
使用 Bright Data API 和 AI 抓取分析 Google 广告并发送邮件报告
使用 Bright Data API 和 AI 抓取分析 Google 广告并发送邮件报告
Set
Code
Gmail
+15
45 节点Zacharia Kimotho
市场调研
选题捕手模板
使用Gemini分析Reddit、YouTube和X生成内容策略报告
If
Set
Code
+14
34 节点Sheryl
市场调研
01 使用AI媒体买家分析Facebook广告表现并将洞察发送到Google Sheets
使用Gemini AI分析Facebook广告并将洞察发送到Google Sheets
If
Set
Code
+13
34 节点JJ Tham
市场调研
在可视化参考库中探索n8n节点
在可视化参考库中探索n8n节点
If
Ftp
Set
+93
113 节点I versus AI
其他
使用Apify、Claude Sonnet 4和Gmail交付生成完整SEO审计
使用Apify、Claude Sonnet 4和Gmail交付生成完整SEO审计
Set
Html
Gmail
+9
41 节点Luka Zivkovic
市场调研
源发现 - 自动搜索更及时的信息源
多平台源发现系统,集成 SerpAPI、DuckDuckGo、GitHub、Reddit 和 Bluesky
Set
Code
Limit
+18
68 节点Hybroht
市场调研
工作流信息
难度等级
中级
节点数量15
分类2
节点类型10
作者
Charles
@charlesnguyenI help Sales & Marketing teams save time with custom n8n workflows. With over 5 years of automation experience, I offer free consultations—book now!
外部链接
在 n8n.io 查看 →
分享此工作流