resume-analyzer / engine /__init__.py
mohit kumar
Initial Resume Analyzer deploy
a4db4ad
Raw History Blame Contribute Delete
8.62 kB
# =============================================================================
# engine/__init__.py β€” Resume Engine Package Initialiser
# =============================================================================
# PURPOSE:
# Makes engine/ a proper Python package.
# Exposes all public functions from every module in one clean import.
#
# BENEFIT β€” instead of writing this in main.py:
# from engine.parser import load_resumes_from_folder
# from engine.database import init_db, insert_resume
# from engine.extractor import build_resume_record
# ... (7 separate import lines)
#
# You can write this:
# from engine import load_resumes_from_folder, init_db, build_resume_record
#
# STATUS LEGEND (updated as each step is completed):
# βœ… Built and tested
# πŸ”² Not built yet β€” imported conditionally so missing modules don't crash
#
# MODULES:
# βœ… parser.py Step 3 β€” PDF/DOCX text extraction
# βœ… database.py Step 2 β€” SQLite read/write operations
# πŸ”² extractor.py Step 4 β€” Structured field extraction (skills, exp, etc)
# πŸ”² jd_parser.py Step 5 β€” Job description parsing
# πŸ”² matcher.py Step 6 β€” Scoring engine
# πŸ”² explainer.py Step 7 β€” Summary + interview question generation
# =============================================================================
# ── Standard library ──────────────────────────────────────────────────────────
import os
import sys
# Ensure project root is always on the path so config.py is importable
# regardless of where you run Python from
_ENGINE_DIR = os.path.dirname(os.path.abspath(__file__))
_PROJECT_ROOT = os.path.dirname(_ENGINE_DIR)
if _PROJECT_ROOT not in sys.path:
sys.path.insert(0, _PROJECT_ROOT)
# =============================================================================
# βœ… STEP 3 β€” parser.py
# Text extraction from PDF and DOCX resume files
# =============================================================================
try:
from engine.parser import (
extract_text, # Route any file to the correct extractor
extract_text_from_pdf, # PDF-specific extractor (pdfplumber)
extract_text_from_docx, # DOCX-specific extractor (python-docx)
load_resumes_from_folder, # Batch-load all resumes from a folder
clean_text, # Internal text cleaner (useful for JD text too)
)
_PARSER_OK = True
except (ImportError, SyntaxError, Exception) as e:
_PARSER_OK = False
import warnings
warnings.warn(f"[engine] parser.py not available: {e}", ImportWarning)
# =============================================================================
# βœ… STEP 2 β€” database.py
# All SQLite read/write operations
# =============================================================================
try:
from engine.database import (
init_db, # Create all tables (run once on startup)
insert_resume, # Insert one parsed resume β†’ returns resume_id
insert_jd, # Insert one job description β†’ returns jd_id
insert_match_result, # Insert one scored match β†’ returns match_id
get_all_resumes, # Fetch all resumes as list of dicts
get_resume_by_id, # Fetch one resume by resume_id
get_all_jds, # Fetch all job descriptions
get_matches_by_jd, # Fetch all matches for a JD, sorted by score
export_matches_to_csv, # Save match results to a CSV file
)
_DATABASE_OK = True
except (ImportError, SyntaxError, Exception) as e:
_DATABASE_OK = False
import warnings
warnings.warn(f"[engine] database.py not available: {e}", ImportWarning)
# =============================================================================
# πŸ”² STEP 4 β€” extractor.py
# Structured field extraction from raw resume text
# (Skills, experience, education, stability, recency etc.)
# =============================================================================
try:
from engine.extractor import (
build_resume_record, # Master function β€” returns complete DB-ready dict
extract_candidate_name,
extract_contact,
extract_skills,
extract_soft_skills,
extract_experience,
extract_education,
extract_projects,
extract_certifications,
extract_recency,
)
_EXTRACTOR_OK = True
except (ImportError, SyntaxError, Exception):
_EXTRACTOR_OK = False # Silently skip β€” not built yet
# =============================================================================
# πŸ”² STEP 5 β€” jd_parser.py
# Job description parsing
# =============================================================================
try:
from engine.jd_parser import (
parse_jd_text, # Parse raw JD text β†’ structured dict
load_jd_from_file, # Load JD from .txt or .pdf file
)
_JD_PARSER_OK = True
except (ImportError, SyntaxError, Exception):
_JD_PARSER_OK = False
# =============================================================================
# πŸ”² STEP 6 β€” matcher.py
# Scoring engine β€” computes all 5 component scores + final weighted score
# =============================================================================
try:
from engine.matcher import (
match_resume_to_jd, # Master scorer β€” returns complete match dict
score_skill_match,
score_experience,
score_stability,
score_recency,
score_education,
compute_final_score,
)
_MATCHER_OK = True
except (ImportError, SyntaxError, Exception):
_MATCHER_OK = False
# =============================================================================
# πŸ”² STEP 7 β€” explainer.py
# Plain-language summaries + interview question generation
# =============================================================================
try:
from engine.explainer import (
generate_summary, # Build structured text explanation
generate_interview_questions, # Call OpenAI to generate questions
build_full_output, # Combine match result + summary + questions
)
_EXPLAINER_OK = True
except (ImportError, SyntaxError, Exception):
_EXPLAINER_OK = False
# =============================================================================
# PACKAGE STATUS β€” what is ready vs pending
# =============================================================================
# Dictionary you can query programmatically: engine.STATUS
STATUS = {
"parser" : _PARSER_OK,
"database" : _DATABASE_OK,
"extractor" : _EXTRACTOR_OK,
"jd_parser" : _JD_PARSER_OK,
"matcher" : _MATCHER_OK,
"explainer" : _EXPLAINER_OK,
}
# Convenience: list of modules that are fully ready
READY_MODULES = [name for name, ok in STATUS.items() if ok]
# =============================================================================
# SELF-TEST
# Run this file directly to see which modules are loaded:
# python engine/__init__.py
# =============================================================================
if __name__ == "__main__":
GREEN = "\033[92m"
RED = "\033[91m"
YELLOW = "\033[93m"
BOLD = "\033[1m"
RESET = "\033[0m"
step_map = {
"parser" : "Step 3",
"database" : "Step 2",
"extractor" : "Step 4",
"jd_parser" : "Step 5",
"matcher" : "Step 6",
"explainer" : "Step 7",
}
print(f"\n{BOLD}{'='*55}{RESET}")
print(f"{BOLD} RESUME ENGINE β€” MODULE STATUS{RESET}")
print(f"{BOLD}{'='*55}{RESET}\n")
all_built = ["parser", "database"] # steps confirmed built
for module, ok in STATUS.items():
step = step_map[module]
if ok:
tag = f"{GREEN}βœ… LOADED{RESET}"
elif module in all_built:
tag = f"{RED}βœ— FAILED TO IMPORT β€” check for errors in {module}.py{RESET}"
else:
tag = f"{YELLOW}πŸ”² NOT BUILT YET{RESET}"
print(f" {step:<8} {module:<12} {tag}")
built_count = sum(STATUS.values())
total = len(STATUS)
print(f"\n{BOLD} Progress: {built_count}/{total} modules loaded{RESET}")
if STATUS["parser"] and STATUS["database"]:
print(f"\n {GREEN}{BOLD}βœ“ Core modules ready β€” proceed to Step 4 (extractor.py){RESET}")
else:
print(f"\n {RED}Fix import errors above before proceeding.{RESET}")
print(f"\n{'='*55}\n")