File size: 4,198 Bytes
97cdcdc
 
51c72d3
97cdcdc
 
51c72d3
97cdcdc
 
 
 
 
 
 
 
 
505be46
97cdcdc
51c72d3
9281337
97cdcdc
 
 
 
 
 
 
 
29fc8f7
97cdcdc
 
1f85315
29fc8f7
1f85315
29fc8f7
1f85315
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
505be46
1f85315
 
 
 
 
 
29fc8f7
 
 
d91db4a
29fc8f7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d91db4a
29fc8f7
 
 
 
1f85315
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
import os
import json
import re
import logging
import fitz  # PyMuPDF
import google.generativeai as genai
from dotenv import load_dotenv

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

load_dotenv()

api_key = os.getenv("GEMINI_API_KEY")
if not api_key:
    raise ValueError("GEMINI_API_KEY is missing.")

genai.configure(api_key=api_key)

def extract_text_from_stream(file_bytes: bytes) -> str:
    text = ""
    try:
        with fitz.open(stream=file_bytes, filetype="pdf") as doc:
            for page in doc:
                text += page.get_text()
    except Exception as e:
        logger.error(f"PDF Extraction Error: {e}")
        raise ValueError("Failed to extract text from PDF.")
    return text

def get_available_model_name():
    """
    Dynamically finds a working model from the user's account.
    """
    try:
        available_models = []
        for m in genai.list_models():
            if 'generateContent' in m.supported_generation_methods:
                available_models.append(m.name)
        
        if not available_models:
            logger.error("No models found.")
            return None

        # Priority list: Try to find these specific powerful models first
        preferred_order = [
            "models/gemini-1.5-flash",
            "models/gemini-1.5-pro",
            "models/gemini-pro",
            "models/gemini-1.0-pro"
        ]
        
        # 1. Check if any preferred model is in the available list
        for preferred in preferred_order:
            if preferred in available_models:
                logger.info(f"Selected Preferred Model: {preferred}")
                return preferred

        # 2. If none of the preferred ones exist, take the first available one
        fallback = available_models[0]
        logger.warning(f"Preferred models missing. Falling back to: {fallback}")
        return fallback

    except Exception as e:
        logger.error(f"Error listing models: {e}")
        return None

def analyze_resume(resume_text: str, job_description: str = None) -> dict:
    
    # 1. FIND A WORKING MODEL (The Critical Fix)
    model_name = get_available_model_name()
    if not model_name:
        return {"error": "CRITICAL: No available AI models found for this API Key."}

    # 2. CONSTRUCT PROMPT
    if job_description:
        prompt = f"""
        Act as a strict AI Recruiter. Compare the Resume against the Job Description.
        
        RETURN JSON ONLY with this exact structure:
        {{
            "candidate": {{
                "name": "string",
                "email": "string",
                "phone": "string",
                "skills": ["list", "of", "candidate", "skills"],
                "experience_years": "string or null"
            }},
            "match_analysis": {{
                "score": integer_0_to_100,
                "reasoning": "brief summary of why this score was given",
                "matching_skills": ["skills in both resume and JD"],
                "missing_skills": ["skills in JD but NOT in resume"],
                "verdict": "Interview" | "Shortlist" | "Reject"
            }}
        }}

        JOB DESCRIPTION:
        {job_description[:5000]}

        RESUME TEXT:
        {resume_text[:10000]}
        """
    else:
        prompt = f"""
        Extract structured data from the resume. Return JSON:
        {{
            "candidate": {{
                "name": "string",
                "email": "string",
                "phone": "string",
                "skills": ["list", "of", "skills"],
                "summary": "string"
            }}
        }}
        
        RESUME TEXT:
        {resume_text[:10000]}
        """

    # 3. GENERATE CONTENT
    try:
        model = genai.GenerativeModel(model_name)
        response = model.generate_content(prompt)
        
        raw = response.text.strip()
        clean_json = re.sub(r'```json\s*|```', '', raw, flags=re.MULTILINE).strip()
        return json.loads(clean_json)
        
    except Exception as e:
        logger.error(f"Analysis failed with model {model_name}: {e}")
        return {"error": f"Analysis failed using {model_name}. Detail: {str(e)}"}