Spaces:
Sleeping
Sleeping
Resume analysis upgrade: structured CV↔JD analysis (sub-scores, matched/missing skills, experience, summary, verdict), .docx parsing, strong skills-based fallback; store full cv_analysis
46df6a4 | import uuid | |
| from datetime import datetime | |
| from services.db import applications_col | |
| import logging | |
| logger = logging.getLogger(__name__) | |
| def create_application(data): | |
| """ | |
| Create a new application record in database | |
| """ | |
| try: | |
| application = { | |
| "id": str(uuid.uuid4()), | |
| "job_id": data.get("job_id"), | |
| "user_id": data.get("user_id"), | |
| "candidate_name": data.get("candidate_name"), | |
| "candidate_email": data.get("candidate_email"), | |
| "cover_letter": data.get("cover_letter", ""), | |
| "resume_path": data.get("resume_path"), | |
| "cv_text": data.get("cv_text", ""), | |
| "cv_score": data.get("cv_score", 0), | |
| "cv_analysis": data.get("cv_analysis"), # full CV↔JD breakdown for recruiters | |
| "status": data.get("status", "pending"), | |
| "applied_at": data.get("applied_at", datetime.now().isoformat()), | |
| "updated_at": datetime.now().isoformat() | |
| } | |
| applications_col.insert_one(application) | |
| application.pop("_id", None) | |
| logger.info(f"✅ Application created: {application['id']} for user {application['user_id']}") | |
| return application | |
| except Exception as e: | |
| logger.error(f"Error creating application: {e}") | |
| raise e | |
| def get_applications_by_job(job_id): | |
| """ | |
| Get all applications for a specific job | |
| """ | |
| try: | |
| apps = list(applications_col.find({"job_id": job_id})) | |
| for app in apps: | |
| app.pop("_id", None) | |
| logger.info(f"Found {len(apps)} applications for job {job_id}") | |
| return apps | |
| except Exception as e: | |
| logger.error(f"Error getting applications by job: {e}") | |
| return [] | |
| def get_applications_by_user(user_id): | |
| """ | |
| Get all applications by a specific user (candidate) | |
| """ | |
| try: | |
| apps = list(applications_col.find({"user_id": user_id})) | |
| for app in apps: | |
| app.pop("_id", None) | |
| logger.info(f"Found {len(apps)} applications for user {user_id}") | |
| return apps | |
| except Exception as e: | |
| logger.error(f"Error getting applications by user: {e}") | |
| return [] | |
| def get_application_by_id(application_id): | |
| """ | |
| Get a single application by ID | |
| """ | |
| try: | |
| app = applications_col.find_one({"id": application_id}) | |
| if app: | |
| app.pop("_id", None) | |
| return app | |
| except Exception as e: | |
| logger.error(f"Error getting application: {e}") | |
| return None | |
| def update_status(application_id, new_status): | |
| """ | |
| Update the status of an application | |
| """ | |
| try: | |
| applications_col.update_one( | |
| {"id": application_id}, | |
| {"$set": { | |
| "status": new_status, | |
| "updated_at": datetime.now().isoformat() | |
| }} | |
| ) | |
| app = get_application_by_id(application_id) | |
| logger.info(f"✅ Application {application_id} status updated to {new_status}") | |
| return app | |
| except Exception as e: | |
| logger.error(f"Error updating application status: {e}") | |
| raise e | |
| def update_cv_score(application_id, cv_score): | |
| """ | |
| Update the CV score for an application | |
| """ | |
| try: | |
| applications_col.update_one( | |
| {"id": application_id}, | |
| {"$set": { | |
| "cv_score": cv_score, | |
| "updated_at": datetime.now().isoformat() | |
| }} | |
| ) | |
| logger.info(f"✅ CV score updated for {application_id}: {cv_score}%") | |
| return get_application_by_id(application_id) | |
| except Exception as e: | |
| logger.error(f"Error updating CV score: {e}") | |
| raise e | |
| def get_applications_by_company(company_id): | |
| """ | |
| Get all applications for jobs posted by a company | |
| This requires joining with jobs collection | |
| """ | |
| try: | |
| from services.job_manager import get_jobs_by_company | |
| company_jobs = get_jobs_by_company(company_id) | |
| job_ids = [job["id"] for job in company_jobs] | |
| apps = list(applications_col.find({"job_id": {"$in": job_ids}})) | |
| for app in apps: | |
| app.pop("_id", None) | |
| logger.info(f"Found {len(apps)} applications for company {company_id}") | |
| return apps | |
| except Exception as e: | |
| logger.error(f"Error getting applications by company: {e}") | |
| return [] |