Created
July 9, 2025 07:55
-
-
Save masylum/f8e918bc59da8522011620b12b3079ca to your computer and use it in GitHub Desktop.
A job search bot example using n8n and handinger
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| { | |
| "name": "Soham Bot", | |
| "nodes": [ | |
| { | |
| "parameters": { "rule": { "interval": [ {} ] } }, | |
| "type": "n8n-nodes-base.scheduleTrigger", | |
| "typeVersion": 1.2, | |
| "position": [ 40, 60 ], | |
| "id": "3ff110bf-6a51-4fef-aa1a-cd188c3b7792", | |
| "name": "Schedule Trigger" | |
| }, | |
| { | |
| "parameters": { | |
| "fromEmail": "Soham Bot <soham@handinger.com>", | |
| "toEmail": "Test <test@handinger.com>", | |
| "subject": "=Soham Bot: We have discovered {{ $json.data.length }} job offers", | |
| "html": "={{ $json.htmlTable }}", | |
| "options": {} | |
| }, | |
| "type": "n8n-nodes-base.emailSend", | |
| "typeVersion": 2.1, | |
| "position": [ 2240, 120 ], | |
| "id": "8bd43c9b-0a72-4d7d-8efc-dfe607fcdd8b", | |
| "name": "Send email", | |
| "webhookId": "075c9e02-e865-4898-a222-95e819b895c1", | |
| "credentials": { | |
| } | |
| }, | |
| { | |
| "parameters": { | |
| "jsCode": "const items = $input.all().flatMap((item) => item.json).flatMap(json => json.data);\nconsole.log(items)\nconst htmlTable = `\n <table>\n <tr>\n <th>Company</th>\n <th>Offer</th>\n <th>Salary Range</th>\n <th>Summary</th>\n <th>Is the job offer good fit?</th>\n </tr>\n ${items.map((item) => `\n <tr>\n <td>${item.company}</td>\n <td><a href=\"${item.link}\">${item.title}</a></td>\n <td>${item.salary_range}</td>\n <td>${item.summary}</td>\n <td style=\"${\n item.fit === 'good'\n ? 'background: #ddffcc'\n : item.fit === 'medium' ? 'background: #ffffdd'\n : 'background: #ffdddd'\n }\"\n >\n <strong style=\"${\n item.fit === 'good'\n ? 'color: #447733'\n : item.fit === 'medium' ? 'color: #777733'\n : 'color: #773333'\n }\">${item.fit}</strong>:\n ${item.fit_reason}\n </td>\n </tr>\n`,\n )\n .join(\"\")}\n</table>\n`;\n\nreturn { htmlTable };\n" | |
| }, | |
| "type": "n8n-nodes-base.code", | |
| "typeVersion": 2, | |
| "position": [ 1800, 220 ], | |
| "id": "d10dcd3e-91d0-48e0-bdde-2f932db6f319", | |
| "name": "Code1" | |
| }, | |
| { | |
| "parameters": {}, | |
| "type": "n8n-nodes-base.merge", | |
| "typeVersion": 3.2, | |
| "position": [ 1140, 120 ], | |
| "id": "250ed82b-a322-4dbd-951c-5ff8eab66fc8", | |
| "name": "Merge" | |
| }, | |
| { | |
| "parameters": { | |
| "fieldToSplitOut": "link", | |
| "options": {} | |
| }, | |
| "type": "n8n-nodes-base.splitOut", | |
| "typeVersion": 1, | |
| "position": [ 480, -40 ], | |
| "id": "db1411ca-a9b0-4bbe-8f8a-4bbacf2fa14b", | |
| "name": "Split Out" | |
| }, | |
| { | |
| "parameters": { | |
| "fieldToSplitOut": "items", | |
| "options": {} | |
| }, | |
| "type": "n8n-nodes-base.splitOut", | |
| "typeVersion": 1, | |
| "position": [ 480, 220 ], | |
| "id": "499d95b1-9dd1-4e1c-b7c4-8bb9da4d4c19", | |
| "name": "Split Out1" | |
| }, | |
| { | |
| "parameters": { | |
| "aggregate": "aggregateAllItemData", | |
| "options": {} | |
| }, | |
| "type": "n8n-nodes-base.aggregate", | |
| "typeVersion": 1, | |
| "position": [ 1580, 120 ], | |
| "id": "bc18385d-2af1-4c01-a0ee-d263614891fc", | |
| "name": "Aggregate" | |
| }, | |
| { | |
| "parameters": { | |
| "mode": "combine", | |
| "combineBy": "combineByPosition", | |
| "options": {} | |
| }, | |
| "type": "n8n-nodes-base.merge", | |
| "typeVersion": 3.2, | |
| "position": [ 2020, 120 ], | |
| "id": "5aba0de4-74ea-4300-9b55-a5fb85080a5c", | |
| "name": "Merge1" | |
| }, | |
| { | |
| "parameters": { | |
| "mode": "combine", | |
| "combineBy": "combineByPosition", | |
| "options": {} | |
| }, | |
| "type": "n8n-nodes-base.merge", | |
| "typeVersion": 3.2, | |
| "position": [ 920, -40 ], | |
| "id": "4e83cb49-1416-4e89-9e85-3c0d2cfe0a1f", | |
| "name": "Merge2" | |
| }, | |
| { | |
| "parameters": { | |
| "type": "code", | |
| "code": "const fieldName = 'fit';\nconst priority = { good: 0, medium: 1, bad: 2 };\n\nif (priority[a.json[fieldName]] < priority[b.json[fieldName]]) {\n return -1;\n}\nif (priority[a.json[fieldName]] > priority[b.json[fieldName]]) {\n return 1;\n}\nreturn 0;" | |
| }, | |
| "type": "n8n-nodes-base.sort", | |
| "typeVersion": 1, | |
| "position": [ 1360, 120 ], | |
| "id": "d6ec33fc-7a6f-4104-90b1-e427d0c88e0e", | |
| "name": "Sort" | |
| }, | |
| { | |
| "parameters": { | |
| "url": "https://api.handinger.com/llm", | |
| "sendQuery": true, | |
| "queryParameters": { | |
| "parameters": [ | |
| { | |
| "name": "prompt", | |
| "value": "=I'm a senior frontend engineer with 5 years experience. I've worked with React, Angular, Typescript, CSS, HTML and also Tailwind. I can also design and have some basic knowledge on devops and backend.\n\nI live in a remote town in Spain and I want to earn at least $70k.\n\nExtract the following information from a markdown document containing a list of jobs. Output a json.\n\nFor each job offer return:\n- company name\n- job title\n- job link\n- the salary range if available.\n- a short summary of the job offer\n- fit: do the technologies, the experience, the salary, and the location approximately match? Can it be \"bad\", \"medium\", \"good\"\n- fit reason: Explanation of the fit\n\nContent:" | |
| }, | |
| { | |
| "name": "json_schema", | |
| "value": "={\n \"type\":\"object\",\n \"properties\":{\n \"items\":{\n \"type\":\"array\",\n \"items\":{\n \"type\":\"object\",\n \"properties\":{\n \"company\":{ \"type\":\"string\" },\n \"title\":{ \"type\":\"string\" },\n \"link\": {\"type\": \"string\"},\n \"salary_range\":{ \"type\":\"string\" },\n \"summary\":{ \"type\":\"string\" },\n \"fit\":{ \"enum\": [\"bad\", \"medium\", \"good\"] },\n \"fit_reason\":{ \"type\":\"string\" }\n },\n \"required\":[ \"company\", \"title\", \"link\", \"salary_range\", \"summary\", \"fit\", \"fit_reason\" ]\n }\n }\n },\n \"required\":[ \"items\" ]\n}" | |
| }, | |
| { | |
| "name": "url", | |
| "value": "https://remoteok.com/?min_salary=70000&order_by=date&action=get_jobs" | |
| }, | |
| { | |
| "name": "fresh", | |
| "value": "true" | |
| } | |
| ] | |
| }, | |
| "sendHeaders": true, | |
| "headerParameters": { | |
| "parameters": [ | |
| { | |
| "name": "Authorization", | |
| "value": "Bearer XXXXXXXX" | |
| } | |
| ] | |
| }, | |
| "options": {} | |
| }, | |
| "type": "n8n-nodes-base.httpRequest", | |
| "typeVersion": 4.2, | |
| "position": [ 260, 220 ], | |
| "id": "427cad8f-2c77-4105-85da-f0b0a5a7b96c", | |
| "name": "Fetch remoteok" | |
| }, | |
| { | |
| "parameters": { | |
| "url": "https://api.handinger.com/llm", | |
| "sendQuery": true, | |
| "queryParameters": { | |
| "parameters": [ | |
| { | |
| "name": "prompt", | |
| "value": "=I'm a senior frontend engineer with 5 years experience. I've worked with React, Angular, Typescript, CSS, HTML and also Tailwind. I can also design and have some basic knowledge on devops and backend.\n\nI live in a remote town in Spain and I want to earn at least $70k.\n\nExtract the following information from a job offer written in markdown:\n- company name\n- job title\n- the salary range if available.\n- a short summary of the job offer\n- fit: do the technologies, the experience, the salary, and the location approximately match? Can it be \"bad\", \"medium\", \"good\"\n- fit reason: Explanation of the fit\n\nContent:" | |
| }, | |
| { | |
| "name": "json_schema", | |
| "value": "={\n \"type\": \"object\",\n \"properties\": {\n \"company\": {\n \"type\": \"string\"\n },\n \"title\": {\n \"type\": \"string\"\n },\n \"salary_range\": {\n \"type\": \"string\"\n },\n \"summary\": {\n \"type\": \"string\"\n },\n \"fit\": {\n \"enum\": [\n \"bad\",\n \"medium\",\n \"good\"\n ]\n },\n \"fit_reason\": {\n \"type\": \"string\"\n }\n },\n \"required\": [\n \"company\",\n \"title\",\n \"salary_range\",\n \"summary\",\n \"fit\",\n \"fit_reason\"\n ]\n}" | |
| }, | |
| { | |
| "name": "fresh", | |
| "value": "true" | |
| }, | |
| { | |
| "name": "url", | |
| "value": "={{ $json.link }}" | |
| } | |
| ] | |
| }, | |
| "sendHeaders": true, | |
| "headerParameters": { | |
| "parameters": [ | |
| { | |
| "name": "Authorization", | |
| "value": "Bearer XXXXXXXX" | |
| } | |
| ] | |
| }, | |
| "options": { | |
| "batching": { | |
| "batch": { | |
| "batchSize": 20, | |
| "batchInterval": 20000 | |
| } | |
| } | |
| } | |
| }, | |
| "type": "n8n-nodes-base.httpRequest", | |
| "typeVersion": 4.2, | |
| "position": [ 700, 35 ], | |
| "id": "90be77d8-a512-43eb-8756-834f749edb0d", | |
| "name": "Fetch details: weworkremotely" | |
| }, | |
| { | |
| "parameters": { | |
| "url": "https://api.handinger.com/llm", | |
| "sendQuery": true, | |
| "queryParameters": { | |
| "parameters": [ | |
| { | |
| "name": "prompt", | |
| "value": "=Given a markdown with a list of job offers.\nFor each job, extract the job offer link.\n\nContent:" | |
| }, | |
| { | |
| "name": "json_schema", | |
| "value": "={\n \"type\":\"object\",\n \"properties\":{\n \"link\":{\n \"type\":\"array\",\n \"items\":{\n \"type\":\"string\",\n }\n }\n }\n}" | |
| }, | |
| { | |
| "name": "url", | |
| "value": "https://weworkremotely.com/categories/remote-full-stack-programming-jobs" | |
| } | |
| ] | |
| }, | |
| "sendHeaders": true, | |
| "headerParameters": { | |
| "parameters": [ | |
| { | |
| "name": "Authorization", | |
| "value": "Bearer XXXXXXXX" | |
| } | |
| ] | |
| }, | |
| "options": {} | |
| }, | |
| "type": "n8n-nodes-base.httpRequest", | |
| "typeVersion": 4.2, | |
| "position": [ 260, -40 ], | |
| "id": "a165f020-2145-4100-982f-cd997dabfda3", | |
| "name": "Fetch list from weworkremotely", | |
| "retryOnFail": true | |
| } | |
| ], | |
| "pinData": {}, | |
| "connections": { | |
| "Schedule Trigger": { | |
| "main": [ | |
| [ | |
| { | |
| "node": "Fetch remoteok", | |
| "type": "main", | |
| "index": 0 | |
| }, | |
| { | |
| "node": "Fetch list from weworkremotely", | |
| "type": "main", | |
| "index": 0 | |
| } | |
| ] | |
| ] | |
| }, | |
| "Send email": { | |
| "main": [ | |
| [] | |
| ] | |
| }, | |
| "Code1": { | |
| "main": [ | |
| [ | |
| { | |
| "node": "Merge1", | |
| "type": "main", | |
| "index": 1 | |
| } | |
| ] | |
| ] | |
| }, | |
| "Split Out": { | |
| "main": [ | |
| [ | |
| { | |
| "node": "Fetch details: weworkremotely", | |
| "type": "main", | |
| "index": 0 | |
| }, | |
| { | |
| "node": "Merge2", | |
| "type": "main", | |
| "index": 0 | |
| } | |
| ] | |
| ] | |
| }, | |
| "Split Out1": { | |
| "main": [ | |
| [ | |
| { | |
| "node": "Merge", | |
| "type": "main", | |
| "index": 1 | |
| } | |
| ] | |
| ] | |
| }, | |
| "Merge": { | |
| "main": [ | |
| [ | |
| { | |
| "node": "Sort", | |
| "type": "main", | |
| "index": 0 | |
| } | |
| ] | |
| ] | |
| }, | |
| "Aggregate": { | |
| "main": [ | |
| [ | |
| { | |
| "node": "Code1", | |
| "type": "main", | |
| "index": 0 | |
| }, | |
| { | |
| "node": "Merge1", | |
| "type": "main", | |
| "index": 0 | |
| } | |
| ] | |
| ] | |
| }, | |
| "Merge1": { | |
| "main": [ | |
| [ | |
| { | |
| "node": "Send email", | |
| "type": "main", | |
| "index": 0 | |
| } | |
| ] | |
| ] | |
| }, | |
| "Merge2": { | |
| "main": [ | |
| [ | |
| { | |
| "node": "Merge", | |
| "type": "main", | |
| "index": 0 | |
| } | |
| ] | |
| ] | |
| }, | |
| "Sort": { | |
| "main": [ | |
| [ | |
| { | |
| "node": "Aggregate", | |
| "type": "main", | |
| "index": 0 | |
| } | |
| ] | |
| ] | |
| }, | |
| "Fetch remoteok": { | |
| "main": [ | |
| [ | |
| { | |
| "node": "Split Out1", | |
| "type": "main", | |
| "index": 0 | |
| } | |
| ] | |
| ] | |
| }, | |
| "Fetch details: weworkremotely": { | |
| "main": [ | |
| [ | |
| { | |
| "node": "Merge2", | |
| "type": "main", | |
| "index": 1 | |
| } | |
| ] | |
| ] | |
| }, | |
| "Fetch list from weworkremotely": { | |
| "main": [ | |
| [ | |
| { | |
| "node": "Split Out", | |
| "type": "main", | |
| "index": 0 | |
| } | |
| ] | |
| ] | |
| } | |
| }, | |
| "active": false, | |
| "settings": { | |
| "executionOrder": "v1" | |
| }, | |
| "versionId": "d9ac3f9c-fef1-443b-a067-56227521cb6c", | |
| "meta": { | |
| "templateCredsSetupCompleted": true, | |
| "instanceId": "380234b0f7d1bfa6f3115ce8d46ba296f995cd10c30cff5125872ac16ea20d4b" | |
| }, | |
| "id": "Kr2zGjIw7o36PD4v", | |
| "tags": [] | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment