{ "name": "CV Interview Assistant", "nodes": [ { "parameters": { "httpMethod": "POST", "path": "cv-analysis", "responseMode": "responseNode", "options": {} }, "id": "f8b4c5d6-7890-1234-5678-90abcdef1234", "name": "Webhook", "type": "n8n-nodes-base.webhook", "typeVersion": 1.1, "position": [240, 300], "webhookId": "cv-analysis-webhook" }, { "parameters": { "jsCode": "// Extract and structure CV data for AI processing\nconst input = $input.first().json;\nconst cvProfile = input.cvProfile || {};\nconst personalInfo = cvProfile.personalInfo || {};\nconst skills = cvProfile.skills || [];\nconst experience = cvProfile.experience || [];\nconst education = cvProfile.education || [];\n\n// Extract key information\nconst candidateName = personalInfo.fullName || 'Candidate';\nconst skillNames = skills.map(s => s.name).filter(Boolean);\nconst technicalSkills = skills.filter(s => s.category === 'technical').map(s => s.name);\nconst yearsExperience = Math.max(...skills.map(s => s.yearsOfExperience || 0), 0);\nconst totalPositions = experience.length;\nconst educationLevel = education.length > 0 ? education[0].degree : 'Not specified';\n\n// Create structured prompt data\nconst promptData = {\n analysisId: input.analysisId,\n candidateName: candidateName,\n email: personalInfo.email || '',\n skills: skillNames,\n technicalSkills: technicalSkills,\n yearsExperience: yearsExperience,\n totalPositions: totalPositions,\n educationLevel: educationLevel,\n fullCvText: cvProfile.parsedText || '',\n experienceSummary: experience.map(exp => `${exp.jobTitle} at ${exp.company} (${exp.duration})`).join('; '),\n skillsSummary: skills.map(s => `${s.name}${s.yearsOfExperience ? ` (${s.yearsOfExperience} years)` : ''}`).join(', ')\n};\n\nreturn [{ json: promptData }];" }, "id": "a1b2c3d4-5678-9012-3456-789abcdef012", "name": "Extract CV Data", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [460, 300] }, { "parameters": { "resource": "chat", "operation": "create", "model": "gpt-4", "messages": { "values": [ { "role": "system", "content": "You are an expert interview question generator. Create relevant, insightful interview questions based on the candidate's CV profile." }, { "role": "user", "content": "Generate 10 diverse interview questions for this candidate profile:\n\n**Candidate:** {{$json.candidateName}}\n**Email:** {{$json.email}}\n**Experience:** {{$json.yearsExperience}} years total, {{$json.totalPositions}} positions\n**Education:** {{$json.educationLevel}}\n**Technical Skills:** {{$json.technicalSkills.join(', ')}}\n**All Skills:** {{$json.skillsSummary}}\n**Experience Summary:** {{$json.experienceSummary}}\n\n**Full CV Content:**\n{{$json.fullCvText}}\n\n---\n\nGenerate exactly 10 questions covering:\n- 4 Technical questions (specific to their skills/experience)\n- 3 Behavioral questions (leadership, teamwork, problem-solving)\n- 2 Scenario-based questions (hypothetical situations)\n- 1 Career/Growth question\n\nReturn ONLY a valid JSON array with this exact format:\n```json\n[\n {\n \"id\": 1,\n \"question\": \"Detailed question text here\",\n \"category\": \"technical\",\n \"difficulty\": \"medium\",\n \"expectedSkills\": [\"JavaScript\", \"Problem Solving\"],\n \"reasoning\": \"Why this question is relevant to the candidate\"\n }\n]\n```\n\nEnsure questions are:\n- Specific to the candidate's actual experience\n- Appropriate difficulty level\n- Clear and actionable\n- Professional and respectful" } ] }, "options": { "temperature": 0.7, "maxTokens": 2000 } }, "id": "b2c3d4e5-6789-0123-4567-89abcdef0123", "name": "Generate Questions (OpenAI)", "type": "n8n-nodes-base.openAi", "typeVersion": 1.3, "position": [680, 300] }, { "parameters": { "jsCode": "// Parse and validate AI response\nconst aiResponse = $input.first().json.choices[0].message.content;\nconst extractData = $('Extract CV Data').first().json;\n\ntry {\n // Extract JSON from AI response (handle markdown code blocks)\n let jsonStr = aiResponse;\n if (aiResponse.includes('```json')) {\n const start = aiResponse.indexOf('```json') + 7;\n const end = aiResponse.lastIndexOf('```');\n jsonStr = aiResponse.substring(start, end).trim();\n }\n \n const questions = JSON.parse(jsonStr);\n \n // Validate and enhance questions\n const validatedQuestions = questions.map((q, index) => ({\n id: q.id || (index + 1),\n question: q.question || 'Question not generated',\n category: q.category || 'general',\n difficulty: q.difficulty || 'medium',\n expectedSkills: Array.isArray(q.expectedSkills) ? q.expectedSkills : [],\n reasoning: q.reasoning || 'Standard interview question',\n generatedAt: new Date().toISOString()\n }));\n \n // Generate question bank ID\n const questionBankId = `qb_${extractData.analysisId}_${Date.now()}`;\n \n return [{\n json: {\n status: 'completed',\n analysisId: extractData.analysisId,\n questionBankId: questionBankId,\n questionsGenerated: validatedQuestions.length,\n candidateName: extractData.candidateName,\n questions: validatedQuestions,\n metadata: {\n skillsAnalyzed: extractData.skills.length,\n experienceYears: extractData.yearsExperience,\n processingTime: new Date().toISOString()\n }\n }\n }];\n \n} catch (error) {\n // Handle parsing errors gracefully\n return [{\n json: {\n status: 'failed',\n analysisId: extractData.analysisId,\n error: 'Failed to generate questions',\n errorDetails: error.message,\n fallbackQuestions: [\n {\n id: 1,\n question: `Tell me about your experience with ${extractData.technicalSkills[0] || 'your main technology stack'}.`,\n category: 'technical',\n difficulty: 'medium',\n expectedSkills: extractData.technicalSkills.slice(0, 2),\n reasoning: 'Fallback technical question'\n },\n {\n id: 2,\n question: 'Describe a challenging project you worked on and how you overcame obstacles.',\n category: 'behavioral',\n difficulty: 'medium',\n expectedSkills: ['Problem Solving', 'Communication'],\n reasoning: 'Fallback behavioral question'\n }\n ]\n }\n }];\n}" }, "id": "c3d4e5f6-7890-1234-5678-9abcdef01234", "name": "Process AI Response", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [900, 300] }, { "parameters": { "respondWith": "json", "responseBody": "={{$json}}", "options": { "responseHeaders": { "entries": [ { "name": "Content-Type", "value": "application/json" }, { "name": "Access-Control-Allow-Origin", "value": "*" }, { "name": "Access-Control-Allow-Methods", "value": "POST, OPTIONS" }, { "name": "Access-Control-Allow-Headers", "value": "Content-Type, Authorization" } ] } } }, "id": "d4e5f6g7-8901-2345-6789-abcdef012345", "name": "Return Response", "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.1, "position": [1120, 300] }, { "parameters": { "conditions": { "options": { "caseSensitive": true, "leftValue": "", "typeValidation": "strict" }, "conditions": [ { "id": "error-condition", "leftValue": "={{$json.status}}", "rightValue": "failed", "operator": { "type": "string", "operation": "equals" } } ], "combinator": "and" }, "options": {} }, "id": "e5f6g7h8-9012-3456-7890-bcdef0123456", "name": "Check for Errors", "type": "n8n-nodes-base.if", "typeVersion": 2, "position": [1120, 480] } ], "connections": { "Webhook": { "main": [ [ { "node": "Extract CV Data", "type": "main", "index": 0 } ] ] }, "Extract CV Data": { "main": [ [ { "node": "Generate Questions (OpenAI)", "type": "main", "index": 0 } ] ] }, "Generate Questions (OpenAI)": { "main": [ [ { "node": "Process AI Response", "type": "main", "index": 0 } ] ] }, "Process AI Response": { "main": [ [ { "node": "Return Response", "type": "main", "index": 0 } ] ] } }, "pinData": {}, "settings": { "executionOrder": "v1" }, "staticData": null, "tags": [ { "id": "interview-assistant", "name": "Interview Assistant" } ], "triggerCount": 1, "updatedAt": "2025-09-16T22:00:00.000Z", "versionId": "1" }