Scoring & analysis
How reveilio scores resumes against job descriptions and what the result contains.
How scoring works
Reveilio performs resume extraction and scoring in a single LLM call. The prompt instructs the model to:
- Phase 1: Extract structured data from the resume (name, skills, experience, education, certifications, career gaps).
- Phase 2: Score the candidate against the JD using weighted criteria.
The model returns a single JSON document with both the extracted data and the analysis. This is faster and cheaper than making two separate calls, and produces more coherent results because the model reasons about the raw text and the scoring criteria simultaneously.
The seven scoring dimensions
Each dimension receives a score from 0 to 100, plus a written reasoning explaining
the score. The weights are configurable via configure(weights=...).
| Dimension | Default weight | What it measures |
|---|---|---|
| skills | 20% | Direct keyword match between JD required skills and resume skills. |
| semantic_skills | 20% | Conceptual overlap. A candidate who knows Flask may score well for a Django role because the underlying concepts are similar. |
| experience | 25% | Years of relevant experience, role progression, seniority alignment. |
| education | 15% | Degree relevance, institution prestige, academic achievements. |
| certifications | 10% | Professional certifications that match JD requirements. |
| soft_skills | 5% | Communication, leadership, teamwork, and other interpersonal skills. |
| domain_relevance | 5% | Industry-specific experience. A fintech role benefits from finance experience. |
The AnalysisResult object
Every call to analyze_resume() or score() returns an
AnalysisResult with these fields:
Core scores
| Field | Type | Description |
|---|---|---|
overall_score | float | 0 to 100 weighted composite score. |
confidence_level | string | "High", "Medium", or "Low". Reflects how confident the model is in its assessment. |
recommendation | string | "Shortlist", "Needs Review", or "Not Suitable". |
detailed_scores | dict | Per-dimension breakdown. Each key maps to {"score": 85, "reasoning": "..."}. |
Qualitative analysis
| Field | Type | Description |
|---|---|---|
ai_summary | string | A concise executive critique, approximately 120 words. Written as an objective assessment. |
strengths | list | What the candidate does well relative to the JD. Concrete and specific. |
weaknesses | list | Gaps between the candidate and the JD requirements. |
career_flags | list | Potential concerns such as frequent job changes, unexplained gaps, or misaligned career trajectory. |
reasoning | list | Step-by-step logic behind the overall score. |
experience_analysis | list | Deep dive into how the candidate's work history aligns with the role. |
Advanced metrics
| Field | Type | Description |
|---|---|---|
kpis | list | Key performance indicators derived from the resume (e.g. "Led a team of 12", "Reduced latency by 40%"). |
relevancy_metrics | list | Metrics such as "Average Tenure per Company", with value, relevancy level (high/medium/low), reasoning, and criteria definitions. |
suggested_roles | list | Alternative roles the candidate might be a better fit for, each with a match score. |
suggested_questions | list | 3 to 5 role-aligned interview questions. Only populated when recommendation is "Shortlist". Empty for "Needs Review" and "Not Suitable". |
Extracted candidate data
| Field | Description |
|---|---|
candidate_data.name | Candidate full name. |
candidate_data.email | Email address. |
candidate_data.skills | List of extracted skills. |
candidate_data.experience | List of positions with title, company, duration, description, location. |
candidate_data.education | List of degrees with institution, year, location. |
candidate_data.total_experience | Calculated total years of experience. |
candidate_data.career_gaps | Detected employment gaps. |
candidate_data.filename | Name of the source file. |
Single resume analysis
result = reveilio.analyze_resume("resumes/alice.pdf", jd)
print(result.overall_score) # 82.0
print(result.recommendation) # "Shortlist"
print(result.detailed_scores["skills"]["score"]) # 90
print(result.detailed_scores["skills"]["reasoning"]) # "Strong match..."
print(result.ai_summary) # 120-word critique
print(result.suggested_questions) # interview Qs
Batch folder analysis
analyze_folder() processes every supported file in a directory,
scores them in parallel using threads, sorts results by overall_score
descending, and assigns a 1-based rank.
results = reveilio.analyze_folder(
"./applicants",
jd,
extensions=(".pdf", ".docx"), # optional filter
max_workers=4, # parallel LLM calls
recursive=True, # include subfolders
)
for r in results:
print(f"#{r.rank} {r.candidate_data.name} {r.overall_score}%")
Error handling
If the LLM call fails for a specific resume (network error, malformed response, etc.), the scorer catches the exception and returns a safe fallback result with:
overall_score = 0confidence_level = "Low"recommendation = "Needs Review"- The error message in
ai_summary
This means a single bad resume in a 500-resume batch will not crash the entire run. You can detect error results by checking the summary:
errors = [r for r in results if "Error" in (r.ai_summary or "")]
print(f"{len(errors)} resume(s) failed analysis")
Customizing weights
Pass a custom weights dictionary to configure() to change what the
scorer optimizes for. The weights are embedded directly into the LLM prompt.
reveilio.configure(
provider="openai",
api_key="sk-...",
weights={
"skills": 0.35, # heavy emphasis on skills
"semantic_skills": 0.15,
"experience": 0.25,
"education": 0.05, # de-emphasize education
"certifications": 0.10,
"soft_skills": 0.05,
"domain_relevance": 0.05,
},
)
Continue to PDF reports.