Error with Community Literature Review Workflow

Describe the problem/error/question

I m trying to use the Commnity Literature Review workflow but it fails on execution

What is the error message (if any)?

Problem in node ‘Export BibTeX File‘

This operation expects the node’s input data to contain a binary file ‘data’, but none was found [item 0]

Please share your workflow

{
“name”: “Academic Research Search Across Five Databases with PDF Vector & Multiple Exports”,
“nodes”: [
{
“parameters”: {
“content”: “## Multi-Database Search\n\nSearches:\n- PubMed\n- ArXiv\n- Google Scholar\n- Semantic Scholar\n- ERIC\n\nDeduplicates and ranks results”
},
“id”: “search-info”,
“name”: “Search Configuration”,
“type”: “n8n-nodes-base.stickyNote”,
“position”: [
384,
64
],
“typeVersion”: 1
},
{
“parameters”: {
“values”: {
“number”: [
{
“name”: “yearFrom”,
“value”: 2020
},
{
“name”: “resultsPerSource”,
“value”: 25
}
],
“string”: [
{
“name”: “searchQuery”,
“value”: “machine learning healthcare applications”
}
]
},
“options”: {}
},
“id”: “search-params”,
“name”: “Set Search Parameters”,
“type”: “n8n-nodes-base.set”,
“position”: [
576,
400
],
“typeVersion”: 1
},
{
“parameters”: {
“query”: “={{ $json.searchQuery }}”,
“providers”: [
“pubmed”,
“arxiv”,
“eric”,
“google-scholar”,
“semantic-scholar”
],
“limit”: “={{ $json.resultsPerSource }}”,
“yearFrom”: “={{ $json.yearFrom }}”,
“additionalFields”: {}
},
“id”: “pdfvector-search”,
“name”: “PDF Vector - Multi-DB Search”,
“type”: “n8n-nodes-pdfvector.pdfVector”,
“position”: [
768,
400
],
“typeVersion”: 1,
“credentials”: {
“pdfVectorApi”: {
“id”: “q76YQwYHaBcm2Hgo”,
“name”: “PDF Vector account”
}
}
},
{
“parameters”: {
“jsCode”: “// Loop over input items and add a new field called ‘myNewField’ to the JSON of each one\nfor (const item of $input.all()) {\n item.json.myNewField = 1;\n}\n\nreturn $input.all();”
},
“id”: “deduplicate”,
“name”: “Deduplicate Results”,
“type”: “n8n-nodes-base.code”,
“position”: [
976,
400
],
“typeVersion”: 1
},
{
“parameters”: {
“jsCode”: “// Loop over input items and add a new field called ‘myNewField’ to the JSON of each one\nfor (const item of $input.all()) {\n item.json.myNewField = 1;\n}\n\nreturn $input.all();”
},
“id”: “rank-results”,
“name”: “Rank by Relevance”,
“type”: “n8n-nodes-base.code”,
“position”: [
1168,
400
],
“typeVersion”: 1
},
{
“parameters”: {
“jsCode”: “// Loop over input items and add a new field called ‘myNewField’ to the JSON of each one\nfor (const item of $input.all()) {\n item.json.myNewField = 1;\n}\n\nreturn $input.all();”
},
“id”: “generate-bibtex”,
“name”: “Generate BibTeX”,
“type”: “n8n-nodes-base.code”,
“position”: [
1376,
352
],
“typeVersion”: 1
},
{
“parameters”: {
“fileName”: “search_results_{{ $now.format(‘yyyy-MM-dd’) }}.bib”,
“options”: {}
},
“id”: “export-bibtex”,
“name”: “Export BibTeX File”,
“type”: “n8n-nodes-base.writeBinaryFile”,
“position”: [
1568,
352
],
“typeVersion”: 1
},
{
“parameters”: {
“fileName”: “search_results_{{ $now.format(‘yyyy-MM-dd’) }}.json”,
“options”: {}
},
“id”: “export-json”,
“name”: “Export JSON”,
“type”: “n8n-nodes-base.writeBinaryFile”,
“position”: [
1568,
448
],
“typeVersion”: 1
},
{
“parameters”: {
“fileName”: “search_results_{{ $now.format(‘yyyy-MM-dd’) }}.csv”,
“options”: {}
},
“id”: “export-csv”,
“name”: “Export CSV”,
“type”: “n8n-nodes-base.writeBinaryFile”,
“position”: [
1568,
544
],
“typeVersion”: 1
},
{
“parameters”: {},
“type”: “n8n-nodes-base.manualTrigger”,
“typeVersion”: 1,
“position”: [
352,
400
],
“id”: “4732f6b5-bf5e-405d-8b44-3e5a1de9c00d”,
“name”: “When clicking ‘Execute workflow’”
}
],
“pinData”: {},
“connections”: {
“Generate BibTeX”: {
“main”: [
[
{
“node”: “Export BibTeX File”,
“type”: “main”,
“index”: 0
},
{
“node”: “Export JSON”,
“type”: “main”,
“index”: 0
},
{
“node”: “Export CSV”,
“type”: “main”,
“index”: 0
}
]
]
},
“Rank by Relevance”: {
“main”: [
[
{
“node”: “Generate BibTeX”,
“type”: “main”,
“index”: 0
}
]
]
},
“Deduplicate Results”: {
“main”: [
[
{
“node”: “Rank by Relevance”,
“type”: “main”,
“index”: 0
}
]
]
},
“Set Search Parameters”: {
“main”: [
[
{
“node”: “PDF Vector - Multi-DB Search”,
“type”: “main”,
“index”: 0
}
]
]
},
“PDF Vector - Multi-DB Search”: {
“main”: [
[
{
“node”: “Deduplicate Results”,
“type”: “main”,
“index”: 0
}
]
]
},
“When clicking ‘Execute workflow’”: {
“main”: [
[
{
“node”: “Set Search Parameters”,
“type”: “main”,
“index”: 0
}
]
]
}
},
“active”: false,
“settings”: {},
“versionId”: “240eed22-e081-495f-b27a-5ce88c2dc6b9”,
“meta”: {
“templateId”: “7360”,
“instanceId”: “ddc8b19b7fa20047424f31044d87873eaee7496fb5be5378767f1db53a15213a”
},
“id”: “ntfUBwqvVF7VhLwx”,
“tags”:
}

