diff --git a/tags.json b/tags.json index e27aacc..c171883 100644 --- a/tags.json +++ b/tags.json @@ -78,10 +78,6 @@ "workflowId": "H6TZCHyiYOr1X6Xf", "tagId": "FydpKYmttDwoZVAA" }, - { - "workflowId": "WkAdUd9jXTtPagGO", - "tagId": "FydpKYmttDwoZVAA" - }, { "workflowId": "cPWZKfrHOUSUZjIp", "tagId": "FydpKYmttDwoZVAA" diff --git a/workflows/WkAdUd9jXTtPagGO.json b/workflows/WkAdUd9jXTtPagGO.json index df68506..8704153 100644 --- a/workflows/WkAdUd9jXTtPagGO.json +++ b/workflows/WkAdUd9jXTtPagGO.json @@ -22,7 +22,7 @@ "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 816, + 768, 304 ] }, @@ -68,31 +68,17 @@ "type": "n8n-nodes-base.postgres", "typeVersion": 2.6, "position": [ - 640, + 528, 304 ], "id": "2f0708e1-996c-4705-b374-2a119fcd6b18", "name": "Get Active Followed Series", "credentials": { "postgres": { - "id": "dsnKfvOBMkgU21Lt", - "name": "supabase postgres account" + "id": "9grzZwW7Br6SzdV8", + "name": "n8n-media" } } - }, - { - "parameters": { - "language": "pythonNative", - "pythonCode": "# Mode: Run Once for All Items\n# Purpose: Debug the environment context passed from Parent to Child\n\nresults = []\n\nfor _item in _items:\n # We create a debug log of the current execution context\n debug_info = {\n \"execution_id\": _item['json'].get('executionId', 'N/A'),\n \"parent_execution_id\": _item['json'].get('parentExecutionId', 'N/A'),\n # Check if internal n8n variables are reachable\n \"workflow_id\": _item['json'].get('workflowId', 'N/A'),\n }\n \n _item['json']['debug_context'] = debug_info\n results.append(_item)\n\nreturn results" - }, - "type": "n8n-nodes-base.code", - "typeVersion": 2, - "position": [ - 432, - 304 - ], - "id": "b538b6ba-0c72-40ee-ba3e-723e79fc0d21", - "name": "Code in Python" } ], "connections": { @@ -100,7 +86,7 @@ "main": [ [ { - "node": "Code in Python", + "node": "Get Active Followed Series", "type": "main", "index": 0 } @@ -128,17 +114,6 @@ } ] ] - }, - "Code in Python": { - "main": [ - [ - { - "node": "Get Active Followed Series", - "type": "main", - "index": 0 - } - ] - ] } }, "settings": { @@ -149,7 +124,7 @@ "saveExecutionProgress": true }, "triggerCount": 0, - "versionId": "dfde93ca-153c-4dce-b4f3-eac86c25d2e5", + "versionId": "9c096562-3d33-4d44-8f30-5afdd1bfc05e", "owner": { "type": "personal", "projectId": "FeLO36wNUAcn61Wj", diff --git a/workflows/cPWZKfrHOUSUZjIp.json b/workflows/cPWZKfrHOUSUZjIp.json index 951a0af..5a96248 100644 --- a/workflows/cPWZKfrHOUSUZjIp.json +++ b/workflows/cPWZKfrHOUSUZjIp.json @@ -7,8 +7,8 @@ "id": "workflow-trigger", "name": "Workflow Trigger", "position": [ - 2272, - 864 + 48, + 640 ], "type": "n8n-nodes-base.executeWorkflowTrigger", "typeVersion": 1 @@ -21,8 +21,8 @@ "id": "ssh-list-general", "name": "List General Folders", "position": [ - 2496, - 768 + 272, + 544 ], "type": "n8n-nodes-base.ssh", "typeVersion": 1, @@ -40,8 +40,8 @@ "id": "code-parse", "name": "Code", "position": [ - 2720, - 672 + 496, + 448 ], "type": "n8n-nodes-base.code", "typeVersion": 2 @@ -61,8 +61,8 @@ "type": "@n8n/n8n-nodes-langchain.agent", "typeVersion": 3, "position": [ - 3872, - 592 + 1648, + 368 ], "id": "409e6caa-c009-4b43-9170-e8c3251ef003", "name": "Lookup Agent", @@ -84,8 +84,8 @@ "type": "@tavily/n8n-nodes-tavily.tavilyTool", "typeVersion": 1, "position": [ - 4000, - 816 + 1776, + 592 ], "id": "b7ce39bf-87d5-4af4-bcf2-2b58381f1956", "name": "tavily_search", @@ -286,8 +286,8 @@ "type": "n8n-nodes-base.postgres", "typeVersion": 2.6, "position": [ - 5424, - 704 + 3200, + 480 ], "id": "a85dde4b-2471-4ced-8e3c-f999a6297895", "name": "Insert or update rows in a table", @@ -308,8 +308,8 @@ "type": "n8n-nodes-base.splitInBatches", "typeVersion": 3, "position": [ - 3392, - 768 + 1168, + 544 ], "id": "3e1127d2-a059-475c-a90e-9cf2dc3a8d46", "name": "Loop Over Items" @@ -342,8 +342,8 @@ "type": "n8n-nodes-base.httpRequestTool", "typeVersion": 4.3, "position": [ - 4128, - 816 + 1904, + 592 ], "id": "14c979cf-00b4-4f79-8b49-e3e1b6fe54da", "name": "google_search" @@ -384,8 +384,8 @@ "type": "n8n-nodes-base.filter", "typeVersion": 2.3, "position": [ - 3168, - 768 + 944, + 544 ], "id": "8b666e89-b553-42a1-8d91-94fd5404760c", "name": "Filter Unwanted", @@ -401,8 +401,8 @@ "type": "n8n-nodes-base.merge", "typeVersion": 3.2, "position": [ - 4624, - 768 + 2400, + 544 ], "id": "31313285-3e56-44d1-a79b-c65bd2206460", "name": "Merge" @@ -443,8 +443,8 @@ "type": "n8n-nodes-base.if", "typeVersion": 2.3, "position": [ - 5200, - 768 + 2976, + 544 ], "id": "d0d29d9a-606e-41d4-a8e9-867f51469f1e", "name": "verified" @@ -454,8 +454,8 @@ "type": "n8n-nodes-base.noOp", "typeVersion": 1, "position": [ - 5648, - 944 + 3424, + 720 ], "id": "618a5f45-e4d2-4ba3-a61a-858b7025ab85", "name": "Formatting" @@ -469,8 +469,8 @@ "type": "@n8n/n8n-nodes-langchain.outputParserStructured", "typeVersion": 1.3, "position": [ - 4256, - 816 + 2032, + 592 ], "id": "3baa52c0-8ce1-40fb-9b91-cfe6f869e9ae", "name": "Structured Output Parser", @@ -486,8 +486,8 @@ "id": "postgres-filter", "name": "Fetch Existing", "position": [ - 2720, - 864 + 496, + 640 ], "type": "n8n-nodes-base.postgres", "typeVersion": 1, @@ -509,8 +509,8 @@ "id": "merge-check", "name": "Filter Existing", "position": [ - 2944, - 768 + 720, + 544 ], "type": "n8n-nodes-base.merge", "typeVersion": 3.2 @@ -526,8 +526,8 @@ "type": "n8n-nodes-base.scheduleTrigger", "typeVersion": 1.3, "position": [ - 2272, - 672 + 48, + 448 ], "id": "f411d807-43c9-459b-a0bb-1c079a4d8666", "name": "Schedule Trigger" @@ -545,8 +545,8 @@ "type": "n8n-nodes-base.gmail", "typeVersion": 2.2, "position": [ - 4000, - 416 + 1776, + 192 ], "id": "383ff376-cec7-4cde-a9a6-265cee6db626", "name": "Send a message", @@ -565,8 +565,8 @@ "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [ - 3824, - 416 + 1600, + 192 ], "id": "b77eac76-096e-40d6-907e-cc861acca2dd", "name": "Code in JavaScript" @@ -599,8 +599,8 @@ "type": "n8n-nodes-base.if", "typeVersion": 2.3, "position": [ - 3600, - 640 + 1376, + 416 ], "id": "e357ecd8-c8e7-48e0-9505-7044f883dc14", "name": "If" @@ -614,8 +614,8 @@ "type": "@n8n/n8n-nodes-langchain.chainLlm", "typeVersion": 1.7, "position": [ - 4848, - 768 + 2624, + 544 ], "id": "273ae694-f28a-456c-ad24-0dcd4e64e710", "name": "QA Agent" @@ -630,14 +630,15 @@ }, "responsesApiEnabled": false, "options": { - "responseFormat": "json_object" + "responseFormat": "json_object", + "temperature": 0 } }, "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi", "typeVersion": 1.3, "position": [ - 4400, - 992 + 2176, + 768 ], "id": "8198be70-fcae-44f1-8643-a6b97d7a33b0", "name": "gpt-oss:120b - Validator", @@ -703,8 +704,8 @@ "type": "@n8n/n8n-nodes-langchain.toolWorkflow", "typeVersion": 2.2, "position": [ - 3712, - 848 + 1488, + 624 ], "id": "78150d6a-0c28-46e5-ba55-953b063b6872", "name": "audible_lookup_asin" @@ -765,8 +766,8 @@ "type": "@n8n/n8n-nodes-langchain.toolWorkflow", "typeVersion": 2.2, "position": [ - 3840, - 816 + 1616, + 592 ], "id": "a41d0ed6-78a1-401b-9dcb-74f533dedb51", "name": "audible_search_book" @@ -808,8 +809,8 @@ "type": "@n8n/n8n-nodes-langchain.toolWorkflow", "typeVersion": 2.2, "position": [ - 4112, - 976 + 1888, + 752 ], "id": "943011b5-1af5-45f9-8146-fcf5069e2fa5", "name": "brave_search" @@ -819,8 +820,8 @@ "type": "@n8n/n8n-nodes-langchain.toolWikipedia", "typeVersion": 1, "position": [ - 3984, - 976 + 1760, + 752 ], "id": "c31ac1dc-4653-4d01-98dc-0b20f83f7c01", "name": "Wikipedia" @@ -834,8 +835,8 @@ "type": "n8n-nodes-base.stickyNote", "typeVersion": 1, "position": [ - 2176, - 336 + -48, + 112 ], "id": "83bb9595-37ee-47ee-a3b2-ab034cc75333", "name": "Sticky Note" @@ -854,8 +855,8 @@ "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi", "typeVersion": 1.3, "position": [ - 3856, - 960 + 1632, + 736 ], "id": "c69843d8-49d9-43c7-8de9-f67918c87e12", "name": "gpt/oss-120b", @@ -880,8 +881,8 @@ "type": "@n8n/n8n-nodes-langchain.lmChatOpenAi", "typeVersion": 1.3, "position": [ - 3600, - 960 + 1376, + 736 ], "id": "ae56277d-f35d-4ece-b6b5-7981e649f242", "name": "OpenAI Chat Model", @@ -894,56 +895,33 @@ }, { "parameters": { - "jsCode": "// Fuzzy match incoming title against followed series\n// Input: title from Execute Workflow trigger\n// Output: matched series or null\n\nconst inputItem = $input.first();\nconst title = inputItem.json.title || '';\nconst metadata = inputItem.json.metadata || {};\n\n// Get all followed series from Supabase\nconst seriesList = $('Get Active Followed Series').all();\n\n// Helper function to normalize strings for comparison\nfunction normalize(str) {\n return str.toLowerCase()\n .replace(/[^a-z0-9\\s]/g, '')\n .replace(/\\s+/g, ' ')\n .trim();\n}\n\n// Helper function to extract patterns from title\nfunction extractPatterns(title) {\n const patterns = {\n volume: null,\n author: null,\n cleanTitle: title\n };\n \n // Extract volume numbers (e.g., \"Vol 01\", \"Volume 1\", \"v01\")\n const volumeMatch = title.match(/\\b(?:vol(?:ume)?\\.?\\s*(\\d+)|v(\\d+))\\b/i);\n if (volumeMatch) {\n patterns.volume = parseInt(volumeMatch[1] || volumeMatch[2]);\n }\n \n // Extract author (common patterns: \"Author Name - Title\", \"[Author Name]\")\n const authorMatch1 = title.match(/^([^-\\[\\]]+?)\\s*-\\s*(.+)/);\n const authorMatch2 = title.match(/\\[([^\\]]+)\\]/);\n \n if (authorMatch1) {\n patterns.author = authorMatch1[1].trim();\n patterns.cleanTitle = authorMatch1[2].trim();\n } else if (authorMatch2) {\n patterns.author = authorMatch2[1].trim();\n }\n \n return patterns;\n}\n\n// Extract patterns from input title\nconst inputPatterns = extractPatterns(title);\nconst normalizedInput = normalize(inputPatterns.cleanTitle);\n\n// Try to match against series\nlet bestMatch = null;\nlet bestScore = 0;\n\nfor (const series of seriesList) {\n const seriesName = series.json.series_name || '';\n const author = series.json.author || '';\n const normalizedSeries = normalize(seriesName);\n const normalizedAuthor = normalize(author);\n \n let score = 0;\n \n // Check if series name is contained in title\n if (normalizedInput.includes(normalizedSeries)) {\n score += 50;\n }\n \n // Check if title is contained in series name\n if (normalizedSeries.includes(normalizedInput)) {\n score += 40;\n }\n \n // Check author match\n if (inputPatterns.author && normalizedAuthor) {\n if (normalize(inputPatterns.author).includes(normalizedAuthor)) {\n score += 30;\n }\n }\n \n // Simple word overlap check\n const inputWords = normalizedInput.split(' ').filter(w => w.length > 2);\n const seriesWords = normalizedSeries.split(' ').filter(w => w.length > 2);\n const commonWords = inputWords.filter(w => seriesWords.includes(w));\n score += commonWords.length * 5;\n \n if (score > bestScore) {\n bestScore = score;\n bestMatch = series.json;\n }\n}\n\n// Return match if score is above threshold\nif (bestMatch && bestScore >= 40) {\n return [{\n json: {\n matched: true,\n series_id: bestMatch.id,\n series_name: bestMatch.series_name,\n author: bestMatch.author,\n category: bestMatch.category,\n smb_path: bestMatch.smb_path,\n match_score: bestScore,\n original_title: title,\n extracted_volume: inputPatterns.volume,\n extracted_author: inputPatterns.author\n }\n }];\n} else {\n return [{\n json: {\n matched: false,\n series_id: null,\n series_name: null,\n author: null,\n category: null,\n smb_path: null,\n match_score: bestScore,\n original_title: title\n }\n }];\n}" - }, - "id": "6bc67604-5a6a-45ed-af56-5ab176e65e54", - "name": "Fuzzy Match Title", - "type": "n8n-nodes-base.code", - "typeVersion": 2, - "position": [ - 4624, - 560 - ] - }, - { - "parameters": { - "operation": "select", - "schema": { + "workflowId": { "__rl": true, + "value": "WkAdUd9jXTtPagGO", "mode": "list", - "value": "public" + "cachedResultUrl": "/workflow/WkAdUd9jXTtPagGO", + "cachedResultName": "MAM Series Matcher" }, - "table": { - "__rl": true, - "value": "followed_series", - "mode": "list", - "cachedResultName": "followed_series" + "workflowInputs": { + "mappingMode": "defineBelow", + "value": {}, + "matchingColumns": [], + "schema": [], + "attemptToConvertTypes": false, + "convertFieldsToString": true }, - "returnAll": true, - "where": { - "values": [ - { - "column": "active", - "value": "true" - } - ] - }, - "options": {} - }, - "type": "n8n-nodes-base.postgres", - "typeVersion": 2.6, - "position": [ - 4352, - 528 - ], - "id": "e10726a0-7a1c-4b9b-ba16-1ee3120c6486", - "name": "Get Active Followed Series", - "credentials": { - "postgres": { - "id": "9grzZwW7Br6SzdV8", - "name": "n8n-media" + "options": { + "waitForSubWorkflow": true } - } + }, + "type": "n8n-nodes-base.executeWorkflow", + "typeVersion": 1.3, + "position": [ + 2128, + 368 + ], + "id": "5e966fb1-22e6-405c-b2cb-14cc7ae53cb1", + "name": "Call 'MAM Series Matcher'" } ], "connections": { @@ -951,9 +929,9 @@ "main": [ [ { + "index": 0, "node": "Filter Existing", - "type": "main", - "index": 0 + "type": "main" } ] ] @@ -962,9 +940,9 @@ "main": [ [ { + "index": 0, "node": "Code", - "type": "main", - "index": 0 + "type": "main" }, { "node": "Fetch Existing", @@ -978,9 +956,9 @@ "main": [ [ { + "index": 0, "node": "List General Folders", - "type": "main", - "index": 0 + "type": "main" } ] ] @@ -1000,7 +978,7 @@ "main": [ [ { - "node": "Get Active Followed Series", + "node": "Call 'MAM Series Matcher'", "type": "main", "index": 0 } @@ -1125,9 +1103,9 @@ "main": [ [ { + "index": 1, "node": "Filter Existing", - "type": "main", - "index": 1 + "type": "main" } ] ] @@ -1247,6 +1225,11 @@ ] ] }, + "gpt/oss-120b": { + "ai_languageModel": [ + [] + ] + }, "OpenAI Chat Model": { "ai_languageModel": [ [ @@ -1258,7 +1241,7 @@ ] ] }, - "Fuzzy Match Title": { + "Call 'MAM Series Matcher'": { "main": [ [ { @@ -1268,17 +1251,6 @@ } ] ] - }, - "Get Active Followed Series": { - "main": [ - [ - { - "node": "Fuzzy Match Title", - "type": "main", - "index": 0 - } - ] - ] } }, "settings": { @@ -1287,7 +1259,7 @@ "availableInMCP": false }, "triggerCount": 1, - "versionId": "28f307b7-5456-4809-a3e6-af121a2058dc", + "versionId": "7ed1b1cb-2859-483e-9091-51b0cb05b2df", "owner": { "type": "personal", "projectId": "FeLO36wNUAcn61Wj",