Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/abhinavsingh1311_projects.json
T
OpenCode 68a9071cf1 feat: reconcile local master with origin (exa/hot-platform hunters, leaks ledger, latest results)
Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
2026-08-07 12:53:47 +08:00

1 line
16 KiB
JSON

{"repo": "abhinavsingh1311/projects", "files": {"resume-scanner/src/server/services/jobMatcher.js": {"dfdc9454b9de2fb90d17cd48d79c47c234b68f8c": {"t": 1786068268.833534, "n": 15695, "h": "88a5bb4ff5313aa2", "c": "// src/server/services/jobMatcher.js - Updated to use OpenAI directly\nconst { OpenAI } = require('openai');\n// const { DeepSeekAPI } = import('deepseek-api');\n\nconst { supabaseAdmin } = require('../config/database_connection');\n\n// Initialize OpenAI client with API key from environment variables\nconst openai = new OpenAI({\n baseURL: 'https://api.deepseek.com/v1',\n apiKey: process.env.DEEPSEEK_API_KEY,\n});\n\n/**\n * Find job matches for a resume based on skills using OpenAI\n * @param {string} resumeId - Resume ID\n * @returns {Promise<Object>} - Matching results\n */\nasync function findJobMatches(resumeId) {\n try {\n console.log(`Finding job matches for resume ID: ${resumeId}`);\n\n // Get resume information\n const { data: resume, error: resumeError } = await supabaseAdmin\n .from('resumes')\n .select('id, title, status')\n .eq('id', resumeId)\n .single();\n\n if (resumeError) {\n throw new Error(`Resume not found: ${resumeError.message}`);\n }\n\n // Get resume's parsed data\n const { data: parsedData, error: parsedError } = await supabaseAdmin\n .from('resume_parsed_data')\n .select('raw_text, parsed_data')\n .eq('resume_id', resumeId)\n .single();\n\n if (parsedError) {\n throw new Error(`Parsed data not found: ${parsedError.message}`);\n }\n\n // Get resume's analysis\n const { data: analysis, error: analysisError } = await supabaseAdmin\n .from('resume_analysis')\n .select('analysis_json')\n .eq('resume_id', resumeId)\n .order('created_at', { ascending: false })\n .limit(1)\n .maybeSingle();\n\n // Get all the skills associated with this resume\n const { data: resumeSkills, error: skillsError } = await supabaseAdmin\n .from('resume_skills')\n .select(`\n skill_id,\n level,\n skills(id, name, category)\n `)\n .eq('resume_id', resumeId);\n\n if (skillsError) {\n console.warn('Error getting resume skills:', skillsError);\n }\n\n // Extract skills from various sources\n let skills = [];\n\n // From resume_skills table\n if (resumeSkills && resumeSkills.length > 0) {\n skills = resumeSkills.map(rs => rs.skills.name);\n }\n\n // Add skills from the analysis if they're not already in our list\n if (analysis && analysis.analysis_json && analysis.analysis_json.skills) {\n const allAnalysisSkills = [\n ...(analysis.analysis_json.skills.technical || []),\n ...(analysis.analysis_json.skills.soft || []),\n ...(analysis.analysis_json.skills.tools || [])\n ];\n\n // Get existing skill names\n const existingSkillNames = skills.map(s => s.toLowerCase());\n\n // Add new skills from analysis\n for (const skillName of allAnalysisSkills) {\n if (!existingSkillNames.includes(skillName.toLowerCase())) {\n skills.push(skillName);\n }\n }\n }\n\n // If we still don't have skills, extract them directly from parsed text\n if (skills.length === 0 && parsedData.raw_text) {\n console.log(\"No skills found, extracting directly from resume text...\");\n\n // Use OpenAI to extract skills\n const extractionResponse = await openai.chat.completions.create({\n model: process.env.DEEPSEEK_MODEL || \"deepseek-chat\",\n messages: [\n {\n role: 'system',\n content: `You are a skilled resume parser. Extract all professional skills from the provided resume text. \n Return the skills as a comma-separated list of single words or short phrases. Include technical skills, \n soft skills, tools, programming languages, and other job-relevant competencies.`\n },\n {\n role: 'user',\n content: parsedData.raw_text.substring(0, 4000) // Limit to prevent token issues\n }\n ],\n temperature: 0.3,\n });\n\n const extractedSkillsText = extractionResponse.choices[0].message.content;\n skills = extractedSkillsText.split(',').map(s => s.trim()).filter(s => s);\n console.log(`Extracted ${skills.length} skills directly from resume text`);\n }\n\n if (skills.length === 0) {\n throw new Error(\"No skills found in the resume. Cannot find job matches without skills.\");\n }\n\n console.log(`Found ${skills.length} skills to use for job matching`);\n console.log(\"Skills:\", skills.join(\", \"));\n\n // Get job matches using OpenAI\n const jobMatchResponse = await openai.chat.completions.create({\n model: process.env.DEEPSEEK_MODEL || 'deepseek-chat',\n messages: [\n {\n role: 'system',\n content: `You are an expert job matching system. Based on a candidate's skills and experience, provide \n 5-7 realistic job matches that would be suitable. Format your response as a JSON array with the following structure:\n \n [\n {\n \"title\": \"Job Title\",\n \"company\": \"Company Name\",\n \"location\": \"Location (city or Remote)\",\n \"jobType\": \"Full-time/Part-time/Contract\",\n \"description\": \"Brief job description\",\n \"requirements\": \"Key requirements for the role\",\n \"matchingSkills\": [\"Skill1\", \"Skill2\", \"Skill3\"], // Skills from the resume that match this job\n \"missingSkills\": [\"Skill4\", \"Skill5\"], // Important skills for this job that aren't in the resume\n \"salaryRange\": \"$X - $Y\",\n \"score\": 85, // Match percentage (1-100)\n \"url\": \"https://example.com/job-posting\" // Include a realistic job board URL (LinkedIn, Indeed, etc.)\n }\n ]\n \n Make each job realistic and well-matched to the provided skills. For URLs, use realistic job board domains \n like linkedin.com/jobs, indeed.com, glassdoor.com, etc. with paths that look like real job listings.`\n },\n {\n role: 'user',\n content: `These are my skills: ${skills.join(\", \")}\n \n ${analysis && analysis.analysis_json && analysis.analysis_json.experience_summary ?\n `My experience: ${analysis.analysis_json.experience_summary}` : ''}\n \n Please find 5-7 suitable job matches. Return only the JSON array.`\n }\n ],\n temperature: 0.7,\n response_format: { type: \"json_object\" }\n });\n\n // Parse and process the job matches\n let jsonContent = jobMatchResponse.choices[0].message.content;\n let jobMatches;\n\n try {\n // Handle case where response might not be properly formatted\n const jsonObject = JSON.parse(jsonContent);\n jobMatches = Array.isArray(jsonObject) ? jsonObject :\n (jsonObject.jobs || jsonObject.matches || []);\n } catch (jsonError) {\n console.error(\"Error parsing JSON from OpenAI:\", jsonError);\n // Try to extract JSON from the text if it's not properly formatted\n const jsonMatch = jsonContent.match(/\\[\\s*\\{.*\\}\\s*\\]/s);\n if (jsonMatch) {\n try {\n jobMatches = JSON.parse(jsonMatch[0]);\n } catch (e) {\n throw new Error(\"Failed to parse job matches from OpenAI response\");\n }\n } else {\n throw new Error(\"Invalid response format from OpenAI\");\n }\n }\n\n // Store the job matches in the database\n console.log(`Storing ${jobMatches.length} job matches for resume ${resumeId}`);\n\n // Clear existing matches first\n await supabaseAdmin\n .from('job_matches')\n .delete()\n .eq('resume_id', resumeId);\n\n // Process and store each job match\n for (const match of jobMatches) {\n // In the job storage section of findJobMatches\n const { data: jobData, error: jobError } = await supabaseAdmin\n .from('jobs')\n .upsert({\n title: match.title,\n company_name: match.company,\n location: match.location || 'Remote',\n job_types: match.jobType || 'Full-time',\n description: match.description || '',\n requirements: match.requirements || '',\n salary_min: parseInt(match.salaryRange?.split('-')[0]?.replace(/\\D/g, '') || 0),\n salary_max: parseInt(match.salaryRange?.split('-')[1]?.replace(/\\D/g, '') || 0),\n url: match.url || `https://www.linkedin.com/jobs/search/?keywords=${encodeURIComponent(match.title)}`, // Default URL if none provided\n source: 'openai',\n created_at: new Date().toISOString(),\n updated_at: new Date().toISOString()\n }, {\n onConflict: 'title,company_name',\n ignoreDuplicates: false\n })\n .select('id')\n .single();\n\n if (jobError) {\n console.warn(`Warning: Failed to store job \"${match.title}\":`, jobError);\n continue;\n }\n\n // Then store the match\n const { error: matchError } = await supabaseAdmin\n .from('job_matches')\n .insert({\n resume_id: resumeId,\n job_id: jobData.id,\n match_score: match.score || 0,\n match_details: {\n matchingSkills: match.matchingSkills || [],\n missingSkills: match.missingSkills || [],\n skillMatch: match.score || 0,\n keywordMatch: 0,\n aiGenerated: true\n },\n created_at: new Date().toISOString()\n });\n\n if (matchError) {\n console.warn(`Warning: Failed to store job match for \"${match.title}\":`, matchError);\n }\n }\n\n return {\n success: true,\n resumeId,\n matchCount: jobMatches.length,\n topMatchScore: Math.max(...jobMatches.map(m => m.score || 0), 0),\n message: `Found ${jobMatches.length} job matches`\n };\n } catch (error) {\n console.error('Error finding job matches:', error);\n return {\n success: false,\n error: error.message || 'Unknown error finding job matches'\n };\n }\n}\n\n/**\n * Analyze job match using AI for more detailed insights\n * @param {string} resumeId - Resume ID\n * @param {string} jobId - Job ID\n * @returns {Promise<Object>} - Detailed AI analysis of match\n */\nasync function analyzeJobMatchWithAI(resumeId, jobId) {\n try {\n // Get resume text\n const { data: resumeData, error: resumeError } = await supabaseAdmin\n .from('resume_parsed_data')\n .select('raw_text')\n .eq('resume_id', resumeId)\n .single();\n\n if (resumeError) {\n throw new Error(`Resume text not found: ${resumeError.message}`);\n }\n\n // Get job data\n const { data: job, error: jobError } = await supabaseAdmin\n .from('jobs')\n .select('*')\n .eq('id', jobId)\n .single();\n\n if (jobError) {\n throw new Error(`Job not found: ${jobError.message}`);\n }\n\n // Use OpenAI to analyze the match\n const response = await openai.chat.completions.create({\n model: process.env.DEEPSEEK_MODEL || \"deepseek-chat\",\n messages: [\n {\n role: 'system',\n content: `You are an expert resume reviewer with deep knowledge of job matching. \n Analyze how well a resume matches a job description and provide a detailed report in JSON format.`\n },\n {\n role: 'user',\n content: `I need a detailed match analysis between this resume and job.\n \n RESUME:\n ${resumeData.raw_text.substring(0, 4000)}\n \n JOB DESCRIPTION:\n Title: ${job.title}\n Company: ${job.company_name}\n Description: ${job.description}\n \n Provide a detailed analysis of how well this resume matches the job requirements. Return your analysis in this JSON format:\n {\n \"matchPercentage\": number (0-100),\n \"overallAssessment\": string,\n \"strengths\": string[],\n \"gaps\": string[],\n \"recommendations\": string[],\n \"keySkillsPresent\": string[],\n \"keySkillsMissing\": string[],\n \"experienceAlignment\": {\n \"score\": number (0-100),\n \"assessment\": string\n },\n \"educationAlignment\": {\n \"score\": number (0-100),\n \"assessment\": string\n },\n \"culturalFit\": {\n \"score\": number (0-100),\n \"assessment\": string\n }\n }`\n }\n ],\n temperature: 0.2,\n response_format: { type: \"json_object\" }\n });\n\n // Parse the response\n const analysisResult = JSON.parse(response.choices[0].message.content);\n\n // Save the enhanced analysis to the database\n await supabaseAdmin\n .from('job_matches')\n .update({\n match_score: analysisResult.matchPercentage,\n match_details: {\n ...analysisResult,\n aiGenerated: true,\n analyzedAt: new Date().toISOString()\n }\n })\n .eq('resume_id', resumeId)\n .eq('job_id', jobId);\n\n return {\n success: true,\n resumeId,\n jobId,\n analysis: analysisResult\n };\n } catch (error) {\n console.error('Error analyzing job match with AI:', error);\n return {\n success: false,\n error: error.message || 'Unknown error analyzing job match'\n };\n }\n}\n\n/**\n * Gets potential jobs based on resume skills\n * @param {string} resumeId - Resume ID\n * @returns {Promise<Object>} - Potential jobs\n */\nasync function getPotentialJobs(resumeId) {\n // We'll directly use findJobMatches since we're now using OpenAI for job matching\n return findJobMatches(resumeId);\n}\n\nmodule.exports = {\n findJobMatches,\n analyzeJobMatchWithAI,\n getPotentialJobs\n};"}}}}