Spaces:
Sleeping
Sleeping
| import os | |
| import json | |
| import numpy as np | |
| from typing import List, Dict, Any | |
| from google import genai | |
| import google.genai.types as types | |
| from src.embeddings.local_embedder import generate_embedding, generate_list_embedding, get_model | |
| # Initialize Gemini Client | |
| client = genai.Client(api_key="AIzaSyB2Dw-nep3SwQav5S_1qJ2FoVc4I83a2yk") | |
| def cosine_similarity(v1, v2): | |
| v1 = np.array(v1) | |
| v2 = np.array(v2) | |
| return np.dot(v1, v2) / (np.linalg.norm(v1) * np.linalg.norm(v2)) | |
| def identify_missing_skills(job_skills: List[str], profile_skills: List[str], threshold: float = 0.7) -> List[str]: | |
| """ | |
| Identifies skills required by the job but missing (semantically) in the profile. | |
| """ | |
| if not job_skills: | |
| return [] | |
| if not profile_skills: | |
| return job_skills | |
| # Generate embeddings for profile skills | |
| model = get_model() | |
| profile_embeddings = model.encode(profile_skills, normalize_embeddings=True) | |
| job_embeddings = model.encode(job_skills, normalize_embeddings=True) | |
| missing_skills = [] | |
| for i, job_skill in enumerate(job_skills): | |
| job_vec = job_embeddings[i] | |
| # Find max similarity with any profile skill | |
| similarities = [np.dot(job_vec, prof_vec) for prof_vec in profile_embeddings] | |
| max_sim = max(similarities) if similarities else 0 | |
| if max_sim < threshold: | |
| missing_skills.append(job_skill) | |
| return missing_skills | |
| def generate_ai_analysis(profile_text: str, job_description: str) -> Dict[str, Any]: | |
| """ | |
| Uses Gemini to generate a professional summary and evaluation. | |
| """ | |
| system_prompt = """ | |
| You are an expert HR Analyst. Analyze the provided candidate resume text against the job description. | |
| Return a JSON object with: | |
| - "summary": A 2-3 sentence professional summary of why the candidate is or isn't a good fit. | |
| - "strengths": A list of top 3 core strengths matching the job. | |
| - "weaknesses": A list of top 2-3 areas for improvement or missing qualifications. | |
| - "score": An overall suitability score from 0 to 100 based on their experience and skills relative to the job requirements. | |
| Be objective, professional, and concise. | |
| """ | |
| user_content = f"JOB DESCRIPTION:\n{job_description}\n\nCANDIDATE RESUME:\n{profile_text}" | |
| try: | |
| response = client.models.generate_content( | |
| model="gemini-2.5-flash-lite", # Updated to confirmed model name | |
| contents=system_prompt + "\n\n" + user_content, | |
| config=types.GenerateContentConfig( | |
| temperature=0.2, | |
| response_mime_type="application/json" | |
| ) | |
| ) | |
| return json.loads(response.text) | |
| except Exception as e: | |
| print(f"❌ AI Analysis failed: {e}") | |
| return { | |
| "summary": "Analysis currently unavailable.", | |
| "strengths": [], | |
| "weaknesses": [], | |
| "score": 0 | |
| } | |