Share the output returned by the last node

  • n8n version: 1.108.2 Self-Hostedaon Elest.io
  • Database (default: SQLite): Default
  • n8n EXECUTIONS_PROCESS setting (default: own, main): Default
  • Running n8n via (Docker, npm, n8n cloud, desktop app): Docker
  • Operating system: Linux

Hey @rkaplan hope all is good.

What does this workflow JSON dump have to do with the mentioned template? If you changed 2/3 of the nodes this isn’t the workflow template that isn’t working :slight_smile:

In any case, I would start by updating all the outdated nodes:

Then regarding the error you are getting:
The last node (or rather 3 last nodes) require that it’s input is a binary file (not a json, but an actual binary). If no binary is provided, the error is triggered. Show us the input for the write binary file node.

1 Like

Better solution here - again thanks for your help:

{
“nodes”: [
{
“parameters”: {},
“type”: “n8n-nodes-base.manualTrigger”,
“typeVersion”: 1,
“position”: [
-1056,
1792
],
“id”: “68ce03a1-38d8-4e4c-b211-b8318b7ad7ee”,
“name”: “When clicking ‘Execute workflow’”
},
{
“parameters”: {
“query”: “=machine learning in healthcare”,
“providers”: [
“pubmed”
],
“limit”: 20,
“yearFrom”: 2020,
“yearTo”: 2025,
“additionalFields”: {}
},
“id”: “07cb9b28-755e-4372-ac36-b00616e9f11b”,
“name”: “PDF Vector - Search Papers”,
“type”: “n8n-nodes-pdfvector.pdfVector”,
“position”: [
-832,
1792
],
“typeVersion”: 1,
“credentials”: {
“pdfVectorApi”: {
“id”: “q76YQwYHaBcm2Hgo”,
“name”: “PDF Vector account”
}
},
“notes”: “Search across multiple academic databases”
},
{
“parameters”: {
“jsCode”: “// Get the input data from the previous node\nconst items = $input.all();\n\n// Extract the results array from the search response\nconst results = items[0].json.results || ;\n\n// CAPTURE THE SEARCH QUERY from the original search parameters\nconst searchQuery = items[0].json.query || \n $(‘PDF Vector - Search Papers’).first().json.query || \n ‘machine learning in healthcare’; // fallback\n\nconsole.log(Found ${results.length} total papers for query: \"${searchQuery}\");\n\n// Sort papers by citation count (descending order)\nconst sortedResults = results.sort((a, b) => {\n const citationsA = a.totalCitations || a.citations || 0;\n const citationsB = b.totalCitations || b.citations || 0;\n return citationsB - citationsA;\n});\n\nconsole.log(‘Top 5 papers by citations:’);\nsortedResults.slice(0, 5).forEach((paper, i) => {\n console.log(${i+1}. ${paper.title} (${paper.totalCitations || paper.citations || 0} citations));\n});\n\n// Return sorted results as individual items WITH search query attached\nreturn sortedResults.map(paper => ({\n json: {\n …paper,\n originalSearchQuery: searchQuery // Pass the search query along\n },\n binary: {}\n}));”
},
“id”: “8b7a4002-1b83-4364-ba99-49c5a930f3a4”,
“name”: “Sort by Citations”,
“type”: “n8n-nodes-base.code”,
“position”: [
-608,
1792
],
“typeVersion”: 1
},
{
“parameters”: {
“jsCode”: “// Get all input items (sorted papers)\nconst items = $input.all();\n\nconsole.log(Processing ${items.length} sorted papers);\n\n// Filter for papers with abstracts and good metadata\nconst qualityPapers = items.filter(item => {\n const paper = item.json;\n const hasAbstract = paper.abstract && paper.abstract.length > 50;\n const hasTitle = paper.title && paper.title.length > 10;\n const hasAuthors = paper.authors && paper.authors.length > 0;\n \n if (hasAbstract && hasTitle && hasAuthors) {\n return true;\n }\n \n console.log(Filtered out: ${paper.title || 'No title'} - Missing abstract or metadata);\n return false;\n});\n\nconsole.log(${qualityPapers.length} papers have quality abstracts and metadata);\n\n// Select top papers with good abstracts\nconst maxPapers = 10;\nconst selectedPapers = qualityPapers.slice(0, maxPapers);\n\nconsole.log(Selected top ${selectedPapers.length} papers for analysis);\n\n// Return selected papers as individual items\nreturn selectedPapers.map(item => ({\n json: item.json,\n binary: {}\n}));”
},
“id”: “a55d7785-4e64-4f9a-ad84-9eba8a6859e0”,
“name”: “Select Top Papers”,
“type”: “n8n-nodes-base.code”,
“position”: [
-384,
1792
],
“typeVersion”: 1
},
{
“parameters”: {
“jsCode”: “// n8n Code Node (v2) — builds the LLM prompt and a structured papers array\n\nconst inputItems = $input.all();\n\nconsole.log(Processing ${inputItems.length} paper items directly);\n\nlet paperList = ‘’;\nlet paperCount = 0;\n\n// Each incoming item is a single paper\ninputItems.forEach((item, itemIndex) => {\n const paper = item.json;\n\n console.log(Processing paper ${itemIndex + 1}: ${paper.title || 'No title'});\n\n if (paper && paper.title) {\n paperCount++;\n\n // Normalize authors\n let authorList = ‘Unknown Authors’;\n if (paper.authors && Array.isArray(paper.authors)) {\n authorList = paper.authors.map(author => {\n if (typeof author === ‘string’) return author;\n if (author?.name) return author.name;\n return ‘Unknown Author’;\n }).join(', ‘);\n } else if (typeof paper.authors === ‘string’) {\n authorList = paper.authors;\n }\n\n paperList += **Paper ${paperCount}:**\\n**Title:** ${paper.title || 'Unknown'}\\n**Authors:** ${authorList}\\n**Year:** ${paper.year || 'Unknown'}\\n**Journal:** ${paper.journal || 'Unknown'}\\n**Citations:** ${paper.totalCitations || paper.citations || 'Unknown'}\\n**DOI:** ${paper.doi || 'Not available'}\\n**Provider:** ${paper.provider || 'Unknown'}\\n**Abstract:** ${paper.abstract || 'Abstract not available'}\\n**URL:** ${paper.providerURL || paper.url || 'URL not available'}\\n---\\n\\n;\n } else {\n console.log(Skipped item ${itemIndex + 1} - missing title or invalid paper data);\n }\n});\n\nconsole.log(Found ${paperCount} valid papers out of ${inputItems.length} items);\n\nconst fullPrompt = Create a comprehensive literature review analysis based on the following research papers and their abstracts:\\n\\n${paperList}\\n\\n**ANALYSIS INSTRUCTIONS:**\\nBased on these ${paperCount} research papers, provide a comprehensive literature review with the following sections:\\n\\n## 1. Executive Summary (2-3 paragraphs)\\nSummarize the key trends, findings, and contributions across all papers.\\n\\n## 2. Thematic Analysis\\nIdentify and discuss the major themes and research directions, such as:\\n- Clinical decision support systems\\n- Medical imaging and diagnostics\\n- Drug discovery and development\\n- Patient monitoring and wearables\\n- Electronic health records analysis\\n- Predictive modeling for health outcomes\\n\\n## 3. Methodological Approaches\\nAnalyze the common machine learning methods and techniques used:\\n- Deep learning approaches (CNNs, RNNs, Transformers)\\n- Traditional ML methods (SVM, Random Forest, etc.)\\n- Ensemble methods\\n- Data preprocessing and feature engineering\\n- Validation and evaluation metrics\\n\\n## 4. Key Findings and Contributions\\nHighlight the most significant discoveries, innovations, and clinical impacts demonstrated across the papers.\\n\\n## 5. Clinical Applications and Impact\\nDiscuss real-world applications and their potential impact on healthcare delivery, patient outcomes, and clinical workflows.\\n\\n## 6. Challenges and Limitations\\nIdentify common challenges mentioned across papers:\\n- Data privacy and security\\n- Regulatory approval processes\\n- Model interpretability and explainability\\n- Data quality and standardization\\n- Integration with existing healthcare systems\\n\\n## 7. Research Gaps and Future Directions\\nBased on the collective insights, identify areas needing further investigation and recommend next steps for the field.\\n\\n## 8. Conclusion\\nProvide a synthesis of how these papers collectively advance the field.\\n\\n**REQUIREMENTS:**\\n- Focus on synthesizing insights ACROSS papers rather than summarizing each individually\\n- Identify patterns, trends, and connections between different studies\\n- Highlight contradictions or different approaches to similar problems\\n- Ensure the analysis is suitable for researchers, clinicians, and healthcare technology professionals\\n- Use clear, professional academic language\\n- Cite papers by number (Paper 1, Paper 2, etc.) when referencing specific findings;\n\nconst detectedQuery = inputItems.length > 0 && inputItems[0].json.originalSearchQuery\n ? inputItems[0].json.originalSearchQuery\n : ‘research topic’;\n\nconsole.log(Detected research query: \"${detectedQuery}\");\n\nconst structuredPapers = inputItems.map((item, index) => {\n const p = item.json;\n\n let authorList = ‘Unknown Authors’;\n if (p.authors && Array.isArray(p.authors)) {\n authorList = p.authors.map(a => {\n if (typeof a === ‘string’) return a;\n if (a?.name) return a.name;\n return ‘Unknown Author’;\n }).join(’, ');\n } else if (typeof p.authors === ‘string’) {\n authorList = p.authors;\n }\n\n return {\n id: index + 1,\n title: p.title || ‘Unknown Title’,\n authors: authorList,\n year: p.year || ‘Unknown Year’,\n journal: p.journal || ‘Unknown Journal’,\n citations: p.totalCitations || p.citations || 0,\n abstract: p.abstract || ‘No abstract available’,\n doi: p.doi || ‘’,\n url: p.providerURL || p.url || ‘’,\n provider: p.provider || ‘Unknown’,\n originalSearchQuery: detectedQuery,\n };\n});\n\nreturn {\n prompt: fullPrompt,\n paperCount,\n paperList,\n papers: structuredPapers,\n totalPapers: structuredPapers.length,\n searchQuery: detectedQuery,\n};”
},
“type”: “n8n-nodes-base.code”,
“typeVersion”: 2,
“position”: [
-208,
1776
],
“id”: “93077724-87c2-4621-9769-c79f4dff70ee”,
“name”: “Code”
},
{
“parameters”: {
“modelId”: {
“__rl”: true,
“value”: “gpt-5-mini”,
“mode”: “list”,
“cachedResultName”: “GPT-5-MINI”
},
“messages”: {
“values”: [
{
“content”: “={{ $json.prompt }}”
}
]
},
“options”: {}
},
“type”: “@n8n/n8n-nodes-langchain.openAi”,
“typeVersion”: 1.8,
“position”: [
32,
1600
],
“id”: “03a08dc9-3560-45f0-98bf-3efca972fbec”,
“name”: “Message a model”,
“credentials”: {
“openAiApi”: {
“id”: “xjEGLjNNtlk2c7OM”,
“name”: “OpenAi account”
}
}
},
{
“parameters”: {
“mode”: “combine”,
“combinationMode”: “mergeByPosition”,
“options”: {}
},
“id”: “8d2c141a-3b57-40dc-bcc0-8d22214d3a4d”,
“name”: “Merge (Wait for both)”,
“type”: “n8n-nodes-base.merge”,
“typeVersion”: 2,
“position”: [
416,
1792
]
},
{
“parameters”: {
“jsCode”: “// Combine Sections — final version\nconst allItems = $input.all();\n\nlet synthesis = ‘No synthesis available’;\nlet paperData = null;\nlet searchQuery = ‘research’;\n\n// 1) Pick up the LLM output\nconst synthItem = allItems.find(i =>\n i.json?.response || i.json?.content || i.json?.message?.content || typeof i.json === ‘string’\n);\nif (synthItem) {\n synthesis =\n synthItem.json.response ||\n synthItem.json.content ||\n synthItem.json.message?.content ||\n (typeof synthItem.json === ‘string’ ? synthItem.json : ‘No synthesis available’);\n}\n\n// 2) Pick up structured papers\nconst dataItem = allItems.find(i => Array.isArray(i.json?.papers));\nif (dataItem) {\n paperData = dataItem.json;\n searchQuery = paperData.searchQuery || ‘research’;\n}\n\n// 3) Replace “Paper X” with links whose text is the full title\nlet enhanced = String(synthesis);\nif (paperData?.papers) {\n paperData.papers.forEach((paper, idx) => {\n const num = idx + 1;\n const url = paper.url || ‘’;\n if (!url) return;\n\n const title = paper.title || Paper ${num};\n const anchor = <a href=\"${url}\" target=\"_blank\" style=\"color:#3498db;text-decoration:none;font-weight:bold;\">${title}</a>;\n\n // (Paper X) → (Title link)\n enhanced = enhanced.replace(\n new RegExp(\\\\((?:Paper|paper)\\\\s+${num}\\\\), ‘g’),\n (${anchor})\n );\n\n // Standalone “Paper X” → Title link\n enhanced = enhanced.replace(\n new RegExp(\\\\b(Paper|paper)\\\\s+${num}(?=\\\\b|'s\\\\b|[.,:;)]|\\\\s), ‘gi’),\n anchor\n );\n });\n\n // Link every number inside “Papers 1, 2 and 3 …” lists\n // Match from "Papers " up to ., newline, ), ;, :, or end-of-string\n enhanced = enhanced.replace(\n /Papers?\s+([^\n\.\)\;\:]?)(?=[\.\n\)\;\:]|$)/gi,\n (whole, list) => {\n const updated = list.replace(/\b\d+\b/g, (nStr) => {\n const idx = parseInt(nStr, 10) - 1;\n const p = paperData.papers[idx];\n if (!p || !p.url) return nStr;\n const t = p.title || Paper ${nStr};\n return <a href=\"${p.url}\" target=\"_blank\" style=\"color:#3498db;font-weight:bold;\">${t}</a>;\n });\n return whole.replace(list, updated);\n }\n );\n}\n\n// 4) Escape stray \u to avoid Unicode parse errors when the JSON is serialized\nconst safeSynthesis = enhanced.replace(/\\u/g, ‘\\\\u’);\n\n// 5) Markdown-ish → HTML (and convert newlines)\nfunction formatSynthesisAsHtml(text) {\n return String(text)\n .replace(/## (.)/g, ‘$1’)\n .replace(/### (.)/g, ‘$1’)\n .replace(/\\(.?)\\/g, ‘$1’)\n .replace(/\n\s*\n/g, ‘’) // paragraph breaks (2+ newlines)\n .replace(/\n/g, ‘’) // single newlines\n .replace(/^/, ‘’)\n .replace(/$/, ‘’)\n .replace(/<h/g, ‘<h’)\n .replace(/<\/h([1-6])><\/p>/g, ‘</h$1>’);\n}\n\n// 6) Build the page\nconst titleCaseQuery = searchQuery.split(’ ‘)\n .map(w => w.charAt(0).toUpperCase() + w.slice(1))\n .join(’ ');\n\nconst literatureReview = {\n title: Literature Review: ${titleCaseQuery},\n subtitle: ‘A Comprehensive Analysis of Recent Research Trends and Applications’,\n generatedAt: new Date().toISOString(),\n totalPapers: paperData ? paperData.papers.length : 0,\n searchQuery,\n dateRange: ‘2020-2025’,\n methodology: ‘Analysis based on abstracts and metadata from academic databases including PubMed, arXiv, Google Scholar, and Semantic Scholar. Papers were selected based on citation count and abstract quality.’,\n synthesis: safeSynthesis,\n papers: paperData ? paperData.papers : ,\n};\n\nconst papers = Array.isArray(literatureReview.papers) ? literatureReview.papers : ;\nconst papersSummary = {\n totalCitations: papers.reduce((s, p) => s + (p.citations || 0), 0),\n averageCitations: papers.length ? Math.round(papers.reduce((s, p) => s + (p.citations || 0), 0) / papers.length) : 0,\n yearDistribution: papers.reduce((acc, p) => { const y = p.year || ‘Unknown’; acc[y] = (acc[y] || 0) + 1; return acc; }, {}),\n providerDistribution: papers.reduce((acc, p) => { const k = p.provider || ‘Unknown’; acc[k] = (acc[k] || 0) + 1; return acc; }, {}),\n};\n\n// 7) HTML (regular template literal — no “\n” anywhere)\nconst htmlContent = \n<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"UTF-8\" />\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\" />\n  <title>${literatureReview.title}</title>\n  <style>\n    body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; line-height: 1.6; max-width: 1000px; margin: 0 auto; padding: 20px; color: #333; background-color: #ffffff; }\n    h1 { color: #2c3e50; border-bottom: 3px solid #3498db; padding-bottom: 10px; margin-bottom: 5px; }\n    h2 { color: #34495e; border-bottom: 2px solid #ecf0f1; padding-bottom: 8px; margin-top: 30px; }\n    h3 { color: #2c3e50; margin-top: 25px; }\n    .subtitle { font-size: 1.2em; color: #7f8c8d; font-style: italic; margin-bottom: 30px; }\n    .meta-info { background-color: #f8f9fa; border-left: 4px solid #3498db; padding: 15px; margin: 20px 0; border-radius: 4px; }\n    .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 15px; margin: 20px 0; }\n    .stat-box { background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 15px; border-radius: 8px; text-align: center; }\n    .stat-number { font-size: 2em; font-weight: bold; display: block; }\n    .paper-item { background-color: #ffffff; border: 1px solid #e1e8ed; border-radius: 8px; padding: 20px; margin: 15px 0; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }\n    .paper-title { font-size: 1.1em; font-weight: bold; color: #2c3e50; margin-bottom: 10px; }\n    .paper-meta { color: #7f8c8d; font-size: 0.9em; margin-bottom: 10px; }\n    .paper-abstract { color: #555; font-style: italic; border-left: 3px solid #3498db; padding-left: 15px; margin-top: 10px; }\n    .citation-count { background-color: #e74c3c; color: white; padding: 3px 8px; border-radius: 12px; font-size: 0.8em; font-weight: bold; }\n    .provider-tag { background-color: #95a5a6; color: white; padding: 2px 6px; border-radius: 4px; font-size: 0.7em; text-transform: uppercase; }\n    .synthesis-content { background-color: #f8f9fa; border-radius: 8px; padding: 25px; margin: 20px 0; }\n    a { color: #3498db; text-decoration: none; font-weight: bold; }\n    a:hover { text-decoration: underline; color: #2980b9; }\n    .synthesis-content a { background-color: #e3f2fd; padding: 2px 6px; border-radius: 4px; border: 1px solid #3498db; }\n    .synthesis-content a:hover { background-color: #bbdefb; }\n    .distribution-item { display: flex; justify-content: space-between; padding: 5px 0; border-bottom: 1px solid #ecf0f1; }\n    .methodology { background-color: #fff3cd; border: 1px solid #ffeaa7; border-radius: 4px; padding: 15px; margin: 20px 0; }\n    .footer { margin-top: 40px; padding-top: 20px; border-top: 2px solid #ecf0f1; text-align: center; color: #7f8c8d; font-size: 0.9em; }\n  </style>\n</head>\n<body>\n  <h1>${literatureReview.title}</h1>\n  <div class=\"subtitle\">${literatureReview.subtitle}</div>\n\n  <div class=\"meta-info\">\n    <strong>Generated:</strong> ${new Date(literatureReview.generatedAt).toLocaleDateString()}<br>\n    <strong>Search Query:</strong> ${literatureReview.searchQuery}<br>\n    <strong>Date Range:</strong> ${literatureReview.dateRange}\n  </div>\n\n  <div class=\"stats-grid\">\n    <div class=\"stat-box\"><span class=\"stat-number\">${literatureReview.totalPapers}</span>Papers Analyzed</div>\n    <div class=\"stat-box\"><span class=\"stat-number\">${papersSummary.totalCitations.toLocaleString()}</span>Total Citations</div>\n    <div class=\"stat-box\"><span class=\"stat-number\">${papersSummary.averageCitations}</span>Avg Citations/Paper</div>\n  </div>\n\n  <div class=\"methodology\">\n    <h3>Methodology</h3>\n    <p>${literatureReview.methodology}</p>\n  </div>\n\n  <h2>Dataset Overview</h2>\n\n  <h3>Year Distribution</h3>\n  ${Object.entries(papersSummary.yearDistribution)\n      .sort(([a],[b]) => b.localeCompare(a))\n      .map(([year, count]) => 

${year}${count} papers)\n .join('')}\n\n <h3>Source Distribution</h3>\n ${Object.entries(papersSummary.providerDistribution)\n .sort(([,a],[,b]) => b - a)\n .map(([provider, count]) =>
${provider}${count} papers)\n .join('')}\n\n <h2>Literature Review Analysis</h2>\n <div class=\"synthesis-content\">\n ${formatSynthesisAsHtml(literatureReview.synthesis)}\n </div>\n\n <h2>Papers Included in Analysis</h2>\n ${papers\n .slice()\n .sort((a,b) => (b.citations||0) - (a.citations||0))\n .map(p => \n
\n
\n ${p.title}\n \n
\n Authors: ${p.authors}\n Publication: ${p.journal} (${p.year})\n ${(p.citations || 0).toLocaleString()} citations\n ${p.provider}\n ${p.doi ? <br><strong>DOI:</strong> ${p.doi} : ‘’}\n URL: View Paper\n \n
Abstract: ${p.abstract}\n \n ).join('')}\n\n <div class=\"footer\">\n <p><em>This literature review was generated automatically using n8n workflow automation and AI.</em></p>\n <p>Generated on ${new Date().toLocaleDateString()} at ${new Date().toLocaleTimeString()}</p>\n </div>\n</body>\n</html>\n;\n\nreturn {\n json: {\n title: literatureReview.title,\n totalPapers: literatureReview.totalPapers,\n searchQuery: literatureReview.searchQuery,\n htmlContent,\n emailSubject: ${literatureReview.title} - ${new Date().toLocaleDateString()},\n emailPreview: Comprehensive analysis of ${literatureReview.totalPapers} research papers on \"${searchQuery}\" with ${papersSummary.totalCitations.toLocaleString()} total citations,\n },\n};\n”
},
“id”: “42723803-a139-4e1b-a7b5-6cb543b52b2c”,
“name”: “Combine Sections”,
“type”: “n8n-nodes-base.code”,
“position”: [
640,
1792
],
“typeVersion”: 1
},
{
“parameters”: {
“sendTo”: “[email protected]”,
“subject”: “={{ $json.emailSubject }}”,
“message”: “={{ $json.htmlContent }}”,
“options”: {}
},
“id”: “2492b0b1-0b2b-4d4a-9f30-b10d6f3c8812”,
“name”: “Send Email Report”,
“type”: “n8n-nodes-base.gmail”,
“position”: [
864,
1792
],
“typeVersion”: 2,
“webhookId”: “d044e9d8-ac7c-4f49-829b-e2735d5c6c9b”,
“credentials”: {
“gmailOAuth2”: {
“id”: “lepdJBYpmcE2dlhT”,
“name”: “Gmail account”
}
}
}
],
“connections”: {
“When clicking ‘Execute workflow’”: {
“main”: [
[
{
“node”: “PDF Vector - Search Papers”,
“type”: “main”,
“index”: 0
}
]
]
},
“PDF Vector - Search Papers”: {
“main”: [
[
{
“node”: “Sort by Citations”,
“type”: “main”,
“index”: 0
}
]
]
},
“Sort by Citations”: {
“main”: [
[
{
“node”: “Select Top Papers”,
“type”: “main”,
“index”: 0
}
]
]
},
“Select Top Papers”: {
“main”: [
[
{
“node”: “Code”,
“type”: “main”,
“index”: 0
}
]
]
},
“Code”: {
“main”: [
[
{
“node”: “Message a model”,
“type”: “main”,
“index”: 0
},
{
“node”: “Merge (Wait for both)”,
“type”: “main”,
“index”: 1
}
]
]
},
“Message a model”: {
“main”: [
[
{
“node”: “Merge (Wait for both)”,
“type”: “main”,
“index”: 0
}
]
]
},
“Merge (Wait for both)”: {
“main”: [
[
{
“node”: “Combine Sections”,
“type”: “main”,
“index”: 0
}
]
]
},
“Combine Sections”: {
“main”: [
[
{
“node”: “Send Email Report”,
“type”: “main”,
“index”: 0
}
]
]
}
},
“pinData”: {},
“meta”: {
“templateId”: “7354”,
“templateCredsSetupCompleted”: true,
“instanceId”: “ddc8b19b7fa20047424f31044d87873eaee7496fb5be5378767f1db53a15213a”
}
}

}

1 Like

Hello, I’m very happy that you fixed the issue. Let us know if you need any help with PDF Vector.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.