from django.db.models.signals import post_save from django.dispatch import receiver from . import models # @receiver(post_save, sender=models.Candidate) # def parse_resume(sender, instance, created, **kwargs): # if instance.resume and not instance.summary: # from .utils import extract_summary_from_pdf,match_resume_with_job_description # summary = extract_summary_from_pdf(instance.resume.path) # if 'error' not in summary: # instance.summary = summary # instance.save() # match_resume_with_job_description import logging logger = logging.getLogger(__name__) import os from .utils import extract_text_from_pdf,score_resume_with_openrouter @receiver(post_save, sender=models.Candidate) def score_candidate_resume(sender, instance, created, **kwargs): # Skip if no resume or OpenRouter not configured if instance.resume is None: return if kwargs.get('update_fields') is not None: return # Optional: Only re-score if resume changed (advanced: track file hash) # For simplicity, we score on every save with a resume try: # Get absolute file path file_path = instance.resume.path if not os.path.exists(file_path): logger.warning(f"Resume file not found: {file_path}") return resume_text = extract_text_from_pdf(file_path) # if not resume_text: # instance.scoring_error = "Could not extract text from resume." # instance.save(update_fields=['scoring_error']) # return result = score_resume_with_openrouter(resume_text) # Update candidate with scoring results instance.match_score = result.get('match_score') instance.strengths = result.get('strengths', '') instance.weaknesses = result.get('weaknesses', '') instance.criteria_checklist = result.get('criteria_checklist', {}) # Save only scoring-related fields to avoid recursion instance.save(update_fields=[ 'match_score', 'strengths', 'weaknesses', 'criteria_checklist' ]) logger.info(f"Successfully scored resume for candidate {instance.id}") except Exception as e: # error_msg = str(e)[:500] # Truncate to fit TextField # instance.scoring_error = error_msg # instance.save(update_fields=['scoring_error']) logger.error(f"Failed to score resume for candidate {instance.id}: {e}")