File size: 6,327 Bytes
0b6ad4c
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
"""
Utility Functions
Helper functions for the Resume Analyzer system.
"""

import os
import json
import hashlib
from datetime import datetime
from typing import Any, Dict, List
import logging
from pathlib import Path

logger = logging.getLogger(__name__)


def setup_logging(log_file: str = "logs/app.log", level: str = "INFO"):
    """
    Setup logging configuration.
    
    Args:
        log_file: Path to log file
        level: Logging level
    """
    # Create logs directory if it doesn't exist
    log_dir = os.path.dirname(log_file)
    if log_dir and not os.path.exists(log_dir):
        os.makedirs(log_dir)
    
    logging.basicConfig(
        level=getattr(logging, level),
        format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
        handlers=[
            logging.FileHandler(log_file),
            logging.StreamHandler()
        ]
    )
    logger.info("Logging initialized")


def save_json(data: Dict, filepath: str):
    """
    Save data to JSON file.
    
    Args:
        data: Dictionary to save
        filepath: Output file path
    """
    try:
        os.makedirs(os.path.dirname(filepath), exist_ok=True)
        with open(filepath, 'w', encoding='utf-8') as f:
            json.dump(data, f, indent=2, ensure_ascii=False)
        logger.info(f"Saved data to {filepath}")
    except Exception as e:
        logger.error(f"Failed to save JSON: {e}")
        raise


def load_json(filepath: str) -> Dict:
    """
    Load data from JSON file.
    
    Args:
        filepath: Input file path
        
    Returns:
        Loaded dictionary
    """
    try:
        with open(filepath, 'r', encoding='utf-8') as f:
            data = json.load(f)
        logger.info(f"Loaded data from {filepath}")
        return data
    except Exception as e:
        logger.error(f"Failed to load JSON: {e}")
        raise


def generate_file_hash(filepath: str) -> str:
    """
    Generate MD5 hash of file.
    
    Args:
        filepath: Path to file
        
    Returns:
        MD5 hash string
    """
    hash_md5 = hashlib.md5()
    with open(filepath, "rb") as f:
        for chunk in iter(lambda: f.read(4096), b""):
            hash_md5.update(chunk)
    return hash_md5.hexdigest()


def log_analysis(
    resume_name: str, 
    ats_score: float, 
    match_score: float = None,
    log_file: str = "logs/analysis_log.jsonl"
):
    """
    Log analysis results for monitoring.
    
    Args:
        resume_name: Name of resume file
        ats_score: ATS compatibility score
        match_score: Job match score (optional)
        log_file: Path to log file
    """
    log_entry = {
        'timestamp': datetime.now().isoformat(),
        'resume_name': resume_name,
        'ats_score': ats_score,
        'match_score': match_score,
    }
    
    try:
        os.makedirs(os.path.dirname(log_file), exist_ok=True)
        with open(log_file, 'a', encoding='utf-8') as f:
            f.write(json.dumps(log_entry) + '\n')
    except Exception as e:
        logger.error(f"Failed to log analysis: {e}")


def format_skills_list(skills_dict: Dict[str, List[str]]) -> str:
    """
    Format skills dictionary into readable string.
    
    Args:
        skills_dict: Dictionary of categorized skills
        
    Returns:
        Formatted string
    """
    formatted = []
    for category, skills in skills_dict.items():
        category_name = category.replace('_', ' ').title()
        skills_str = ', '.join(skills)
        formatted.append(f"**{category_name}**: {skills_str}")
    
    return '\n'.join(formatted)


def truncate_text(text: str, max_length: int = 100) -> str:
    """
    Truncate text to maximum length.
    
    Args:
        text: Input text
        max_length: Maximum length
        
    Returns:
        Truncated text
    """
    if len(text) <= max_length:
        return text
    return text[:max_length-3] + '...'


def validate_file_upload(file_path: str, max_size_mb: int = 10) -> bool:
    """
    Validate uploaded file.
    
    Args:
        file_path: Path to file
        max_size_mb: Maximum file size in MB
        
    Returns:
        True if valid, raises exception otherwise
    """
    if not os.path.exists(file_path):
        raise FileNotFoundError(f"File not found: {file_path}")
    
    # Check file size
    file_size_mb = os.path.getsize(file_path) / (1024 * 1024)
    if file_size_mb > max_size_mb:
        raise ValueError(f"File too large: {file_size_mb:.1f}MB (max: {max_size_mb}MB)")
    
    # Check file extension
    valid_extensions = ['.pdf', '.docx', '.txt']
    file_ext = os.path.splitext(file_path)[1].lower()
    if file_ext not in valid_extensions:
        raise ValueError(f"Invalid file type: {file_ext}")
    
    return True


def create_result_summary(analysis_results: Dict) -> str:
    """
    Create a summary of analysis results.
    
    Args:
        analysis_results: Complete analysis dictionary
        
    Returns:
        Formatted summary string
    """
    summary_parts = []
    
    # ATS Score
    if 'ats_score' in analysis_results:
        ats = analysis_results['ats_score']
        summary_parts.append(
            f"📊 **ATS Score**: {ats.get('overall_score', 0)}/100 "
            f"(Grade: {ats.get('grade', 'N/A')})"
        )
    
    # Skills
    if 'skills' in analysis_results:
        total_skills = sum(
            len(skills) for skills in analysis_results['skills'].values()
        )
        summary_parts.append(f"🎯 **Skills Found**: {total_skills}")
    
    # Experience
    if 'experience_years' in analysis_results:
        summary_parts.append(
            f"💼 **Experience**: ~{analysis_results['experience_years']} years"
        )
    
    # Job Matches
    if 'job_matches' in analysis_results and analysis_results['job_matches']:
        top_match = analysis_results['job_matches'][0]
        summary_parts.append(
            f"🎯 **Top Match**: {top_match['job']['title']} "
            f"({top_match['match_percentage']:.0f}% match)"
        )
    
    return '\n'.join(summary_parts)


def get_timestamp() -> str:
    """Get current timestamp string."""
    return datetime.now().strftime('%Y-%m-%d %H:%M:%S')


def ensure_dir(directory: str):
    """Ensure directory exists."""
    Path(directory).mkdir(parents=True, exist_ok=True)