
{
"nodes": [
{
"parameters": {
"functionCode": "// 從 items[0].json 中取出 body 內的資料\\nconst payload = items[0].json.body;\\n\\n// 檢查 payload 是否存在且有 events 屬性\\nif (!payload || !payload.events || !Array.isArray(payload.events) || payload.events.length === 0) {\\n throw new Error('未收到有效的 events 資料');\\n}\\n\\n// 提取 replyToken 與 userMessage\\nconst replyToken = payload.events[0].replyToken;\\nconst userMessage = payload.events[0].message.text;\\n\\nreturn [{ replyToken, userMessage }];\\n"
},
"name": "Parse LINE Message",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
140,
-180
],
"id": "c6e10252-eaef-4d38-8ab9-39aabce39dd0"
},
{
"parameters": {
"requestMethod": "POST",
"url": "<https://api.line.me/v2/bot/message/reply>",
"responseFormat": "string",
"jsonParameters": true,
"options": {},
"bodyParametersJson": "={\\n \\"replyToken\\": \\"{{ $json.replyToken }}\\",\\n \\"messages\\": [\\n {\\n \\"type\\": \\"text\\",\\n \\"text\\": \\"{{ $json.answer }}\\"\\n }\\n ]\\n}\\n",
"headerParametersJson": "{\\n \\"Authorization\\": \\"Bearer j3EbNCnP+c47jLfFtd0TuEMgCVvNeonxALwtRMxhwNumaM4HARI6/GSmDMFhmXvGDbnCyy3h1/tMh6FUDDg8MewR9LSid+0kqBDK5UlcbvQecQvpb8+kZdSOQKFHhgAlHGqu9YMz+rjet2xR5bT5nQdB04t89/1O/w1cDnyilFU=\\",\\n \\"Content-Type\\": \\"application/json\\"\\n}"
},
"name": "Reply to LINE",
"type": "n8n-nodes-base.httpRequest",
"typeVersion": 1,
"position": [
1560,
-120
],
"id": "590db112-209f-4e6c-8bbc-c725dcd6fd3a"
},
{
"parameters": {
"httpMethod": "POST",
"path": "line-webhook",
"options": {}
},
"name": "Webhook1",
"type": "n8n-nodes-base.webhook",
"typeVersion": 1,
"position": [
-120,
-120
],
"id": "88dc7f78-90c7-4326-80e8-e2a79dcb3af0",
"webhookId": "73099445-ab48-4c29-ae8e-ea32299d1988"
},
{
"parameters": {
"operation": "search",
"text": "我初進宮的那一天",
"options": {}
},
"name": "Get Existing Records",
"type": "n8n-nodes-base.notion",
"typeVersion": 2,
"position": [
40,
40
],
"id": "6e4530ff-701a-413a-89b4-9188210de8ca",
"executeOnce": true,
"credentials": {
"notionApi": {
"id": "mLkW1oHj5qZYbd3M",
"name": "Notion account"
}
}
},
{
"parameters": {
"functionCode": "// 取得所有輸入項目\\nconst inputItems = $input.all();\\n\\n// 建立新的結果陣列\\nconst outputItems = inputItems.map(item => {\\n let nameField = item.json.name;\\n \\n // 如果 nameField 是字串,嘗試將它解析成 JSON 或直接包裝成陣列\\n if (typeof nameField === 'string') {\\n const trimmed = nameField.trim();\\n // 如果看起來像 JSON 陣列,就嘗試解析\\n if (trimmed.startsWith('[') && trimmed.endsWith(']')) {\\n try {\\n nameField = JSON.parse(nameField);\\n } catch (error) {\\n // 解析失敗則直接包裝整個字串\\n nameField = [{ Text: nameField }];\\n }\\n } else {\\n // 直接包裝成陣列\\n nameField = [{ Text: nameField }];\\n }\\n }\\n \\n // 檢查 nameField 是否為陣列且至少有一個元素\\n if (!Array.isArray(nameField) || nameField.length === 0) {\\n return { json: { error: 'No text found in the \\"name\\" field' } };\\n }\\n \\n // 取得第一個物件的 Text 屬性作為文本內容\\n const text = nameField[0].Text;\\n if (!text) {\\n return { json: { error: 'No text found in this item' } };\\n }\\n \\n // 以單一換行符號分割文本\\n // 並移除每行前後的空白,過濾掉空行\\n const lines = text.split('\\\\n').map(line => line.trim()).filter(line => line !== \\"\\");\\n \\n // 如果需要對每行進行進一步處理,例如長度超過200字時根據句號拆分:\\n const segments = [];\\n lines.forEach(line => {\\n if (line.length > 200) {\\n // 以句號拆分,並保留句號\\n const sentences = line.split('。').map(s => s.trim()).filter(s => s !== \\"\\");\\n let temp = \\"\\";\\n sentences.forEach((s, index) => {\\n temp += s + \\"。\\";\\n // 每3個句子合併成一個片段\\n if ((index + 1) % 3 === 0) {\\n segments.push(temp.trim());\\n temp = \\"\\";\\n }\\n });\\n if (temp !== \\"\\") {\\n segments.push(temp.trim());\\n }\\n } else {\\n segments.push(line);\\n }\\n });\\n \\n return { json: { segments: segments } };\\n});\\n\\n// 回傳處理後的結果\\nreturn outputItems;\\n"
},
"name": "Clean Answer1",
"type": "n8n-nodes-base.function",
"typeVersion": 1,
"position": [
200,
40
],
"id": "3978f25a-d35d-4fac-90f8-a29039625ab1"
},
{
"parameters": {
"mode": "insert"
},
"type": "@n8n/n8n-nodes-langchain.vectorStoreInMemory",
"typeVersion": 1,
"position": [
340,
0
],
"id": "49204389-fdd3-45d6-bb5b-2384a453d448",
"name": "In-Memory Vector Store1"
},
{
"parameters": {
"model": "nomic-embed-text:latest"
},
"type": "@n8n/n8n-nodes-langchain.embeddingsOllama",
"typeVersion": 1,
"position": [
300,
220
],
"id": "b76707f9-118a-48fb-b98c-a0374c1f17ca",
"name": "Embeddings Ollama",
"credentials": {
"ollamaApi": {
"id": "3YPITdUvF4SqZwvs",
"name": "Ollama account 2"
}
}
},
{
"parameters": {
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.documentDefaultDataLoader",
"typeVersion": 1,
"position": [
460,
160
],
"id": "738c991a-095d-40e0-8392-efa9be66b196",
"name": "Default Data Loader"
},
{
"parameters": {
"model": "deepseek-r1:7b",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.lmOllama",
"typeVersion": 1,
"position": [
760,
60
],
"id": "440a200b-1d0c-4cc6-8fca-f842982979c5",
"name": "Ollama Model1",
"credentials": {
"ollamaApi": {
"id": "3YPITdUvF4SqZwvs",
"name": "Ollama account 2"
}
}
},
{
"parameters": {
"topK": 666
},
"type": "@n8n/n8n-nodes-langchain.retrieverVectorStore",
"typeVersion": 1,
"position": [
940,
60
],
"id": "0892163a-2715-4c96-ad7d-d139e157f413",
"name": "Vector Store Retriever"
},
{
"parameters": {},
"type": "@n8n/n8n-nodes-langchain.vectorStoreInMemory",
"typeVersion": 1,
"position": [
940,
200
],
"id": "49ef2739-e50f-4be7-ba28-cf45c587b73b",
"name": "In-Memory Vector Store"
},
{
"parameters": {
"model": "nomic-embed-text:latest"
},
"type": "@n8n/n8n-nodes-langchain.embeddingsOllama",
"typeVersion": 1,
"position": [
960,
360
],
"id": "b8f5c58f-d81a-4199-a685-43f07e275149",
"name": "Embeddings Ollama1",
"credentials": {
"ollamaApi": {
"id": "3YPITdUvF4SqZwvs",
"name": "Ollama account 2"
}
}
},
{
"parameters": {},
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [
660,
-160
],
"id": "0b054147-16a8-4605-859b-183fab3e9ff0",
"name": "Merge"
},
{
"parameters": {
"promptType": "define",
"text": "={\\n \\"prompt\\": \\"使用以下背景資料回答問題:{{ $json.userMessage }}\\\\n\\\\n{context}\\"\\n}\\n",
"options": {}
},
"type": "@n8n/n8n-nodes-langchain.chainRetrievalQa",
"typeVersion": 1.4,
"position": [
840,
-120
],
"id": "fdeb4b84-eb10-46e4-aedd-34af8971a48f",
"name": "Question and Answer Chain",
"executeOnce": true
},
{
"parameters": {
"chunkSize": 5000
},
"type": "@n8n/n8n-nodes-langchain.textSplitterTokenSplitter",
"typeVersion": 1,
"position": [
480,
320
],
"id": "88560be7-cc22-470a-a6e5-13f5299ece46",
"name": "Token Splitter"
},
{
"parameters": {
"jsCode": "/*\\n 此節點用來清洗答案,去除 \\\\n、*、- 和 <think> 標籤的內容\\n 假設輸入的答案格式為 \\"<think>\\\\n\\\\n</think>\\\\n\\\\n1 + 1 = **2**\\"\\n*/\\nconst input = $input.first().json.response.text || \\"\\";\\n\\n\\n// 使用正則表達式去除 <think> 標籤與其內容,並去除多餘空白\\nlet cleaned = input.replace(/[\\\\s\\\\S]*?\\\\s*/gi, '').trim();\\n\\n// 去除所有 \\\\n、*、- 和多餘的空格\\ncleaned = cleaned.replace(/[\\\\n\\\\*\\\\-\\\\\\"\\\\”\\\\“]/g, ' ').replace(/\\\\s+/g, ' ').trim();\\n\\n// 返回 JSON 格式的答案\\nreturn [{ answer: cleaned }];\\n"
},
"type": "n8n-nodes-base.code",
"typeVersion": 2,
"position": [
1200,
-120
],
"id": "ff1e6ec4-b644-4675-b3c2-d7d21cd620cd",
"name": "Code"
},
{
"parameters": {
"mode": "combine",
"combineBy": "combineAll",
"options": {}
},
"type": "n8n-nodes-base.merge",
"typeVersion": 3,
"position": [
1340,
-260
],
"id": "d5ae6790-a398-4162-8e46-d546093b1f6c",
"name": "Merge1"
}
],
"connections": {
"Parse LINE Message": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 0
},
{
"node": "Merge1",
"type": "main",
"index": 0
}
]
]
},
"Reply to LINE": {
"main": [
[]
]
},
"Webhook1": {
"main": [
[
{
"node": "Parse LINE Message",
"type": "main",
"index": 0
},
{
"node": "Get Existing Records",
"type": "main",
"index": 0
}
]
]
},
"Get Existing Records": {
"main": [
[
{
"node": "Clean Answer1",
"type": "main",
"index": 0
}
]
]
},
"Clean Answer1": {
"main": [
[
{
"node": "In-Memory Vector Store1",
"type": "main",
"index": 0
}
]
]
},
"In-Memory Vector Store1": {
"main": [
[
{
"node": "Merge",
"type": "main",
"index": 1
}
]
]
},
"Embeddings Ollama": {
"ai_embedding": [
[
{
"node": "In-Memory Vector Store1",
"type": "ai_embedding",
"index": 0
}
]
]
},
"Default Data Loader": {
"ai_document": [
[
{
"node": "In-Memory Vector Store1",
"type": "ai_document",
"index": 0
}
]
]
},
"Ollama Model1": {
"ai_languageModel": [
[
{
"node": "Question and Answer Chain",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Vector Store Retriever": {
"ai_retriever": [
[
{
"node": "Question and Answer Chain",
"type": "ai_retriever",
"index": 0
}
]
]
},
"In-Memory Vector Store": {
"ai_vectorStore": [
[
{
"node": "Vector Store Retriever",
"type": "ai_vectorStore",
"index": 0
}
]
]
},
"Embeddings Ollama1": {
"ai_embedding": [
[
{
"node": "In-Memory Vector Store",
"type": "ai_embedding",
"index": 0
}
]
]
},
"Merge": {
"main": [
[
{
"node": "Question and Answer Chain",
"type": "main",
"index": 0
}
]
]
},
"Question and Answer Chain": {
"main": [
[
{
"node": "Code",
"type": "main",
"index": 0
}
]
]
},
"Token Splitter": {
"ai_textSplitter": [
[
{
"node": "Default Data Loader",
"type": "ai_textSplitter",
"index": 0
}
]
]
},
"Code": {
"main": [
[
{
"node": "Merge1",
"type": "main",
"index": 1
}
]
]
},
"Merge1": {
"main": [
[
{
"node": "Reply to LINE",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {},
"meta": {
"templateCredsSetupCompleted": true,
"instanceId": "b4675dd1a7ebe0e31fae9b043df25c973d6121b6f98cd79084b3ea3b081c6fe8"
}
}