-
Notifications
You must be signed in to change notification settings - Fork 0
Scoring
How reveilio scores resumes against job descriptions and what the result contains.
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 two separate calls, and produces more coherent results because the model reasons about the raw text and scoring criteria simultaneously.
Each dimension receives a score from 0 to 100, plus a written reasoning explaining the score. 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 overlap. |
| experience | 25% | Years of relevant experience, role progression, seniority alignment. |
| education | 15% | Degree relevance, institution prestige, academic achievements. |
| certifications | 10% | Professional certifications matching 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. |
Every call to analyze_resume() or score() returns an AnalysisResult with these fields.
| Field | Type | Description |
|---|---|---|
overall_score |
float | 0 to 100 weighted composite score. |
confidence_level |
string | "High", "Medium", or "Low". 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": "..."}. |
| Field | Type | Description |
|---|---|---|
ai_summary |
string | Concise executive critique, ~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 candidate and JD requirements. |
career_flags |
list | 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. |
| Field | Type | Description |
|---|---|---|
kpis |
list | KPIs derived from the resume (e.g. "Led a team of 12", "Reduced latency by 40%"). |
relevancy_metrics |
list | Metrics like "Average Tenure per Company" with value, relevancy level (high/medium/low), reasoning, criteria definitions. |
suggested_roles |
list | Alternative roles the candidate might be a better fit for, each with a match score. |
suggested_questions |
list | 3–5 role-aligned interview questions. Only populated when recommendation is "Shortlist". Empty for other outcomes. |
| 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. |
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 Qsanalyze_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}%")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
A single bad resume in a 500-resume batch will not crash the entire run. 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")Pass a custom weights dictionary to configure() to change what the scorer optimizes for. 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.
v0.1.1 · docs
Getting started
Core features
- Configuration & providers
- Job descriptions
- Resume parsing
- Scoring & analysis
- PDF reports
- Database storage
Using reveilio
Deployment
Deep dive