{
  "name": "LinkedIn_Job_Hunt_and_Cover_Letter",
  "nodes": [
    {
      "parameters": {
        "content": "## \u81ea\u52a8\u5316\u6c42\u804c\u52a9\u624b\uff08LinkedIn + Indeed\uff09\uff1a\u901a\u8fc7\u90ae\u4ef6\u83b7\u53d6\u6700\u4f73\u804c\u4f4d\u5339\u914d + \u751f\u6210\u6c42\u804c\u4fe1 + \u4fdd\u5b58\u5230Notion\n\n**\u4f5c\u8005**: Wen\n**Email\u5730\u5740**: wenjiaqi8255@outlook.com\n\n**\u63cf\u8ff0**: \n\u6b64n8n\u5de5\u4f5c\u6d41\u7a0b\u65e8\u5728\u81ea\u52a8\u5316\u5bfb\u627e\u548c\u63a8\u9001\u6700\u4f73\u804c\u4f4d\u63a8\u8350\u7684\u8fc7\u7a0b\u3002\u5b83\u4f1a\u83b7\u53d6\u60a8\u7684\u7b80\u5386\uff0c\u4eceLinkedIn\u548cIndeed\u6293\u53d6\u804c\u4f4d\u5217\u8868\uff0c\u4f7f\u7528AI\uff08Google Gemini\uff09\u5c06\u804c\u4f4d\u4e0e\u60a8\u7684\u7b80\u5386\u8fdb\u884c\u5339\u914d\uff0c\u7136\u540e\u901a\u8fc7\u7535\u5b50\u90ae\u4ef6\u53d1\u9001\u6700\u4f73\u804c\u4f4d\u63a8\u8350\u7ed9\u60a8\u3002\u8be5\u5de5\u4f5c\u6d41\u7a0b\u6309\u8ba1\u5212\u81ea\u52a8\u8fd0\u884c\u3002\n\n**\u6838\u5fc3\u529f\u80fd**:\n- \u7b80\u5386\u4e0e\u804c\u4f4d\u81ea\u52a8\u5339\u914d\n- \u4e2a\u6027\u5316\u6c42\u804c\u4fe1\u751f\u6210\n- \u5b9a\u65f6\u90ae\u4ef6\u63a8\u9001\u9ad8\u5339\u914d\u5ea6\u804c\u4f4d\n- Notion\u4e00\u4f53\u5316\u804c\u4f4d\u7ba1\u7406\n- \u591a\u5e73\u53f0\u804c\u4f4d\u6570\u636e\u6c47\u603b\uff08LinkedIn, Indeed\uff09\n\n**Credit**: Tianyi tianyi.datascience@gmail.com",
        "height": 820,
        "width": 640,
        "color": 5
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -2460,
        -600
      ],
      "id": "bcd6de88-108f-4743-875d-af3fd117ca4e",
      "name": "Sticky Note"
    },
    {
      "parameters": {
        "rule": {
          "interval": [
            {
              "triggerAtHour": 8
            }
          ]
        }
      },
      "type": "n8n-nodes-base.scheduleTrigger",
      "typeVersion": 1.2,
      "position": [
        -2380,
        580
      ],
      "id": "1eba2d78-167b-43d8-9260-5ebe1fa59016",
      "name": "Schedule Trigger"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "a08ebfd2-be88-4870-9f83-9430eda33d56",
              "name": "Resume",
              "value": "={{ $json.text }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -1040,
        580
      ],
      "id": "5dbb0ffa-7d5c-49ef-843e-32626bbd5f86",
      "name": "SetResumeField"
    },
    {
      "parameters": {
        "schemaType": "manual",
        "inputSchema": "{\n    \"database_id\": 1,\n    \"Company Name\": \"Innovatech Solutions\",\n    \"Job Title\": \"Senior Software Engineer\",\n    \"Industry\": \"Technology / SaaS\",\n    \"Reason for Match\": \"Strong alignment with your 7 years of backend development experience (Java/Spring) listed in CV and your preference for mid-sized tech companies.\",\n    \"Application URL\": \"https://linkedin.com/jobs/view/1234567890\",\n    \"Location\": \"San Francisco, CA\",\n    \"Flexibility\": \"Hybrid\",\n    \"Salary Range\": \"$120,000 - $150,000\"\n}"
      },
      "type": "@n8n/n8n-nodes-langchain.outputParserStructured",
      "typeVersion": 1.2,
      "position": [
        2960,
        680
      ],
      "id": "d2f5bddf-9623-44b1-85d3-9873935b3768",
      "name": "Structured Output Parser"
    },
    {
      "parameters": {
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.outputParserAutofixing",
      "typeVersion": 1,
      "position": [
        2740,
        460
      ],
      "id": "d5aefbc3-cbc1-4e80-b1e7-2adaa2b51c17",
      "name": "Auto-fixing Output Parser"
    },
    {
      "parameters": {
        "operation": "download",
        "fileId": {
          "__rl": true,
          "value": "1Sk87acRe343xHRCzjffoLmuq1oAaI1Zt",
          "mode": "list",
          "cachedResultName": "your_cv.pdf",
          "cachedResultUrl": "https://drive.google.com/file/d/your_cv.pdf/view?usp=sharing"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        -1500,
        580
      ],
      "id": "0b7b87e5-101d-472f-a709-19e3a33d43db",
      "name": "DownloadResume",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "pdf",
        "options": {}
      },
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1,
      "position": [
        -1280,
        580
      ],
      "id": "09873953-c590-48c9-8604-da1ab5736ae4",
      "name": "Extract Information from Resume PDF"
    },
    {
      "parameters": {
        "promptType": "=define",
        "text": "=You are an expert AI assistant specializing in career matching and job recommendation.\n\nYour Goal:\nYour primary task is to analyze a provided dataset of 100 LinkedIn job descriptions , a user's Curriculum Vitae (CV) provided as a string, and the user's job preferences is also provided as a string. Based on this analysis, you must identify and select the top 5 most suitable job opportunities for the user from the provided list.\n\nInputs You Will Receive:\n\njob_descriptions {{ $('stringify_json').item.json.stringified }}: A collection containing 100 job descriptions scraped from LinkedIn. Each job has the following structure:\n{\n  \"id\": [database ID],\n  \"company_name\": [company name],\n  \"job_title\": [job title],\n  \"industry\": [industry],\n  \"application_url\": [URL],\n  \"location\": [job location],\n  \"flexibility\": [work arrangement],\n  \"salary_range\": [salary if available],\n  \"created_at\": [timestamp]\n}\nuser_cv {{ $('SetResumeField').first().json.Resume }}: A single string containing the user's full CV text.\nuser_preferences {{ $('Input').first().json.Preference }}: A single string outlining the user's job preferences (e.g., desired roles, industries, company size, location constraints, salary expectations, work culture).\n\nYour Task Breakdown:\n\nAnalyze: Meticulously parse and understand the content of the user_cv and user_preferences.\nEvaluate: For each of the 100 job_descriptions:\nExtract key information: Company Name, Job Title, Industry (if explicitly mentioned or inferable), and Application URL.\nCompare the job's requirements, responsibilities, and company details against the user's skills, experience (from user_cv), and stated desires (from user_preferences).\nRank: Assess the suitability of each job for the user based on the comparison. Create a ranked list of all 100 jobs from most to least suitable.\nSelect: Choose the top {{ $('Input').first().json.RecommendedJobCount || 8 }} from your ranked list.\nFormat Output: Prepare the final output containing detailed information for only these 8 selected jobs.\n\nOutput Requirements:\n\nYou must return a structured list containing exactly 8 job recommendations. For each of the 8 jobs, provide the following specific details:\n\ndatabase_id: The \"id\" field from the job record.\nCompany Name: The name of the hiring company from \"company_name\".\nJob Title: The official title of the position from \"job_title\".\nIndustry: The industry sector from \"industry\" (if available).\nReason for Match: A brief (1-2 sentences) explanation justifying why this specific job is a strong match for the user. This explanation should explicitly reference alignment between the user's CV/preferences and the job description.\nApplication URL: The direct URL to apply from \"application_url\". If the apply URL is not found or empty, return the linkedin link for this job.\nLocation: The job location from \"location\".\nFlexibility: Work arrangement type from \"flexibility\".\nSalary Range: Salary information from \"salary_range\" if available, otherwise \"Not specified\".\n\nOutput format Example:\n[\n  {\n    \"database_id\": 1,\n    \"Company Name\": \"Innovatech Solutions\",\n    \"Job Title\": \"Senior Software Engineer\",\n    \"Industry\": \"Technology / SaaS\",\n    \"Reason for Match\": \"Strong alignment with your 7 years of backend development experience (Java/Spring) listed in CV and your preference for mid-sized tech companies.\",\n    \"Application URL\": \"https://linkedin.com/jobs/view/1234567890\",\n    \"Location\": \"San Francisco, CA\",\n    \"Flexibility\": \"Hybrid\",\n    \"Salary Range\": \"$120,000 - $150,000\"\n  },\n  {\n    \"database_id\": 2,\n    \"Company Name\": \"FinSecure Corp\",\n    \"Job Title\": \"Data Scientist\",\n    \"Industry\": \"Financial Services\",\n    \"Reason for Match\": \"Matches your PhD in Statistics, experience with machine learning models detailed in your CV, and stated interest in the Fintech sector.\",\n    \"Application URL\": \"https://linkedin.com/jobs/view/0987654321\",\n    \"Location\": \"New York, NY\",\n    \"Flexibility\": \"On-site\",\n    \"Salary Range\": \"$110,000 - $130,000\"\n  },\n  {\n    \"database_id\": 3,\n    \"Company Name\": \"Global Health Initiative\",\n    \"Job Title\": \"Biostatistician\",\n    \"Industry\": \"Healthcare / Research\",\n    \"Reason for Match\": \"Aligns with your strong statistical background and published research in healthcare outcomes mentioned in your CV.\",\n    \"Application URL\": \"https://linkedin.com/jobs/view/5678901234\",\n    \"Location\": \"Boston, MA\",\n    \"Flexibility\": \"Hybrid\",\n    \"Salary Range\": \"Not specified\"\n  },\n  {\n    \"database_id\": 4,\n    \"Company Name\": \"EcoSolutions\",\n    \"Job Title\": \"Sustainability Analyst\",\n    \"Industry\": \"Environmental Services\",\n    \"Reason for Match\": \"Matches your environmental science background and stated preference for working in sustainability-focused organizations.\",\n    \"Application URL\": \"https://linkedin.com/jobs/view/2345678901\",\n    \"Location\": \"Portland, OR\",\n    \"Flexibility\": \"Remote\",\n    \"Salary Range\": \"$85,000 - $95,000\"\n  },\n  {\n    \"database_id\": 5,\n    \"Company Name\": \"TechStart Accelerator\",\n    \"Job Title\": \"Technology Consultant\",\n    \"Industry\": \"Consulting\",\n    \"Reason for Match\": \"Aligns with your technical advisory experience and preference for varied project work mentioned in your preferences.\",\n    \"Application URL\": \"https://linkedin.com/jobs/view/3456789012\",\n    \"Location\": \"Austin, TX\",\n    \"Flexibility\": \"Hybrid\",\n    \"Salary Range\": \"$100,000 - $120,000\"\n  },\n  {\n    \"database_id\": 6,\n    \"Company Name\": \"TechStart Accelerator\",\n    \"Job Title\": \"Technology Consultant\",\n    \"Industry\": \"Consulting\",\n    \"Reason for Match\": \"Aligns with your technical advisory experience and preference for varied project work mentioned in your preferences.\",\n    \"Application URL\": \"https://linkedin.com/jobs/view/3456789012\",\n    \"Location\": \"Austin, TX\",\n    \"Flexibility\": \"Hybrid\",\n    \"Salary Range\": \"$100,000 - $120,000\"\n  },\n  {\n    \"database_id\": 7,\n    \"Company Name\": \"TechStart Accelerator\",\n    \"Job Title\": \"Technology Consultant\",\n    \"Industry\": \"Consulting\",\n    \"Reason for Match\": \"Aligns with your technical advisory experience and preference for varied project work mentioned in your preferences.\",\n    \"Application URL\": \"https://linkedin.com/jobs/view/3456789012\",\n    \"Location\": \"Austin, TX\",\n    \"Flexibility\": \"Hybrid\",\n    \"Salary Range\": \"$100,000 - $120,000\"\n  },\n  {\n    \"database_id\": 8,\n    \"Company Name\": \"TechStart Accelerator\",\n    \"Job Title\": \"Technology Consultant\",\n    \"Industry\": \"Consulting\",\n    \"Reason for Match\": \"Aligns with your technical advisory experience and preference for varied project work mentioned in your preferences.\",\n    \"Application URL\": \"https://linkedin.com/jobs/view/3456789012\",\n    \"Location\": \"Austin, TX\",\n    \"Flexibility\": \"Hybrid\",\n    \"Salary Range\": \"$100,000 - $120,000\"\n  }\n]",
        "hasOutputParser": true,
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 1.8,
      "position": [
        2620,
        220
      ],
      "id": "c76cea73-18b0-42fa-a3ab-550a4e2bfc5d",
      "name": "AI Agent: Find Best-matched jobs",
      "retryOnFail": true,
      "executeOnce": true
    },
    {
      "parameters": {
        "sendTo": "={{ $('Input').first().json.EmailAddressToReceiveJobRecommendations}}",
        "subject": "=Best-Matched Jobs - {{ $now.format('yyyy-MM-dd') }} ",
        "message": "={{$input.item.json.html}}",
        "options": {}
      },
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        4040,
        560
      ],
      "id": "040a2699-d850-4238-8b3b-00a7f2e5ce75",
      "name": "Email the top job recommendations",
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "content": "### Schedule Trigger\n\u6b64\u8282\u70b9\u89e6\u53d1\u5de5\u4f5c\u6d41\u7a0b\u6309\u6307\u5b9a\u65f6\u95f4\u81ea\u52a8\u8fd0\u884c\u3002\u9ed8\u8ba4\u8bbe\u7f6e\u4e3a\u6bcf\u5929\u65e9\u4e0a8:00\u89e6\u53d1\uff0c\u60a8\u53ef\u4ee5\u6839\u636e\u9700\u6c42\u8c03\u6574\u65f6\u95f4\u9891\u7387\u3002\n\u6ce8\uff1a\u5728n8n Settings\u91cc\u53ef\u8bbe\u7f6e\u65f6\u533a",
        "height": 640,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -2460,
        280
      ],
      "id": "4258d07a-938b-4a6b-ac7f-2bbc0d070d6c",
      "name": "Sticky Note1"
    },
    {
      "parameters": {
        "content": "### Input\n**\u5173\u952e\u914d\u7f6e\u8282\u70b9**\n\u8fd9\u91cc\u8bbe\u7f6e\u4e86\u6574\u4e2a\u5de5\u4f5c\u6d41\u7a0b\u4e2d\u4f7f\u7528\u7684\u91cd\u8981\u53d8\u91cf\uff1a\n- **ApifyAPIKey**: \u7528\u4e8e\u8bbf\u95eeApify\u670d\u52a1\u7684API\u5bc6\u94a5\n- **Preference**: \u60a8\u7684\u6c42\u804c\u504f\u597d\uff0c\u5f71\u54cdAI\u5339\u914d\u7ed3\u679c\n- **EmailAddressToReceiveJobRecommendations**: \u63a5\u6536\u804c\u4f4d\u63a8\u8350\u7684\u90ae\u7bb1\n- **recommendedJobCount**: \u6bcf\u6b21\u63a8\u8350\u7684\u804c\u4f4d\u6570\u91cf\n- **first_timeout**: \u9996\u6b21API\u8bf7\u6c42\u8d85\u65f6\u65f6\u95f4\uff08\u79d2\uff09\n- **request_interval**: \u91cd\u8bd5\u8bf7\u6c42\u95f4\u9694\u65f6\u95f4\uff08\u79d2\uff09",
        "height": 640,
        "width": 500,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -2160,
        280
      ],
      "id": "b1622b06-9a1b-4e68-8947-4df119793d9b",
      "name": "Sticky Note2"
    },
    {
      "parameters": {
        "content": "### DownloadResume\n\u4eceGoogle Drive\u4e0b\u8f7d\u60a8\u7684\u7b80\u5386PDF\u6587\u4ef6\u3002\u8bf7\u786e\u4fdd\u4e0a\u4f20\u60a8\u7684\u7b80\u5386\u5230Google Drive\u5e76\u83b7\u53d6\u6587\u4ef6ID\u3002\n\n### Extract Information from Resume PDF\n\u63d0\u53d6\u7b80\u5386PDF\u4e2d\u7684\u6587\u672c\u5185\u5bb9\uff0c\u4e3a\u540e\u7eedAI\u5339\u914d\u505a\u51c6\u5907\u3002\n\n### SetResumeField\n\u5c06\u63d0\u53d6\u7684\u7b80\u5386\u6587\u672c\u8bbe\u7f6e\u4e3a\u53d8\u91cf\uff0c\u4ee5\u4fbf\u5728\u5de5\u4f5c\u6d41\u7a0b\u7684\u540e\u7eed\u6b65\u9aa4\u4e2d\u4f7f\u7528\u3002",
        "height": 640,
        "width": 740
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1600,
        280
      ],
      "id": "08001c75-b495-4ad1-bc8b-f8cd8875dbf1",
      "name": "Sticky Note3"
    },
    {
      "parameters": {
        "content": "### start_apify_run_linkedin\n\u542f\u52a8Apify\u722c\u866b\uff0c\u6293\u53d6LinkedIn\u4e0a\u7684\u804c\u4f4d\u4fe1\u606f\u3002\n\u786e\u4fdd\u5728jsonBody\u4e2d\u8bbe\u7f6e\u6b63\u786e\u7684\u641c\u7d22URL\u548c\u53c2\u6570\u3002\n\n### Check Run Status / Get Dataset Items\n\u8fd9\u4e9b\u8282\u70b9\u68c0\u67e5\u722c\u866b\u8fd0\u884c\u72b6\u6001\u5e76\u83b7\u53d6\u7ed3\u679c\u6570\u636e\u3002\n\u5305\u542b\u9519\u8bef\u5904\u7406\u548c\u91cd\u8bd5\u673a\u5236\uff0c\u786e\u4fdd\u53ef\u9760\u83b7\u53d6\u804c\u4f4d\u4fe1\u606f\u3002\n",
        "height": 640,
        "width": 1280,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -800,
        280
      ],
      "id": "27bf44a1-cbb7-4c10-b991-ca1b67582d25",
      "name": "Sticky Note6"
    },
    {
      "parameters": {
        "content": "\n### Merge\n\u5408\u5e76\u6765\u81eaLinkedIn\u548cIndeed\u7684\u804c\u4f4d\u6570\u636e\uff0c\u521b\u5efa\u7edf\u4e00\u7684\u804c\u4f4d\u5217\u8868\u3002",
        "height": 640,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        840,
        280
      ],
      "id": "5c9525bd-3d5c-422e-b432-df6a5365f24b",
      "name": "Sticky Note7"
    },
    {
      "parameters": {
        "content": "### AI Agent: Find Best-matched jobs\n**\u6838\u5fc3\u5339\u914d\u8282\u70b9**\n\n**\u8f93\u5165**:\n- **scraped_job_data**: \u4eceLinkedIn\u548cIndeed\u6293\u53d6\u7684\u6240\u6709\u804c\u4f4d\u4fe1\u606f\n- **user_cv**: \u7528\u6237\u7b80\u5386\u6587\u672c\uff08\u4ecePDF\u63d0\u53d6\uff09\n- **user_preferences**: \u7528\u6237\u7684\u6c42\u804c\u504f\u597d\u8bbe\u7f6e\uff08\u5982\u5730\u70b9\u3001\u884c\u4e1a\u3001\u85aa\u8d44\u671f\u671b\u7b49\uff09\n- **recommendedJobCount**: \u9700\u8981\u5339\u914d\u7684\u804c\u4f4d\u6570\u91cf\n\n**\u8f93\u51fa**:\n\u7ed3\u6784\u5316\u5217\u8868\uff0c\u5305\u542b\u63a8\u8350\u804c\u4f4d\u7684\u8be6\u7ec6\u4fe1\u606f\uff1a\n- **database_id**: \u804c\u4f4d\u8bb0\u5f55ID\n- **Company Name**: \u62db\u8058\u516c\u53f8\u540d\u79f0\n- **Job Title**: \u804c\u4f4d\u540d\u79f0\n- **Industry**: \u884c\u4e1a\u9886\u57df\n- **Reason for Match**: \u5339\u914d\u539f\u56e0\u8bf4\u660e\uff081-2\u53e5\u8bdd\u8bf4\u660e\u4e3a\u4f55\u6b64\u804c\u4f4d\u4e0e\u7528\u6237\u5339\u914d\uff09\n- **Application URL**: \u7533\u8bf7\u94fe\u63a5\n- **Location**: \u5de5\u4f5c\u5730\u70b9\n- **Flexibility**: \u5de5\u4f5c\u5b89\u6392\u65b9\u5f0f\uff08\u8fdc\u7a0b\u3001\u6df7\u5408\u3001\u73b0\u573a\u7b49\uff09\n- **Salary Range**: \u85aa\u8d44\u8303\u56f4\uff08\u5982\u6709\uff09",
        "height": 1200,
        "width": 580,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        2500,
        -280
      ],
      "id": "8a4d335c-a196-4333-8fa9-9e8281f77a8a",
      "name": "Sticky Note9"
    },
    {
      "parameters": {
        "content": "### Email the top job recommendations\n\u5c06\u6700\u4f73\u5339\u914d\u7684\u804c\u4f4d\u901a\u8fc7\u7535\u5b50\u90ae\u4ef6\u53d1\u9001\u7ed9\u60a8\uff0c\u90ae\u4ef6\u5305\u542b\u804c\u4f4d\u6807\u9898\u3001\u516c\u53f8\u3001\u5730\u70b9\u3001\u85aa\u8d44\u548c\u7533\u8bf7\u94fe\u63a5\u7b49\u4fe1\u606f\u3002",
        "height": 620,
        "color": 2
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        3980,
        300
      ],
      "id": "04c1ad11-ce69-4cbc-b8dc-facda79487e2",
      "name": "Sticky Note10"
    },
    {
      "parameters": {
        "content": "## \u5de5\u4f5c\u6d41\u7a0b\u8bbe\u7f6e\u6307\u5357\n### \u8bf7\u6309\u7167\u4ee5\u4e0b\u6b65\u9aa4\u8bbe\u7f6e\u5de5\u4f5c\u6d41\u7a0b\uff1a\n\n### 1. \u914d\u7f6e\u8f93\u5165\u8282\u70b9\uff1a\n\u6253\u5f00\u5de5\u4f5c\u6d41\u4e2d\u7684\"Input\"\u8282\u70b9\u3002\n\u586b\u5199\u5fc5\u586b\u5b57\u6bb5\uff1a\n- **ApifyAPIKey**: \u8f93\u5165\u60a8\u7684Apify API\u5bc6\u94a5\uff08\u767b\u5f55Apify: https://www.apify.com?fpr=oljm1 -> \u8bbe\u7f6e -> API & Integration\uff09\n- **Preference**: \u6307\u5b9a\u60a8\u7684\u6c42\u804c\u504f\u597d\uff08\u5982\"\u65e0\u5fb7\u8bed\u8981\u6c42\uff0c\u9ad8\u85aa\"\uff09\n- **EmailAddressToReceiveJobRecommendations**: \u63d0\u4f9b\u60a8\u5e0c\u671b\u63a5\u6536\u804c\u4f4d\u63a8\u8350\u7684\u7535\u5b50\u90ae\u4ef6\u5730\u5740\n- **recommendedJobCount**: \u8bbe\u7f6e\u6bcf\u6b21\u63a8\u8350\u7684\u804c\u4f4d\u6570\u91cf\uff08\u9ed8\u8ba4\u4e3a10\uff09\n\n### 2. \u914d\u7f6eLinkedIn\u804c\u4f4d\u641c\u7d22URL\uff1a\n\n- \u5728\u6d4f\u89c8\u5668\u7684\u9690\u79c1/\u65e0\u75d5\u7a97\u53e3\u4e2d\u6253\u5f00LinkedIn Jobs\u641c\u7d22\u9875\u9762\uff1ahttps://www.linkedin.com/jobs/search/\n- \u4f7f\u7528LinkedIn\u641c\u7d22\u754c\u9762\u8bbe\u7f6e\u60a8\u9700\u8981\u7684\u7b5b\u9009\u6761\u4ef6\uff08\u5173\u952e\u8bcd\u3001\u5730\u70b9\u3001\u7ecf\u9a8c\u6c34\u5e73\u7b49\uff09\u3002**\u52a1\u5fc5\u6dfb\u52a0\"\u8fc7\u53bb24\u5c0f\u65f6\"\u7b5b\u9009\u6761\u4ef6**\n- \u590d\u5236\u6d4f\u89c8\u5668\u5730\u5740\u680f\u4e2d\u7684\u5b8c\u6574URL\n- \u6253\u5f00\u5de5\u4f5c\u6d41\u4e2d\u7684\"start_apify_run_linkedin\"\u8282\u70b9\n- \u5728\"jsonBody\"\u53c2\u6570\u4e2d\u627e\u5230\"urls\"\u6570\u7ec4\uff1a\n  ```json\n  \"urls\": [\n      \"https://www.linkedin.com/jobs/search/...\"\n  ]\n\n\u5c06\u73b0\u6709URL\uff08\"https://www.linkedin.com/jobs/search/...\"\uff09\u66ff\u6362\u4e3a\u60a8\u4ece\u9690\u79c1\u7a97\u53e3\u590d\u5236\u7684\u5b8c\u6574URL\u3002\u786e\u4fddURL\u7528\u53cc\u5f15\u53f7\u62ec\u8d77\u6765\n\n3. \u914d\u7f6eIndeed\u804c\u4f4d\u641c\u7d22\uff08\u53ef\u9009\uff09\uff1a\n\n\u7c7b\u4f3c\u5730\uff0c\u53ef\u4ee5\u5728\"start_apify_run_indeed\"\u8282\u70b9\u4e2d\u914d\u7f6eIndeed\u641c\u7d22\u53c2\u6570\n\u81ea\u5b9a\u4e49\u641c\u7d22\u5173\u952e\u8bcd\u3001\u5730\u70b9\u548c\u5176\u4ed6\u53c2\u6570\u4ee5\u7b26\u5408\u60a8\u7684\u6c42\u804c\u9700\u6c42\n\n4. \u4e0a\u4f20\u60a8\u7684\u7b80\u5386\uff1a\n\n\u5c06\u60a8\u7684\u7b80\u5386\uff08PDF\u683c\u5f0f\uff09\u4e0a\u4f20\u5230Google Drive\n\u5728\"DownloadResume\"\u8282\u70b9\u4e2d\u66f4\u65b0\u6587\u4ef6ID\u4ee5\u6307\u5411\u60a8\u7684\u7b80\u5386\n\n",
        "height": 820,
        "width": 900,
        "color": 5
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1760,
        -600
      ],
      "id": "831b9298-2b78-49db-83a0-4eaf7dcee63d",
      "name": "Sticky Note11"
    },
    {
      "parameters": {
        "modelName": "models/gemini-2.0-flash",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1,
      "position": [
        2600,
        420
      ],
      "id": "d83824f0-9c3d-4bd6-a448-eb8fa552b074",
      "name": "Google Gemini Chat Model",
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "modelName": "models/gemini-2.0-flash",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1,
      "position": [
        2700,
        660
      ],
      "id": "e6a594bb-5cb2-497c-a799-b37ac8c9a243",
      "name": "Google Gemini Chat Model1",
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "tableId": "job_listings",
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "company_name",
              "fieldValue": "={{ $json.company_name }}"
            },
            {
              "fieldId": "job_title",
              "fieldValue": "={{ $json.job_title }}"
            },
            {
              "fieldId": "industry",
              "fieldValue": "={{ $json.industry }}"
            },
            {
              "fieldId": "application_url",
              "fieldValue": "={{ $json.application_url }}"
            },
            {
              "fieldId": "location",
              "fieldValue": "={{ $json.location }}"
            },
            {
              "fieldId": "flexibility",
              "fieldValue": "={{ $json.flexibility }}"
            },
            {
              "fieldId": "salary_range",
              "fieldValue": "={{ $json.salary_range }}"
            },
            {
              "fieldId": "id",
              "fieldValue": "={{ $json.id }}"
            },
            {
              "fieldId": "description",
              "fieldValue": "={{ $json.description.substring(0,4000) }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        1860,
        440
      ],
      "id": "698fcc9b-0a64-4f8c-b0f4-9f2c2b0f48f3",
      "name": "Supabase",
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "path": "2f32a889-c6d8-4dda-a550-71d963063aa7",
        "options": {}
      },
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [
        -2900,
        2220
      ],
      "id": "d9951f93-3343-4622-be8f-27aa22489dd7",
      "name": "Webhook"
    },
    {
      "parameters": {
        "operation": "download",
        "fileId": {
          "__rl": true,
          "value": "1BFLqG74itZyelxhdJrAjgHTGAJNiECeR",
          "mode": "list",
          "cachedResultName": "your_cv.pdf",
          "cachedResultUrl": "https://drive.google.com/file/d/your_cv.pdf/view?usp=sharing"
        },
        "options": {}
      },
      "type": "n8n-nodes-base.googleDrive",
      "typeVersion": 3,
      "position": [
        -1500,
        2220
      ],
      "id": "288968e3-8d8f-49ba-95d1-c8ced682d0b5",
      "name": "DownloadResume1",
      "credentials": {
        "googleDriveOAuth2Api": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "operation": "get",
        "tableId": "job_listings",
        "filters": {
          "conditions": [
            {
              "keyName": "id",
              "keyValue": "={{ $('get_job_id').item.json.jobId }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        -2160,
        2220
      ],
      "id": "09770e2e-d7d5-4556-91f9-0eeb5d52e7d1",
      "name": "Supabase_get",
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// \u4eceWebhook\u8c03\u7528\u4e2d\u63d0\u53d6jobId\u53c2\u6570\nconst jobId = $('Webhook').first().json?.query?.jobId;\n\nif (!jobId) {\n  return {\n    json: {\n      success: false,\n      message: \"Missing job ID parameter. Please provide a jobId query parameter.\"\n    }\n  };\n}\n\nreturn {\n  json: {\n    success: true,\n    jobId: jobId\n  }\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -2320,
        2220
      ],
      "id": "7a0b34f3-df6b-4dd9-a13a-810171ef9536",
      "name": "get_job_id"
    },
    {
      "parameters": {
        "promptType": "define",
        "text": "=# Cover Letter Assistant\n\nYou are a professional cover letter consultant who creates authentic, targeted, and personalized cover letters. Your task is to create an effective cover letter based on a job description and resume.\n\n## Basic Information\n\nPosition: {{ $('Supabase_get').item.json.job_title }}\nCompany: {{ $('Supabase_get').item.json.company_name }}\nIndustry: {{ $('Supabase_get').item.json.industry }}\nLocation: {{ $('Supabase_get').item.json.location }}\n\nJob Description: {{ $('Supabase_get').item.json.description }}\nResume Content: {{ $json.text }}\n\n## Cover Letter Guidelines\n\n### Core Principles\n\n1. **Company-needs focused**: Start with \"how my skills solve this company's specific problems\" rather than simply listing personal achievements\n2. **Concise and direct**: Use clear, short sentences; avoid complex structures and decorative vocabulary\n3. **Authentic personality**: Show the applicant's genuine work style and personality, avoid clich\u00e9s\n4. **Targeted approach**: Address key requirements from the job description directly, not vaguely\n5. **Quality over quantity**: Prefer a few powerful examples rather than many vague accomplishments\n\n### Structure Suggestions\n\n**Opening paragraph**:\n- Briefly express why you're interested in this position\n- Mention a specific company project, value, or challenge, showing your research\n- Keep within 2-3 short sentences\n\n**Skills matching paragraphs**:\n- Focus each paragraph on one core skill or company need\n- State the company's need first, then introduce your relevant experience\n- Provide 1-2 specific examples, using data only when actually supported\n- Keep each paragraph to 3-4 short sentences\n\n**Unique value paragraph**:\n- Include a paragraph showcasing your unique advantage\n- This could be a relevant side project, special skill, or personal work approach\n- Show how this unique value benefits the company\n\n**Closing paragraph**:\n- Simply express your interest in further discussion\n- Consider mentioning your personal website or portfolio\n- Keep it brief, 2-3 sentences is enough\n\n### Language Style Guide\n\n- Use active language, avoid passive voice\n- Avoid clich\u00e9s like \"I am excited to apply...\" or \"I believe I am the best candidate...\"\n- Adjust tone for company culture: technical companies use precise terminology, creative companies emphasize innovative thinking, etc.\n- Use natural, conversational language, as if talking with the hiring manager\n\n### Common Mistakes to Avoid\n\n- Overusing industry jargon and abbreviations\n- Long paragraphs and complex sentences\n- Data claims without supporting context\n- Vague achievement descriptions\n- Too much focus on \"what I did\" rather than \"what I can do for you\"\n\n## Final Check\n\nBefore finalizing, ensure the cover letter:\n- Totals 300-400 words (not exceeding one page)\n- Uses no templated expressions or business clich\u00e9s\n- Addresses all key requirements from the job description\n- Has a clear focus and natural transitions in each paragraph\n- Shows the applicant's personality and work style\n- Is oriented toward solving company problems\n\nPlease create a cover letter following these guidelines, keeping it authentic, concise, and targeted.",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.agent",
      "typeVersion": 1.9,
      "position": [
        -1040,
        2220
      ],
      "id": "ff220f55-7235-4360-b23b-aaf6b766a433",
      "name": "AI Agent"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "9ba8a38a-17fc-4b4a-8a4e-6981b92cbee4",
              "name": "ApifyAPIKey",
              "value": "apify_api_your_api_key",
              "type": "string"
            },
            {
              "id": "a08ebfd2-be88-4870-9f83-9430eda33d56",
              "name": "Preference",
              "value": "=no German proficiency requirement, high pay",
              "type": "string"
            },
            {
              "id": "82b79f4d-43b9-4a36-80df-0d4ca51ab5e5",
              "name": "EmailAddressToReceiveJobRecommendations",
              "value": "your@email.com",
              "type": "string"
            },
            {
              "id": "3ee98ee6-7c9f-4f2c-afe7-12bb4d53c7c2",
              "name": "recommendedJobCount",
              "value": 10,
              "type": "number"
            },
            {
              "id": "b4c797c5-da56-47e1-84c1-ce64ea9b508e",
              "name": "first_timeout",
              "value": 60,
              "type": "number"
            },
            {
              "id": "8e16b176-2cd3-448a-a859-6570cacda1f0",
              "name": "request_interval",
              "value": 30,
              "type": "number"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -1980,
        580
      ],
      "id": "f9734f5e-1ea9-4407-84b4-3ab299e87b3a",
      "name": "Input"
    },
    {
      "parameters": {
        "sendTo": "={{ $('Input1').first().json.EmailAddressToReceiveCoverLetter}}",
        "subject": "Cover Letter",
        "message": "={{ $json.data }}",
        "options": {}
      },
      "type": "n8n-nodes-base.gmail",
      "typeVersion": 2.1,
      "position": [
        -60,
        2220
      ],
      "id": "ad6411f2-2608-4f7f-9efe-3b6656710d0d",
      "name": "Gmail",
      "credentials": {
        "gmailOAuth2": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "mode": "markdownToHtml",
        "markdown": "={{ $('AI Agent').item.json.output }}",
        "options": {}
      },
      "type": "n8n-nodes-base.markdown",
      "typeVersion": 1,
      "position": [
        -260,
        2220
      ],
      "id": "30683ac7-89bd-4df4-9071-593ee43d4e1f",
      "name": "Markdown"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "97e6b24a-a185-4e8e-9767-b0fe88264885",
              "name": "stringified",
              "value": "={{ JSON.stringify($json) }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        2320,
        580
      ],
      "id": "a3930751-dacb-4c9d-89be-b2fc42590513",
      "name": "stringify_json"
    },
    {
      "parameters": {
        "operation": "pdf",
        "options": {}
      },
      "type": "n8n-nodes-base.extractFromFile",
      "typeVersion": 1,
      "position": [
        -1320,
        2220
      ],
      "id": "899a0ede-0749-4e88-9539-8fb4d9a5fa95",
      "name": "Extract Information from Resume PDF1"
    },
    {
      "parameters": {
        "operation": "getAll",
        "tableId": "job_listings",
        "returnAll": true
      },
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        1220,
        580
      ],
      "id": "0b09f2ef-e1f2-4535-9e35-be43e37651e2",
      "name": "Supabase1",
      "executeOnce": true,
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// \u83b7\u53d6AI Agent\u7684\u8f93\u51fa\u6587\u672c\nconst fullText = $('set_cover_letter').first().json.output;\n\n// \u6309\u81ea\u7136\u6bb5\u843d\u5206\u5272\u6587\u672c\nconst paragraphs = fullText.split(\"\\n\\n\");\n\n// \u63d0\u53d6\u7b2c\u4e00\u6bb5\u4f5c\u4e3a\u6807\u9898\uff08\u53ef\u9009\uff09\nconst title = paragraphs[0].trim();\n\n// \u521b\u5efa\u5757\u5185\u5bb9\nconst blocks = [];\n\nparagraphs.forEach((paragraph, index) => {\n  if (paragraph.trim().length > 0) {\n    // \u786e\u4fdd\u6bb5\u843d\u4e0d\u8d85\u8fc72000\u5b57\u7b26\n    if (paragraph.length > 2000) {\n      // \u5982\u679c\u8d85\u8fc7\uff0c\u8fdb\u4e00\u6b65\u5206\u5272\n      let startIdx = 0;\n      while (startIdx < paragraph.length) {\n        const chunk = paragraph.substring(startIdx, Math.min(startIdx + 1900, paragraph.length));\n        blocks.push({\n          \"type\": \"paragraph\",\n          \"paragraph\": {\n            \"rich_text\": [{\n              \"type\": \"text\",\n              \"text\": {\n                \"content\": chunk\n              }\n            }]\n          }\n        });\n        startIdx += 1900;\n      }\n    } else {\n      // \u5982\u679c\u6bb5\u843d\u957f\u5ea6\u5408\u9002\uff0c\u76f4\u63a5\u6dfb\u52a0\n      blocks.push({\n        \"type\": \"paragraph\",\n        \"paragraph\": {\n          \"rich_text\": [{\n            \"type\": \"text\",\n            \"text\": {\n              \"content\": paragraph\n            }\n          }]\n        }\n      });\n    }\n  }\n});\n\n// \u8fd4\u56de\u7ed3\u679c\uff0c\u5305\u542b\u6807\u9898\u548c\u5757\nreturn {\n  json: {\n    title: title,\n    blocks: blocks\n  }\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        -440,
        2220
      ],
      "id": "0d98d61f-bd18-4022-beba-49d7e4b9ebd3",
      "name": "parse_to_markdown"
    },
    {
      "parameters": {
        "jsCode": "// \u83b7\u53d6AI Agent\u7684\u8f93\u51fa\u6587\u672c\nconst fullText = $('set_cover_letter').first().json.output;\n\n// \u6309\u81ea\u7136\u6bb5\u843d\u5206\u5272\u6587\u672c\nconst paragraphs = fullText.split(\"\\n\\n\");\n\n// \u521b\u5efa\u591a\u4e2a\u8f93\u51fa\u9879\uff0c\u6bcf\u9879\u5bf9\u5e94\u4e00\u4e2aNotion\u6bb5\u843d\nconst returnItems = [];\n\nparagraphs.forEach((paragraph, index) => {\n  if (paragraph.trim().length > 0) {\n    // \u786e\u4fdd\u6bb5\u843d\u4e0d\u8d85\u8fc72000\u5b57\u7b26\n    if (paragraph.length > 2000) {\n      // \u5982\u679c\u8d85\u8fc7\uff0c\u8fdb\u4e00\u6b65\u5206\u5272\n      let startIdx = 0;\n      while (startIdx < paragraph.length) {\n        const chunk = paragraph.substring(startIdx, Math.min(startIdx + 1900, paragraph.length));\n        returnItems.push({\n          json: {\n            index: returnItems.length,\n            content: chunk,\n            type: \"paragraph\"\n          }\n        });\n        startIdx += 1900;\n      }\n    } else {\n      // \u5982\u679c\u6bb5\u843d\u957f\u5ea6\u5408\u9002\uff0c\u76f4\u63a5\u6dfb\u52a0\n      returnItems.push({\n        json: {\n          index: index,\n          content: paragraph,\n          type: \"paragraph\"\n        }\n      });\n    }\n  }\n});\n\nreturn returnItems;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        220,
        2220
      ],
      "id": "9506bc44-cd63-4036-9117-b90f3c0ae659",
      "name": "parse_to_paragraphs"
    },
    {
      "parameters": {
        "jsCode": "return $('parse_to_paragraphs').all().map(item => ({\n  json: {\n    content: item.json.content,\n    type: item.json.type,\n    index: item.json.index\n  }\n}))"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        580,
        2220
      ],
      "id": "9aa6a16e-eb1b-4f0c-80fa-4ddd2901e59e",
      "name": "return_all_items"
    },
    {
      "parameters": {
        "resource": "block",
        "blockId": {
          "__rl": true,
          "value": "={{ $('create_new_cover_letter').item.json.id }}",
          "mode": "id"
        },
        "blockUi": {
          "blockValues": [
            {
              "textContent": "={{ $json.content }}"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.notion",
      "typeVersion": 2.2,
      "position": [
        760,
        2220
      ],
      "id": "2c177160-fb3d-461d-9692-f336edf9b504",
      "name": "append_blocks",
      "executeOnce": false,
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "value": "1ed2e9a3-326a-8177-8956-c0b5c8378bd9",
          "mode": "list",
          "cachedResultName": "Job Tracker",
          "cachedResultUrl": "https://www.notion.so/1ed2e9a3326a81778956c0b5c8378bd9"
        },
        "title": "={{ $json.company_name }}",
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Application URL|url",
              "urlValue": "={{ $json.application_url }}"
            },
            {
              "key": "Flexibility|multi_select",
              "multiSelectValue": "={{ $json.flexibility }}"
            },
            {
              "key": "Industry|rich_text",
              "textContent": "={{ $json.industry }}"
            },
            {
              "key": "Salary Range|rich_text",
              "textContent": "={{ $json.salary_range }}"
            },
            {
              "key": "Status|select",
              "selectValue": "Applied"
            },
            {
              "key": "Location|rich_text",
              "textContent": "={{ $json.location }}"
            },
            {
              "key": "Job Title|rich_text",
              "textContent": "={{ $json.job_title }}"
            }
          ]
        },
        "blockUi": {
          "blockValues": [
            {
              "textContent": "={{ $json.description.substring(0,1998) }}"
            },
            {
              "textContent": "=created at {{ $json.created_at }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.notion",
      "typeVersion": 2.2,
      "position": [
        -1900,
        2220
      ],
      "id": "bb4a25b8-f2f5-477d-af13-2b56de8b04d6",
      "name": "create_new_job_listing",
      "executeOnce": true,
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "resource": "databasePage",
        "databaseId": {
          "__rl": true,
          "value": "1ed2e9a3-326a-809c-8508-f4faad3a019c",
          "mode": "list",
          "cachedResultName": "Cover Letter",
          "cachedResultUrl": "https://www.notion.so/1ed2e9a3326a809c8508f4faad3a019c"
        },
        "title": "=Jiaqi_Wen_ {{ $now.format('yyyy-MM-dd HH:MM') }}",
        "propertiesUi": {
          "propertyValues": [
            {
              "key": "Company Name|title",
              "title": "={{ $('create_new_job_listing').item.json.property_company_name }}"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.notion",
      "typeVersion": 2.2,
      "position": [
        400,
        2220
      ],
      "id": "39db0f2b-6270-43a8-93d8-3dc582ff50cf",
      "name": "create_new_cover_letter",
      "executeOnce": true,
      "credentials": {
        "notionApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "7385ee1c-5a5e-4576-b311-c6fd3f678a8b",
              "name": "property_company_name",
              "value": "={{ $json.property_company_name }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -1660,
        2220
      ],
      "id": "0cbfcbe5-8579-46be-b855-a5c60bed2636",
      "name": "set_company_name"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "12c45e38-79d5-49d1-92ed-8e1aee3081b6",
              "name": "output",
              "value": "={{ $json.output }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -700,
        2220
      ],
      "id": "5a01466f-ad94-4471-9937-c18289e1b228",
      "name": "set_cover_letter"
    },
    {
      "parameters": {
        "jsCode": "// \u4ece Supabase \u67e5\u8be2\u7ed3\u679c\u4e2d\u63d0\u53d6\u5df2\u5b58\u5728\u7684\u804c\u4f4d ID\n// \u786e\u4fdd\u6240\u6709 ID \u90fd\u8f6c\u6362\u4e3a\u76f8\u540c\u7684\u7c7b\u578b\uff08\u5b57\u7b26\u4e32\uff09\nconst existingJobIds = $('Supabase1').all().map(item => String(item.json.id));\nconsole.log(`\u6570\u636e\u5e93\u4e2d\u5df2\u6709 ${existingJobIds.length} \u4e2a\u804c\u4f4d ID`);\n// \u83b7\u53d6\u65b0\u6293\u53d6\u7684\u804c\u4f4d\u6570\u636e\nconst newJobs = $('Merge').all();\nconsole.log(`\u65b0\u6293\u53d6\u7684\u804c\u4f4d\u6570\u91cf: ${newJobs.length} \u4e2a`);\n// \u8fc7\u6ee4\u6389\u5df2\u5b58\u5728\u7684\u804c\u4f4d - \u540c\u6837\u786e\u4fdd ID \u8f6c\u6362\u4e3a\u76f8\u540c\u7c7b\u578b\u8fdb\u884c\u6bd4\u8f83\nconst uniqueJobs = newJobs.filter(job => !existingJobIds.includes(String(job.json.id)));\nconsole.log(`\u8fc7\u6ee4\u540e\u7684\u4e0d\u91cd\u590d\u804c\u4f4d\u6570\u91cf: ${uniqueJobs.length} \u4e2a`);\n// \u5728 return \u524d\u518d\u6b21\u8fc7\u6ee4 uniqueJobs \u6570\u7ec4\u4e2d\u7684\u91cd\u590d\u503c\nconst finalUniqueJobs = uniqueJobs.filter((job, index, self) => \n  index === self.findIndex(j => String(j.json.id) === String(job.json.id))\n);\nconsole.log(`\u6700\u7ec8\u53bb\u91cd\u540e\u7684\u804c\u4f4d\u6570\u91cf: ${finalUniqueJobs.length} \u4e2a`);\n// \u8fd4\u56de\u4e0d\u91cd\u590d\u7684\u804c\u4f4d\u6570\u636e\nreturn finalUniqueJobs;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1640,
        580
      ],
      "id": "a1c6bea1-932d-4381-a8f8-7c3a0a0eadf7",
      "name": "get_unique_jobs"
    },
    {
      "parameters": {
        "modelName": "models/gemini-2.0-flash-lite-001",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini",
      "typeVersion": 1,
      "position": [
        -1020,
        2440
      ],
      "id": "07500052-1a4b-4d0f-b347-24aac8650882",
      "name": "Google Gemini Chat Model2",
      "credentials": {
        "googlePalmApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "6c37a80a-a136-4f79-b8c8-056cd044d5c0",
              "name": "runId",
              "value": "={{ $json.data.id }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -520,
        580
      ],
      "name": "Extract Run ID",
      "id": "e4024b46-2576-44b3-b4ec-a49d642a655a"
    },
    {
      "parameters": {
        "url": "=https://api.apify.com/v2/actor-runs/{{ $('Extract Run ID').item.json.runId }}?token={{ $('Input').item.json.ApifyAPIKey }}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -120,
        580
      ],
      "name": "Check Run Status",
      "id": "b020a447-3c83-4abe-9101-332a32f14446"
    },
    {
      "parameters": {
        "conditions": {
          "number": [
            {
              "value1": "={{ $json.data.status }}",
              "operation": "equal",
              "value2": "=SUCCEEDED"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        80,
        580
      ],
      "name": "Check if Succeeded",
      "id": "7dc13011-3cb0-4945-942b-2e3df15f9bc5"
    },
    {
      "parameters": {
        "url": "=https://api.apify.com/v2/actor-runs/{{ $('Extract Run ID').item.json.runId }}/dataset/items?token={{ $('Input').item.json.ApifyAPIKey }}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        280,
        480
      ],
      "name": "Get Dataset Items",
      "id": "08b46bef-3eff-402e-bc09-ad70e4d15cd0"
    },
    {
      "parameters": {
        "amount": "={{ $('Input').first().json.request_interval }}"
      },
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        280,
        680
      ],
      "name": "Wait and Retry",
      "id": "6b420dda-f126-4f32-a492-e71c0d8043bf"
    },
    {
      "parameters": {
        "amount": "={{ $('Input').first().json.first_timeout }}"
      },
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        -320,
        580
      ],
      "name": "Wait 1 Minutes",
      "id": "980a6288-1a93-4a2d-88ce-8bf4fd064872"
    },
    {
      "parameters": {
        "jsCode": "// \u83b7\u53d6\u6240\u6709\u804c\u4f4d\nconst allJobs = $input.all();\nconsole.log(`\u603b\u804c\u4f4d\u6570: ${allJobs.length}`);\n\n// \u8fc7\u6ee4\u51fa\u65b0\u804c\u4f4d\u548c\u672a\u5904\u7406\u804c\u4f4d\nconst jobsForProcessing = allJobs.filter(item => {\n  const job = item.json;\n  // \u9009\u62e9'new'\u72b6\u6001\u6216\u65e0\u72b6\u6001\u7684\u804c\u4f4d\n  return job.status === 'new' || job.status === null || job.status === undefined;\n});\n\nconsole.log(`\u8fc7\u6ee4\u540e\u5f85\u5904\u7406\u804c\u4f4d\u6570: ${jobsForProcessing.length}`);\n\n// \u5982\u679c\u6ca1\u6709\u65b0\u804c\u4f4d\uff0c\u6dfb\u52a0\u4e00\u4e2a\u65e5\u5fd7\u6d88\u606f\nif (jobsForProcessing.length === 0) {\n  console.log('\u6ca1\u6709\u65b0\u804c\u4f4d\u9700\u8981\u5904\u7406');\n}\n\nreturn jobsForProcessing;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        1440,
        580
      ],
      "id": "cb23b816-4d97-4a35-84e8-6cac1999f011",
      "name": "filter_by_status"
    },
    {
      "parameters": {
        "jsCode": "// \u5728n8n\u7684Function\u8282\u70b9\u4e2d\nlet jobListingsHTML = '';\nlet jobs;\n\n// \u5c1d\u8bd5\u591a\u79cd\u53ef\u80fd\u7684\u6570\u636e\u7ed3\u6784\ntry {\n  if ($input.item && $input.item[0] && $input.item[0].json && $input.item[0].json.output) {\n    jobs = $input.item[0].json.output;\n  } else if ($input.all()[0].json.output) {\n    jobs = $input.all()[0].json.output;\n  } else if ($input.first().json[0] && $input.first().json[0].output) {\n    jobs = $input.first().json[0].output;\n  } else {\n    // \u53ef\u80fd\u6570\u636e\u5728\u66f4\u6df1\u7684\u5d4c\u5957\u4e2d\n    jobs = $input.first().json;\n    if (Array.isArray(jobs) && jobs[0] && jobs[0].output) {\n      jobs = jobs[0].output;\n    }\n  }\n} catch (error) {\n  // \u6570\u636e\u7ed3\u6784\u95ee\u9898\u65f6\u7684\u5907\u9009\u65b9\u6848\n  jobs = [];\n  console.log('Error accessing job data:', error.message);\n}\n\n// \u5982\u679cjobs\u8fd8\u4e0d\u662f\u6570\u7ec4\uff0c\u5c1d\u8bd5\u6700\u540e\u7684\u65b9\u6cd5\nif (!Array.isArray(jobs)) {\n  console.log('Jobs is not an array, trying alternative method');\n  // \u6253\u5370\u51fa\u5b9e\u9645\u6570\u636e\u7ed3\u6784\u4ee5\u4fbf\u8c03\u8bd5\n  console.log('Actual data structure:', JSON.stringify($input.all()));\n  jobs = [];\n}\n\n// \u751f\u6210HTML...\n// \u4e3a\u6bcf\u4e2a\u5de5\u4f5c\u673a\u4f1a\u521b\u5efaHTML\njobs.forEach(job => {\n  jobListingsHTML += `\n    <!-- Job for ${job['Company Name']} -->\n    <tr>\n        <td style=\"padding: 0 25px;\">\n            <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"border: 1px solid #dce3ea; border-radius: 10px; margin-bottom: 25px; overflow: hidden;\">\n                <tr>\n                    <td style=\"background-color: #4a6fa5; color: #ffffff; padding: 18px 20px;\">\n                        <strong style=\"font-size: 18px;\">${job['Company Name']}</strong><br>\n                        <span style=\"font-size: 14px; opacity: 0.9;\">${job['Job Title']}</span>\n                    </td>\n                </tr>\n                <tr>\n                    <td style=\"padding: 20px; background-color: #ffffff;\">\n                        <div style=\"display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 14px;\">\n                            <div style=\"background-color: #eef2f7; color: #4a6fa5; border-radius: 20px; padding: 8px 14px; font-size: 13px; display: inline-block;\">${job.Industry}</div>\n                            <div style=\"background-color: #f0f7f4; color: #00a06a; border-radius: 20px; padding: 8px 14px; font-size: 13px; display: inline-block;\">${job.Flexibility}</div>\n                            <div style=\"background-color: #f7f4f0; color: #a06a00; border-radius: 20px; padding: 8px 14px; font-size: 13px; display: inline-block;\">${job['Salary Range']}</div>\n                        </div>\n                        \n                        <div style=\"margin-bottom: 12px; background-color: #fafafa; padding: 12px; border-radius: 6px;\">\n                            <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n                                <tr>\n                                    <td style=\"padding-bottom: 8px;\">\n                                        <span style=\"font-size: 13px; color: #666666;\">\ud83d\udccd Location:</span>\n                                        <span style=\"font-size: 13px; color: #333333; font-weight: bold; margin-left: 4px;\">${job.Location}</span>\n                                    </td>\n                                </tr>\n                            </table>\n                        </div>\n                        \n                        <div style=\"margin-bottom: 18px; border-left: 4px solid #4a6fa5; padding-left: 14px; background-color: #f9f9f9; padding-top: 10px; padding-bottom: 10px;\">\n                            <strong style=\"color: #2a5298; font-size: 15px;\">Why this matches your profile:</strong>\n                            <p style=\"font-size: 13px; color: #444444; margin: 10px 0 0;\">${job['Reason for Match']}</p>\n                        </div>\n\n                        <a href=\"${job['Application URL']}\" target=\"_blank\" style=\"display: inline-block; background-color: #00c07f; color: #ffffff; text-decoration: none; padding: 12px 24px; font-size: 14px; font-weight: bold; border-radius: 6px;\">Apply Now</a>\n                        <div style=\"display: flex; margin-top: 15px;\">\n                            <a href=\"http://localhost:5678/webhook/2f32a889-c6d8-4dda-a550-71d963063aa7?jobId=${job['database_id']}\" target=\"_blank\" style=\"display: inline-block; background-color: #4a6fa5; color: #ffffff; text-decoration: none; padding: 8px 16px; font-size: 12px; border-radius: 4px;\">Generate Cover Letter</a>\n                        </div>\n                    </td>\n                </tr>\n            </table>\n        </td>\n    </tr>\n  `;\n});\n\n// \u5728\u4f60\u539f\u59cb\u7684HTML\u6a21\u677f\u4e2d\u66ff\u6362\u6389\u5355\u4e2a\u5de5\u4f5c\u9879\u7684\u90e8\u5206\nconst fullHTML = `<!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>Your Tailored Career Opportunities</title>\n</head>\n<body style=\"font-family: Arial, 'Helvetica Neue', Helvetica, sans-serif; line-height: 1.6; color: #333333; background-color: #f5f7fa; margin: 0; padding: 0;\">\n    <table width=\"100%\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\">\n        <tr>\n            <td align=\"center\" style=\"padding: 30px 15px;\">\n                <table width=\"600\" cellpadding=\"0\" cellspacing=\"0\" border=\"0\" style=\"background-color: #ffffff; border-collapse: collapse; box-shadow: 0 0 12px rgba(0,0,0,0.05); border-radius: 8px; overflow: hidden;\">\n                    <tr>\n                        <td style=\"background-color: #2a5298; color: #ffffff; padding: 40px 30px; text-align: center;\">\n                            <h1 style=\"margin: 0; font-size: 24px; font-weight: bold;\">Your Personalized Career Opportunities</h1>\n                            <p style=\"margin: 15px 0 0; font-size: 15px; opacity: 0.9;\">Handpicked opportunities aligned with your expertise and preferences</p>\n                        </td>\n                    </tr>\n\n                    <tr><td height=\"30\"></td></tr>\n\n                    ${jobListingsHTML}\n\n                </table>\n            </td>\n        </tr>\n    </table>\n</body>\n</html>`;\n\n// \u8fd4\u56de\u6b63\u786e\u683c\u5f0f\nreturn [{json: {html: fullHTML}}];"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3740,
        560
      ],
      "id": "ce73e0d7-28ec-4001-98ed-11a82f954279",
      "name": "generate_html_template"
    },
    {
      "parameters": {
        "jsCode": "// \u83b7\u53d6AI\u5339\u914d\u540e\u7684\u804c\u4f4d\nlet matchedJobs = [];\nconsole.log('t')\n\ntry {\n  // \u5c1d\u8bd5\u4ece\u4e0d\u540c\u53ef\u80fd\u7684\u4f4d\u7f6e\u83b7\u53d6\u5339\u914d\u7684\u804c\u4f4d\n  if ($input.first().json.output && Array.isArray($input.first().json.output)) {\n    matchedJobs = $input.first().json.output;\n  } else if ($input.first().json && Array.isArray($input.first().json)) {\n    matchedJobs = $input.first().json;\n  } else {\n    console.log('\u65e0\u6cd5\u627e\u5230\u5339\u914d\u7684\u804c\u4f4d\u6570\u636e\uff0c\u68c0\u67e5\u8f93\u5165\u683c\u5f0f');\n    console.log('\u8f93\u5165\u6570\u636e:', JSON.stringify($input.first().json));\n  }\n} catch (error) {\n  console.error('\u89e3\u6790\u5339\u914d\u804c\u4f4d\u65f6\u51fa\u9519:', error.message);\n}\n\nconsole.log(`\u627e\u5230 ${matchedJobs.length} \u4e2a\u5339\u914d\u7684\u804c\u4f4d`);\n\n// \u51c6\u5907\u8981\u66f4\u65b0\u7684\u804c\u4f4dID\u5217\u8868\nconst jobIdsToUpdate = matchedJobs.map(job => job.database_id || job.id);\nconsole.log('\u8981\u66f4\u65b0\u7684\u804c\u4f4dID:', jobIdsToUpdate);\n\n// \u51c6\u5907\u8981\u4fdd\u5b58\u5230Supabase\u7684\u6570\u636e\nconst updateOperations = [];\nfor (const id of jobIdsToUpdate) {\n  if (id) {\n    updateOperations.push({\n      json: {\n        id: id,\n        status: 'processed',\n        processed_at: new Date().toISOString()\n      }\n    });\n  }\n}\n\n// \u4fdd\u5b58\u539f\u59cb\u5339\u914d\u7ed3\u679c\uff0c\u4ee5\u4fbf\u540e\u7eed\u6d41\u7a0b\u4f7f\u7528\nconst originalData = $input.first().json;\n\n// \u8fd4\u56de\u5305\u542b\u539f\u59cb\u6570\u636e\u548c\u66f4\u65b0\u64cd\u4f5c\u7684\u590d\u5408\u5bf9\u8c61\nreturn {\n  json: {\n    matchedJobs: originalData,\n    updateOperations: updateOperations\n  }\n};"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3200,
        560
      ],
      "id": "15e09766-5173-4ae4-bdcb-307bb1eb8463",
      "name": "update_job_status"
    },
    {
      "parameters": {
        "content": "### Supabase / Supabase1\n\u5c06\u722c\u53d6\u7684\u804c\u4f4d\u6570\u636e\u5b58\u50a8\u5230Supabase\u6570\u636e\u5e93\u4e2d\uff0c\u7528\u4e8e\u6301\u4e45\u5316\u5b58\u50a8\u548c\u53bb\u91cd\u3002\n\u786e\u4fdd\u4e0d\u91cd\u590d\u5904\u7406\u540c\u4e00\u804c\u4f4d\u4fe1\u606f\u3002\n\n### filter_by_status / get_unique_jobs\n\u8fc7\u6ee4\u51fa\u65b0\u7684\u3001\u672a\u5904\u7406\u8fc7\u7684\u804c\u4f4d\u4fe1\u606f\uff0c\u5e76\u786e\u4fdd\u804c\u4f4dID\u7684\u552f\u4e00\u6027\u3002",
        "height": 640,
        "width": 920,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        1140,
        280
      ],
      "id": "49900548-3976-4a2c-bd9d-f4b4fc1fd335",
      "name": "Sticky Note8"
    },
    {
      "parameters": {
        "content": "### start_apify_run_indeed\n\u542f\u52a8Apify\u722c\u866b\uff0c\u6293\u53d6LinkedIn\u4e0a\u7684\u804c\u4f4d\u4fe1\u606f\u3002\n\u786e\u4fdd\u5728jsonBody\u4e2d\u8bbe\u7f6e\u6b63\u786e\u7684\u641c\u7d22URL\u548c\u53c2\u6570\u3002\n\n### Check Run Status / Get Dataset Items\n\u8fd9\u4e9b\u8282\u70b9\u68c0\u67e5\u722c\u866b\u8fd0\u884c\u72b6\u6001\u5e76\u83b7\u53d6\u7ed3\u679c\u6570\u636e\u3002\n\u5305\u542b\u9519\u8bef\u5904\u7406\u548c\u91cd\u8bd5\u673a\u5236\uff0c\u786e\u4fdd\u53ef\u9760\u83b7\u53d6\u804c\u4f4d\u4fe1\u606f\u3002\n",
        "height": 660,
        "width": 1280,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -800,
        1020
      ],
      "id": "c3e70cdb-90ef-44bb-bc9e-90cb9d8ed2ba",
      "name": "Sticky Note12"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "6c37a80a-a136-4f79-b8c8-056cd044d5c0",
              "name": "runId",
              "value": "={{ $json.data.id }}",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -520,
        1340
      ],
      "name": "Extract Run ID1",
      "id": "743c0c6a-08bd-4d82-b38c-ba4a01fc48bf"
    },
    {
      "parameters": {
        "url": "=https://api.apify.com/v2/actor-runs/{{ $('Extract Run ID1').item.json.runId }}?token={{ $('Input').first().json.ApifyAPIKey }}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -120,
        1340
      ],
      "name": "Check Run Status1",
      "id": "93631c3d-9415-43dd-904a-6b2752f7fb6d"
    },
    {
      "parameters": {
        "conditions": {
          "number": [
            {
              "value1": "={{ $json.data.status }}",
              "operation": "equal",
              "value2": "=SUCCEEDED"
            }
          ]
        }
      },
      "type": "n8n-nodes-base.if",
      "typeVersion": 1,
      "position": [
        80,
        1340
      ],
      "name": "Check if Succeeded1",
      "id": "9ea1abca-2877-4b1d-bd57-fd6590a09886"
    },
    {
      "parameters": {
        "url": "=https://api.apify.com/v2/actor-runs/{{ $('Extract Run ID1').item.json.runId }}/dataset/items?token={{ $('Input').first().json.ApifyAPIKey }}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        280,
        1240
      ],
      "name": "Get Dataset Items1",
      "id": "b3402b6d-7c6c-4d48-ad1e-32fda20c3142"
    },
    {
      "parameters": {
        "amount": "={{ $('Input').first().json.request_interval }}"
      },
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        280,
        1440
      ],
      "name": "Wait and Retry1",
      "id": "8520cb71-5518-4044-ae51-1218287e4dca"
    },
    {
      "parameters": {
        "amount": "={{ $('Input').first().json.first_timeout }}"
      },
      "type": "n8n-nodes-base.wait",
      "typeVersion": 1.1,
      "position": [
        -320,
        1340
      ],
      "name": "Wait 1 Minutes1",
      "id": "fc4a65d9-4795-4570-bdbc-a9dac5f91551"
    },
    {
      "parameters": {
        "jsCode": "// \u6807\u51c6\u5316\u804c\u4f4d\u6570\u636e\u7684\u51fd\u6570\u8282\u70b9\nfunction normalizeJobData(inputData) {\n  // \u521b\u5efa\u542b\u9ed8\u8ba4\u503c\u7684\u6807\u51c6\u804c\u4f4d\u5bf9\u8c61\n  const standardJob = {\n    id:'',\n    company_name: '',\n    job_title: '',\n    application_url: '',\n    location: '',\n    description: '',\n    industry: 'Not specified',\n    flexibility: 'Not specified',\n    salary_range: 'Not specified',\n    status: 'new',\n    source: 'external',\n    created_at: new Date().toISOString()\n  };\n  \n  // \u5c1d\u8bd5\u6620\u5c04\u8f93\u5165\u5b57\u6bb5 - \u4f7f\u7528\u591a\u79cd\u53ef\u80fd\u7684\u547d\u540d\n  // \u516c\u53f8\u540d\u79f0\n  standardJob.id = inputData.id || inputData.ID || inputData.job_id\n  // \u786e\u4fddID\u59cb\u7ec8\u662f\u5b57\u7b26\u4e32\n  if (inputData.id !== undefined && inputData.id !== null) {\n    standardJob.id = String(inputData.id); // \u5f3a\u5236\u8f6c\u6362\u4e3a\u5b57\u7b26\u4e32\n  } else if (inputData.database_id !== undefined && inputData.database_id !== null) {\n    standardJob.id = String(inputData.database_id);\n  }\n  \n  standardJob.company_name = inputData.company_name || inputData.company || \n                            inputData.companyName || inputData.employer || 'Unknown Company';\n  \n  // \u804c\u4f4d\u540d\u79f0\n  standardJob.job_title = inputData.job_title || inputData.title || \n                         inputData.position || inputData.role || inputData.positionName || inputData.position_name || 'Unknown Position';\n  \n  // \u5e94\u7528\u94fe\u63a5\n  standardJob.application_url = inputData.application_url || inputData.url || \n                               inputData.link || inputData.apply_url || inputData.applyUrl || '';\n  \n  // \u5730\u70b9\n  standardJob.location = inputData.location || inputData.place || \n                        inputData.job_location || inputData.city || '';\n  \n  // \u63cf\u8ff0\n  standardJob.description = inputData.description || inputData.job_description || \n                           inputData.desc || inputData.details || inputData.desription || inputData.descriptionText || '';\n  \n  // \u884c\u4e1a\n  standardJob.industry = inputData.industry || inputData.sector || \n                        inputData.field || inputData.industries || standardJob.industry;\n  \n  // \u7075\u6d3b\u6027/\u5de5\u4f5c\u5b89\u6392\n  standardJob.flexibility = inputData.flexibility || inputData.work_type ||\n                           inputData.arrangement || standardJob.flexibility;\n  \n  // \u85aa\u8d44\u8303\u56f4\n  standardJob.salary_range = inputData.salary_range || inputData.salary || \n                            inputData.compensation || standardJob.salary_range;\n  \n  // \u6765\u6e90\u53ef\u4ee5\u88ab\u8986\u76d6\n  if (inputData.source) {\n    standardJob.source = inputData.source;\n  }\n  \n  // \u65e5\u5fd7\u8bb0\u5f55\uff0c\u5e2e\u52a9\u8c03\u8bd5\n  console.log('\u539f\u59cb\u6570\u636e:', JSON.stringify(inputData));\n  console.log('\u6807\u51c6\u5316\u540e:', JSON.stringify(standardJob));\n  \n  return standardJob;\n}\n\n// \u83b7\u53d6\u6240\u6709\u8f93\u5165\u9879\nconst inputItems = $input.all();\nconsole.log(`\u5904\u7406 ${inputItems.length} \u4e2a\u804c\u4f4d\u9879`);\n\n// \u4f7f\u7528map\u5904\u7406\u6bcf\u4e2a\u9879\u76ee\nconst normalizedJobs = inputItems.map(item => {\n  const inputData = item.json || {};\n  return { json: normalizeJobData(inputData) };\n});\n\n// \u8bb0\u5f55\u5904\u7406\u7ed3\u679c\nconsole.log(`\u6807\u51c6\u5316\u540e\u5f97\u5230 ${normalizedJobs.length} \u4e2a\u804c\u4f4d`);\n\n// \u8fd4\u56de\u6807\u51c6\u5316\u7684\u804c\u4f4d\u6570\u636e\u6570\u7ec4\nreturn normalizedJobs;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        600,
        1240
      ],
      "id": "e2c6f06c-d197-4f99-be0d-2e5f3cf2c4bc",
      "name": "normalize_job_data"
    },
    {
      "parameters": {
        "jsCode": "// \u6807\u51c6\u5316\u804c\u4f4d\u6570\u636e\u7684\u51fd\u6570\u8282\u70b9\nfunction normalizeJobData(inputData) {\n  // \u521b\u5efa\u542b\u9ed8\u8ba4\u503c\u7684\u6807\u51c6\u804c\u4f4d\u5bf9\u8c61\n  const standardJob = {\n    id:'',\n    company_name: '',\n    job_title: '',\n    application_url: '',\n    location: '',\n    description: '',\n    industry: 'Not specified',\n    flexibility: 'Not specified',\n    salary_range: 'Not specified',\n    status: 'new',\n    source: 'external',\n    created_at: new Date().toISOString()\n  };\n  \n  // \u5c1d\u8bd5\u6620\u5c04\u8f93\u5165\u5b57\u6bb5 - \u4f7f\u7528\u591a\u79cd\u53ef\u80fd\u7684\u547d\u540d\n  // \u516c\u53f8\u540d\u79f0\n  standardJob.id = inputData.id || inputData.ID || inputData.job_id\n  // \u786e\u4fddID\u59cb\u7ec8\u662f\u5b57\u7b26\u4e32\n  if (inputData.id !== undefined && inputData.id !== null) {\n    standardJob.id = String(inputData.id); // \u5f3a\u5236\u8f6c\u6362\u4e3a\u5b57\u7b26\u4e32\n  } else if (inputData.database_id !== undefined && inputData.database_id !== null) {\n    standardJob.id = String(inputData.database_id);\n  }\n  \n  standardJob.company_name = inputData.company_name || inputData.company || \n                            inputData.companyName || inputData.employer || 'Unknown Company';\n  \n  // \u804c\u4f4d\u540d\u79f0\n  standardJob.job_title = inputData.job_title || inputData.title || \n                         inputData.position || inputData.role || inputData.positionName || inputData.position_name || 'Unknown Position';\n  \n  // \u5e94\u7528\u94fe\u63a5\n  standardJob.application_url = inputData.application_url || inputData.url || \n                               inputData.link || inputData.apply_url || inputData.applyUrl || '';\n  \n  // \u5730\u70b9\n  standardJob.location = inputData.location || inputData.place || \n                        inputData.job_location || inputData.city || '';\n  \n  // \u63cf\u8ff0\n  standardJob.description = inputData.description || inputData.job_description || \n                           inputData.desc || inputData.details || inputData.desription || inputData.descriptionText || '';\n  \n  // \u884c\u4e1a\n  standardJob.industry = inputData.industry || inputData.sector || \n                        inputData.field || inputData.industries || standardJob.industry;\n  \n  // \u7075\u6d3b\u6027/\u5de5\u4f5c\u5b89\u6392\n  standardJob.flexibility = inputData.flexibility || inputData.work_type ||\n                           inputData.arrangement || standardJob.flexibility;\n  \n  // \u85aa\u8d44\u8303\u56f4\n  standardJob.salary_range = inputData.salary_range || inputData.salary || \n                            inputData.compensation || standardJob.salary_range;\n  \n  // \u6765\u6e90\u53ef\u4ee5\u88ab\u8986\u76d6\n  if (inputData.source) {\n    standardJob.source = inputData.source;\n  }\n  \n  // \u65e5\u5fd7\u8bb0\u5f55\uff0c\u5e2e\u52a9\u8c03\u8bd5\n  console.log('\u539f\u59cb\u6570\u636e:', JSON.stringify(inputData));\n  console.log('\u6807\u51c6\u5316\u540e:', JSON.stringify(standardJob));\n  \n  return standardJob;\n}\n\n// \u83b7\u53d6\u6240\u6709\u8f93\u5165\u9879\nconst inputItems = $input.all();\nconsole.log(`\u5904\u7406 ${inputItems.length} \u4e2a\u804c\u4f4d\u9879`);\n\n// \u4f7f\u7528map\u5904\u7406\u6bcf\u4e2a\u9879\u76ee\nconst normalizedJobs = inputItems.map(item => {\n  const inputData = item.json || {};\n  return { json: normalizeJobData(inputData) };\n});\n\n// \u8bb0\u5f55\u5904\u7406\u7ed3\u679c\nconsole.log(`\u6807\u51c6\u5316\u540e\u5f97\u5230 ${normalizedJobs.length} \u4e2a\u804c\u4f4d`);\n\n// \u8fd4\u56de\u6807\u51c6\u5316\u7684\u804c\u4f4d\u6570\u636e\u6570\u7ec4\nreturn normalizedJobs;"
      },
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        600,
        560
      ],
      "id": "107cb74f-c30c-4f33-bd18-bd3ca126eba3",
      "name": "normalize_job_data1"
    },
    {
      "parameters": {},
      "type": "n8n-nodes-base.merge",
      "typeVersion": 3.1,
      "position": [
        920,
        580
      ],
      "id": "0e1853fa-e4cf-42da-a3a5-b0e6635b2f7e",
      "name": "Merge"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://api.apify.com/v2/acts/curious_coder~linkedin-jobs-scraper/runs?token={{ $('Input').item.json.ApifyAPIKey }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            },
            {}
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "{\n    \"count\": 100,\n    \"scrapeCompany\": true,\n    \"urls\": [\n        \"https://www.linkedin.com/jobs/search?keywords=&location=%E5%BE%B7%E5%9B%BD&geoId=101282230&f_JT=P%2CT&f_PP=100477049&f_TPR=r604800&position=1&pageNum=0\"\n    ]\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -720,
        580
      ],
      "name": "start_apify_run_linkedin",
      "id": "7c98cd7e-ad41-4745-b388-865750627599"
    },
    {
      "parameters": {
        "method": "POST",
        "url": "=https://api.apify.com/v2/acts/misceres~indeed-scraper/runs?token={{ $('Input').item.json.ApifyAPIKey }}",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "{\n  \"position\": \"werkstudent\",\n  \"country\": \"DE\",\n  \"location\": \"Munich\",\n  \"maxItems\": 20,\n  \"parseCompanyDetails\": false,\n  \"saveOnlyUniqueItems\": true,\n  \"followApplyRedirects\": false\n}",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [
        -720,
        1340
      ],
      "name": "start_apify_run_indeed",
      "id": "8cf94baa-0668-4f78-b639-51ec4b662bb3"
    },
    {
      "parameters": {
        "aggregate": "aggregateAllItemData",
        "options": {}
      },
      "type": "n8n-nodes-base.aggregate",
      "typeVersion": 1,
      "position": [
        2140,
        580
      ],
      "id": "44a55512-45d7-4019-8f9a-688a7cc48ea2",
      "name": "Aggregate"
    },
    {
      "parameters": {
        "content": "### stringify_json / Aggregate\n\u51c6\u5907\u804c\u4f4d\u6570\u636e\uff0c\u8f6c\u4e3aAI\u53ef\u5904\u7406\u7684\u683c\u5f0f\uff0c\u5e76\u805a\u5408\u6240\u6709\u76f8\u5173\u4fe1\u606f\u3002",
        "height": 640,
        "width": 320,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        2120,
        280
      ],
      "id": "b0f2893e-0ebe-4f21-abce-bdb738573b7d",
      "name": "Sticky Note13"
    },
    {
      "parameters": {
        "operation": "update",
        "tableId": "job_listings",
        "filters": {
          "conditions": [
            {
              "keyName": "id",
              "condition": "eq",
              "keyValue": "={{ $json.id }}"
            }
          ]
        },
        "fieldsUi": {
          "fieldValues": [
            {
              "fieldId": "status",
              "fieldValue": "={{ $json.status }}"
            },
            {
              "fieldId": "processed_at",
              "fieldValue": "={{ $json.processed_at }}"
            }
          ]
        }
      },
      "id": "07ccc1de-a175-4077-94cf-a97aee091c8a",
      "name": "Supabase_update_job_status",
      "type": "n8n-nodes-base.supabase",
      "typeVersion": 1,
      "position": [
        3740,
        -40
      ],
      "credentials": {
        "supabaseApi": {
          "name": "<your credential>"
        }
      }
    },
    {
      "parameters": {
        "jsCode": "// \u83b7\u53d6\u8981\u66f4\u65b0\u7684\u64cd\u4f5c\nconst updateOps = $input.first().json.updateOperations;\n\n// \u5c06\u6bcf\u4e2a\u66f4\u65b0\u64cd\u4f5c\u62c6\u5206\u4e3a\u5355\u72ec\u7684\u9879\nreturn updateOps.map(op => op.json);"
      },
      "id": "0d6f0378-6f67-44ce-b091-cc586bf3b2c1",
      "name": "extract_update_operation",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3520,
        -40
      ]
    },
    {
      "parameters": {
        "jsCode": "// \u4ece\u590d\u5408\u5bf9\u8c61\u4e2d\u63d0\u53d6\u539f\u59cb\u5339\u914d\u7ed3\u679c\nreturn $input.first().json.matchedJobs;"
      },
      "id": "5de02ab2-6968-44c0-9ecd-5b309c1b3e47",
      "name": "extract_matched_jobs",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        3520,
        560
      ]
    },
    {
      "parameters": {
        "content": "### \u6ce8\u610f\u82b1\u8d39\n\u5efa\u8baerun\u5b8c\u4e4b\u540e\uff0cpin\u4f4f\u6570\u636e",
        "height": 420,
        "width": 220,
        "color": 3
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -780,
        480
      ],
      "id": "4c6d92dc-a798-4f42-ae2d-d681826cdc20",
      "name": "Sticky Note14"
    },
    {
      "parameters": {
        "content": "### \u6ce8\u610f\u82b1\u8d39\n\u5efa\u8baerun\u5b8c\u4e4b\u540e\uff0cpin\u4f4f\u6570\u636e",
        "height": 420,
        "width": 220,
        "color": 3
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -780,
        1240
      ],
      "id": "48b38117-786d-4fab-96a2-150669858000",
      "name": "Sticky Note15"
    },
    {
      "parameters": {
        "content": "### normalize_job_data \n\u6807\u51c6\u5316\u4ece\u4e0d\u540c\u5e73\u53f0\u83b7\u53d6\u7684\u804c\u4f4d\u6570\u636e\uff0c\u786e\u4fdd\u7edf\u4e00\u7684\u6570\u636e\u7ed3\u6784\u3002\n\u5904\u7406\u5404\u5b57\u6bb5\u7684\u6620\u5c04\u548c\u9ed8\u8ba4\u503c\u8bbe\u7f6e\u3002",
        "height": 640,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        540,
        280
      ],
      "id": "a3e9d6a0-04cb-4fec-88d5-38693bbd50e8",
      "name": "Sticky Note16"
    },
    {
      "parameters": {
        "content": "### normalize_job_data \n\u6807\u51c6\u5316\u4ece\u4e0d\u540c\u5e73\u53f0\u83b7\u53d6\u7684\u804c\u4f4d\u6570\u636e\uff0c\u786e\u4fdd\u7edf\u4e00\u7684\u6570\u636e\u7ed3\u6784\u3002\n\u5904\u7406\u5404\u5b57\u6bb5\u7684\u6620\u5c04\u548c\u9ed8\u8ba4\u503c\u8bbe\u7f6e\u3002",
        "height": 640,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        540,
        1020
      ],
      "id": "1d3262e9-58cd-4eb8-82ca-fd93f39dd7a1",
      "name": "Sticky Note17"
    },
    {
      "parameters": {
        "content": "### extract_matched_jobs / extract_update_operation\n\u4eceAI\u5339\u914d\u7ed3\u679c\u4e2d\u63d0\u53d6\u6700\u7ec8\u63a8\u8350\u804c\u4f4d\u548c\u9700\u8981\u66f4\u65b0\u7684\u6570\u636e\u5e93\u8bb0\u5f55\u3002\n",
        "height": 460,
        "width": 480,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        3440,
        -220
      ],
      "id": "62314cd8-38b2-4f47-8ce0-9365f188acd0",
      "name": "Sticky Note18"
    },
    {
      "parameters": {
        "content": "### update_job_status\n\u66f4\u65b0\u5df2\u5904\u7406\u804c\u4f4d\u7684\u72b6\u6001\uff0c\u907f\u514d\u91cd\u590d\u63a8\u8350\u540c\u4e00\u804c\u4f4d\u3002\n",
        "height": 620,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        3140,
        300
      ],
      "id": "1938735f-c13f-4c39-b33b-bbb8b3e4b714",
      "name": "Sticky Note19"
    },
    {
      "parameters": {
        "content": "\n### generate_html_template\n\u5c06\u5339\u914d\u7ed3\u679c\u8f6c\u6362\u4e3a\u7f8e\u89c2\u7684HTML\u90ae\u4ef6\u6a21\u677f\uff0c\u5305\u542b\u804c\u4f4d\u8be6\u60c5\u548c\u76f4\u63a5\u5e94\u7528\u94fe\u63a5\u3002",
        "height": 620,
        "width": 480,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        3440,
        300
      ],
      "id": "8443703a-7c20-4252-91e7-a6c0e4e93a31",
      "name": "Sticky Note20"
    },
    {
      "parameters": {
        "content": "\n### AI Agent (\u6c42\u804c\u4fe1\u751f\u6210)\n**\u4e2a\u6027\u5316\u6c42\u804c\u4fe1\u751f\u6210\u5668**\n\u57fa\u4e8e\u60a8\u7684\u7b80\u5386\u548c\u7279\u5b9a\u804c\u4f4d\u63cf\u8ff0\uff0c\u4f7f\u7528AI\u751f\u6210\u91cf\u8eab\u5b9a\u5236\u7684\u4e13\u4e1a\u6c42\u804c\u4fe1\u3002\n\u6c42\u804c\u4fe1\u98ce\u683c\u7279\u70b9\uff1a\n- \u4ee5\u516c\u53f8\u9700\u6c42\u4e3a\u4e2d\u5fc3\uff0c\u7a81\u51fa\u60a8\u5982\u4f55\u89e3\u51b3\u7279\u5b9a\u95ee\u9898\n- \u7b80\u6d01\u76f4\u63a5\u7684\u8868\u8fbe\u65b9\u5f0f\n- \u771f\u5b9e\u4e2a\u6027\u5316\u5185\u5bb9\uff0c\u907f\u514d\u9648\u8bcd\u6ee5\u8c03\n- \u9488\u5bf9\u804c\u4f4d\u5173\u952e\u8981\u6c42\u63d0\u4f9b\u6709\u529b\u8bc1\u660e\n- \u8d28\u91cf\u4f18\u5148\uff0c\u63d0\u4f9b\u6709\u529b\u7684\u5b9e\u4f8b\u800c\u975e\u7a7a\u6cdb\u6210\u5c31\n",
        "height": 1080,
        "width": 580,
        "color": 6
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1120,
        1780
      ],
      "id": "deb0c021-c55c-4bd2-a007-0e7b775dd84a",
      "name": "Sticky Note21"
    },
    {
      "parameters": {
        "content": "### Webhook\n\u63a5\u6536\u6c42\u804c\u4fe1\u751f\u6210\u8bf7\u6c42\uff0c\u5904\u7406\u7279\u5b9a\u804c\u4f4dID\u7684\u6c42\u804c\u4fe1\u751f\u6210\u3002",
        "height": 640,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -2960,
        1940
      ],
      "id": "fe1f46c5-a55b-4931-804d-0289de307096",
      "name": "Sticky Note4"
    },
    {
      "parameters": {
        "content": "\n### Gmail / Markdown\n\u683c\u5f0f\u5316\u6c42\u804c\u4fe1\u5185\u5bb9\u5e76\u901a\u8fc7\u7535\u5b50\u90ae\u4ef6\u53d1\u9001\u7ed9\u60a8\u3002\n",
        "height": 640,
        "width": 220,
        "color": 2
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -120,
        1940
      ],
      "id": "3473e0e9-5d63-4850-add5-757fe1209834",
      "name": "Sticky Note22"
    },
    {
      "parameters": {
        "content": "\n### create_new_cover_letter / append_blocks\n\u5c06\u751f\u6210\u7684\u6c42\u804c\u4fe1\u5b58\u50a8\u5230Notion\u6570\u636e\u5e93\u4e2d\uff0c\u65b9\u4fbf\u540e\u7eed\u67e5\u770b\u548c\u7f16\u8f91\u3002",
        "height": 640,
        "width": 760,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        160,
        1940
      ],
      "id": "c8deb8fb-25ca-49f9-8f25-07c74c14d6a6",
      "name": "Sticky Note23"
    },
    {
      "parameters": {
        "content": "\n5. \u914d\u7f6eNotion\u96c6\u6210\uff08\u53ef\u9009\uff09\uff1a\n\n\u5982\u9700\u4f7f\u7528Notion\u8ddf\u8e2a\u5e94\u7528\u8fdb\u5ea6\uff0c\u8bf7\u786e\u4fdd\u8bbe\u7f6e\u4e86\u6b63\u786e\u7684Notion Database ID\n\u6ce8\uff1a\u5efa\u8bae\u521b\u5efa\u4e24\u4e2a\u6570\u636e\u5e93\uff1a\n\nJob Tracker\u6570\u636e\u5e93\n\u5c5e\u6027\uff1aCompany Name(\u6807\u9898), Job Title, Industry, Application URL, Location, Flexibility, Salary Range, Status\n\n\nCover Letter\u6570\u636e\u5e93\n\u5c5e\u6027\uff1aTitle(\u6807\u9898), Company Name\n\n6. \u6570\u636e\u5e93\u914d\u7f6e\uff1a\n\n\u786e\u4fdd\u5728Supabase\u6216\u60a8\u9009\u62e9\u7684\u6570\u636e\u5e93\u7cfb\u7edf\u4e2d\u521b\u5efa\u4e86\u540d\u4e3ajob_listings\u7684\u8868\n\u8868\u7ed3\u6784\u5e94\u5305\u542b\u4ee5\u4e0b\u5b57\u6bb5\uff08\u53ef\u4f7f\u7528\u4ee5\u4e0bSQL\u521b\u5efa\uff09:\n\nsqlCREATE TABLE job_listings (\n  id TEXT PRIMARY KEY,\n  company_name TEXT NOT NULL,\n  job_title TEXT NOT NULL,\n  application_url TEXT,\n  location TEXT,\n  description TEXT,\n  industry TEXT,\n  flexibility TEXT,\n  salary_range TEXT,\n  status TEXT,\n  source TEXT,\n  created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,\n  processed_at TIMESTAMP WITH TIME ZONE,\n  reason_for_match TEXT\n);\n",
        "height": 820,
        "width": 900,
        "color": 5
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -800,
        -600
      ],
      "id": "339fecf0-ec3b-4fed-94b8-93d79fdb36a3",
      "name": "Sticky Note24"
    },
    {
      "parameters": {
        "content": "### DownloadResume\n\u4eceGoogle Drive\u4e0b\u8f7d\u60a8\u7684\u7b80\u5386PDF\u6587\u4ef6\u3002\u8bf7\u786e\u4fdd\u4e0a\u4f20\u60a8\u7684\u7b80\u5386\u5230Google Drive\u5e76\u83b7\u53d6\u6587\u4ef6ID\u3002\n\n### Extract Information from Resume PDF\n\u63d0\u53d6\u7b80\u5386PDF\u4e2d\u7684\u6587\u672c\u5185\u5bb9\uff0c\u4e3a\u540e\u7eedAI\u5339\u914d\u505a\u51c6\u5907\u3002\n\n### SetResumeField\n\u5c06\u63d0\u53d6\u7684\u7b80\u5386\u6587\u672c\u8bbe\u7f6e\u4e3a\u53d8\u91cf\uff0c\u4ee5\u4fbf\u5728\u5de5\u4f5c\u6d41\u7a0b\u7684\u540e\u7eed\u6b65\u9aa4\u4e2d\u4f7f\u7528\u3002",
        "height": 640,
        "width": 540
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1700,
        1940
      ],
      "id": "b90970fe-b19a-4b09-81d1-3ee7731dcba1",
      "name": "Sticky Note5"
    },
    {
      "parameters": {
        "content": "\n### create_new_job_listing\n\u5728job tracker\u6570\u636e\u5e93\u5efa\u6863",
        "height": 640,
        "width": 210,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -1960,
        1940
      ],
      "id": "a44820e3-c5f1-48eb-b076-6ed303ac6ce5",
      "name": "Sticky Note25"
    },
    {
      "parameters": {
        "content": "\n### supabase_get\n\u6309\u4f20\u5165\u7684id\uff0c\u5728\u6570\u636e\u5e93\u91cc\u627e\u5230\u5bf9\u5e94\u7684\u5de5\u4f5c\u63cf\u8ff0\u3002",
        "height": 640,
        "width": 370,
        "color": 4
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -2380,
        1940
      ],
      "id": "9b4619b3-90f1-4e93-aec5-2e6ffdd8214f",
      "name": "Sticky Note26"
    },
    {
      "parameters": {
        "assignments": {
          "assignments": [
            {
              "id": "8e16b176-2cd3-448a-a859-6570cacda1f0",
              "name": "EmailAddressToReceiveCoverLetter",
              "value": "your@email.com",
              "type": "string"
            }
          ]
        },
        "options": {}
      },
      "type": "n8n-nodes-base.set",
      "typeVersion": 3.4,
      "position": [
        -2600,
        2220
      ],
      "id": "90b4feae-dedb-467e-abc4-c655630c86fe",
      "name": "Input1"
    },
    {
      "parameters": {
        "content": "### Input\n**\u5173\u952e\u914d\u7f6e\u8282\u70b9**\n\u8fd9\u91cc\u8bbe\u7f6e\u4e86\u6574\u4e2a\u5de5\u4f5c\u6d41\u7a0b\u4e2d\u4f7f\u7528\u7684\u91cd\u8981\u53d8\u91cf\uff1a**EmailAddressToReceiveCoverLetter**: \u63a5\u6536\u804c\u4f4d\u63a8\u8350\u7684\u90ae\u7bb1",
        "height": 640,
        "color": 7
      },
      "type": "n8n-nodes-base.stickyNote",
      "typeVersion": 1,
      "position": [
        -2680,
        1940
      ],
      "id": "fc3d73fa-5f75-44fa-84ae-a1cdd7230328",
      "name": "Sticky Note27"
    }
  ],
  "connections": {
    "Schedule Trigger": {
      "main": [
        [
          {
            "node": "Input",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "SetResumeField": {
      "main": [
        [
          {
            "node": "start_apify_run_linkedin",
            "type": "main",
            "index": 0
          },
          {
            "node": "start_apify_run_indeed",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Structured Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "Auto-fixing Output Parser",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "Auto-fixing Output Parser": {
      "ai_outputParser": [
        [
          {
            "node": "AI Agent: Find Best-matched jobs",
            "type": "ai_outputParser",
            "index": 0
          }
        ]
      ]
    },
    "DownloadResume": {
      "main": [
        [
          {
            "node": "Extract Information from Resume PDF",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Information from Resume PDF": {
      "main": [
        [
          {
            "node": "SetResumeField",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent: Find Best-matched jobs": {
      "main": [
        [
          {
            "node": "update_job_status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent: Find Best-matched jobs",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model1": {
      "ai_languageModel": [
        [
          {
            "node": "Auto-fixing Output Parser",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Email the top job recommendations": {
      "main": [
        []
      ]
    },
    "Supabase": {
      "main": [
        []
      ]
    },
    "Webhook": {
      "main": [
        [
          {
            "node": "Input1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase_get": {
      "main": [
        [
          {
            "node": "create_new_job_listing",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "get_job_id": {
      "main": [
        [
          {
            "node": "Supabase_get",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "DownloadResume1": {
      "main": [
        [
          {
            "node": "Extract Information from Resume PDF1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Input": {
      "main": [
        [
          {
            "node": "DownloadResume",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "AI Agent": {
      "main": [
        [
          {
            "node": "set_cover_letter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Gmail": {
      "main": [
        [
          {
            "node": "parse_to_paragraphs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Markdown": {
      "main": [
        [
          {
            "node": "Gmail",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "stringify_json": {
      "main": [
        [
          {
            "node": "AI Agent: Find Best-matched jobs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Information from Resume PDF1": {
      "main": [
        [
          {
            "node": "AI Agent",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Supabase1": {
      "main": [
        [
          {
            "node": "filter_by_status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "parse_to_markdown": {
      "main": [
        [
          {
            "node": "Markdown",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "parse_to_paragraphs": {
      "main": [
        [
          {
            "node": "create_new_cover_letter",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "return_all_items": {
      "main": [
        [
          {
            "node": "append_blocks",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "append_blocks": {
      "main": [
        []
      ]
    },
    "create_new_job_listing": {
      "main": [
        [
          {
            "node": "set_company_name",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "create_new_cover_letter": {
      "main": [
        [
          {
            "node": "return_all_items",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "set_company_name": {
      "main": [
        [
          {
            "node": "DownloadResume1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "set_cover_letter": {
      "main": [
        [
          {
            "node": "parse_to_markdown",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "get_unique_jobs": {
      "main": [
        [
          {
            "node": "Supabase",
            "type": "main",
            "index": 0
          },
          {
            "node": "Aggregate",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Google Gemini Chat Model2": {
      "ai_languageModel": [
        [
          {
            "node": "AI Agent",
            "type": "ai_languageModel",
            "index": 0
          }
        ]
      ]
    },
    "Extract Run ID": {
      "main": [
        [
          {
            "node": "Wait 1 Minutes",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Run Status": {
      "main": [
        [
          {
            "node": "Check if Succeeded",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check if Succeeded": {
      "main": [
        [
          {
            "node": "Get Dataset Items",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait and Retry",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait and Retry": {
      "main": [
        [
          {
            "node": "Check Run Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Dataset Items": {
      "main": [
        [
          {
            "node": "normalize_job_data1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 1 Minutes": {
      "main": [
        [
          {
            "node": "Check Run Status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "filter_by_status": {
      "main": [
        [
          {
            "node": "get_unique_jobs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "generate_html_template": {
      "main": [
        [
          {
            "node": "Email the top job recommendations",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "update_job_status": {
      "main": [
        [
          {
            "node": "extract_update_operation",
            "type": "main",
            "index": 0
          },
          {
            "node": "extract_matched_jobs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Extract Run ID1": {
      "main": [
        [
          {
            "node": "Wait 1 Minutes1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check Run Status1": {
      "main": [
        [
          {
            "node": "Check if Succeeded1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check if Succeeded1": {
      "main": [
        [
          {
            "node": "Get Dataset Items1",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Wait and Retry1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait and Retry1": {
      "main": [
        [
          {
            "node": "Check Run Status1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Wait 1 Minutes1": {
      "main": [
        [
          {
            "node": "Check Run Status1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Get Dataset Items1": {
      "main": [
        [
          {
            "node": "normalize_job_data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "normalize_job_data": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "normalize_job_data1": {
      "main": [
        [
          {
            "node": "Merge",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge": {
      "main": [
        [
          {
            "node": "Supabase1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "start_apify_run_linkedin": {
      "main": [
        [
          {
            "node": "Extract Run ID",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "start_apify_run_indeed": {
      "main": [
        [
          {
            "node": "Extract Run ID1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Aggregate": {
      "main": [
        [
          {
            "node": "stringify_json",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "extract_update_operation": {
      "main": [
        [
          {
            "node": "Supabase_update_job_status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "extract_matched_jobs": {
      "main": [
        [
          {
            "node": "generate_html_template",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Input1": {
      "main": [
        [
          {
            "node": "get_job_id",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "active": true,
  "settings": {
    "executionOrder": "v1",
    "timezone": "Europe/Berlin",
    "callerPolicy": "workflowsFromSameOwner"
  },
  "versionId": "4b799270-9a76-45af-9cf6-34cc35b6b3bb",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "id": "hdtyEN3TSE5lcYuU",
  "tags": [
    {
      "createdAt": "2025-05-07T19:03:39.508Z",
      "updatedAt": "2025-05-07T19:03:39.508Z",
      "id": "aMCUQslRcX5XDhov",
      "name": "Linkedin"
    }
  ]
}